Checkwright v0.12.0

2026-07-22

Checkwright is the verification layer under agent orchestration, and this release makes the delegation budget oracle honest in the one direction that matters. Its post-login reroute used to fire ahead of the threshold compares and exit unconditionally as STALE — and STALE never blocks a dispatch, so a reading that should have refused an expensive delegation waved it through. The reroute now suppresses only the non-blocking outcome, and it stands down entirely when the usage trend log can prove the rate window already rolled.

Tightened gates

None. No gate landed or got stricter; the new coverage is test cases in delegation-kit’s own suites, which are not battery gates.

Renamed knobs

None.

Behavior changes

  • delegation-kit/bin/usage-verdict.sh — the post-login reroute (DELEGATION_KIT_LOGIN_WINDOW) is now asymmetric. It previously preceded both pause-axis compares and exited 2 unconditionally, so an over-threshold reading inside the login window printed STALE; because STALE is advisory and never blocks, an over-budget reading silently permitted the dispatch it existed to refuse. The verdict now evaluates both pause axes first and lets the reroute downgrade only an OK, never a PAUSE. The script’s # exit: header changed with it: exit 2 was documented as (fail-closed), which named the trust axis while reading as a claim about the blocking one, and now states the consequence — (budget unknown, never blocks). What a consumer reconciles: dispatches that previously proceeded during the login window on an over-threshold reading will now be blocked. That is the intended correction, but it is a live change in what the guard permits — a consumer who tuned around the old permissiveness should expect PAUSEs it did not see before.
  • delegation-kit/bin/usage-verdict.sh — the reroute now consults the usage trend log before deciding, so the verdict path reads a file it previously only appended to. A credentials-file mtime cannot distinguish an actual /login from a routine OAuth token rotation, so every rotation minted a fake auth event and blinded the verdict for the whole window — and rotations cluster around long-session resume, exactly when a verdict is asked for. Two witnesses of a genuine window roll are now read conjunctively from the newest history sample (the snapshot’s resets_at differing from that sample’s, and updated_at past the previous boundary); both firing disarms the reroute. The read is strictly fall-open — knob unset, file absent, or a malformed tail all leave the prior behavior — and it happens before the run’s own append, so the witness can only ever be a previous reading. What a consumer reconciles: nothing to configure, but DELEGATION_KIT_USAGE_HISTORY is now an input to the verdict and not only an output; a consumer pointing it at a shared or synthetic file should know that file now influences whether a dispatch is permitted.
  • delegation-kit/smoke/install.sh — the smoke now strips the whole DELEGATION_KIT_* namespace in one prelude instead of pinning knobs instance-by-instance. It previously pinned the credentials file and both pause thresholds but never neutralized DELEGATION_KIT_USAGE_HISTORY, so every smoke verdict appended a synthetic sample wherever ambient config pointed sampling — indistinguishable in shape from a real operator reading, and a real risk for any consumer whose history path is absolute. The credentials pin stays at each invocation, where check-test-hermetic reads it. What a consumer reconciles: a copied-out smoke carries the old instance-pinning shape and the same pollution exposure; re-sync it, or add the namespace strip to your copy.

Upgrading

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

No allowed reds. Tightened gates is empty, so a clean upgrade turns no gate red; a red after this sync is a defect, not a migration step.

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.