Checkwright v0.19.0

2026-07-31

Checkwright is the verification layer under agent orchestration, and this release closes a class where an assertion passes without asserting: the release note’s allowed-red declaration and the parser reading it disagreed, so a note naming several gates compiled to an empty set and reported a vacuous pass. It also gives the pre-release containment proof something to prove before the tag, and lands a gate for the workflow job that calls gh with no repository to resolve.

Tightened gates

  • check-action-gh-repo — new, in gate-sdk. Reds once per job whose run: bodies invoke gh while the job establishes no repository context. Such a job cannot resolve a target repository and dies on fatal: not a git repository before its first API call — this repo’s own v0.17.0 release job did exactly that, in seconds, on its first live run. Clear it on any of three arms: an actions/checkout step ordered before the first gh call, GH_REPO set at workflow, job, or invoking-step level, or --repo on every detected call in the job. The --repo arm is universally quantified rather than satisfied by a witness, so a job mixing prefixed and unprefixed calls still reds. A job that must stand outside the assertion takes a # gh-repo-exempt: <reason> marker, which requires a non-empty reason.

Renamed knobs

None. The new tightened-gates declaration surface derives its path from the existing GATE_SDK_WORKFLOW_DIR and adds no knob of its own — deliberately, since a knob naming that file would add a way to configure the assertion away without adding a way to satisfy it honestly.

Behavior changes

  • gate-sdk/bin/upgrade-smoke.sh — the containment step changes on both of its arms. When TO is untagged (the HEAD default) it now reads the tightened-gates declaration surface out of TO’s tree instead of resolving no note at all; previously an untagged TO resolved an empty declaration, so the red set had to be empty, and the standing pre-release assertion was satisfiable only by an iteration that tightened nothing. When TO is tagged it resolves the note as before, but a declaration that does not parse is now a loud failure rather than a silently empty allowed-red set. You reconcile only if you run the smoke against an untagged tree that tightens gates: add a tracked <workflow-dir>/tightened-gates.txt carrying a # contract: header line and one bare gate name per data line. An absent file is still tolerated on a green battery — it fails only when there is a red to contain, and then it says so.
  • gate-sdk/lib/declaration.sh — new, and it is now the single parser behind every reader of a tightened-gates declaration, over two container arms and one token predicate. With it, the note’s Tightened-gates lead token has one canonical spelling: a backticked, unbolded bare gate name directly after the bullet marker. The invariant that closes the class is independent of the spelling — a Tightened-gates section resolves to an explicit “None” or to a non-empty token set, and a non-“None” section yielding no token is a failure rather than a declaration of nothing. Twelve bullets across seven shipped notes were restyled to the canonical form, so an older note now resolves to the token set it always claimed; no note’s claim changed. Reconcile if you parse these notes yourself (use the shipped parser) or keep a note corpus in this grammar (restyle bolded lead tokens).
  • lifecycle-kit/templates/stages/build.md — the build stage now appends every gate it lands or tightens to the declaration surface, in the same commit, and only for gates a vendored tree can run. Build is the only stage that knows what it tightened at the moment it tightens it, which is what keeps the declaration written from knowledge rather than reconstructed from a red. If you have copied this template out, add that step; the release step composes the note’s Tightened gates section from the surface and drains it at the tag.

Upgrading

Replace the vendored kit directories wholesale at v0.19.0, then regenerate the generated artifacts — the pre-commit hook and the graph projection. Then run the full battery.

The allowed red. check-action-gh-repo is new: register it, then clear it by giving each flagged job a repository context on one of the three arms named above, or by marking a job exempt with a stated reason.

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.