Checkwright v0.20.0
2026-08-01
Checkwright is the verification layer under agent orchestration, and this release puts the release pointer itself under a probe. A GitHub Release body lives on the host, out of every gate’s reach, so the one artifact that tells a reader where a release is documented was governed by nothing but the hand that wrote it — and it had already shipped empty once, and shipped a URL that 404s once. The daily site-health monitor now reads every published Release body and asserts both that it points at its note and that the URLs it carries actually resolve.
Tightened gates
None. The release-body arm is a monitor arm, not a battery gate: it joins no
gates.list, reds only its own scheduled run, and signals by filing a
site-health issue. Nothing in a clean upgrade turns red because of it.
Renamed knobs
None. The template gains three RELEASE_NOTE_* values, added rather than renamed
or removed. They are step-level workflow env in a file you copy and edit, not
SITE_KIT_* kit knobs — deliberately, since a copied workflow must not reach into
a vendored gates directory to resolve its own configuration.
Behavior changes
site-kit/templates/site-health.yml— the scheduled probe gains a sixth arm over release-note pointers, and the workflow’spermissions:block gainscontents: readto feed it. For every tracked note whose front-matter tag key names a tag that exists on the remote, the arm reads that tag’s GitHub Release body and makes two assertions over two different strings: presence, that the body contains the note’s apex URL as derived from the note’s filename, and resolution, that every apex URL literally written in the body answers 200. They are not collapsible — a trailing-slash URL contains its own bare form, so a presence check alone passes on a link that 404s live, which is one of the two defects the arm exists for. Three refusals ride with it, each a silent-green path closed: the tag list comes from the API rather thangit tag, because a depth-1 checkout fetches no tags and a git-driven arm would report zero released notes forever; theghcall is asserted on its own exit status rather than inferred from the resulting count, because the step runs underset +eand a failed call otherwise yields an empty tag list and a clean run; and pagination is consumed by streaming names rather than by alengthquery, which returns the last page’s count. A census line states which zero-case a reader is in. Reconcile if you have copied this template out: re-copy it, then either setRELEASE_NOTE_GLOB/RELEASE_NOTE_TAG_KEY/RELEASE_NOTE_URL_PATHand keep thecontents: readscope, or delete the arm together with its three env if you publish no release notes.RELEASE_NOTE_URL_PATHis the value worth checking twice — it must match the URL form your host actually serves and the form your Release bodies are written to carry. Apermissions:block is an allowlist rather than an addition, so omittingcontents: readmakes the arm’s reads return 404, which reads like “no such Release” rather than “not permitted”.
Upgrading
Replace the vendored kit directories wholesale at v0.20.0, then regenerate the
generated artifacts — the pre-commit hook and the graph projection. Then run the
full battery.
No allowed reds. This release tightens no gate; the new assertion is a monitor arm and cannot red your battery. The work, if any, is the template re-copy named above, and it is yours only if you had copied the workflow out.
The behavior changes above are declared for reading, not a mechanical scan. If a gate reds that this note does not name, the upgrade smoke was supposed to catch it first — open an issue, because that is a defect in the release rather than work for you.