Checkwright v0.26.0
2026-09-26
Checkwright is the verification layer under agent orchestration, and this release adds a one-step CI action and a demo command, and moves every kit’s configuration onto knob files. It batches every change declared since v0.25.0, so the sections below are long; the brief says what to do first.
In brief
- You must act on your configuration. Every kit now reads its settings from a
.knobsfile, and a left-behind<stem>-config.shin your gates directory refuses the gates that read it. Rewrite what you set into the matching.knobsfile and delete the shell file; a copyinitseeded that you never edited is simply deleted. - Some knobs were renamed or removed. Renamed knobs below lists each one with what to change in your config.
- CI now takes one step.
initseeds a GitHub workflow that runs the battery at the release you installed and marks each red on the pull request; an existing install gets it onupdate. - A new
democommand runs the adoption arc in a throwaway repository of its own: install, a green battery, and a task marked done with no evidence, caught and withdrawn. Your tree is never touched. - Many gates are new or stricter. Expect reds on your first battery after upgrading; each is named under Tightened gates with what clears it.
Tightened gates
-
check-gate-exemption-tasks— the port oracle’s exclusion corpus was narrower than its own directive; widened, so the gate can now red on a# port-until:hold it previously could not see. It is zero-config, so it reaches every vendored tree. It also reads gate-sdk’s knobs from a knob file now, so a left-behind<gates-dir>/gate-sdk-config.shrefuses it at exit 2, including the one an earlierinitwrote beside the gate binary — rewrite what you set intogate-sdk-config.knobsand delete the shell config. -
check-survey-record— every word-bounded 7–40-character lowercase-hex run carrying a letter inside a survey record’scorpus,oracle,findingorinferredfield must resolve to a real git object, catching a minted identifier that fakes a citation’s precision; and every block must now carry a non-empty- inferred:line (each claim no command established, or the literalnone) in place of the retired- edges:line. A survey record mid-iteration at upgrade reds until its blocks are re-keyed tocorpus/oracle/rev/finding/inferred, or until the next scope boundary truncates it. It also reads lifecycle-kit’s knobs from a knob file now, so a left-behind<gates-dir>/lifecycle-config.shrefuses it at exit 2 — rewrite what you set into the.knobsfile and delete the shell config. It also reads gate-sdk’s knobs from a knob file now, so a left-behind<gates-dir>/gate-sdk-config.shrefuses it at exit 2, including the one an earlierinitwrote beside the gate binary — rewrite what you set intogate-sdk-config.knobsand delete the shell config. -
check-evidence-baseline— gains a fifth arm, flip causation: a row heldfail/ignorewhose scenario waspassin the baseline at the iteration-start commit must carryreproduces-at=<rev>naming that commit or an ancestor of it, and every such token must resolve and sit outside the iteration. It takes the state file as a new third positional (defaultEVIDENCE_KIT_STATE_FILE) and is disarmed, saying so on its clean line, wherever no iteration-start commit resolves — a shallow CI clone included. If a held row of yours flipped this iteration, reproduce its red at the iteration-start commit and add the token, or fix the regression; a fixture or wrapper passing only two positionals now reads your state file. It also gains a fourth arm: every configured suite must carry at least one baseline row. It also reads evidence-kit’s knobs from a knob file now, so a left-behind<gates-dir>/evidence-config.shrefuses it at exit 2, including the copy an earlierinitseeded that you never edited — rewrite what you set into the.knobsfile and delete the shell config. It also reads gate-sdk’s knobs from a knob file now, so a left-behind<gates-dir>/gate-sdk-config.shrefuses it at exit 2, including the one an earlierinitwrote beside the gate binary — rewrite what you set intogate-sdk-config.knobsand delete the shell config. -
check-action-permissions— new: a workflow job that consumes the GitHub token must declare its scopes rather than inherit the repository default. It also reads gate-sdk’s knobs from a knob file now, so a left-behind<gates-dir>/gate-sdk-config.shrefuses it at exit 2, including the one an earlierinitwrote beside the gate binary — rewrite what you set intogate-sdk-config.knobsand delete the shell config. -
check-install-claimandcheck-payload-claim— the gates’ own rules stand still, but their input moved: the manifest finder’s two configured branches now prune, so if you setCANON_KIT_MANIFEST_FILESorCANON_KIT_PROSE_SURFACE_GLOBSand the doc carrying your primary-install-transport or payload-disclosure declaration was reached through a glob crossing aGATE_SDK_PRUNE_DIRSdirectory, it leaves the governed-doc set and the gate reds on a zero count where it was green. Both are the only members of this corpus that red on a count rather than on a violation, so no other reader of it can move this way. Remedy: name that doc’s path in the knob outright rather than reaching it through a**. -
check-docs-liquid-parse— new in site-kit,on-surface, with the knobSITE_KIT_LIQUID_PARSERdefaulting to a ruby Liquid parse; where you register it, it needs ruby with theliquidgem. Every Liquid-processed docs file must parse, so a page carrying an unbalanced output delimiter or an unclosed tag reds — wrap text a page means literally in a raw block, or remove the token. -
check-action-job-ref— new, opt-in: a backticked span matching one of yourGATE_SDK_JOB_REF_PATTERNSmust name a job some workflow in the tree defines. The knob defaults empty, so the gate is a clean skip until you list the job-name patterns your docs cite. -
check-action-run-shell— resolves an absentshell:key’s dialect fromruns-oninstead of assuming bash (a Windows runner defaults topwsh), and refuses adefaults.runsubtree whose dialect it cannot resolve. It also reads gate-sdk’s knobs from a knob file now, so a left-behind<gates-dir>/gate-sdk-config.shrefuses it at exit 2, including the one an earlierinitwrote beside the gate binary — rewrite what you set intogate-sdk-config.knobsand delete the shell config. -
check-template-registry-parity— the population predicate widens so a native-dispatch registry stays gated after its sibling shell directory is deleted. It also reads gate-sdk’s knobs from a knob file now, so a left-behind<gates-dir>/gate-sdk-config.shrefuses it at exit 2, including the one an earlierinitwrote beside the gate binary — rewrite what you set intogate-sdk-config.knobsand delete the shell config. -
check-path-dialect— new: a path value reaching a dialect-sensitive consumer (a shellcd, or a Rust path API) must be cleared for that substrate at the occurrence. It also reads gate-sdk’s knobs from a knob file now, so a left-behind<gates-dir>/gate-sdk-config.shrefuses it at exit 2, including the one an earlierinitwrote beside the gate binary — rewrite what you set intogate-sdk-config.knobsand delete the shell config. -
check-gate-substrate-parity— assertion G widens to the union of the declaration set and the tracked shell tree, so a malformed port declaration on an unregistered shell script is caught rather than counted as owed. It also reads canon-kit’s, evidence-kit’s, lifecycle-kit’s, and queue-kit’s knobs from knob files now, so a left-behind<gates-dir>/canon-config.sh,evidence-config.sh,lifecycle-config.sh, orqueue-config.shrefuses it at exit 2 — rewrite what you set into the matching.knobsfile and delete the shell config. It also reads gate-sdk’s knobs from a knob file now, so a left-behind<gates-dir>/gate-sdk-config.shrefuses it at exit 2, including the one an earlierinitwrote beside the gate binary — rewrite what you set intogate-sdk-config.knobsand delete the shell config. -
check-stage-skill-coverage— gains a third direction: every configured stage’s executed surface must cite the stage-journal closing step. It also reads lifecycle-kit’s knobs from a knob file now, so a left-behind<gates-dir>/lifecycle-config.shrefuses it at exit 2 — rewrite what you set into the.knobsfile and delete the shell config. -
check-skill-binding— the lead template gains anopen-authorization-channelbinding slot, and an unbound slot reds a vendoring consumer until it is bound. It also reads lifecycle-kit’s knobs from a knob file now, so a left-behind<gates-dir>/lifecycle-config.shrefuses it at exit 2 — rewrite what you set into the.knobsfile and delete the shell config. -
check-portability-floor— new: no file on the configured adopter-install-path corpus may use a banned non-portable shell construct without a# portability-declared:valve; absent config disables it. It also reads gate-sdk’s knobs from a knob file now, so a left-behind<gates-dir>/gate-sdk-config.shrefuses it at exit 2, including the one an earlierinitwrote beside the gate binary — rewrite what you set intogate-sdk-config.knobsand delete the shell config. -
check-amendment-retired-spelling— new: every amendment carries a## Retired spellingsblock, and each declared spelling survives only at a path the amendment’s update-target roster names. It also reads canon-kit’s knobs from a knob file now, so a left-behind<gates-dir>/canon-config.shrefuses it at exit 2 — rewrite what you set into the.knobsfile and delete the shell config. It also reads gate-sdk’s knobs from a knob file now, so a left-behind<gates-dir>/gate-sdk-config.shrefuses it at exit 2, including the one an earlierinitwrote beside the gate binary — rewrite what you set intogate-sdk-config.knobsand delete the shell config. -
check-doctrine-registration— gains assertion F: an installed digest bullet’s text must match its doctrine rule’sDigest:trailer verbatim. It also reads doctrine-kit’s knobs from a knob file now, so a left-behind<gates-dir>/doctrine-config.shrefuses it at exit 2 — rewrite what you set into the.knobsfile and delete the shell config. -
check-tag-lead-line— the class table gains[observed-by: <producer>]as a governed tag. It also reads queue-kit’s knobs from a knob file now, so a left-behind<gates-dir>/queue-config.shrefuses it at exit 2 — rewrite what you set into the.knobsfile and delete the shell config. It also reads gate-sdk’s knobs from a knob file now, so a left-behind<gates-dir>/gate-sdk-config.shrefuses it at exit 2, including the one an earlierinitwrote beside the gate binary — rewrite what you set intogate-sdk-config.knobsand delete the shell config. -
check-deferred-board-tags— new, opt-in: every top-level deferred queue entry carries exactly one valid[cost:]and one valid[surface:]tag, and no active entry carries either. It also reads queue-kit’s knobs from a knob file now, so a left-behind<gates-dir>/queue-config.shrefuses it at exit 2 — rewrite what you set into the.knobsfile and delete the shell config. It also reads gate-sdk’s knobs from a knob file now, so a left-behind<gates-dir>/gate-sdk-config.shrefuses it at exit 2, including the one an earlierinitwrote beside the gate binary — rewrite what you set intogate-sdk-config.knobsand delete the shell config. -
check-surface-ratchet— new: every governed always-loaded surface is held at or below its committed line-count ceiling. It also reads context-kit’s knobs from a knob file now, so a left-behind<gates-dir>/context-config.shrefuses it at exit 2 — rewrite what you set into the.knobsfile and delete the shell config. It also reads gate-sdk’s knobs from a knob file now, so a left-behind<gates-dir>/gate-sdk-config.shrefuses it at exit 2, including the one an earlierinitwrote beside the gate binary — rewrite what you set intogate-sdk-config.knobsand delete the shell config. -
check-brevity— governs a configurable section set and every top-level bullet, not only bold-named ones. It also reads context-kit’s knobs from a knob file now, so a left-behind<gates-dir>/context-config.shrefuses it at exit 2 — rewrite what you set into the.knobsfile and delete the shell config. -
check-docs-cmd— gains assertion C: a path cited in an inline code span in the governed doc set reds when the repository has retired it (deleted in reachable history, or deleted in the index) and it resolves under neither the doc’s directory, the repo root nor any kit root, unless check-manifest-temporal’s valves mark the site as history. A doc citing a script your tree deleted now reds until the citation is re-pointed or the line carries<!-- manifest-temporal-exempt: <reason> -->. Assertion C also reads a bare amendment basename in a code span (one segment matchingCANON_KIT_AMENDMENT_GLOB,SPEC-x.mdby default) and reds it when no tracked file carries that basename and a deleted one did; cite the owning SPEC section in place of a merged amendment’s name, or valve the line as history. It also reads canon-kit’s knobs from a knob file now, so a left-behind<gates-dir>/canon-config.shrefuses it at exit 2 — rewrite what you set into the.knobsfile and delete the shell config. It also reads gate-sdk’s knobs from a knob file now, so a left-behind<gates-dir>/gate-sdk-config.shrefuses it at exit 2, including the one an earlierinitwrote beside the gate binary — rewrite what you set intogate-sdk-config.knobsand delete the shell config. -
check-agent-tier-explicit— reads delegation-kit’s knobs from a knob file now, so a left-behind<gates-dir>/delegation-config.shrefuses it at exit 2, including the copy an earlierinitseeded that you never edited — rewrite what you set into the.knobsfile and delete the shell config. It also reads gate-sdk’s knobs from a knob file now, so a left-behind<gates-dir>/gate-sdk-config.shrefuses it at exit 2, including the one an earlierinitwrote beside the gate binary — rewrite what you set intogate-sdk-config.knobsand delete the shell config. -
check-amendment-queue— reads canon-kit’s knobs from a knob file now, so a left-behind<gates-dir>/canon-config.shrefuses it at exit 2, including the copy an earlierinitseeded that you never edited — rewrite what you set into the.knobsfile and delete the shell config. It also reads gate-sdk’s knobs from a knob file now, so a left-behind<gates-dir>/gate-sdk-config.shrefuses it at exit 2, including the one an earlierinitwrote beside the gate binary — rewrite what you set intogate-sdk-config.knobsand delete the shell config. -
check-amendment-update-target— reads canon-kit’s knobs from a knob file now, so a left-behind<gates-dir>/canon-config.shrefuses it at exit 2, including the copy an earlierinitseeded that you never edited — rewrite what you set into the.knobsfile and delete the shell config. It also reads gate-sdk’s knobs from a knob file now, so a left-behind<gates-dir>/gate-sdk-config.shrefuses it at exit 2, including the one an earlierinitwrote beside the gate binary — rewrite what you set intogate-sdk-config.knobsand delete the shell config. -
check-close-surfaces— reads lifecycle-kit’s knobs from a knob file now, so a left-behind<gates-dir>/lifecycle-config.shrefuses it at exit 2, including the copy an earlierinitseeded that you never edited — rewrite what you set into the.knobsfile and delete the shell config. It also reads gate-sdk’s knobs from a knob file now, so a left-behind<gates-dir>/gate-sdk-config.shrefuses it at exit 2, including the one an earlierinitwrote beside the gate binary — rewrite what you set intogate-sdk-config.knobsand delete the shell config. -
check-comment-tier— reads canon-kit’s knobs from a knob file now, so a left-behind<gates-dir>/canon-config.shrefuses it at exit 2, including the copy an earlierinitseeded that you never edited — rewrite what you set into the.knobsfile and delete the shell config. It also reads gate-sdk’s knobs from a knob file now, so a left-behind<gates-dir>/gate-sdk-config.shrefuses it at exit 2, including the one an earlierinitwrote beside the gate binary — rewrite what you set intogate-sdk-config.knobsand delete the shell config. -
check-deprecation-task— reads canon-kit’s knobs from a knob file now, so a left-behind<gates-dir>/canon-config.shrefuses it at exit 2, including the copy an earlierinitseeded that you never edited — rewrite what you set into the.knobsfile and delete the shell config. It also reads gate-sdk’s knobs from a knob file now, so a left-behind<gates-dir>/gate-sdk-config.shrefuses it at exit 2, including the one an earlierinitwrote beside the gate binary — rewrite what you set intogate-sdk-config.knobsand delete the shell config. -
check-docs-cname-parity— reads site-kit’s knobs from a knob file now, so a left-behind<gates-dir>/site-config.shrefuses it at exit 2, including the copy an earlierinitseeded that you never edited — rewrite what you set into the.knobsfile and delete the shell config. It also reads gate-sdk’s knobs from a knob file now, so a left-behind<gates-dir>/gate-sdk-config.shrefuses it at exit 2, including the one an earlierinitwrote beside the gate binary — rewrite what you set intogate-sdk-config.knobsand delete the shell config. -
check-docs-link-convention— reads canon-kit’s knobs from a knob file now, so a left-behind<gates-dir>/canon-config.shrefuses it at exit 2, including the copy an earlierinitseeded that you never edited — rewrite what you set into the.knobsfile and delete the shell config. -
check-docs-render-fidelity— reads site-kit’s knobs from a knob file now, so a left-behind<gates-dir>/site-config.shrefuses it at exit 2, including the copy an earlierinitseeded that you never edited — rewrite what you set into the.knobsfile and delete the shell config. It also reads gate-sdk’s knobs from a knob file now, so a left-behind<gates-dir>/gate-sdk-config.shrefuses it at exit 2, including the one an earlierinitwrote beside the gate binary — rewrite what you set intogate-sdk-config.knobsand delete the shell config. -
check-enforcement-fresh— reads canon-kit’s, context-kit’s, drift-kit’s, evidence-kit’s, and lifecycle-kit’s knobs from knob files now, so a left-behind<gates-dir>/canon-config.sh,context-config.sh,drift-config.sh,evidence-config.sh, orlifecycle-config.shrefuses it at exit 2, including the copy an earlierinitseeded that you never edited — rewrite what you set into the matching.knobsfile and delete the shell config. It also reads gate-sdk’s knobs from a knob file now, so a left-behind<gates-dir>/gate-sdk-config.shrefuses it at exit 2, including the one an earlierinitwrote beside the gate binary — rewrite what you set intogate-sdk-config.knobsand delete the shell config. -
check-footprint-fresh— reads context-kit’s knobs from a knob file now, so a left-behind<gates-dir>/context-config.shrefuses it at exit 2, including the copy an earlierinitseeded that you never edited — rewrite what you set into the.knobsfile and delete the shell config. Its descriptor also couples*/SPEC.md, the kit roster its emitter derives, so a kit’sSPEC.mdarriving, leaving or changing now fires it: regenerate your hooks. -
check-gap-inbox-neutrality— reads lifecycle-kit’s knobs from a knob file now, so a left-behind<gates-dir>/lifecycle-config.shrefuses it at exit 2, including the copy an earlierinitseeded that you never edited — rewrite what you set into the.knobsfile and delete the shell config. It also reads gate-sdk’s knobs from a knob file now, so a left-behind<gates-dir>/gate-sdk-config.shrefuses it at exit 2, including the one an earlierinitwrote beside the gate binary — rewrite what you set intogate-sdk-config.knobsand delete the shell config. -
check-gate-tamper— reads delegation-kit’s knobs from a knob file now, so a left-behind<gates-dir>/delegation-config.shrefuses it at exit 2, including the copy an earlierinitseeded that you never edited — rewrite what you set into the.knobsfile and delete the shell config. It also reads gate-sdk’s knobs from a knob file now, so a left-behind<gates-dir>/gate-sdk-config.shrefuses it at exit 2, including the one an earlierinitwrote beside the gate binary — rewrite what you set intogate-sdk-config.knobsand delete the shell config. -
check-graph— reads canon-kit’s, evidence-kit’s, lifecycle-kit’s, and queue-kit’s knobs from knob files now, so a left-behind<gates-dir>/canon-config.sh,evidence-config.sh,lifecycle-config.sh, orqueue-config.shrefuses it at exit 2, including the copy an earlierinitseeded that you never edited — rewrite what you set into the matching.knobsfile and delete the shell config. It also reads gate-sdk’s knobs from a knob file now, so a left-behind<gates-dir>/gate-sdk-config.shrefuses it at exit 2, including the one an earlierinitwrote beside the gate binary — rewrite what you set intogate-sdk-config.knobsand delete the shell config. It also reds aknob:token in a descriptor’scouples=ortrigger=, or in an amendment’s# graph:manifest, that names a word-list knob (a row declared.words(), such asGATE_SDK_KIT_DIRS): such a token is inert when the knob is unset and refused when it is set — drop the token and keep the descriptor’s literal globs. -
check-install-claim— reads canon-kit’s knobs from a knob file now, so a left-behind<gates-dir>/canon-config.shrefuses it at exit 2, including the copy an earlierinitseeded that you never edited — rewrite what you set into the.knobsfile and delete the shell config. It also reads gate-sdk’s knobs from a knob file now, so a left-behind<gates-dir>/gate-sdk-config.shrefuses it at exit 2, including the one an earlierinitwrote beside the gate binary — rewrite what you set intogate-sdk-config.knobsand delete the shell config. -
check-knob-citation— reads canon-kit’s knobs from a knob file now, so a left-behind<gates-dir>/canon-config.shrefuses it at exit 2, including the copy an earlierinitseeded that you never edited — rewrite what you set into the.knobsfile and delete the shell config. It also reads gate-sdk’s knobs from a knob file now, so a left-behind<gates-dir>/gate-sdk-config.shrefuses it at exit 2, including the one an earlierinitwrote beside the gate binary — rewrite what you set intogate-sdk-config.knobsand delete the shell config. -
check-knob-default-coupling— reads canon-kit’s knobs from a knob file now, so a left-behind<gates-dir>/canon-config.shrefuses it at exit 2, including the copy an earlierinitseeded that you never edited — rewrite what you set into the.knobsfile and delete the shell config. It also reads gate-sdk’s knobs from a knob file now, so a left-behind<gates-dir>/gate-sdk-config.shrefuses it at exit 2, including the one an earlierinitwrote beside the gate binary — rewrite what you set intogate-sdk-config.knobsand delete the shell config. -
check-lesson-disposition— reads lifecycle-kit’s knobs from a knob file now, so a left-behind<gates-dir>/lifecycle-config.shrefuses it at exit 2, including the copy an earlierinitseeded that you never edited — rewrite what you set into the.knobsfile and delete the shell config. It also reads gate-sdk’s knobs from a knob file now, so a left-behind<gates-dir>/gate-sdk-config.shrefuses it at exit 2, including the one an earlierinitwrote beside the gate binary — rewrite what you set intogate-sdk-config.knobsand delete the shell config. -
check-lifecycle-registration— reads lifecycle-kit’s knobs from a knob file now, so a left-behind<gates-dir>/lifecycle-config.shrefuses it at exit 2, including the copy an earlierinitseeded that you never edited — rewrite what you set into the.knobsfile and delete the shell config. It also reads gate-sdk’s knobs from a knob file now, so a left-behind<gates-dir>/gate-sdk-config.shrefuses it at exit 2, including the one an earlierinitwrote beside the gate binary — rewrite what you set intogate-sdk-config.knobsand delete the shell config. -
check-manifest-count— reads canon-kit’s knobs from a knob file now, so a left-behind<gates-dir>/canon-config.shrefuses it at exit 2, including the copy an earlierinitseeded that you never edited — rewrite what you set into the.knobsfile and delete the shell config. It also reads gate-sdk’s knobs from a knob file now, so a left-behind<gates-dir>/gate-sdk-config.shrefuses it at exit 2, including the one an earlierinitwrote beside the gate binary — rewrite what you set intogate-sdk-config.knobsand delete the shell config. -
check-manifest-temporal— reads canon-kit’s knobs from a knob file now, so a left-behind<gates-dir>/canon-config.shrefuses it at exit 2, including the copy an earlierinitseeded that you never edited — rewrite what you set into the.knobsfile and delete the shell config. It also reads gate-sdk’s knobs from a knob file now, so a left-behind<gates-dir>/gate-sdk-config.shrefuses it at exit 2, including the one an earlierinitwrote beside the gate binary — rewrite what you set intogate-sdk-config.knobsand delete the shell config. -
check-md-refs— reads canon-kit’s knobs from a knob file now, so a left-behind<gates-dir>/canon-config.shrefuses it at exit 2, including the copy an earlierinitseeded that you never edited — rewrite what you set into the.knobsfile and delete the shell config. It also reads gate-sdk’s knobs from a knob file now, so a left-behind<gates-dir>/gate-sdk-config.shrefuses it at exit 2, including the one an earlierinitwrote beside the gate binary — rewrite what you set intogate-sdk-config.knobsand delete the shell config. -
check-measured-claim— reads canon-kit’s knobs from a knob file now, so a left-behind<gates-dir>/canon-config.shrefuses it at exit 2, including the copy an earlierinitseeded that you never edited — rewrite what you set into the.knobsfile and delete the shell config. It also reads an inline<!-- measured: <key>=<value> -->written inside a prose line, binding the one sentence it follows, and a full-line marker’s claim loses any inline-bound sentence: a mid-line marker outside inline code that it used to ignore is now resolved against your oracle and can red — backtick a specimen, or fix the key and the sentence. -
check-memory-off— reads context-kit’s knobs from a knob file now, so a left-behind<gates-dir>/context-config.shrefuses it at exit 2, including the copy an earlierinitseeded that you never edited — rewrite what you set into the.knobsfile and delete the shell config. -
check-merge-attrs— reads lifecycle-kit’s knobs from a knob file now, so a left-behind<gates-dir>/lifecycle-config.shrefuses it at exit 2, including the copy an earlierinitseeded that you never edited — rewrite what you set into the.knobsfile and delete the shell config. It also reads gate-sdk’s knobs from a knob file now, so a left-behind<gates-dir>/gate-sdk-config.shrefuses it at exit 2, including the one an earlierinitwrote beside the gate binary — rewrite what you set intogate-sdk-config.knobsand delete the shell config. -
check-payload-claim— reads canon-kit’s knobs from a knob file now, so a left-behind<gates-dir>/canon-config.shrefuses it at exit 2, including the copy an earlierinitseeded that you never edited — rewrite what you set into the.knobsfile and delete the shell config. It also reads gate-sdk’s knobs from a knob file now, so a left-behind<gates-dir>/gate-sdk-config.shrefuses it at exit 2, including the one an earlierinitwrote beside the gate binary — rewrite what you set intogate-sdk-config.knobsand delete the shell config. -
check-prose-enum— the bundled--emit enum-setsarm now also declareskpi-builtin, the binary’s bundled KPI ids, so a consumer on the bundled sets command whose prose hand-lists two or more bundled KPI ids in a delimited run reds until the list names all of them or cites the set; a consumer-configured sets command is unaffected. Two members separated by whitespace alone no longer chain into a hand list, which only removes findings — aprose-enum-exempt:marker you added for two ordinary words side by side can be deleted. Its chaining test is also no longer length-capped: a separator carrying no letter, holding a delimiter or a singleand/or, chains two members whatever its length, where a gap over 8 bytes (16 withand/or) did not, and a digit or other non-letter beside the delimiter no longer breaks the chain — a hand list the caps hid now reds until it names every member or cites the set. It also reads canon-kit’s and queue-kit’s knobs from knob files now, so a left-behind<gates-dir>/canon-config.shorqueue-config.shrefuses it at exit 2, including the copy an earlierinitseeded that you never edited — rewrite what you set into the matching.knobsfile and delete the shell config. It also reads gate-sdk’s knobs from a knob file now, so a left-behind<gates-dir>/gate-sdk-config.shrefuses it at exit 2, including the one an earlierinitwrote beside the gate binary — rewrite what you set intogate-sdk-config.knobsand delete the shell config. -
check-prose-tells— reads canon-kit’s knobs from a knob file now, so a left-behind<gates-dir>/canon-config.shrefuses it at exit 2, including the copy an earlierinitseeded that you never edited — rewrite what you set into the.knobsfile and delete the shell config. -
check-queue-entry-budget— gains assertion (E): every top-level deferred entry must resolve a defer date, aSurfaced <date>orFiled <date>mark with the ISO date directly after it on one body line; an entry whose mark is lowercase, split from its date by a reflow, or separated from it by a word reds until respelled (the shipped queue template gains aFiledline for this reason). It also reads queue-kit’s knobs from a knob file now, so a left-behind<gates-dir>/queue-config.shrefuses it at exit 2, including the copy an earlierinitseeded that you never edited — rewrite what you set into the.knobsfile and delete the shell config. It also reads gate-sdk’s knobs from a knob file now, so a left-behind<gates-dir>/gate-sdk-config.shrefuses it at exit 2, including the one an earlierinitwrote beside the gate binary — rewrite what you set intogate-sdk-config.knobsand delete the shell config. -
check-queue-hygiene— reads queue-kit’s knobs from a knob file now, so a left-behind<gates-dir>/queue-config.shrefuses it at exit 2, including the copy an earlierinitseeded that you never edited — rewrite what you set into the.knobsfile and delete the shell config. It also reads gate-sdk’s knobs from a knob file now, so a left-behind<gates-dir>/gate-sdk-config.shrefuses it at exit 2, including the one an earlierinitwrote beside the gate binary — rewrite what you set intogate-sdk-config.knobsand delete the shell config. -
check-queue-prose-precondition— reads queue-kit’s knobs from a knob file now, so a left-behind<gates-dir>/queue-config.shrefuses it at exit 2, including the copy an earlierinitseeded that you never edited — rewrite what you set into the.knobsfile and delete the shell config. It also reads gate-sdk’s knobs from a knob file now, so a left-behind<gates-dir>/gate-sdk-config.shrefuses it at exit 2, including the one an earlierinitwrote beside the gate binary — rewrite what you set intogate-sdk-config.knobsand delete the shell config. -
check-queue-sections— reads queue-kit’s knobs from a knob file now, so a left-behind<gates-dir>/queue-config.shrefuses it at exit 2, including the copy an earlierinitseeded that you never edited — rewrite what you set into the.knobsfile and delete the shell config. It also reads gate-sdk’s knobs from a knob file now, so a left-behind<gates-dir>/gate-sdk-config.shrefuses it at exit 2, including the one an earlierinitwrote beside the gate binary — rewrite what you set intogate-sdk-config.knobsand delete the shell config. -
check-queue-slug-liveness— gains assertion B: on the surfaces a new knob,QUEUE_KIT_CITATION_SURFACE_GLOBS(default empty, so nothing changes until you set it), names, a single-backtick token naming a retired queue slug that is no tracked file’s stem reds; replace the slug with the owning SPEC section or the defect’s own description, or mark a history line<!-- retired-citation-exempt: <reason> -->. It also gains assertion C: in the queue file, a cited slug followed by(deferred),(icebox),(done)(your configured single-word section names, lowercased) or(retired)reds when the slug is not there; correct or drop the parenthetical. The gate now runsgitand readsQUEUE_KIT_DONE_SECTION, and its clean line’s wording changed, so re-pin a log-matching tool. It also reads queue-kit’s knobs from a knob file now, so a left-behind<gates-dir>/queue-config.shrefuses it at exit 2, including the copy an earlierinitseeded that you never edited — rewrite what you set into the.knobsfile and delete the shell config. It also reads gate-sdk’s knobs from a knob file now, so a left-behind<gates-dir>/gate-sdk-config.shrefuses it at exit 2, including the one an earlierinitwrote beside the gate binary — rewrite what you set intogate-sdk-config.knobsand delete the shell config. -
check-queue-wrap— reads queue-kit’s knobs from a knob file now, so a left-behind<gates-dir>/queue-config.shrefuses it at exit 2, including the copy an earlierinitseeded that you never edited — rewrite what you set into the.knobsfile and delete the shell config. It also reads gate-sdk’s knobs from a knob file now, so a left-behind<gates-dir>/gate-sdk-config.shrefuses it at exit 2, including the one an earlierinitwrote beside the gate binary — rewrite what you set intogate-sdk-config.knobsand delete the shell config. -
check-reads-couples— reads canon-kit’s, evidence-kit’s, lifecycle-kit’s, and queue-kit’s knobs from knob files now, so a left-behind<gates-dir>/canon-config.sh,evidence-config.sh,lifecycle-config.sh, orqueue-config.shrefuses it at exit 2, including the copy an earlierinitseeded that you never edited — rewrite what you set into the matching.knobsfile and delete the shell config. It also reads gate-sdk’s knobs from a knob file now, so a left-behind<gates-dir>/gate-sdk-config.shrefuses it at exit 2, including the one an earlierinitwrote beside the gate binary — rewrite what you set intogate-sdk-config.knobsand delete the shell config. It also asserts the coverage of canon-kit’s kit-literal fallback walks, which it skipped as?, on a tree that leavesCANON_KIT_MANIFEST_FILESorCANON_KIT_COMMENT_SURFACEempty; the shipped descriptors cover them, so it reds only where you shadow one of those members’ descriptors with narrower couples — widen them. It also asserts the coverage ofcheck-footprint-fresh’s kit-roster read, every*/SPEC.md, which that member declared as no walk at all; the shipped descriptor covers it, so it reds only where you shadow that descriptor with narrower couples — add*/SPEC.md. -
check-roadmap-fresh— reads queue-kit’s knobs from a knob file now, so a left-behind<gates-dir>/queue-config.shrefuses it at exit 2, including the copy an earlierinitseeded that you never edited — rewrite what you set into the.knobsfile and delete the shell config. It also reads gate-sdk’s knobs from a knob file now, so a left-behind<gates-dir>/gate-sdk-config.shrefuses it at exit 2, including the one an earlierinitwrote beside the gate binary — rewrite what you set intogate-sdk-config.knobsand delete the shell config. -
check-scratch-citation— reads lifecycle-kit’s knobs from a knob file now, so a left-behind<gates-dir>/lifecycle-config.shrefuses it at exit 2, including the copy an earlierinitseeded that you never edited — rewrite what you set into the.knobsfile and delete the shell config. It also reads gate-sdk’s knobs from a knob file now, so a left-behind<gates-dir>/gate-sdk-config.shrefuses it at exit 2, including the one an earlierinitwrote beside the gate binary — rewrite what you set intogate-sdk-config.knobsand delete the shell config. -
check-settings-paths— reads context-kit’s knobs from a knob file now, so a left-behind<gates-dir>/context-config.shrefuses it at exit 2, including the copy an earlierinitseeded that you never edited — rewrite what you set into the.knobsfile and delete the shell config. -
check-settings-pins— reads context-kit’s knobs from a knob file now, so a left-behind<gates-dir>/context-config.shrefuses it at exit 2, including the copy an earlierinitseeded that you never edited — rewrite what you set into the.knobsfile and delete the shell config. -
check-shim-restatement— reads lifecycle-kit’s knobs from a knob file now, so a left-behind<gates-dir>/lifecycle-config.shrefuses it at exit 2, including the copy an earlierinitseeded that you never edited — rewrite what you set into the.knobsfile and delete the shell config. It also reads gate-sdk’s knobs from a knob file now, so a left-behind<gates-dir>/gate-sdk-config.shrefuses it at exit 2, including the one an earlierinitwrote beside the gate binary — rewrite what you set intogate-sdk-config.knobsand delete the shell config. -
check-spec-derivable-section— reads canon-kit’s knobs from a knob file now, so a left-behind<gates-dir>/canon-config.shrefuses it at exit 2, including the copy an earlierinitseeded that you never edited — rewrite what you set into the.knobsfile and delete the shell config. It also reads gate-sdk’s knobs from a knob file now, so a left-behind<gates-dir>/gate-sdk-config.shrefuses it at exit 2, including the one an earlierinitwrote beside the gate binary — rewrite what you set intogate-sdk-config.knobsand delete the shell config. -
check-spec-dod-singleton— reads canon-kit’s knobs from a knob file now, so a left-behind<gates-dir>/canon-config.shrefuses it at exit 2, including the copy an earlierinitseeded that you never edited — rewrite what you set into the.knobsfile and delete the shell config. It also reads gate-sdk’s knobs from a knob file now, so a left-behind<gates-dir>/gate-sdk-config.shrefuses it at exit 2, including the one an earlierinitwrote beside the gate binary — rewrite what you set intogate-sdk-config.knobsand delete the shell config. -
check-spec-embedded-source— reads canon-kit’s knobs from a knob file now, so a left-behind<gates-dir>/canon-config.shrefuses it at exit 2, including the copy an earlierinitseeded that you never edited — rewrite what you set into the.knobsfile and delete the shell config. It also reads gate-sdk’s knobs from a knob file now, so a left-behind<gates-dir>/gate-sdk-config.shrefuses it at exit 2, including the one an earlierinitwrote beside the gate binary — rewrite what you set intogate-sdk-config.knobsand delete the shell config. -
check-spec-fence-balance— reads canon-kit’s knobs from a knob file now, so a left-behind<gates-dir>/canon-config.shrefuses it at exit 2, including the copy an earlierinitseeded that you never edited — rewrite what you set into the.knobsfile and delete the shell config. It also reads gate-sdk’s knobs from a knob file now, so a left-behind<gates-dir>/gate-sdk-config.shrefuses it at exit 2, including the one an earlierinitwrote beside the gate binary — rewrite what you set intogate-sdk-config.knobsand delete the shell config. -
check-spec-pointer— the prose pass now reads a§citation with no path, resolving it against the headings of your whole manifest set, and a markdown link followed by§, resolving it against the link target; it also reds a manifest file carrying one qualifier-stripped heading title twice. A heading may be cited by its lead clause, the text before its first comma, em dash or colon. Fix each new red by citing a heading that exists (a bold paragraph lead-in is not a heading, so cite its enclosing heading), by writing a grammar placeholder as§<heading>, or by renaming one of two same-titled headings apart and re-reading its inbound pointers; the clean line’s wording changed, so re-pin a log-matching tool. It also reads canon-kit’s knobs from a knob file now, so a left-behind<gates-dir>/canon-config.shrefuses it at exit 2, including the copy an earlierinitseeded that you never edited — rewrite what you set into the.knobsfile and delete the shell config. It also reads gate-sdk’s knobs from a knob file now, so a left-behind<gates-dir>/gate-sdk-config.shrefuses it at exit 2, including the one an earlierinitwrote beside the gate binary — rewrite what you set intogate-sdk-config.knobsand delete the shell config. -
check-stage-entry— reads lifecycle-kit’s knobs from a knob file now, so a left-behind<gates-dir>/lifecycle-config.shrefuses it at exit 2, including the copy an earlierinitseeded that you never edited — rewrite what you set into the.knobsfile and delete the shell config. It also reads gate-sdk’s knobs from a knob file now, so a left-behind<gates-dir>/gate-sdk-config.shrefuses it at exit 2, including the one an earlierinitwrote beside the gate binary — rewrite what you set intogate-sdk-config.knobsand delete the shell config. -
check-stage-evidence— reads lifecycle-kit’s knobs from a knob file now, so a left-behind<gates-dir>/lifecycle-config.shrefuses it at exit 2, including the copy an earlierinitseeded that you never edited — rewrite what you set into the.knobsfile and delete the shell config. It also reads gate-sdk’s knobs from a knob file now, so a left-behind<gates-dir>/gate-sdk-config.shrefuses it at exit 2, including the one an earlierinitwrote beside the gate binary — rewrite what you set intogate-sdk-config.knobsand delete the shell config. -
check-surface-duplication— reads canon-kit’s knobs from a knob file now, so a left-behind<gates-dir>/canon-config.shrefuses it at exit 2, including the copy an earlierinitseeded that you never edited — rewrite what you set into the.knobsfile and delete the shell config. It also reads gate-sdk’s knobs from a knob file now, so a left-behind<gates-dir>/gate-sdk-config.shrefuses it at exit 2, including the one an earlierinitwrote beside the gate binary — rewrite what you set intogate-sdk-config.knobsand delete the shell config. -
check-task-conservation— reads queue-kit’s knobs from a knob file now, so a left-behind<gates-dir>/queue-config.shrefuses it at exit 2, including the copy an earlierinitseeded that you never edited — rewrite what you set into the.knobsfile and delete the shell config. It also reads gate-sdk’s knobs from a knob file now, so a left-behind<gates-dir>/gate-sdk-config.shrefuses it at exit 2, including the one an earlierinitwrote beside the gate binary — rewrite what you set intogate-sdk-config.knobsand delete the shell config. -
check-task-names— reads queue-kit’s knobs from a knob file now, so a left-behind<gates-dir>/queue-config.shrefuses it at exit 2, including the copy an earlierinitseeded that you never edited — rewrite what you set into the.knobsfile and delete the shell config. It also reads gate-sdk’s knobs from a knob file now, so a left-behind<gates-dir>/gate-sdk-config.shrefuses it at exit 2, including the one an earlierinitwrote beside the gate binary — rewrite what you set intogate-sdk-config.knobsand delete the shell config. -
check-todo-task-liveness— reads canon-kit’s knobs from a knob file now, so a left-behind<gates-dir>/canon-config.shrefuses it at exit 2, including the copy an earlierinitseeded that you never edited — rewrite what you set into the.knobsfile and delete the shell config. It also reads gate-sdk’s knobs from a knob file now, so a left-behind<gates-dir>/gate-sdk-config.shrefuses it at exit 2, including the one an earlierinitwrote beside the gate binary — rewrite what you set intogate-sdk-config.knobsand delete the shell config. -
check-tracking-claim— reads canon-kit’s knobs from a knob file now, so a left-behind<gates-dir>/canon-config.shrefuses it at exit 2, including the copy an earlierinitseeded that you never edited — rewrite what you set into the.knobsfile and delete the shell config. It also reads gate-sdk’s knobs from a knob file now, so a left-behind<gates-dir>/gate-sdk-config.shrefuses it at exit 2, including the one an earlierinitwrote beside the gate binary — rewrite what you set intogate-sdk-config.knobsand delete the shell config. -
check-unmarked-claim— reads canon-kit’s knobs from a knob file now, so a left-behind<gates-dir>/canon-config.shrefuses it at exit 2, including the copy an earlierinitseeded that you never edited — rewrite what you set into the.knobsfile and delete the shell config. It also takes an inlinemeasured:marker as discharging a class match that starts inside the sentence it binds, and no other; nothing that passed before reds. A full-line marker now discharges only the claim it binds, where it discharged its whole paragraph: underCANON_KIT_MEASURED_SPAN=sentencethat is the marker’s first sentence, and at every span a class match above a mid-paragraph marker is unmarked — mark the later sentence inline, move the marker above the claim, or rewrite the sentence out of the class. -
check-battery-roster— reads evidence-kit’s knobs from a knob file now, so a left-behind<gates-dir>/evidence-config.shrefuses it at exit 2, including the copy an earlierinitseeded that you never edited — rewrite what you set into the.knobsfile and delete the shell config. It also reads gate-sdk’s knobs from a knob file now, so a left-behind<gates-dir>/gate-sdk-config.shrefuses it at exit 2, including the one an earlierinitwrote beside the gate binary — rewrite what you set intogate-sdk-config.knobsand delete the shell config. -
check-evidence-manifest— reads evidence-kit’s knobs from a knob file now, so a left-behind<gates-dir>/evidence-config.shrefuses it at exit 2, including the copy an earlierinitseeded that you never edited — rewrite what you set into the.knobsfile and delete the shell config. It also reads gate-sdk’s knobs from a knob file now, so a left-behind<gates-dir>/gate-sdk-config.shrefuses it at exit 2, including the one an earlierinitwrote beside the gate binary — rewrite what you set intogate-sdk-config.knobsand delete the shell config. -
check-producer-liveness— reads evidence-kit’s knobs from a knob file now, so a left-behind<gates-dir>/evidence-config.shrefuses it at exit 2, including the copy an earlierinitseeded that you never edited — rewrite what you set into the.knobsfile and delete the shell config. It also reads gate-sdk’s knobs from a knob file now, so a left-behind<gates-dir>/gate-sdk-config.shrefuses it at exit 2, including the one an earlierinitwrote beside the gate binary — rewrite what you set intogate-sdk-config.knobsand delete the shell config. -
check-action-gh-repo— reads gate-sdk’s knobs from a knob file now, so a left-behind<gates-dir>/gate-sdk-config.shrefuses it at exit 2, including the one an earlierinitwrote beside the gate binary — rewrite what you set intogate-sdk-config.knobsand delete the shell config. -
check-action-pinning— reads gate-sdk’s knobs from a knob file now, so a left-behind<gates-dir>/gate-sdk-config.shrefuses it at exit 2, including the one an earlierinitwrote beside the gate binary — rewrite what you set intogate-sdk-config.knobsand delete the shell config. -
check-assertion-strength— reads gate-sdk’s knobs from a knob file now, so a left-behind<gates-dir>/gate-sdk-config.shrefuses it at exit 2, including the one an earlierinitwrote beside the gate binary — rewrite what you set intogate-sdk-config.knobsand delete the shell config. -
check-commit-msg— reads gate-sdk’s knobs from a knob file now, so a left-behind<gates-dir>/gate-sdk-config.shrefuses it at exit 2, including the one an earlierinitwrote beside the gate binary — rewrite what you set intogate-sdk-config.knobsand delete the shell config. -
check-commit-subject— reads gate-sdk’s knobs from a knob file now, so a left-behind<gates-dir>/gate-sdk-config.shrefuses it at exit 2, including the one an earlierinitwrote beside the gate binary — rewrite what you set intogate-sdk-config.knobsand delete the shell config. -
check-core-files— reads gate-sdk’s knobs from a knob file now, so a left-behind<gates-dir>/gate-sdk-config.shrefuses it at exit 2, including the one an earlierinitwrote beside the gate binary — rewrite what you set intogate-sdk-config.knobsand delete the shell config. -
check-crate-arms— reads gate-sdk’s knobs from a knob file now, so a left-behind<gates-dir>/gate-sdk-config.shrefuses it at exit 2, including the one an earlierinitwrote beside the gate binary — rewrite what you set intogate-sdk-config.knobsand delete the shell config. -
check-docs-kit-parity— reads gate-sdk’s knobs from a knob file now, so a left-behind<gates-dir>/gate-sdk-config.shrefuses it at exit 2, including the one an earlierinitwrote beside the gate binary — rewrite what you set intogate-sdk-config.knobsand delete the shell config. -
check-exec-bit— reads gate-sdk’s knobs from a knob file now, so a left-behind<gates-dir>/gate-sdk-config.shrefuses it at exit 2, including the one an earlierinitwrote beside the gate binary — rewrite what you set intogate-sdk-config.knobsand delete the shell config. -
check-gate-assertions— discovery reads the count-word through canon-kit’s spelled-cardinal grammar, so a section counting ten or more assertions (twelve assertions) is now discovered and coupled to its markers, where the hand list stopping atnineskipped it; such a section reds until its gate code carries a marker per label. It also reads gate-sdk’s knobs from a knob file now, so a left-behind<gates-dir>/gate-sdk-config.shrefuses it at exit 2, including the one an earlierinitwrote beside the gate binary — rewrite what you set intogate-sdk-config.knobsand delete the shell config. -
check-gate-binary-fresh— reads gate-sdk’s knobs from a knob file now, so a left-behind<gates-dir>/gate-sdk-config.shrefuses it at exit 2, including the one an earlierinitwrote beside the gate binary — rewrite what you set intogate-sdk-config.knobsand delete the shell config. -
check-gate-fail-closed— reads gate-sdk’s knobs from a knob file now, so a left-behind<gates-dir>/gate-sdk-config.shrefuses it at exit 2, including the one an earlierinitwrote beside the gate binary — rewrite what you set intogate-sdk-config.knobsand delete the shell config. -
check-gate-fixture-coverage— reads gate-sdk’s knobs from a knob file now, so a left-behind<gates-dir>/gate-sdk-config.shrefuses it at exit 2, including the one an earlierinitwrote beside the gate binary — rewrite what you set intogate-sdk-config.knobsand delete the shell config. -
check-gate-output— reads gate-sdk’s knobs from a knob file now, so a left-behind<gates-dir>/gate-sdk-config.shrefuses it at exit 2, including the one an earlierinitwrote beside the gate binary — rewrite what you set intogate-sdk-config.knobsand delete the shell config. -
check-hook-exec-bit— reads gate-sdk’s knobs from a knob file now, so a left-behind<gates-dir>/gate-sdk-config.shrefuses it at exit 2, including the one an earlierinitwrote beside the gate binary — rewrite what you set intogate-sdk-config.knobsand delete the shell config. -
check-identity— reads gate-sdk’s knobs from a knob file now, so a left-behind<gates-dir>/gate-sdk-config.shrefuses it at exit 2, including the one an earlierinitwrote beside the gate binary — rewrite what you set intogate-sdk-config.knobsand delete the shell config. -
check-install-disposition— reads gate-sdk’s knobs from a knob file now, so a left-behind<gates-dir>/gate-sdk-config.shrefuses it at exit 2, including the one an earlierinitwrote beside the gate binary — rewrite what you set intogate-sdk-config.knobsand delete the shell config. -
check-install-platforms— reads gate-sdk’s knobs from a knob file now, so a left-behind<gates-dir>/gate-sdk-config.shrefuses it at exit 2, including the one an earlierinitwrote beside the gate binary — rewrite what you set intogate-sdk-config.knobsand delete the shell config. -
check-kit-enum— reads gate-sdk’s knobs from a knob file now, so a left-behind<gates-dir>/gate-sdk-config.shrefuses it at exit 2, including the one an earlierinitwrote beside the gate binary — rewrite what you set intogate-sdk-config.knobsand delete the shell config. -
check-kit-ref-liveness— reads gate-sdk’s knobs from a knob file now, so a left-behind<gates-dir>/gate-sdk-config.shrefuses it at exit 2, including the one an earlierinitwrote beside the gate binary — rewrite what you set intogate-sdk-config.knobsand delete the shell config. -
check-kit-registration— reads gate-sdk’s knobs from a knob file now, so a left-behind<gates-dir>/gate-sdk-config.shrefuses it at exit 2, including the one an earlierinitwrote beside the gate binary — rewrite what you set intogate-sdk-config.knobsand delete the shell config. -
check-readme-roster— reads gate-sdk’s knobs from a knob file now, so a left-behind<gates-dir>/gate-sdk-config.shrefuses it at exit 2, including the one an earlierinitwrote beside the gate binary — rewrite what you set intogate-sdk-config.knobsand delete the shell config. -
check-root-tiering— reads gate-sdk’s knobs from a knob file now, so a left-behind<gates-dir>/gate-sdk-config.shrefuses it at exit 2, including the one an earlierinitwrote beside the gate binary — rewrite what you set intogate-sdk-config.knobsand delete the shell config. -
check-shellcheck— reads gate-sdk’s knobs from a knob file now, so a left-behind<gates-dir>/gate-sdk-config.shrefuses it at exit 2, including the one an earlierinitwrote beside the gate binary — rewrite what you set intogate-sdk-config.knobsand delete the shell config. -
check-smoke-entry-guard— reads gate-sdk’s knobs from a knob file now, so a left-behind<gates-dir>/gate-sdk-config.shrefuses it at exit 2, including the one an earlierinitwrote beside the gate binary — rewrite what you set intogate-sdk-config.knobsand delete the shell config. -
check-test-hermetic— reads gate-sdk’s knobs from a knob file now, so a left-behind<gates-dir>/gate-sdk-config.shrefuses it at exit 2, including the one an earlierinitwrote beside the gate binary — rewrite what you set intogate-sdk-config.knobsand delete the shell config. -
check-trajectory-fresh— reads gate-sdk’s knobs from a knob file now, so a left-behind<gates-dir>/gate-sdk-config.shrefuses it at exit 2, including the one an earlierinitwrote beside the gate binary — rewrite what you set intogate-sdk-config.knobsand delete the shell config. -
check-tree-terms— reads gate-sdk’s knobs from a knob file now, so a left-behind<gates-dir>/gate-sdk-config.shrefuses it at exit 2, including the one an earlierinitwrote beside the gate binary — rewrite what you set intogate-sdk-config.knobsand delete the shell config. -
check-value-rollup-fresh— reads gate-sdk’s knobs from a knob file now, so a left-behind<gates-dir>/gate-sdk-config.shrefuses it at exit 2, including the one an earlierinitwrote beside the gate binary — rewrite what you set intogate-sdk-config.knobsand delete the shell config. -
check-workflow-tiering— reads gate-sdk’s knobs from a knob file now, so a left-behind<gates-dir>/gate-sdk-config.shrefuses it at exit 2, including the one an earlierinitwrote beside the gate binary — rewrite what you set intogate-sdk-config.knobsand delete the shell config. -
check-audit-roster— new: every block of the audit rosterLIFECYCLE_KIT_AUDIT_ROSTER_FILEnames carriesclass:/scope:/due:/last:and, once swept,corpus:/hits:/declined:, one line each underLIFECYCLE_KIT_AUDIT_ROSTER_LINE_CAPbytes, each class once, with a current-iterationlast:naming a stage the state file stamped. Both knobs are new; the file knob defaults empty, so the gate is inert until you set it — set it only after rewriting your roster into blocks (lifecycle-kit/SPEC.md §The audit roster), and declare the rosterclose-surface: <path> advisoryin the binding that owns it. -
check-provenance-seam— new, canon-kit: no kit SPEC carries a dated attribution, a section or possessive pointer into your agent file, a mention of a private surface you configure, or a live queue slug. It scans only whenCANON_KIT_SCAN_KIT_ROOTSis1, so a tree that vendors kits it does not author passes untouched. Four knobs are new:CANON_KIT_SEAM_AUTHORITY_MARKERS(with_EXTRA),CANON_KIT_SEAM_AGENT_FILES,CANON_KIT_SEAM_PRIVATE_SURFACES(default empty; set your ruling record and local-only brief) andCANON_KIT_SEAM_SLUG_MIN_LEN. If you author kits, register it, set the private surfaces, and sweep what it reds; a queue slug that appears in a kit SPEC reds the commit filing it, so rename the fresh slug. It also gains aconsumer-rosterarm: a kit SPEC paragraph quoting two or more elements of one indexed or keyed knob your tree configured — each as a whole inline-code span, absent from the knob’s default, carrying a/or=(a keyed pair spelled<key>=<value>) — reds, and a knob-file edit now fires it. It reaches only a tree that authors kits; name the knob rather than quote its configured roster. It also gains ahex-referencearm: a 7–40-character lowercase-hex run carrying a digit and a letter, bare or backticked, reds as a commit or digest reference — delete it and state the fact it labelled, or fence a specimen. And a new knob,CANON_KIT_SEAM_SURFACE_GLOBS(default empty), holds the published documents you declare your own to the provenance arms, never the consumer-roster arm, whateverCANON_KIT_SCAN_KIT_ROOTSsays; its clean line now names the seam-surface count and says when that set is off. -
check-stage-entry— new assertion D: at entry toLIFECYCLE_KIT_AUDIT_ENTRY_STAGEit refuses any on-disk amendment carrying a line that opens with**Inferred, not run:**, or with**Inferred, cannot run before build:**and no reason after a spaced em dash, and a bold marker spelling standing mid-line or split across a line break, refused as a misplaced marker; write a mention in a code span. Audit stamp or not; inert where that knob is empty. Before upgrading mid-iteration, run each such marker’s command and correct its passage, or give it the cannot-run form with a reason. -
check-amendment-queue— the[design-pending]tag is retired: section membership is the design-pending state, so the three tag arms are gone and a new arm reds any line in a feature, active, deferred or icebox section that still carries the literal[design-pending], lead line or body.check-tag-lead-lineno longer governs the tag. Before upgrading, delete the[design-pending]tag and the space before it from every lead line of your queue, rename aWhy [design-pending]body field toWhy design-pending, and un-bracket any other body mention; if you copied the close or scope stage template or the queue template out, re-take their deferred-entry sentences. -
check-amendment-queue— new arm: every amendment-glob filename an on-disk amendment cites outside a fence or HTML comment must resolve to a file, a path as a file and a bare basename against the amendment set, so an amendment citing a merged sibling by filename now reds. Before upgrading, repoint each such citation to the canonical section the cited amendment merged into, or move an illustrative filename into a fence. -
check-stage-entry— assertion D now also reads every line inside a top-level entry of aLIFECYCLE_KIT_ACTIVE_SECTIONSsection ofLIFECYCLE_KIT_QUEUE_FILE, so an active queue entry carrying an**Inferred, not run:**marker, or a cannot-run marker with no reason, refuses the audit-entry stage just as an amendment does; the deferred, icebox and done sections stay unread, and the clean count sums both corpora. Before upgrading mid-iteration, run each such marker on your active entries and correct the entry, or give the marker the cannot-run form with a reason. -
check-prose-tells— a generated-region marker now counts only when it is its line’s whole trimmed content, so prose that mentions a<!-- name:begin -->marker inline, backticked or not, no longer opens a held-out region. Prose after such a mention was silently exempt to the next end marker or the end of the file, and it is read now. Before upgrading, run the gate and rewrite the tells it surfaces there. -
check-stamp-subject— new, lifecycle-kit, commit-msg tier: a commit that adds a stamp line toLIFECYCLE_KIT_STATE_FILEmust carry the last added stamp’s stage as its subject scope,<type>(<stage>): ….--enter-stagenow prints that subject on asubject:line after itsnext: commitline; commit your stamps with it. Register the gate and regenerate your hooks with--emit git-hooks --write; a merge commit reds only on a stamp none of its parents carries; stamps a merged branch brought in were checked at their own commits. -
check-front-end-fail-open— new, gate-sdk, zero-config: each vendored front-end stub,gate-sdk/bin/run-gates.shandrun-gates.ps1, must carry one declaration line naming exactly the gate binary’s fail-open set (--hook --statusline), the arms a stub exits 0 for when the binary is absent. The shipped stubs now spell that set asFAIL_OPEN_ARMS='…'and$FailOpenArms = @(…), with unchanged behavior; an absent stub is reported, not red. Register it and regenerate your hooks with--emit git-hooks --write; if you hand-edited a stub’s two-name test, take the shipped stub. -
check-gate-substrate-parity— assertion F’s one-producer-per-digest check now reads arun:body’s commands rather than every line naming the hasher:sha256sumorshasumcounts only in command position and without-c/--check, the alternatives of oneif/elsechain count once, and a script a step calls asbash <path>orsh <path>is read one hop deep at the call. A presence-check loop namingsha256sumstops counting, while a step re-adding a digest beside a called build script that already emits it, or ashasum -a 256computation, now reds. Before upgrading, run the gate and move each digest it reports to the one step that produces its bytes. -
check-door-binding— new, guard-kit, zero-config, and guard-kit’s first registered gate: no kit-shipped surface outside the fail-open set may namegate-sdk/bin/run-gates.shorrun-gates.ps1as a command to run, and no kit template may name a path to the gate binary. The corpus is each kit root’sREADME.md,templates/,lib/andbin/, minusgate-tests/andsmoke/. A mention that names the program as its subject rather than invoking it is a file, not a door, and passes; so does any command carrying--hookor--statusline, the fail-open arms that keep a shell door by construction. Register it (check-door-binding) and regenerate your hooks with--emit git-hooks --write. If you vendored a kit and re-pointed its prose at your own copy of the front end, this gate now reds on it — name the binary throughGATE_SDK_NATIVE_BINinstead. -
check-packed-links— new, gate-sdk, zero-config: the README the packer would put in the payload carries no link to a pathGATE_SDK_PAYLOAD_WITHHOLDwithholds. The gate packs its own corpus by calling the packer’s rewrite rather than spawning--pack-installer, so it needs no clean worktree and nonpm. Two assertions per kit root: under a non-empty base no packed README links a withheld path (asmoke/link and a../<kit>/SPEC.mdlink both red); under an empty base the packed README is its tracked source byte for byte. Where your base is empty the gate packs under its own probe base, so the first assertion is never vacuous. Register it (check-packed-links) and regenerate your hooks with--emit git-hooks --write. If a kit README of yours links intosmoke/or at a sibling kit’sSPEC.md, this gate now reds on it. -
check-kit-roots-dialect— new, gate-sdk, zero-config: one kit tree vendored at the repository root and under a subdirectory must yield one kit-root-derived corpus. It vendors a shipped fixture tree both ways underGATE_SDK_TMP_DIR, makes each a git repository, and re-runs--emit fixture-suitesand--emit enum-setsthrough the binary from inside each, comparing row counts. Register it (check-kit-roots-dialect) and regenerate your hooks with--emit git-hooks --write. If you vendored the kits under a subdirectory — anything but gate-sdk as a direct child of your toplevel — upgrade first: the readers that join a kit root onto a filesystem path or a git pathspec were on the kit-parent spelling, so your--emit enum-sets,--emit close-surfacesand--emit fixture-suiteshave been emitting a corpus that shrank toward empty while exiting 0, andcheck-kit-registrationandcheck-knob-citationhave been printing clean lines with a smaller number in them. Nothing reds to tell you; the counts are the only symptom. And if you hand-listGATE_SDK_KIT_DIRS, spell its members for the layout you actually vendored — a flat hand-list under a nested vendoring is the same silent emptying reached through config, and this gate now reds on it. -
check-template-copy-parity— the gate is unchanged; what moved is a template it reads.context-kit/templates/session-context.shnow resolves the gate binary through gate-sdk’sgate_native_bin_spelledaccessor instead of building its ownRUN_GATESpath, so the template’s declared surface gainedlib:gate_native_bin_spelledand an existing<gates-dir>/session-context.shcopy that has not been re-taken reds assertion B, naming that one token. Propagate the call into your copy — sourcegate-sdk/lib/gate.shand readgate_native_bin_spelledwhere your copy built a front-end path — or re-take the copy from the template and re-apply your[EDIT ME]retargeting. The same release’sdrift-kit/templates/kpi-deprecated-surface.shmoved the same way; it is unpaired in this tree and so outside this gate’s derivation, but a consumer that copied it into its gates directory owes it the same propagation. -
check-path-dialect— a second assertion, over the crate half of its corpus only (GATE_SDK_NATIVE_SRC), holding what §The path-dialect contract’s clause two asserted and nothing enforced: a text-level path primitive — a leading-separator absoluteness test,std::path’s ownis_absolute, a bareformat!("{}/", …)prefix composition, or aformat!with a separator in its template handed straight tostarts_with/strip_prefix— is spelled in the crate’s speller (native/src/walk.rs) and nowhere else. A site whose/-separated value is not a filesystem location declares so with a new comment directive,// path-dialect-exempt: <reason>, on its own line or in the comment run above it; the reason is mandatory and an empty one reds. A recordedspec:verdict deliberately does not clear this arm. The directive joinscheck-comment-tier’s built-in roster, so it needs noCANON_KIT_COMMENT_*entry. This reaches only a consumer that vendors a Rust crate atGATE_SDK_NATIVE_SRC— the default is this repo’s ownnative/src, so a consumer with no such tree scans nothing and the arm is silent. Where you do carry one, route each site throughwalk::path_root,walk::abs_against, or the three containment helpers this release adds —walk::under,walk::at_or_under,walk::rel_under— which compare by path component and so answer the same across both dialects. -
check-door-binding— a third assertion, C, reaching beyond the kit roots: over the surfaces a new knobGUARD_KIT_DOOR_ROOTSnames — each entry a tracked file or a directory yielding its tracked members under assertion A’s own prune — every door reds unless its site declares itself contributor-facing with<!-- door-contributor: <reason> -->, the reason mandatory and an empty one malformed. There is deliberately nodoor-adopter:twin: the unmarked case is adopter-facing, so a page added tomorrow reds the day it lands rather than needing a roster entry. A declaration standing alone on its line covers the fenced block it immediately precedes, or the whole file when it stands before the first#heading; sharing its line with anything else it covers that line and the line below. A door inside a generated region takes its declaration from the emitter, never from the page, which the next regeneration erases. Assertions A and B are untouched and the fail-open arm exemption is shared rather than copied, so the knob ships empty and no consumer’s verdict moves on upgrade — the clean line is one count longer (configured surfaces swept) and that count is a report, never a floor. A misconfigured entry, one resolving to neither a tracked file nor a directory, is exit 2.door-contributor:also joinscheck-comment-tier’s built-in directive roster. To use it, name your own adopter-facing surfaces inGUARD_KIT_DOOR_ROOTSand declare the contributor-facing doors among them; leave it unset and the assertion is inert. -
check-commit-msg— the gate is unchanged; what moved isgate-sdk/templates/msg-patterns.list, the pattern listinitseeds into your gates directory, which gains an account-identification pattern: a handle-shaped backticked token within a few characters of one of four account nouns (account, login, username or handle), singular or plural, in either order; a handle-shaped token carries at least one letter or digit and is not a short all-lowercase CLI name. If you never edited your seeded copy,initrewrites it on upgrade and a commit message naming an account that way now reds; cite the role instead of the account. -
check-tree-terms— reads the same seededmsg-patterns.list, so the account-identification pattern above now also scans your tracked tree: a tracked line pairing an account noun with a handle-shaped backticked token reds until it is reworded to cite the role, or the token is un-backticked where it is not an account. A verb reading of accounts or handles beside such a token reds too; reword the sentence, or edit your own copy of the list, whichinitthen keeps. -
check-gate-tamper— every registered gate’s declaration and the gate-sdk library are gate files whateverDELEGATION_KIT_GATE_FILESsays, so a commit staging a vendored kit’s.gate, orlib/gate.sh, beside product code now reds; split it. The default’s unvendored<gates-dir>/lib/gate.shelement is dropped. The clean line’s wording changed, so re-pin a log-matching tool. -
check-fence-command-head— new, canon-kit: every command in abash,shorshellfence of your governed doc set starts with a word that can run when the fence is pasted as written — a builtin, a configured program, a function the fence defines or sources, an expansion, a placeholder or a tracked path — and a word beginning with-never can. Two knobs are new:CANON_KIT_FENCE_PROGRAMS, a bundled generic utility set, andCANON_KIT_FENCE_PROGRAMS_EXTRA, default empty. Register it, add the toolchain your recipes name (a compiler, a fetch tool, a package manager) to the extra, and relabel a fence meant to be read rather than pasted astextorconsole. The kits’ own READMEs no longer open a fence line on a bare arm flag: each fence now sourcesgate-sdk/lib/gate.shfrom${GATE_SDK_ROOT:-gate-sdk}and runs the binary throughgate_native_bin_spelled, so a copied block runs from your repository root. -
check-docs-restatement-parity— new, canon-kit,zero-config: every--armtoken and kit-prefixed knob token in the code of a page matching the newCANON_KIT_RESTATEMENT_PAGESglobs (default empty) must occur as a whole token in theREADME.mdin that page’s directory. A declared page with no README beside it is exit 2. Because the default is empty, the gate registers on upgrade and scans nothing. To use it, list your pages that restate a README’s runnable line (for example a site’s per-kit landing pages) in the knob, and edit any page whose code names an arm or knob its README no longer carries. -
check-fence-run— new, canon-kit,zero-config, align-only (full battery, not the pre-commit hook): a shell fence your governed docs mark with<!-- fence-runnable -->(or<!-- fence-runnable: exit=<n> -->) immediately above it must pass a narrowed static pass and then run, underbash -euo pipefailin a scratch copy of your tracked tree with a fixed environment, exiting as declared. A fence’s heads are held to builtins, sourced or fence-defined functions, programs in the new knobCANON_KIT_FENCE_RUN_PROGRAMS(defaultgit), and the gate binary under a fence-safe arm;exec,eval,trapandcommandother thancommand -vred. A misspelled or orphaned marker reds. With no marker it runs nothing and spawns nothing, so it registers on upgrade clean. Marking a fence makesbashowed for canon-kit from the nextdoctoror env-probe read; a host withoutbashthen exits 2. To use it, mark the fences a reader can paste and run as written, and name any further program they need in the knob. -
check-projection-roster— new, gate-sdk,zero-config, armed by the new knobGATE_SDK_PROJECTION_ROSTER(default empty;GATE_SDK_PROJECTION_ROSTER_SECTIONnames the heading, default the whole file). Gates may now carry a# projection: <globs>header line declaring that they byte-compare those tracked outputs against an emitter; the shipped freshness gates (check-enforcement-fresh,check-footprint-fresh,check-roadmap-fresh,check-graph) carry it. Once armed, each declaring gate needs exactly one top-level bullet in that section with<!-- projection: <gate> -->on its first line, and each key must name a declaring gate. Unarmed it asserts nothing anddoctornames it disarmed, so it registers on upgrade clean. To use it, point the knob at the page where you list your generated files and key one row per declaring gate.check-graph’s trigger now followsGATE_SDK_GRAPH_ARTIFACT, the generatedcommit-msghook,scripts/graph-theme/*andscripts/*-config.knobs(the default gates dir), so an edit to your graph theme or kit config re-runs it at commit; nothing to change.projection:joinscheck-comment-tier’s built-in directive roster. -
check-docs-highlight-coverage— new, site-kit,zero-config, armed by the new knobSITE_KIT_HIGHLIGHT_TOKENS(default empty;SITE_KIT_HIGHLIGHT_OVERRIDESlists the override files, defaultdocs/_layouts/*.html, andSITE_KIT_HIGHLIGHT_SCOPEnames the highlight scope, default.highlight). Once armed, every class in the named snapshot must have an override rule whose selector, split on commas, ends in<scope> .<class>. Unarmed it asserts nothing anddoctornames it disarmed, so it registers on upgrade clean.templates/site-health.ymlgains an optional theme-drift arm,HIGHLIGHT_CSS_PATHandHIGHLIGHT_TOKENS_FILE, shipped empty and so skipped, that holds the snapshot to the live theme stylesheet in both directions. To use it, if your layout restyles code highlighting, add both env values to your copy of the template along with the arm’s block, track the class list it prints as the snapshot, and point the knob at it. -
check-path-dialect— a third assertion over the tracked shell tree: a shell file that binds two or more roots fromcd … && pwdcaptures, at least one derived fromBASH_SOURCE, and composes any of them by string arithmetic (a$root/join or a${root%…}/${root#…}strip) reds unless its cwd is anchored first. Nothing but the anchor clears it — nospec:verdict or exempt token does. For each file it names, addcd "$(pwd -P)"as a line of its own before the file’s first root binding. -
check-pipe-membership— new, gate-sdk,zero-config: in a tracked shell file that setspipefail, a pipeline whose first stage streams a set (printf/echowith a[@]or[*]expansion, or a loop’sdone) into a short-circuiting reader (head, orgrepwith-q/--quiet/--silent/-m/--max-count) reds, because the writer’sSIGPIPEcan make a present member read as absent. It registers on upgrade; rewrite each site it names as aforloop over the set or a[[ ]]test. -
check-kit-ref-liveness— two changes. First, the gap inbox (LIFECYCLE_KIT_GAP_INBOX_FILE, default.workflow/gap-inbox.md) joins the queue in the design-ahead valve, so a filed gap naming an unminted knob or path by its full prefixed name no longer reds; this only removes findings. Second, the member-to-stem direction now resolves only through a declared family — a static kit’s knob table naming the stem exactly (as evidence-kit’s table namesEVIDENCE_KIT_RUN_), or, for a prefix no static table owns, a stem kit source spells. A stem that was only a wildcard mention in a help line or a comment no longer licenses every misspelled member under it; if such a reference exists in your tree, it now reds until corrected or the stem is declared a family in its owning kit’s table. -
check-prose-tells— its five thresholds (CANON_KIT_PROSE_TELL_EMDASH_MAX,_CONTRAST_MAX,_TRICOLON_MAX,_RHYTHM_MIN_SENTENCES,_RHYTHM_CV_MIN) are now validated by canon-kit’s knob table instead of silently coerced: a malformed value (not a non-negative integer for the three maxes, not an integer of at least2for the rhythm floor, not a non-negative decimal for the CV floor) now refuses every canon-kit gate at exit 2 naming the knob and the value, where it previously read as zero and either fired on everything or never. Every tree’s defaults already meet their shape, so nothing changes unless you set one of the five to a malformed value. -
check-queue-hygiene— two new axes. A<path>:<n>or<path>:<n>-<m>token in your queue body, whose path ends in a dot-extension, now reds: cite the other file by§Section, a symbol beside its path, or a quoted literal instead. An inline code span holding agit logcommand with-Sand your queue file as its path now reds too:-Sis blind to an eviction that keeps the slug, so use-G(queue-kit/SPEC.md §The icebox tier);-Sstays correct over any other file. Rewrite any live line-number cite or-Spickaxe over your queue file before upgrading. -
check-md-unwrapped— new canon-kit gate: no paragraph in the markdown setCANON_KIT_UNWRAP_GLOBSnames (lessCANON_KIT_UNWRAP_EXCLUDE) may be broken across lines. Both knobs default empty, so it is a clean skip until you opt in; it is the alternative tocheck-queue-wrap, so register the one matching your convention. To adopt it, set the globs, run--emit md-unwrap --writeover the files it names, and register the gate. -
check-queue-entry-budget— the per-entry cap now takes a unit,QUEUE_KIT_ENTRY_CAP, defaulting to4300cp(code points, so a reflow moves nothing): an entry the old fifty-line default admitted may now measure over or under it, so read the clean path’s headroom rows after upgrading. It also reds a[cap-credit:]tag that is malformed, in another unit than the cap, overQUEUE_KIT_ENTRY_CREDIT_MAX(default2150cp), set while credits or the cap areoff, or stale (the entry fits the cap without it). To keep measuring lines, setQUEUE_KIT_ENTRY_CAP = 50linesand putcheck-queue-wrapbeside it; to drop the cap, setoff. -
check-tag-lead-line—[cap-credit:]joins the governed set, so a credit written on a continuation line now reds. Move it onto the entry’s lead line. -
check-surface-ratchet— sizes are now code points, and a ceiling row without thecpsuffix exits 2 as a line-unit row. Re-stamp withbash gate-sdk/bin/run-gates.sh --emit always-loaded --ceilingand commit the file. -
check-brevity— the per-bullet budget is nowCONTEXT_KIT_BREVITY_CAPin code points (default330), so a bullet joined onto one line no longer passes on its line count. A bullet near the old four-line budget may land either side; the finding names its size. -
check-lifecycle-registration— the block--install-lifecyclewrites is now one line per paragraph, so an installed block reds as stale after upgrading. Re-run--install-lifecycleon the gate binary and commit the agent file. -
check-task-conservation— gains assertion B, the slug ratchet: a slug entering the live set (new, or renamed) longer thanQUEUE_KIT_SLUG_MAXcode points (default30) now reds; slugs already live are grandfathered. Shorten the new slug before it lands, or set the knob tooff. -
check-task-names— reads the heading grammar: every task entry is a### <slug>heading (a sub-task#### <slug>), a task-section heading that is no slug reds, and a bullet entry left in the old- **<slug>** — …shape reds. Gains assertion R: a same-file link[<slug>] (#<slug>)naming no live entry reds, and a single-backticked live slug in an entry body reds until it is that link. Run--emit queue-migrate --write <queue-file>on the gate binary once; it converts the queue and links the live citations. -
check-tag-lead-line— every governed tag sits on the entry’s tag line, the first line under its heading, and[recurrence:],[roadmap-summary:]and[not-icebox-eligible:]join the governed set; the queue migration writes them there. -
check-roadmap-fresh— reads[roadmap:]and its[roadmap-summary:]tag off the tag line, and the generated block’s bullets link to the queue entry; regenerate the page with--emit roadmap --writeafter migrating the queue. -
check-evidence-baseline— a live slug is an entry heading, so a queue still in the bullet shape resolves no live slug and every held row naming one reds; migrate the queue. -
check-gate-exemption-tasks— a live slug is an entry heading, so a queue still in the bullet shape resolves no# until:or# port-until:slug; migrate the queue. -
check-deprecation-task— a live slug is an entry heading, so a queue still in the bullet shape resolves no marker’s task; migrate the queue. -
check-todo-task-liveness— a live slug is an entry heading, so a queue still in the bullet shape resolves noTODO(task:)slug; migrate the queue. -
check-close-surfaces— assertion C now reaches every declared path git reports gitignored, not only one underGATE_SDK_WORKFLOW_DIR, reading the roster’s new<tracking>column. Before upgrading, give each gitignored declaration outside your workflow directory areclaim=command. -
check-dispatch-entry— new, lifecycle-kit, commit-msg tier: while a lead-dispatched stage session has not entered, a commit that adds no stamp reds (a commit staging the gap inbox alone excepted). Register it, regenerate your hooks with--emit git-hooks --write, and have your lead dispatch through--enter-stage --dispatch <stage>; without a lead nothing declares a dispatch and the gate is inert. -
check-path-dialect— gains a shell locality half: a[[ … == /* ]]glob test or acasealternative that is exactly/*reds in any tracked shell file outsidegate_path_rooted’s own body, because it reads a drive-rooted path as relative. Route the test throughgate_path_rooted "$x"fromgate-sdk/lib/gate.sh, or, where the value is not a filesystem path, mark the line# path-dialect-exempt: <reason>. -
check-portability-floor— gains an ASCII arm: a non-ASCII byte outside a full-line#comment in any.ps1on your configured install-path corpus now reds, even with an empty construct roster, because Windows PowerShell 5.1 reads a BOM-less script in the ANSI code page. Spell the character by code point ([char]0x2014), or move a trailing comment onto its own line; there is no valve. -
check-install-disposition— assertion D accepts and verifies the content form# armed-by: content <KNOB>…: acontentwith no knob after it reds, and so does any knob in its list that no static kit declares or that another kit owns. Give each content declaration at least one knob of the gate’s own kit. -
check-gate-substrate-parity— gains assertion J, in a publishing tree only (one tracking the crate source): each kit’ssmoke/install.shregistry heredoc must register or declare# unregistered:every subcommand that kit owns, and register none it does not. A vendored tree is out of scope and unaffected; a kit author adds each new owned gate to the heredoc. -
check-pipe-membership— now also reads each tests dir’s tracked*.test.shsuites (a direct child of agate-tests/directory, or of the directoryGATE_SDK_TESTS_DIRresolves to where you relocated it, whose path above is unpruned), so a set-fed membership pipe in a suite reds; fixture case trees stay out. Its clean line now counts suites apart (N shell file(s) and S suite(s) scanned). Fix a red with the loop form the finding names. -
check-stage-entry— new assertion E: it refuses a malformed or misplaced inferred-claim marker at every commit and every stage entry, not only at the audit-entry stage, and a not-run marker with no command after a spaced em dash is now malformed. Assertion D keeps only the well-formed not-run residue at audit-entry. Before upgrading, run the gate and write the missing command or reason on each marker it names, or move a misplaced spelling to open its line or into a code span. -
check-graph— a token repeated within onecouples=ortrigger=field of a gate’s# graph:manifest, or of an amendment-body manifest, now reds. Drop the duplicate token, then regenerate your hooks with--emit git-hooks --write. -
check-gate-assertions— discovery skips a lone descriptor line opening a### <gate>section (a backticked.gateor.shpath and its parenthetical), so an enumerated contract in the paragraph after it is now discovered and coupled. Add a# assertion <label>:marker per label it names, or fix the enumeration. -
check-settings-paths— now also resolves everytype: commandhook underhooks, whatever its event: a hook whose command token is a repo-relative path (a leading${CLAUDE_PROJECT_DIR}/stripped) must resolve in the tree, and a hook throughrun-gates.sh/run-gates.ps1 --hook <member>must name a member the gate binary carries. Before upgrading, repoint or drop each hook the gate names; a$-rooted plugin path is skipped and counted. -
check-action-run-path— new: a script a shellrun:step invokes must exist in the tree. Every repo-relative.shpath in invocation position in a workflow’srun:body, single-line values included, must resolve under the scan root, or a step’s literalworking-directory:. It is on-surface, soinitdoes not register it: add it togates.listwhere your tree carries workflows, after repointing or deleting each step the gate names. -
check-evidence-baseline— the suite-coverage arm now also reads the reverse direction: under a non-emptyEVIDENCE_KIT_SUITES, a baseline row whose suite is not in the roster reds, once per such suite, since nothing runs a suite that left the roster and its rows assert nothing. An empty roster still disarms the arm, both directions. Before upgrading, delete the rows of every suite you dropped from the roster. -
check-docs-mirror-fresh— the docs-mirror arm now wraps each mirrored page’s body in a Liquid raw block, its tags inside HTML comments, so a Jekyll site renders a SPEC’s quoted template-looking text verbatim instead of blanking it or failing the build; the arm refuses a source carrying the raw block’s closing tag. A mirror you committed before upgrading reads stale: regenerate it with--emit docs-mirror --write. -
check-prose-bounds— new in canon-kit, on-surface: a sentence overCANON_KIT_PROSE_BOUND_SENTENCE_MAXwords (default45), a unit overCANON_KIT_PROSE_BOUND_PARAGRAPH_MAX(default200), or aCANON_KIT_PROSE_BOUND_REPEAT_WORDS-word phrase (default6) recurring inCANON_KIT_PROSE_BOUND_REPEAT_MINunits of one section (default3) reds, over the filesCANON_KIT_PROSE_BOUND_GLOBSnames. That knob defaults empty, so nothing is scanned until you set it. Adopting it over existing prose, setCANON_KIT_PROSE_BOUND_CEILING_FILEand write one<n> <path>row per file from the run with that knob emptied; each row must then equal its file’s count. -
check-provenance-seam— gains adatedarm: any ISO date outside a fence in a scanned kit SPEC or declared seam surface now reds, attributed or not. Before upgrading, state each measurement undated as its rule’s ground, spell a specimen’s dateYYYY-MM-DD, or fence it.
Renamed knobs
-
CONTEXT_KIT_BREVITY_SECTION→CONTEXT_KIT_BREVITY_SECTIONS— the scalar becomes an array, and the knob-file reader refuses the retired name. Rename it in your config. -
DELEGATION_KIT_VERDICT_BIN→ ∅ — removed with the shell binary it named, the verdict rule having ported to the compiled arm. Delete it from your config. -
SITE_KIT_CONFIG_FILE→SITE_KIT_KNOB_FILE, andDOCTRINE_KIT_CONFIG_FILE→DOCTRINE_KIT_KNOB_FILE— the file they name changes grammar, and a set old name naming a non-empty file is refused at exit 2. Point the new name at your rewritten knob file. -
QUEUE_KIT_CONFIG_FILE→QUEUE_KIT_KNOB_FILE, andLIFECYCLE_KIT_CONFIG_FILE→LIFECYCLE_KIT_KNOB_FILE— the file they name changes grammar, and a set old name naming a non-empty file is refused at exit 2. Point the new name at your rewritten knob file. -
CANON_KIT_CONFIG_FILE→CANON_KIT_KNOB_FILE,CONTEXT_KIT_CONFIG_FILE→CONTEXT_KIT_KNOB_FILE,DELEGATION_KIT_CONFIG_FILE→DELEGATION_KIT_KNOB_FILE, andDRIFT_KIT_CONFIG_FILE→DRIFT_KIT_KNOB_FILE— the file they name changes grammar, and a set old name naming a non-empty file is refused at exit 2. Point the new name at your rewritten knob file. -
CANON_KIT_ENUM_SET_NAMES,CANON_KIT_ENUM_SET_MEMBERS,CANON_KIT_MEASURED_KEYS,CANON_KIT_MEASURED_VALUES,CANON_KIT_INSTALL_TRANSPORT_IDS,CANON_KIT_INSTALL_TRANSPORT_PATTERNS,CANON_KIT_PAYLOAD_CLAIM_IDS,CANON_KIT_PAYLOAD_CLAIM_PATTERNS,CANON_KIT_CLAIM_CLASS_IDS,CANON_KIT_CLAIM_CLASS_PATTERNS→ ∅ — never set by a consumer and read by nothing; delete any reference. -
EVIDENCE_KIT_CONFIG_FILE→EVIDENCE_KIT_KNOB_FILE— the file it names changes grammar, and a set old name naming a non-empty file is refused at exit 2. Point the new name at your rewritten knob file. -
GUARD_KIT_CONFIG_FILE→GUARD_KIT_KNOB_FILE— the file it names changes grammar, and a set old name naming a non-empty file is refused at exit 2. Point the new name at your rewritten knob file. -
GATE_SDK_NATIVE_ARTIFACT_NAMESandGATE_KIT_ROOTS_HERE→ ∅ — never set by a consumer:--pack-installerdiscovers each target’s artifact name, and the gate binary derives the kit roots itself. Delete any reference. -
GATE_SDK_CONFIG_FILE→GATE_SDK_KNOB_FILE— the file it names changes grammar, and a set old name naming a non-empty file is refused at exit 2. Point the new name at your rewritten knob file. -
GATE_PRUNE_DIRS,GATE_EXEC_GLOBS,GATE_EXEC_PRUNE,GATE_LINT_EXTRA_DIRS,GATE_GRAPH_EXTERNAL_REFS,GATE_MSG_PATTERN_FILES,GATE_MSG_PATTERN_FILES_LOCAL,GATE_PORTABILITY_PATTERNS,GATE_PORTABILITY_PATHS,GATE_KIT_ROOTS_RELandGATE_SDK_ROOT_HERE→ ∅ — resolved arraysgate-sdk/lib/gate.shset after sourcing, never consumer-authored; set theGATE_SDK_*knob each was split from. A shell gate of yours that splicedGATE_GREP_EXCLUDEScallsgate_prune_loadfirst. -
QUEUE_KIT_ENTRY_LINE_CAP→QUEUE_KIT_ENTRY_CAP— the value gains a unit (<n>cp,<n>linesoroff), and the knob-file reader refuses the retired name at exit 2. Rename it, writing50linesfor the old50, or drop it to take the4300cpdefault. -
CONTEXT_KIT_BREVITY_BUDGET→CONTEXT_KIT_BREVITY_CAP— lines per bullet become code points per bullet, and the knob-file reader refuses the retired name at exit 2. Rename it and restate the value in code points, or drop it to take the330default.
Behavior changes
-
CANON_KIT_UNWRAP_DECLARATION_LEADS— new canon-kit knob, an array of line leads, default empty: a line whose content starts with a member opens a block, socheck-md-unwrappednever reds it and--emit md-unwrapnever joins it into the paragraph below. Nothing changes at the default. Act only if your tree writes machine-read declaration lines inside prose — aruling:, adischarge:, a trailing-key record — which an unwrap has been folding into the paragraph that follows them, silently taking the declaration out of its reader’s reach: list those leads in the knob and re-run--emit md-unwrap --writeover the affected files. A member that is empty is malformed config and refuses at load. -
lifecycle-kit/templates/lead.md— the “Relay, never assert” list gains one rule: operator answers that seem to conflict go back to the operator as that question, never reconciled by inference and relayed as their words. Act only if your lead binding restates that list rather than pointing at the template — take the template’s copy. Declared here by the close that discovered the omission, the landing session having ended; the gate’s mechanical half reads removed kitbin/paths and changed templateinitclaims, and a template’s prose rules sit outside it by construction. -
CANON_KIT_MANIFEST_FILES/CANON_KIT_PROSE_SURFACE_GLOBS— both knobs’ globs now expand through the pruning walk, asCANON_KIT_COMMENT_SURFACEalready did: a**member no longer descends into aGATE_SDK_PRUNE_DIRSdirectory, and a glob naming one outright yields nothing. Two things get better without action — a value spelling any depth as**stops governing vendoredgate-tests/bodies as manifest content, and no manifest reader stats a build directory a concurrent build is rewriting, which was a fail-closed exit 2 on a clean tree. Act only if a doc you meant to govern sits under a pruned directory: name its path in the knob rather than reaching it through a**(the count-reading gates this can red are declared above). -
check-docs-link-convention— the report is rebalanced toward the remedy: each of the three rules now carries its ownhelp:line, printed only when that rule fired (the valve’s prints on any red), and each finding line states the violation alone where it used to append that rule’s remedy. The verdict set is unchanged, so nothing new reds; act only if you grep this gate’s output, in which case match on the rule phrases (directory-target link,off-root relative link,anchorless back-link), which are unmoved. -
--emit close-surfaces— each row gains a sixth tab-separated column,<tracking>, readingtracked,ignoredoruntracked; a reader splitting a row on five fields folds it into<state>, so split on six.lifecycle-kit/templates/stages/close.mdstep 4 now reads a row that is nottrackedin the closing session, never through an isolated agent. -
--enter-stage --dispatch <stage>and--enter-stage --dispatch-withdraw <stage>— two new forms, with the knobLIFECYCLE_KIT_DISPATCH_MARKER_FILE(defaultstage-dispatch.txt, insideGATE_SDK_TMP_DIR):--dispatchruns the--simulatepre-flight and, when it would proceed, appends the stage to that scratch marker; every stamp removes one line naming its stage;--dispatch-withdrawremoves one for a session that ended without entering.lifecycle-kit/templates/lead.mdnow gates each stage-session dispatch with--dispatchinstead of--simulate; a lead binding that restates the old step should take the template’s. -
check-crate-arms— gains a third arm: whenever the crate’s source stamp misses, after clippy and the tests, it runs--run-gate-testsover every fixture suite--emit fixture-suiteslists, through the binaryGATE_SDK_NATIVE_BINnames, and a failing suite reds the gate. The gate isinstall: never, so this reaches you only if you registered it by hand over a crate of your own: expect the added wall-clock of your suites on a commit that touches the crate, rebuild the binary before reading a suite’s red, and if a fixture case of yours runs this gate, pinGATE_SDK_KIT_DIRSin that case’s knob file to a root with nogate-tests/. -
lifecycle-kit/templates/stages/close.md— gains step 8, Review the audit roster, whereLIFECYCLE_KIT_AUDIT_ROSTER_FILEnames one; the old steps 8–12 are now 9–13. A binding that cites a close step by number (the brevity pass is now step 11) must move its reference, and a binding that ran its own audit-roster review sub-step should delete it in favour of the template step and declare the rosterclose-surface: <path> advisory. -
.workflow/release-declarations.md— replaces<workflow-dir>/tightened-gates.txtas the accumulating declaration surface, and carries all three declaration-bearing sections as release-note bullets rather than bare gate names;--upgrade-smokeat an untaggedTOreads its Tightened-gates section. If your tree keeps the old file, move each name to a- `check-name`bullet under## Tightened gatesin the new file, keep a# contract:first line, and delete the old file. -
lifecycle-kit/templates/stages/build.md— the declaration instruction widens from appending a tightened gate’s bare name to appending a release-note bullet, remedy included, for any kit-shipped gate, knob or behavior change. If you copied the template out, your copy teaches the retired file and grammar. -
context-kit/bin/always-loaded.sh— deleted, reachable as a bridgedrun-gates.sharm; an unrecognized operand now refuses at exit 2 where it exited 0, every operand is validated, and an--update-baselinewrite failure refuses naming the path. -
guard-kit/bin/compare-settings-allow.sh— deleted, reachable as a bridgedrun-gates.sharm with the same tightened operand handling. -
gate-sdk/bin/run-gates.sh— the battery dispatches through the binary’s--runarm on a worker pool sized by the newGATE_SDK_JOBSknob, with per-memberTMPDIRisolation. -
installer/lib/— deleted; its verbs moved behind acheckwright-gates --install <verb>invoke, the omit-and-declare degraded install retired, and the bootstrap has one success path and refuses rather than completing degraded. -
queue-kit/bin/— deleted (lesson-sink.sh,queue-counts.sh,queue-edges.sh), each moved to a bridged arm. Re-point any script that called them. -
couples=manifest field — gains aknob:<NAME>token, widening a regenerated hook’s trigger set; regenerate your hooks. -
--readsdeclaration — gains a third field, a prune set, held to executed behavior bycheck-reads-couples. -
lifecycle-kit/SPEC.md§The committed gap inbox — the recurrence-stamp obligation’s reach half is now answered rather than left open: the rule binds any session, so it is carried on the consumer’s always-loaded surface once and the stage templates stay silent (context-kit/SPEC.md §The consumer footprint). If your always-loaded file does not carry a recurrence-stamping line, a build, align, spec or validate session of yours meets the obligation nowhere — add one; the shipped stage templates will not, by ruling.lifecycle-kit/templates/lead.mdkeeps the lead’s differing discharge (file a gap bullet, since a lead writes no queue) and drops the general obligation it used to restate. -
lifecycle-kit/templates/lead.md— the journal-disposal step no longer lists a knowledge-friction line among the channels a lead disposes findings into, and says so explicitly: that log is capture-in-the-moment, and a line written at disposal time is the deferred capture its own channel counts as none. Three grounds passages move tolifecycle-kit/SPEC.md, which now owns them — the prompt-answered-signal trap’s generality-and-salience argument and the lead-stamp ban’s enforcement reading (§The state machine), and the no-sibling-dispatch clause’s nested-supervisor ground (§templates/lead.md); the template keeps each instruction with a citation. If you copied the template out, re-take the disposal step at minimum: a copy that still lists the friction log teaches the deferred capture. -
context-kit/SPEC.md§The consumer footprint — the resident-ask budget is now one pointer line per obligation a kit owns whose bound actor fires no trigger that loads it, rather than one per kit; a resident block is sanctioned above that budget only where it is generated and held in lockstep by a gate; and an obligation binding any session is carried resident once and is not also restated in the kit templates those sessions load. The roster gains alifecycle-kitrow — its generated registration block plus the gap-inbox and survey-record capture lines — so a consumer costing adoption now reads that ask instead of the retired claim that every kit but three asks nothing. If a template you copied out restates an obligation your always-loaded file already carries, delete the restatement; nothing reds either way, the footprint roster being prose contract. -
DELEGATION_KIT_LIVENESS_CMD— lost its shipped default; without an authored reader every firing reportsverdict=unavailablerather than red. -
turn-end liveness hook — the refusal set gains a third verdict,
unstarted, logged with a spawn field for a resolved reader that could not start (previously loggedunavailable). -
--emit queue-counts— gains--by <tag>, one<section>/<value><TAB><count>line per partition: a field tag yields its first lead-line value, a bare tag its own name, an entry carrying neither(none), and a section with no entries emits nothing. Bare invocation is byte-identical to before, so the in-process statusline caller is unaffected and nothing needs re-pointing. -
--emit queue-edges— a retired target whose slug is the basename, less its final extension, of a file the tracked tree carries now renders as<slug> (<N> inbound, retired — name live at <path>), a further match noted as(+<M>). Evidence only: nothing is filtered, no verdict is added, and an unmarked row is byte-identical to before. If you parse the retired block, widen the pattern past the closing)ofretired.lifecycle-kit’s scope and close templates now route their readers to the mark; re-vendor them to pick that up. -
--emit entry-history <slug>— the addressable domain widens from live slugs to live plus retired ones, so an entry that has left the queue is reported rather than refused: its header names the departure commit and that commit’s subject, and the fall rows are unchanged. A slug in neither set still refuses at exit 2, now naming that class. If you matched the old refusal textthe arm reads a live entry, match the newnot a live or retired sluginstead. -
--icebox-candidates— a standing cause now renders[standing] <date> — <grounds>, dropping the declaration’s ownnot-icebox-eligibletoken now that the✗mark and the[standing]class token already say it; and every cause’s character cap binds only its variable tail (the grounds, or a named live slug) rather than the whole cause string, so a class prefix prints whole regardless of its own width against the cap. If you parse the worklist’s standing rows, match the shortened prefix. -
lifecycle-kit/bin/— deleted,enter-stage.shincluded; reachable viarun-gates.sh --enter-stage. -
--emit always-loaded— the meter, its baseline row and--growthmeasure code points, not lines: the row reads<total>cp <surface>cp <commit>, and a row without the suffix printsbaseline in retired line unit — re-stamp with --update-baselinein place of a delta until re-stamped. Run--update-baselineonce after upgrading;kpi-always-loaded’s trend fragment readsloaded <n>cp, so a trend series crossing the upgrade changes unit there. -
--emit footprint— each cell reads<n>cp · ~<t>tin place of<n>l · ~<t>t, and the page’s prose paragraphs are emitted one line each. Regenerate your footprint page. -
--emit queue-index --icebox-candidatesand--emit entry-history— an entry’s size prints in the cap’s unit with its suffix (4211cp,48lines), code points underoff, where it printed a bare line count. If you parse either, match the suffix. -
context-kit/templates/close-brevity.md— step 1’s growth list is net code points. If you copied the template out, re-take the step’s wording. -
Every kit’s markdown — each kit’s SPEC, README and shipped templates, and
doctrine-kit/DOCTRINE.md, now carry one line per paragraph, andDOCTRINE.md’s*Stages:*and*Digest:*trailers each stand as their own paragraph inside the rule. Nothing reds; a template you copied out differs from the shipped one in line breaks only, so re-take it or leave it. -
check-knob-citation— the “default” marker binds only a knob token it follows within a reach, 100 code points unless you set the new reach knob below, so a knob no longer reds for an unrelated default elsewhere on its line; it fires less, never more. -
gate-sdk/templates/msg-patterns.list— the account-identification pattern needs the account noun and the handle-shaped token inside one clause (no.or;between them). If you copied the template, re-take that line. -
--emit md-unwrap [--write] <file>…— new canon-kit arm joining every paragraph broken across lines, the remedycheck-md-unwrappedprints. -
guard-kit rule 17 — now auto-allows a create-redirect or quoted-delimiter heredoc body to a gitignored target, where it prompted.
-
drift-kit/bin/drift-report.sh— deleted withdrift-kit/kpis/*; reachable viarun-gates.sh --emit-drift-report. -
initdigest repair —initnow rewrites a gate binary that fails its recorded digest, so the remedydoctorprints for a mismatch works. -
context-kit/bin/md-index.sh— deleted withmd-section.sh,pub-index.sh,lib/pub-lang/rust.sh,lib/pub-lang/ts.sh,lifecycle-kit/bin/cite-survey.shandlifecycle-kit/bin/file-survey.sh, each moved to a bridged arm;CONTEXT_KIT_PUB_LANG_DIRshadowing is unchanged. -
guard-kit command classification — an unrecorded backgrounded launch blocks where it advised (rule 22); rules 4 and 7 withhold a rewrite’s allow unless bounded; a path-slot block and a
git rmforce-flag block are new; read-only roster members are withheld on declared write or execute forms; wrapper stripping widens.GUARD_KIT_RO_FORMSandGUARD_KIT_SEARCH_TOOLSare new knobs. -
guard-kit/bin/scan-prompts.sh— deleted; reachable via--emit scan-prompts. -
lifecycle-kit/bin/session-id.sh— removed withcontext-kit/bin/env-probe.sh, both re-pointed at bridged arms. -
evidence-kit/bin/diff-baseline.sh— each argument group is<suite> <logfile> [<status>], and a suite on the exit-code parser named without a status refuses at exit 2; pass the suite’s own exit status. -
install-lifecycle— no longer exits 1 with no output; it works wherever the worktree-lock pattern is configured. -
iteration-boundary worktree check —
--enter-stagerefuses on agent-worktree residue, under the newLIFECYCLE_KIT_BOUNDARY_WORKTREE_CHECKknob defaulting to 1, so an upgrading consumer meets the refusal unopted. -
gate-sdk/bin/port-blockers.sh— deleted; reachable via--emit port-blockers. -
INSTALLER_SMOKE_ARTIFACTS_DIR— new knob: the consumer smoke adopts a producer’s built artifacts instead of always building on the host. -
--enter-stagesurplus argument — refused, where it was silently dropped. -
gate-sdk/bin/run-gate-tests.sh— removed withguard-kit/bin/run-guard-tests.shandcontext-kit/smoke/agents-md.sh, replaced byrun-gates.sharms. -
gate-sdk/bin/upgrade-smoke.sh— deleted; reachable viarun-gates.sh --upgrade-smoke, whose stdout is now reserved for the one verdict line. -
delegation-kit/bin/run-usage-tests.sh— deleted withrun-trend-tests.sh, folded into the crate’s own test lane. -
delegation-kit/bin/wait-probe.sh— deleted; reachable viarun-gates.sh --wait-probe. -
lifecycle-kit/templates/stages/— each of the six stage templates gains a mandatory last step appending to the stage’s resume journal. -
lifecycle-kit/templates/lead.md— the pre-dispatch--simulateread is a mandatory step. -
check-queue-entry-budget— aruled:declaration line no longer counts against the wrap budget. -
gate-sdk/templates/gates-workflow.yml— gains a least-privilegepermissions:block; a copy taken earlier runs the gates job under the repository’s default token scope. -
installer/bin/checkwright.ps1— a PowerShell bootstrap ships beside the bash one. -
installer/lib/init.sh— withuninstall.sh, routes every git call naming the whole vendored roster through batched argv, fixing an argv-width overflow. -
consumer-smoke manifest arm — splits exit 2 from a finding and reports before it fails.
-
check-graph— resolves its own interpreter, changing how it spawns on a Windows host. -
--emit ruling-staleness— a new reporting arm; its threeLIFECYCLE_KIT_RULING_*knobs default empty and inert. -
supported-platform roster —
x86_64-apple-darwinandaarch64-apple-darwinjoined. -
kpi-incident-recurrence(drift-kit) — the counted series is not comparable across this release: everyrecurrence:date before it was matcher-derived, every date after is a session’s judgment. Compare within a segment, never across the break. -
installer/lib/doctor.sh—doctorwalks only the consumer-audience subset of the toolchain roster, so a machine with no Rust toolchain installs. Reconcile if you relied ondoctorfailing on a contributor-side tool. -
context-kit/lib/toolfloor.sh— a roster element gains a fourth positional field,<name>[:<min-version>[:<impl-token>[:<audience>]]]; empty or omitted means every audience, so existing elements are unchanged. -
.github/workflows/site-health.yml— a release-channel arm files asite-healthissue naming every Release whose prerelease flag disagrees with its version line. Reconcile if you copied the workflow out. -
--emit file-survey(withcheck-survey-recordand--emit cite-survey) — a survey block’s fields are nowcorpus,oracle,rev,finding,inferred. Theedgesfield is retired, andinferredholds each claim no command established, ornone. The arm’s fourth and fifth positionals are now"<inferred>" "<finding>". An old-order call still has five arguments and is accepted: its oldedgesargument now files underinferredand its oldfindingargument still files underfinding, unmoved — a safe degrade rather than a misfile, sinceinferredis already re-checked before a reader relies on it. Update any instruction file or script that spells the old order at your own pace, not as a fire drill. A survey record your tree has not yet truncated at its next boundary re-keys its blocks in the same motion, orcheck-survey-recordreds. -
--emit ruling-staleness— a paragraph of your ruling record that states the record’s contract, rather than a ruling, can carry<!-- undeclared-condition-exempt: <reason> -->anywhere inside it, and the undeclared-conditions report then skips that paragraph. The reason is mandatory: a valve without one reports under malformed declarations and excuses nothing. If your record’s framing paragraph shows up as an undeclared condition on every run, add the valve to it; nothing else changes. -
drift-kit/bin/kfric.sh,lifecycle-kit/bin/file-gap.sh— deleted; runrun-gates.sh --emit kfricand--emit file-gapinstead. Neither arm has a-h/--helpform: a leading flag is refused rather than captured, and the refusal prints the arm’s usage. Re-point any instruction file or script naming the old paths. -
doctrine-kit/bin/stage-rules.sh,lifecycle-kit/bin/install-lifecycle.sh,gate-sdk/lib/declaration.sh— deleted; runrun-gates.sh --emit stage-rulesand--install-lifecycleinstead, and the declaration holder is compiled into the gate binary.--install-lifecyclerefuses at exit 2 outside a repository, where the shell tool wrote into the wrong directory and exited 0. -
drift-kit/bin/overhead-meter.sh,drift-kit/bin/stage-economics.sh,guard-kit/bin/scratch-run.sh— deleted; runrun-gates.sh --emit overhead-meter,--emit stage-economicsand--scratch-run <script> [args…]instead. The scratch runner now rides the front-end’s existing grant, so withholding a separate grant no longer opts a consumer out of scratch-execution review. -
evidence-kit/bin/run-validate.sh,evidence-kit/bin/diff-baseline.sh,delegation-kit/bin/usage-trend.sh,gate-sdk/bin/install-hooks.sh— deleted; runrun-gates.sh --run-validate,--diff-baseline,--emit usage-trendand--install-hooksinstead. Re-point any script or instruction file naming the old paths. -
--hook subagent-stop-liveness— the turn-end liveness hook refuses (exit 2, blocking) on a red or unreadable liveness reading instead of only logging it; its log lines gaindecision=<refuse|allow>, andverdict=errorseparates a broken tree from an unconfigured one. Reconcile if you relied on the hook only observing. -
--only— naming exactly one gate now selects it even whengates.listomits it, provided a configured check dir declares it; two or more names still intersect the registry, and an unresolvable name still refuses at exit 2. -
harness hook templates — eight shipped templates are deleted:
delegation-kit/templates/{agent-budget-guard,agent-dispatch-guard,subagent-stop-liveness}.sh,guard-kit/templates/{escalation-guard,wakeup-guard}.shandlifecycle-kit/templates/workflow-state-guard.sh, each nowrun-gates.sh --hook <name>, plusdelegation-kit/templates/statusline-usage.sh(now--statusline) andusage-poller.sh(now--usage-poll). Re-point every hook command in your.claude/settings.json. -
installer/bin/checkwright.sh,checkwright.ps1— host detection reads the host’s libc and refuses on musl or an unidentifiable libc, naming what it detected, where it used to hand a musl host a glibc-linked binary that failed in the dynamic loader. -
the gate binary on Windows — every spawn of
bashrefuses to resolve it by bare name, because the System32 WSL launcher shadows Git for Windows’bash.exeonPATH; a bare-name spawn that used to launch WSL silently now fails with a named refusal. -
context-kit/bin/run-index-tests.sh— deleted; runrun-gates.sh --run-index-testsinstead, and drop any permission grant naming the old path. -
--emit parse-gates-log,--emit parse-smoke-log,--emit enum-sets— new bundled arms you can name inEVIDENCE_KIT_PARSER_<suite>andCANON_KIT_ENUM_SETS_CMDinstead of writing a parser or enum-set script. Both knobs still take any command, so nothing changes unless you adopt them. -
<gates-dir>/site-config.sh,<gates-dir>/doctrine-config.sh— with their.local.shoverlays, replaced bysite-config.knobs/doctrine-config.knobs(and.local.knobs) in the knob-file line grammar (gate-sdk/SPEC.md §The knob file);site-kit/lib/site.shanddoctrine-kit/lib/doctrine.share deleted, the defaults living in the gate binary and printed byrun-gates.sh --emit knob-roster. A left-behind shell config is refused at exit 2. For both kits an exported scalar knob now outranks the file, where a bare assignment in the shell config used to beat it, and the.localoverlay always sits in the gates dir, never beside a relocated file. Rewrite eachNAME=(a b)as oneNAME[] = aline per element, and eachNAME=vasNAME = v. -
--emit drift-report— the iteration-start commit is read from the state file’s first stamp (DRIFT_KIT_STATE_FILE) instead of a pickaxe on the iteration name, so since-iteration KPIs include scope’s own commits and stop anchoring on the oldest sentinel commit. A shallow clone without the stamped commit reportsn/a (no iteration baseline). -
--emit always-loaded—--growthmeasures from the iteration-start commit where the newCONTEXT_KIT_STATE_FILEresolves one, and the bare line adds the surfaces’ delta since it and a(baseline stale)mark. Without a lifecycle state file the output is unchanged. -
--emit overhead-meter— a bare invocation inside a delegated session now prints a notice and logs nothing instead of measuring whichever transcript was newest. A top-level session measures its own transcript exactly. The operand also accepts a stamp’s eight-character session id. Pass your session’s transcript or stamp id wherever you meter from a dispatched session. -
run-gates.sh --only— resolves only the selected gates’ knobs, not every registered gate’s. A misconfigured knob belonging to a gate you did not name no longer fails a--onlyrun; a bare run, and a--onlynaming that gate, still refuse on it. -
check-template-copy-parity— a template and its copy that carry no${NAME:-…}knob idiom are now compared like any other pair, where the whole gate refused at exit 2. A vendored knob-less template that had turned every run red now passes or reports its real findings; nothing to change on your side. -
run-gates.sh --enter-stage— gains--open-lead-journal, which opens the lead journal under a heading keyed on the stage cursor; the boundary’s undisposed-journal advisory now reads the journal per segment and exempts the one the live lead opened with it. If you copiedlifecycle-kit/templates/lead.mdout, re-take its first step (the opener command), or the advisory keeps firing on your live lead. -
<gates-dir>/queue-config.sh,<gates-dir>/lifecycle-config.sh— with queue-kit’s.local.shoverlay, replaced by.knobsfiles in the knob-file line grammar, andqueue-kit/lib/queue.shandlifecycle-kit/lib/stages.share deleted, the defaults printed byrun-gates.sh --emit knob-roster; the binary’s--queue-parityand--stages-lib-parityarms go with them. A left-behind shell config is refused at exit 2, including the copy an earlierinitseeded that you never edited: delete it, or rewrite what you set into the.knobsfileinitnow seeds. For both kits an exported scalar knob now outranks the file. queue-kit’s.localoverlay now sits in the gates directory even when the tracked file is relocated. A<gates-dir>/drift-config.sh(or any bridged config) that sourceslifecycle-config.shto copy a value — the wiring drift-kit’s SPEC documented forDRIFT_KIT_STAGES— breaks at upgrade: replace thesourceline and the copy withgate_static_knob LIFECYCLE_KIT_STAGES DRIFT_KIT_STAGES.gate_static_knobis transitional and is removed when the shell config bridge is. -
Generated pre-commit hook — a gate reading a static kit’s knob file now fires on an edit to
<gates-dir>/<stem>-config.knobswith no couple on its descriptor, andrun-gates.sh --forselects it the same way; regenerate your hooks. A knob file you relocated with<KIT>_KNOB_FILEfires nothing unless your own descriptor couples it. -
<gates-dir>/canon-config.sh,context-config.sh,delegation-config.sh,drift-config.sh— replaced by.knobsfiles (and.local.knobsoverlays) in the knob-file line grammar, andcanon-kit/lib/spec.sh,context-kit/lib/context.sh,delegation-kit/lib/delegation.shanddrift-kit/lib/drift.share deleted;run-gates.sh --emit knob-rosterprints every default. A left-behind shell config is refused at exit 2, including the copy an earlierinitseeded that you never edited: delete it, or rewrite what you set into the.knobsfileinitnow seeds. An exported scalar knob of these kits now outranks the file. Every*_CMDknob is an argv, oneNAME[] = elementline per word, and runs with no shell:CANON_KIT_*_CMD,CONTEXT_KIT_HOOK_CMDandDELEGATION_KIT_REFRESH_CMDvalues that relied on shell syntax need abash,-cand command-string argv, and none takes an environment override.DELEGATION_KIT_LIVENESS_CMDmay now name an interpreter. Adrift-config.shthat calledgate_static_knob LIFECYCLE_KIT_STAGES DRIFT_KIT_STAGESwritesDRIFT_KIT_STAGES[] <- LIFECYCLE_KIT_STAGESinstead. -
drift-kit/templates/kpi-deprecated-surface.sh— reads canon-kit’s knobs throughrun-gates.sh --emit knob-values, finding the front-end in theDRIFT_KIT_KIT_ROOTShandoff, so a copy you adapted from the old template reads nothing after the upgrade: re-copy the template, and passDRIFT_KIT_KIT_ROOTSwhen you run it outside the drift report. -
run-gates.sh --upgrade-smoke— the FROM scratch consumer is now seeded with every config templateinitcopies before the baseline runs, and phase A deletes each shell config a knob-file template replaced at TO before it regenerates. If you drive the suite from your own tree, a gate that reds in phase B once those files are gone must still be named under Tightened gates. -
lifecycle-kit/templates/upgrade.md— phase A gains a middle step: after the kit sync and before the regen, retire each<gates-dir>/<stem>-config.shor.local.shwhose kit now ships a.knobstemplate, rewriting what you set into the.knobsfile first. Without it the regen refuses at exit 2. If you copied the template out, re-take step 1. -
<gates-dir>/evidence-config.sh— with its.local.shoverlay, replaced byevidence-config.knobs(and.local.knobs) in the knob-file line grammar, andevidence-kit/lib/evidence.shis deleted;run-gates.sh --emit knob-rosterprints every default. A left-behind shell config is refused at exit 2, including the copy an earlierinitseeded that you never edited: delete it, or rewrite what you set into the.knobsfileinitnow seeds. An exported scalar knob of this kit, and an exportedEVIDENCE_KIT_RUN_<suite>orEVIDENCE_KIT_PARSER_<suite>member, now outranks the file. A config that builtEVIDENCE_KIT_SUITESandEVIDENCE_KIT_RUN_<suite>in a loop overgate_fixture_suiteswritesEVIDENCE_KIT_SUITES[] <- EVIDENCE_KIT_FIXTURE_SUITESinstead, and the run members for those suites are derived. -
gate_fixture_suites— removed fromgate-sdk/lib/gate.sh;run-gates.sh --emit fixture-suitesprints the same rows. A workflow copied fromgate-sdk/templates/gates-workflow.ymlcaptures that arm’s output and loops over it instead, as the template now shows. -
<gates-dir>/guard-config.sh— with its.local.shoverlay, replaced byguard-config.knobs(and.local.knobs) in the knob-file line grammar: an array is oneNAME[] = elementline per element, adeclare -Amap oneNAME[key] = valueline per pair, andNAME =empties a collection;run-gates.sh --emit knob-rosterprints every default. A left-behind shell config is refused at exit 2, including the copy an earlierinitseeded that you never edited, and the bash guard then blocks every command with the refusal: delete it, or rewrite what you set into the.knobsfileinitnow seeds, using the Edit tool, which the guard does not intercept. An exported scalar knob of this kit now outranks the file.guard-kit/lib/guard.shreads its knobs through the gate binary, so a guard running where the binary is absent steers nothing and says so on every call: build or install the binary besidegate-sdk/lib/gate.sh. A consumer rule in yourbash-guard.shcopy that read aGUARD_KIT_*variable still reads it after the library is sourced. -
guard-kit/lib/guard.sh— new generic rules block: acat,printforechowrite rule 17 would grant alone but compounded with another statement (issue the write as its own call), and a lone emitter write to a target git does not ignore (use the Write or Edit tool, or the capture arm that owns the surface); and abash -corsh -cwrapper (run the payload as the command itself, or a scratch script through--scratch-run). Fall-through logging is no longer a numbered rule: it closes every call after the ruleset, as the template guard’s ownguard_log_fallthroughcall. A consumer rule placed before the generic ruleset is unaffected. -
GATE_SDK_ROOT— the gate binary derives the kit roots from this locator:run-gates.shexports it on every call, and a binary call made without the front-end, such as a generated git hook, reads it from the environment with defaultgate-sdkrelative to the working directory. If you vendor gate-sdk anywhere else, exportGATE_SDK_ROOTfor those calls. A script of yours that readsGATE_SDK_ROOTas a path, is reached throughrun-gates.shand changes directory first now meets the front-end’s relative spelling: absolutize it before thecd.run-gates.sh --emit kit-rootsprints the derived set. -
run-gates.sh --pack-installer— takes each roster target’s artifact name by discovery: the target’s artifact directory must hold exactly one regular file not named*.sha256beside its sidecar, and zero or several refuses at exit 2 naming the directory. Remove stray files from an artifact directory before packing. -
<gates-dir>/gate-sdk-config.sh,<gates-dir>/graph-vocab.sh— replaced bygate-sdk-config.knobs(and.local.knobs) andgraph-vocab.knobs, in the knob-file line grammar;run-gates.sh --emit knob-rosterprints every gate-sdk default. A left-behindgate-sdk-config.shrefuses the whole battery at exit 2, including the one an earlierinitwrote beside the gate binary: rewrite what you set intogate-sdk-config.knobs, whichinitnow writes the binary’s path into, and delete the shell file. A left-behindgraph-vocab.shrefusescheck-graphand--emit graph: write oneGRAPH_LAYERS[] =,GRAPH_LAYER_RULES[] =,GRAPH_VOCAB[] =,GRAPH_LEADING[] =orGRAPH_LAGGING[] =line per element andGRAPH_LAYER_DEFAULT = …. An exported gate-sdk scalar now outranks the file, where a bare assignment in the shell config used to win — so an exportedGATE_SDK_NATIVE_BINoverrides the binary pathinitwrote, and a relative one resolves inside whichever tree the call runs in: unset it, or export an absolute path, around any call into a consumer tree.GATE_SDK_GATES_DIR,GATE_SDK_ROOT,GATE_SDK_JOBSandGATE_SDK_VERBOSEare read from the environment only, and a knob-file line naming one is refused. A whitespace-list knob such asGATE_SDK_PORTABILITY_PATHSno longer expands a glob in its value: list the paths. -
check-knob-default-coupling— on a Windows host it compares a table-derived default with the host’s.exesuffix removed, so theGATE_SDK_NATIVE_BINdefault no longer reds against gate-sdk’s suffix-less SPEC literal in a freshly initialised consumer; nothing to change on your side. -
the shell config bridge — removed.
gate_knob_env,gate_knob_env_set,gate_knob_env_one,gate_static_knob,gate_kit_roots_rel,gate_commit_types, the binary’s--knobsarm and everyGATE_SDK_KNOB_<NAME>variable no longer exist;gate_commandreturns<binary> <name>with noenvprefix, and the binary reads each knob itself from the environment and the knob files. A script of yours that read aGATE_SDK_KNOB_<NAME>variable reads the bare name, or asksrun-gates.sh --emit knob-values <NAME>. -
lifecycle-kit/templates/stages/build.md— gains a paragraph treating an amendment’s roster as a floor: before a merge counts as complete the build session re-derives the roster against the tree, lands every missed site and names it in the commit, and reports a rostered target with nothing to update as a finding rather than editing it or dropping it. Nothing to change on your side; if you copied the template out, re-take the paragraph. -
canon-kit/templates/SPEC-amendment.md— the## Existing sections updatedcomment instructs an amendment’s rosters to name the probe that produced them and never to claim completeness. Nothing to change on your side; if you copied the skeleton out, re-take the comment. -
gate-sdk/bin/gen-pre-commit.sh— deleted; the hooks regenerate withbash gate-sdk/bin/run-gates.sh --emit git-hooks --write, and thepre-commitorcommit-msgoperand prints one hook. A script or CI step of yours calling the old path must switch. Regenerate your hooks: their headers name the new command, and a trigger that repeated aknob:token’s members once per descriptor naming it now lists them once. -
gate-sdk/lib/gate.sh— no longer definesgate_manifest_field,gate_expand_couples_varorgate_expand_couples, and the binary’s--knob-filesflag is gone. A shell gate or script of yours calling one must stop;run-gates.sh --for <path>answers what a path triggers. -
every kit README’s install block — the hook-regeneration line now reads
bash gate-sdk/bin/run-gates.sh --emit git-hooks --write. If you copied the block into your own docs, re-take the line. -
gate-sdk/bin/run-consumer-smoke.sh,gate-sdk/lib/consumer-smoke.sh— deleted; the harness isbash gate-sdk/bin/run-gates.sh --run-consumer-smoke [--keep] [kit-root...], with the same operands, output and exit codes, so a validate suite, script or permission grant naming the old path must switch. A shell script of yours sourcing the library, or calling acsmoke_function, must stop. Its registration accounting now ends at exit 2 when a probed tree holds no gate binary for a.gatedeclaration, where it used to read that as the gate’s own exit 2. -
every kit’s
smoke/install.shandsmoke/violation.sh— the entry-point guard’s hint now readsrun via run-gates.sh --run-consumer-smoke. Nothing to change on your side. -
run-gates.sh --rewrite— a new guard-kit arm replaces a literal, or a line-scoped POSIX ERE, with fixed text in files inside the repository, printing every changed span, and refuses symlinks,.gitpaths and the lifecycle state file. A front-end grant now reaches these bounded rewrites of tracked files, as it already reached unbounded ones through--scratch-run. Nothing to change on your side. -
guard-kit/lib/guard.shrule 8 — now blocks every in-placeperlrewrite on a file operand (perl -pi,-0pi,-i.bak), as it already blockedsed -i, and both steer to the--rewritearm instead of the Edit tool. Nothing to change on your side. -
guard-kit/lib/guard.shrule 25 — now also blocks acat,printforechowrite to a target git does not ignore when it is compounded with another statement, and steers it to the Write or Edit tool as its own call with the rest issued separately; a device target still passes. Nothing to change on your side. -
run-gates.sh --emit scan-prompts— now counts a logged call carrying a write redirect or an expansion as prompting even where a committed or overlay*glob matched it, so its headline count and thekpi-prompt-frictionreading step up once. Nothing to change on your side. -
run-gates.sh --emit compare-settings-allow,guard-kit/templates/close-triage.md— the advisory now prints a dead-path section listing each local-overlay allow entry whose literal.shcommand token names a script that does not exist, and the close-triage step takes it as a third disposition, pruning those entries;--countis unchanged. If you spliced the template into your close skill, re-splice it. -
guard-kit/templates/settings-allow.json— a new template recommending allow entries for the front-end,git rm -qand the read-only banner and diagnostic tools an agent chains, each with its ground and reach in guard-kit/SPEC.md §The recommended allowlist. Nothing merges it for you: review the entries and union the ones you accept into.claude/settings.json’spermissions.allow. -
couples=manifest field — has one semantics: every expanded token is a bash string pattern over the repo-relative path (*and?cross/), for triggers and forcheck-reads-couples’ coverage alike, so that gate stops reporting a read below a couple’s glob depth; and eachknob:member expands to its covering pattern (**/collapsed to*, a leading*added), widening a regenerated hook’s trigger set. Regenerate your hooks; a per-depth sibling glob added only to satisfycheck-reads-couplescan be dropped. -
canon-kit’s comment-surface and manifest readers’
couples=—check-comment-tier,check-todo-task-liveness,check-deprecation-taskandcheck-spec-pointercouple*.shwhere they coupledscripts/*.shandkit:*.sh, and the elevenspec::manifest_filesreaders couple*CLAUDE.mdwhere they coupledCLAUDE.md, so a.shoutside your kit roots or a nestedCLAUDE.mdnow fires them. Their--readsdeclares each kit-literal fallback walk under anelse:guard instead of?, and--emit reads-censuslists 14 fewer members. Regenerate your hooks. -
couples=and--readsknob references — a knob whose row declares an element packing is addressed by field,knob:<NAME>.<field>, and a bare reference to it is refused at exit 2;CANON_KIT_EMBED_LANGSis the one packed knob, with fieldskind,fence-langsandfile-globs.check-spec-embedded-sourcecouplesknob:CANON_KIT_EMBED_LANGS.file-globswhere it transcribed the default globs, so a language you add to that knob now fires the gate and is covered bycheck-reads-couples. Regenerate your hooks. -
canon-kit/SPEC.md§The causal-completeness check, §Merging an amendment,canon-kit/templates/SPEC-amendment.md— the checklist gains a sixth point (a delta obliging every member of an enumerable corpus names each member’s satisfying value, or narrows past a member with none), point 2 now names every roster-holding reader of the surface a minted name lands on, and merge step 2 integrates by re-phrasing rather than appending. Nothing to change on your side; if you copied the skeleton out, re-take its## Producers and consumerscomment and its Causal-completeness and Merged-with-no-information-lost items. -
lifecycle-kit/templates/stages/spec.md,lifecycle-kit/templates/stages/scope.md— the causal-completeness paragraph points at canon-kit’s checklist instead of restating four of its points, and the spec template gains a paragraph telling replacement text to re-phrase rather than append. Nothing to change on your side; if you copied either template out, re-take those paragraphs. -
context-kit/templates/close-brevity.md— the pass reads the growth list against a file not being expected to grow each iteration, and its goal admits growth only where re-phrasing could not carry the change. If you spliced the template into your close skill, re-splice it. -
delegation-kit/templates/agent-execution.md— three obligations a session owes when it backgrounds a child or dispatches into isolation now state their composition rather than each half alone. The record obligation splits producer from observer, so a wait loop or a read-only pipeline writes no.runrecord at all and a wait that must take one owes a self-deadlock check before it starts; the worktree reap moves from the iteration boundary to the dispatching session’s own turn end, scoped to the trees it minted, with the boundary refusal left as the backstop rather than the schedule; and isolation cost (3) gains the D2 composition — a sweep whose corpus includes an untracked or gitignored surface is not delegable at all to a typeDELEGATION_KIT_READONLY_TYPESholds to isolation — plus a child-side clause reporting such a target as a blindness rather than a finding of absence. The header’s propagate obligation now names three passages instead of two. If you copied the template out, re-take those passages; and if your own agent definitions restate the waiting rule, they carry the retired unconditional record obligation until you propagate it. -
GATE_SDK_PAYLOAD_WITHHOLD— new, defaultSPEC.md smoke: the customer payload--pack-installerbuilds now excludes each packed kit root’sSPEC.mdand itssmoke/directory. An adopter installing from a payload therefore receives no kitSPEC.mdand no kitsmoke/— the specification section behind each shipped# spec:pointer is published rather than packed, and--run-consumer-smokerefuses on such a tree, now naming that cause. Set the knob to a different member list if your spec file is named otherwise, or to an explicit empty value to pack each root whole. Hand-vendoring a kit directory still gives you both. -
GATE_SDK_SPEC_BASE_URL— new, default empty: where a publisher publishes the SPEC sections its shipped# spec:pointers name. Empty means resolve in the tree, which is unchanged behavior for any tree holding its kit SPECs. Set it in your own knob file to have--pack-installerstamp it into the payload andinitwrite it into a vendored tree’sgate-sdk-config.knobs. The pointer grammar is untouched — a directive still names a repo-relative path, never a URL. -
run-gates.sh’s red output, andinit’s knob seam — a failing gate now prints its descriptor’s# spec:invariant on a line of its own beneath theFAIL:line, prefixed by four spaces andspec:, resolved throughGATE_SDK_SPEC_BASE_URLwhere that is set. A tool of yours that parses the run log by the two-space-indentedPASS:/FAIL:prefixes, or by content, is unaffected; one that reads a reddened gate’s block by order and stops at the verdict now stops one line short of the remedy. Andinitnow writesGATE_SDK_KIT_DIRSinto<gates-dir>/gate-sdk-config.knobsbesideGATE_SDK_NATIVE_BIN, declaring the vendored kit set rather than leaving it to the on-diskchecks/-or-smoke/predicate, which the withholding above would otherwise narrow silently. Your own lines in that file survive, and an edited seam is still reported and left alone. The--install place-artifactop takes--kitsand--spec-base-urlfor the same two lines. -
check-gate-assertions— its install disposition moves fromzero-configtoon-surface, so a fresh install no longer registers it. Its corpus in a vendored tree is your own<gates-dir>/SPEC.mdand your own gates, a surface you author later; the payload withholds every kitSPEC.md, so at install there is nothing for it to read and its empty-corpus branch is exit 2. Register it in yourgates.listwhen you author a SPEC of your own. The rule and the exit-2 wrong-directory guard are unchanged. -
check-install-dispositionassertion B — a kit shipping nosmoke/install.shis now skipped and counted on the clean line rather than reported as a finding for each of itszero-configgates; there is no roster there to be a superset of. This is what stops a vendored tree, where the payload withholdssmoke/, from reddening on every kit. Its clean line gains the skip count, so a log-matching tool of yours that pinned the old wording needs re-pinning. -
check-knob-default-coupling— a kit whose SPEC file is absent is now skipped and counted on the clean line instead of reporting one finding per knob. The assertion is drift between a source default and the SPEC that states it; a file that is not there is not a second site to drift from, and a kit whose SPEC is PRESENT but states no default still reds. This is what stops a vendored tree, where the payload withholds every kitSPEC.md, from reddening once per knob per kit. Its clean line gains the skip count, so a log-matching tool of yours that pinned the old wording needs re-pinning. -
profiles.list’s derivedfullprofile, and the manifest’skits— the payload’s reservedartifact/directory is no longer counted as a kit.fullstops vendoring it into<root>/artifact/, the manifest stops recording it underkits, and theGATE_SDK_KIT_DIRSlineinitwrites stops naming it. If an earlierinitvendored it, the files stay on your manifest’sfilesroster anduninstallstill removes them — nothing is orphaned — but a re-run atfullwill no longer rewrite them. Named profiles never carried it. -
check-spec-pointer— aspec:/contract:pointer whose target is a kit root’s own SPEC file is now reported as withheld and counted on the clean line, rather than as a dangling pointer, when that kit root resolves as a directory and only the SPEC file is absent. A pointer naming a kit root that does not exist still reds, and a target that is present but missing the named§headingstill reds. This is what stops a vendored tree from reddening on the# contract:headersinitseeds into your workflow directory, each of which names the kit SPEC that rules its file’s format — those pointers are correct, and the document they name is published rather than packed. Its clean line gains the withheld count, so a log-matching tool of yours that pinned the old wording needs re-pinning. -
lifecycle-kit/templates/stages/close.mdandscope.md— every filing of a new deferred entry (a drain or intake →promote, and each finding close files itself) now runs an owner lookup over the queue first and records the terms searched and the result in the filing commit message; a match is stamped as a recurrence on its owner rather than filed again. A binding that restated its own duplicate check can drop it in favour of the template sentence. -
check-queue-prose-precondition— the defaultQUEUE_KIT_PRECONDITION_REGEXleft-bounds its phrases on a non-letter, so a trigger embedded in a longer word (appending close,delegated on) no longer reds an active entry. A trigger set you configured yourself is unchanged; wrap it in(^|[^a-z])(...)to take the same bound. -
--emit stage-economics— a trend-log row’sdateis now the latest stamp date of the stage it prices (a supervision row its iteration’s latest), never the day of the run, and every line the run writes back is re-dated, so your first run rewrites the dates of an existing log once; a re-measured row is replaced where it stands rather than moved to the end, so an unchanged re-run is byte-identical. A row no dated stamp names keeps its date and is counted on stdout asdated by measurement. If you readdateas the day a row was measured, read the run header’s date instead. -
kpi-stage-economics-lag(drift-kit) — a new bundled Lead KPI counting closed iterations stamped after the newest one your stage-economics log prices (econ <N>on the trend line), andtemplates/kpis.listregisters it. Add it to yourkpis.listcopy, and if your decisions read the log, run--emit stage-economicsat your terminal stage (drift-kit/SPEC.md §The stage-economics meter, Feeding). -
run-gates.sh --enter-stage(boundary scratch wipe) — the spare test reads the scratch root’s immediate children only, and a spared directory is kept whole instead of emptied: a nested.gitkeep, or a nested file whose basename equals aLIFECYCLE_KIT_BOUNDARY_PRESERVEentry, is now deleted with its ancestors. A failed removal is reported on its ownboundary-wipe could not remove fromnote instead of counting as wiped, and a keep-list entry containing/is named as sparing nothing. If you track a.gitkeepbelow the scratch root, or relied on a nested basename surviving, name the root child that holds it onLIFECYCLE_KIT_BOUNDARY_PRESERVE. -
--emit close-surfaces,lifecycle-kit/templates/stages/close.md— each roster row gains a fifth tab-separated column,<state>:absent,empty(nothing past the# contract:header run) ornon-emptyfor a file row, andabsentor-for a<file>#<section>row.check-close-surfacesignores it and never reds onabsent. Close’s triage-sweep step now reads it, statingemptyas a clean read and takingabsentas a finding. A parser of yours that split rows into exactly four fields now folds the state into the owner: split on the first four tabs. If you copied the close template out, re-take step 4. -
lifecycle-kit/templates/stages/close.md— step 2 gains a first read before the gap drain’s first bullet, and a new named slot,drain-inputs, naming the capture surfaces that read covers. A binding shim of yours redscheck-skill-bindinguntil it binds the slot: add a**drain-inputs**entry naming your knowledge-friction capture or similar (never a raw machine log), or a line saying you have none. If you copied the template out, re-take step 2’s opening. -
lifecycle-kit/templates/stages/spec.md— gains a paragraph requiring a Definition-of-Done item that moves a queue entry to name a stage before the drain stage (or the drain stage itself, for a[drain-exempt:]entry), by its relation to the drain stage. Nothing to change on your side; if you copied the template out, re-take the paragraph. -
guard-kit/lib/guard.sh(guard_log_fallthrough, rule 8),run-gates.sh --emit scan-prompts— the friction log now records a call as one encoded line (\, newline and tab written as\\,\n,\t) cut at 10,001 characters, and scan-prompts decodes it: a heredoc body is data to the grant test, the command after its terminator is shell, an unquoted-delimiter body expands, and a call past the harness’s 10,000-character analysis bound ranks allowlist-unreachable. A line logged before the upgrade may mis-decode until the next close clears the log. Rule 8 now blocks an inline python body that is a literal rewrite (-cor a heredoc on stdin that writes a file, calls.replace(and computes no text) and steers it to--rewriteor the Edit tool, which a committedBash(python3 -*)grant previously let through. No action is required. -
lifecycle-kit/templates/stages/validate.md,close.md— validate’s red triage reads a filed entry matching a red as a possible cause: a red on an item that passed at the iteration start is reproduced at the iteration-start commit before it is held, and the hold records that commit (evidence-kit’sreproduces-at=<rev>); the valve’s reason payload gains the reproducing commit, and close’s valve-disposition step carries it onto the row it lands. A binding that describes a legitimate baseline edit should name the token; if you copied either template out, re-take validate’s triage, completion and valve paragraphs and close’s step 3. -
lifecycle-kit/templates/lead.md— the Tier each batch to its work class rule of lifecycle-kit/templates/lead.md §Economics gains an escalate-on-discovery transition: a session dispatched on a cheaper tier that finds a fix it must author journals the diagnosis, authors none of it, and escalates a re-tier, and the lead re-dispatches the rest as a same-stage session on the judgment tier rather than resuming the paused one. Name the class in your ruling-config’s escalation roster so a dispatched session recognizes it; if you copied the template out, re-take the bullet. -
lifecycle-kit/templates/stages/close.md, lifecycle-kit/SPEC.md §The state machine and §The audit roster — close step 8 now derives an audit’s corpus from the range itsscope:names, this iteration’s range unlessscope:names another base, and the SPEC defines the previous-close commit (the last close stamp’s<head>in the state file as it stood at the iteration-start commit) as that other base. A roster class that must also see the previous close’s own later commits may name it in itsscope:; nothing changes for a class that names no base. If you copied the close template out, re-take step 8’s range clause. -
lifecycle-kit/templates/stages/spec.md,align.md,build.md— the authoring template gains an authoring-exit pass that runs each delta’s own predicate and load-bearing premises before commit and marks an unrunnable premise with an inferred marker on its passage (lifecycle-kit/SPEC.md §templates/stages/); align runs every not-run marker’s command, and build runs a cannot-run one as soon as its subject exists. If you copied any of the three templates out, re-take the new paragraph and the two added sentences. -
lifecycle-kit/templates/stages/scope.md,spec.md,align.md,close.md,build.md,validate.md— a queue entry now carries the inferred marker: every filing of a new deferred entry (close’s filings and drain →promote, validate’s filed findings) marks each claim it did not run on a body line of its own with no list-item lead; scope runs the markers on each entry it promotes as debt, the authoring stage on the entry it pairs, align runs them in active queue entries as in amendments, and build runs a cannot-run one on an active entry as on a passage. If you copied any of these templates out, re-take the changed sentences. -
kpi-deferred-age(drift-kit) — each deferred entry now contributes one defer date, its firstSurfaced <date>mark else its firstFiled <date>mark read off its body lines, as queue-kit defines it; a date in the section preamble, a later repeat, or an olderFileddate on an entry that also carriesSurfacedno longer counts. The reported oldest defer date can move later on upgrade; nothing to reconcile. -
drift-kit gains the install-observation channel — two arms and one knob.
--emit file-install [--] <kind> <field>...appends one dated line per observed install, per red a non-author hit, and per retention check-in toDRIFT_KIT_INSTALL_RECORD(new; default${DRIFT_KIT_METRIC_DIR}/install-observations.log, so keep your metric dir gitignored — the record keys to people);--emit install-evidenceemits the aggregate-only projection over it, every figure with its denominator and<id>,<profile>and<floor>never published. Nothing is owed unless you capture: the record is created by its first line, and the projection over an absent one is a counted zero rather than a failure. Closed-set fields are enforced at capture, so a mistyped verdict, disposition, behaviour, horizon or retained value is exit 2 with nothing written; a-time-to-first-green files through the--separator. To pin the projection, commit it and add a byte-comparing freshness gate of your own — the gate is consumer-owned, drift-kit registering none. -
guard_allow_match(guard-kit, and its compiled twin) — a closing:*in an allow rule is now read word-bounded, as the harness grants it:Bash(printf:*)matchesprintfalone orprintfthen a space, and no longerprintfxorprintf-x.--emit compare-settings-allowstops calling a local entry redundant against a:*grant that does not in fact cover it, and rule 20 and the--emit scan-promptsranker stop reading a glued continuation as granted. Nothing to change in your config; re-read a redundancy or breadth report you pruned by. -
guard_split_compound(guard-kit, and its compiled twin) —|&is now one statement separator, taken whole, so the statement after it is its own segment to every per-segment guard rule and to the--emit scan-promptsgrant test rather than a segment headed by&. Nothing to change in your config. -
guard_allow_match(guard-kit, and its compiled twin) — a closing space-led*that is an allow rule’s only*now also matches the bare command, as the harness grants it:Bash(git status *)coversgit status.--emit compare-settings-allowmay now report a local bare entry beside such a glob as redundant, and rule 20 stops treating that bare command as ungranted. Nothing to change in your config. -
guard-kit grant tests and rule 15 — a segment a backgrounding
&ends is never read as granted, as the harness grants no backgrounded call: rule 20 counts it as the unmatched segment (blocking where it used to decline), rules 4 and 7 withhold a rewrite’s allow, and--emit scan-promptssections such a call allowlist-unreachable. Rule 15 no longer reads the|&separator as a backgrounded launch, somake |& tailfalls through where it blocked. Nothing to change in your config. -
LIFECYCLE_KIT_WORKTREE_LOCK_PID_RE(lifecycle-kit) — the lock-reason pattern is now compiled and captured by the gate binary’s own POSIX ERE engine rather than by bash’s=~, and the knob validator refuses at exit 2, naming the knob, the value and the rule broken, any pattern bash accepted that the engine does not admit: a GNU extension (\w,\b,\<, a backreference); two or more groups; a quantified group or one inside an alternation; and a group whose body contains an alternation. Write exactly one unquantified group in the pattern’s top-level concatenation with no|inside it, e.g.^held by pid ([0-9]+)$. A pattern already in that shape captures the same pid as before; nothing to change. -
checkwright doctor(andinit, whose last precondition it is) — the toolchain roster’s awk member is now plainawk, no longerawk::GNU: every awk program that ships is POSIX, so a host carrying mawk, BusyBox or BSD awk no longer fails the contract withwrong-impl. Nothing to do; a host that passed before still passes. -
doctrine-kit/DOCTRINE.mdrule 3, De-literalization — gains a reach test that says which source identifiers prose may name, checked before the citation test. Reach is judged at the file: a kit’s SPEC may name any function of the library that kit ships, another kit’s underscore-prefixed helper is internal and naming it is a finding, and a native item may be named when it is visible past its module (a private one belongs to the component its nearestspec:pointer names). The digest line is unchanged, so no installed block moves. Re-vendor the doctrine. If your audit roster’sinternal-identifier-restatementscope line decides internal-ness by some other test, point it at this one. -
check-producer-liveness(evidence-kit, and the--run-validateand--enter-stagearms that share its pid predicate) — on unix the predicate now askskill(2)directly and reads a process that exists but is not yours as alive, so it spawns neitherbashnorps: the absent-psrefusal can no longer fire there, and--needs check-producer-livenessdeclares nothing on unix. A native Windows build keeps thekill -0-then-ps -proute unchanged. Nothing to do. -
drift-kit date KPIs, the overhead meter, the usage poller and
--emit queue-index’s icebox cutoff — on Linux and macOS the gate binary reads civil dates in-process instead of spawning GNUdate -d: an ISO day or an ISO datetime with no written zone is local time, a writtenZor±HH[:MM]applies as written, and any other shape (the free-form phrases GNUdate -dalso took) is no reading. Nothing to do; a host without GNUdatenow gets these readings too. -
--emit overhead-meter(drift-kit) — the runner’s per-FAILinvariant line (the indentedspec:line) now scores asgaterather than task orgovdoc, so a session with red battery runs logs a slightly highergate=andpct=from the first measurement after upgrade. The log’sdatefield partitions the series at that point; nothing to do. -
checkwright doctor(andinit, whose last precondition it is) — the toolchain roster gainscurl, adopter-side and unconstrained, because the usage poller fetches its source with it: a host with nocurlonPATHnow fails the contract andinitrefuses rather than half-installing, as for a missingjqorshellcheck.GATE_SDK_PROGRAM_FLOOR’s default gainsps, so--emit port-blockersstops counting it off-floor; a consumer who set the knob keeps its own value. A consumer command’s spawn failure now names the knob or gate declaration that named it (cannot run <name> (named by <ground>): …), and a payload spawn names the program rather than its resolved path — re-pin a log-matching tool. Installcurlif your host lacks it. -
lifecycle-kit/templates/stages/build.md— the roster-floor paragraph’s declination test is now by obligation, not edit site: a build session declines a rostered update target only by naming, in the commit message, the need its citing delta places on it and the passage that already meets it; a surface with no such passage is a missed site landed in the same unit. If you copied the template out, re-take the paragraph’s closing sentences. -
--run-consumer-smoke— a run vendoring more than gate-sdk and one other kit root now also runs each kit alone: gate-sdk by itself, then gate-sdk plus each root, each in a fresh scratch tree, printingCONSUMER-SMOKE: alone — <n> kit root(s) green alone in <ms>msbefore the clean line and exiting 1 (installer failure included) on a kit that is not green alone. The default run costs roughly one more union pass. A kit of yours whosesmoke/install.shleans on a sibling kit’s install now reds; make it establish every surface its own registered gates read. gate-sdk’s ownsmoke/install.shnow installstemplates/gates-workflow.ymland registers thecheck-action-*gates, which site-kit’s no longer registers. -
gate-sdk/bin/run-gates.ps1,gate-sdk/bin/run-gates.sh— gate-sdk ships a new file: a PowerShell twin of the front-end for a native-Windows host with no bash onPATH, run aspwsh -File gate-sdk/bin/run-gates.ps1 <args>with the stub’s arguments, exits and messages. A new binary arm,--run-front-end-parity, compares the two halves over a fixed corpus and needs bothbashandpwsh. The stub’s outside-a-repository refusal is now its own line alone, without the shell’scddiagnostic before it. Nothing to do; the bash stub stays the front-end every existing caller uses. -
--run-front-end-parity— on a Windows host the arm now runs the PowerShell twin under Windows PowerShell 5.1 (powershell) as well aspwsh, and exits 2 when either does not resolve; a divergence names the host it diverged under, and the clean line names every host that ran. Elsewhere it runspwshalone, as before. Nothing to do unless you run the arm on a Windows host that lacks one of the two. -
checkwright init— on a native Windows host the follow-up block now spells both commands aspowershell -NoProfile -ExecutionPolicy Bypass -File gate-sdk/bin/run-gates.ps1 …, which runs from PowerShell and Git Bash alike; every other host keeps the twobash gate-sdk/bin/run-gates.sh …lines byte for byte.--run-consumer-smokenow asserts a follow-up target executable only where the line spells no interpreter before it. A tool of yours that parsed a Windowsinittranscript forbashshould read the target under installer/SPEC.md §init’s grammar instead. -
checkwright doctor(andinit, whose last precondition it is) and--emit env-probe— the toolchain roster dropsawkandsort::coreutils: the floor predicate compares versions in-process instead of spawningsort -V, so a host without awk or a GNUsortnow passes doctor, and asortlacking-Vcan no longer renderuncomparable.init’s downgrade refusal uses the same comparison, so a recorded or packed version carrying a prerelease suffix is no longer ordered and never refuses as a downgrade. Nothing to do. -
context-kit/templates/session-context.sh,drift-kit/templates/kpi-deprecated-surface.sh,gate-sdk/templates/check-skeleton.sh,installer/bin/checkwright.sh— the shipped awk programs are gone: the stage read and dirty-component list use bash builtins, the KPI counts withwc -l, the bootstrap reads its digest withread, and the skeleton scans withgrep -Hn(exit 1 is a verdict, 2 or more fails closed throughfail_closed … grep), so its finding lines carry the matched line rather than: finding. A copy you made of the session-context or KPI template keeps working; re-copy it to shed its awk. -
check-measured-claim,check-unmarked-claim,check-prose-tells,check-queue-slug-liveness,check-scratch-citation,check-close-surfacesand--emit ruling-staleness— a**in the surface glob you configure no longer descends into a directory the prune set (GATE_SDK_PRUNE_DIRSplusGATE_SDK_PRUNE_EXTRA_DIRS) names, so a build rewritingtarget/beside the battery can no longer fail these at exit 2 on a clean tree; a glob that names a pruned directory outright still reaches it. If one of your**globs meant to scan insidegate-tests/,worktrees/or another pruned directory, name that directory in the glob.check-evidence-baseline’s scenario globs are unchanged. -
drift-kit gains
--emit queue-flow [<n>], andlifecycle-kit/templates/stages/scope.mdreads it — the arm prints the design-pending pool’s filed and drained counts per trailing closed iteration (default five), keyed on iteration-start commits in the state file’s committed history, plus amean-filedrow; it degrades to onen/a (<reason>)line and exits 0. Scope’sComposition:line now ends; drain <k> against inflow <m>with<m>that figure, and the third ranking tier fills past the lead unit’s surface, one whole surface at a time, while the set drains no more than inflow. Nothing to configure: it reads the knobskpi-queue-net-deltaalready does, plusDRIFT_KIT_STATE_FILE; without drift-kit the line states the figure is unmeasured. -
lifecycle-kit/templates/stages/scope.mdandlifecycle-kit/templates/lead.md— a decline of a threshold-proposed deferred entry is now written on the entry with its date and who ruled it; an entry already declined twice is escalated as operator-routed, and the lead relays it rather than declining a third time. Nothing to configure; declines recorded only in commit history before the upgrade are not counted. -
lifecycle-kit/templates/stages/close.md— step 13 gains a new named slot,push-budget: how many pushes an iteration may spend, how many hotfix pushes a red push earns before the operator is asked, and the run a push is watched to. A binding shim of yours redscheck-skill-bindinguntil it binds the slot: add a**push-budget**entry with your numbers, or a “no remote — nothing is pushed” line.templates/stages/build.mdandtemplates/lead.mdnow name the pusher: the stage session whose next act reads the run (for an[observed-by:]entry, the session landing its work, before its Done move), never the lead. -
lifecycle-kit/templates/lead.md,templates/stages/build.mdanddelegation-kit/templates/agent-execution.md— a stage session’s journal path now has one source, its own--enter-stagereport: the lead names no journal path in a dispatch prompt, and a batch session enters even when the cursor already names its stage. If your stage-session agent definition tells the session “the dispatch names the journal path”, replace it with “your journal is the path your own--enter-stageprinted”, and decline a dispatch naming another path or suppressing the entry. -
lifecycle-kit/templates/lead.md— the “Relay, never assert” rule widens: a relayed claim carries its tier (measured, inferred or expected) and a grant whether it is spent, a fix travels as the constraint rather than the mechanism, and a rule travels only to a role its owning surface binds. Consider giving your stage-session agent definition the receiving half: an untiered claim is read as inferred, a relayed mechanism as a proposal, a relayed rule as binding only where its owner names the receiver’s role. -
checkwright doctor(andinit, whose last precondition it is) — the toolchain floor is now conditional on the selection:jqis owed only where guard-kit is selected,curlonly where delegation-kit is, andshellcheckonly where a registered gate needs it (check-shellcheck,check-action-run-shell).initresolves the profile’s kit set before callingdoctor; baredoctorinside an install reads the manifest’s kits and recorded registry, and outside one renders those three asnot probed. A starter or prose install no longer needsjq,curlorshellcheck. Reconcile if a CI step relied ondoctorrefusing a host without them. -
gate-sdk/checks/check-shellcheck.gate— its install disposition is nowon-surface, so no profile’sinitregisters it. If you author gate scripts under your gates directory, register it by hand;doctorthen owesshellcheck. -
docs/install.md§Requirements — the macOS remedy block is nowbrew install bashplus thePATHordering of Homebrew’sbin; coreutils andshellcheckleft it. The Windows remedy block dropschoco install shellcheck jq -yand keeps itsPATHlines. No shipped adopter path needs GNU coreutils; the binary spawnsdateandpsonly off unix. -
checkwright doctor— inside an install, it now names each registered gate that is disarmed: a gate whose header declares# armed-by: <KNOB>and whose knob resolves empty rendersdisarmed <gate> asserts nothing until <KNOB> is set.check-portability-floordeclaresGATE_SDK_PORTABILITY_PATHS, so a starter install shows it until you name your install-path corpus there. The line leaves the exit status and the verdict line unchanged. Set the knob to arm the gate, or leave it and the line. -
check-install-dispositionassertion D — new: achecks/member carries at most one# armed-by:line, naming a declared knob of its own kit; a second line, an undeclared name or another kit’s knob reds. The clean line gains the count of arming declarations. A gate of your own takes an arming line only where it names a declared knob of the kit whosechecks/holds it.armed-by:also joinscheck-comment-tier’s built-in directive roster. -
the generated git hooks (
pre-commit,commit-msg) — now POSIX sh:#!/bin/sh, nomapfile,[[ ]]or ANSI-C quoting, and each header names the gate binary (GATE_SDK_NATIVE_BIN) as the regeneration and--install-hooksdoor. On Linux and macOS they run under/bin/shand no longer needbash. Regenerate your hooks (--emit git-hooks --write). Agen=manualregion now runs undersh, so rewrite any bash-only construct in it before regenerating. -
checkwright init— it now generates the hooks and the coupling graph by running the gate binary it just placed, notbash gate-sdk/bin/run-gates.sh;initspawns onlygitand that binary. Nothing to do. -
checkwright init— the follow-up block now names the gate binary it placed on every host:./scripts/checkwright-gates --install-hooksand./scripts/checkwright-gates --run(with.exeon native Windows), in place of the bash and PowerShell front-ends. A tool that parsed the block forgate-sdk/bin/run-gatesshould read the target under installer/SPEC.md §init’s grammar instead. -
checkwright doctor(andinit, whose last precondition it is) —bash(≥ 4.3) is now owed only where the selection carries context-kit, delegation-kit, drift-kit, guard-kit or lifecycle-kit; a starter or prose install no longer needs it, anddoctoroutside an install renders itnot probed — owed where any of … is selected. The probe roster’s audience field now admits several kit names joined by+. Nothing to do. -
canon-kit/templates/canon-config.knobs— its header now points at the gate binary’s--emit knob-rosterarm rather than the bash front-end. Nothing to do. -
guard-kit’s hook (
lib/guard.sh) — it no longer needsjq: every payload read and every envelope it prints now goes through the gate binary’s new--guard-jsonflag, socheckwright doctornever asks forjq(it is now a contributor-only member) and a guard-kit profile installs on a machine without it. A command whose text carries a CR LF is now read verbatim on native Windows too. Nothing to do. -
guard_input_field <path>— it now takes a path (.name,[N],["key"]steps), not a jq filter; an argument outside that grammar, such as a pipe,//or a function, reads as an absent field and the rule fails open. If a rule in yourbash-guard.shcopy passes a filter, replace it with a path and do the rest in shell. -
kit:couples under a subdirectory vendoring — whereGATE_SDK_ROOTplaces gate-sdk below the repository root (saytools/gate-sdk),run-gates.sh --for,check-reads-couples,check-core-files’kit:lines,--emit port-blockers,check-gate-substrate-parityand the graph artifact now expand akit:token to the repository path the generated hook already matched, so--forselects what the hook runs and those gates stop reporting false reds. A root-level vendoring sees no change. Regenerate the graph artifact with--emit graph. -
GATE_SDK_NATIVE_PUBLISH_WORKFLOW— takes a space-separated list of workflows, andcheck-gate-substrate-parityassertion F audits each one, naming the workflow in every finding and reporting each absent member. A single value you already set reads as a one-element list. If your CI builds and hashes the release-shaped artifact in a second workflow, add it to the list. -
installer/bin/checkwright.sh— the unix bootstrap is POSIX sh (#!/bin/sh) and no longer needsbash. Run it assh package/bin/checkwright.sh <verb>.bash …still works, since bash runs POSIX sh. -
GitHub Release assets — each target’s gate binary now ships as
checkwright-gates-<version>-<target>.tar.gz, holdingcheckwright-gates(or.exe) and its.sha256, in place of the flatcheckwright-gates-<target>pair. Extract the archive and runsha256sum -c checkwright-gates.sha256inside it to cross-check the digest the installer verified. -
checkwright init --dry-run— now plans exactly the file set the real run records. It no longer names.workflow/validate-baseline.txt,.workflow/validate-evidence.txtor.workflow/WORKFLOW-STATE.txtwhere your tree already holds them. It now names an agent file you already hold, which doctrine-kit writes its block into, and the generatedcommit-msghook where a registered gate owes one. Nothing to do. -
checkwright init— a seed-once surface you deleted (the queue file, the agent file, the evidence manifests, the workflow-state file) is re-seeded and recorded at the hash of whatinitwrote. It is no longer reported as a changed file and carried at the previous version’s hash. Nothing to do. -
gate_native_bin_spelled— gate-sdk’slib/gate.shgains one accessor owning how the gate binary is spelled as a command:GATE_SDK_NATIVE_BIN’s value./-prefixed when relative, unchanged when already anchored.bin/run-gates.shandbin/run-gates.ps1now name the binary by that spelling in the absent-or-not-executable diagnostic, so the path you are shown is one you can run;run-gates.ps1gains the matchingGet-NativeBinSpelled. Nothing to do unless you parse that diagnostic’s path, which now carries a leading./. -
guard-kit/lib/guard.sh— the steer messages of rules 8, 19 and 23 no longer tell a session to runbash <vendor-root>/gate-sdk/bin/run-gates.sh; they name the gate binaryGATE_SDK_NATIVE_BINresolves, spelled as a command and resolved once per sourcing into_guard_door. The removed internal_guard_front_endhad no caller outside this file. If your harness allowlist grants only the shell front-end, add a grant for the binary so the steers name something a session may run. -
guard-kit/templates/settings-allow.json— the recommended allowlist now grants two doors, because after this release two different programs get spawned. The two front-end grants are unchanged and stay:settings-hooks.jsonwires its hooks to--hookarms, which keep the front end by construction, and a clone reaches it before its first build. Beside them are two new entries for the gate binary, shipped as the placeholder@GATE_SDK_NATIVE_BIN@— a kit file cannot carry your install location without publishing it. Replace the placeholder with the value yourgate-sdk-config.knobsgives that knob, spelled as a command; left unreplaced it matches no command, so you meet a permission prompt rather than a silent grant. Nothing merges any of this for you, as before. -
Every kit README, template and knob header — each now names the gate binary through
GATE_SDK_NATIVE_BINand the arm as the arm, with nobashand no path literal; the seven<kit>-config.knobsheaders take canon-kit’s landed wording. Usage blocks list arms rather than whole commands, under a lead-in naming what runs them. Nothing you configure changes; if you scripted against a README’s copy-pasteable line, it now names an arm and you supply the door. -
gate-sdk/templates/gates-workflow.yml— the CI starter resolves the binary once, in a newresolve the gate binarystep that sourcesgate-sdk/lib/gate.shand carriesGATESthrough$GITHUB_ENV, then runs"$GATES"in the later steps. If you copied this workflow, take the new step or the later steps will not resolve. -
guard-kit/smoke/install.sh— registerscheck-door-bindingin the scratch consumer’sgates.list, resolves the allowlist placeholder the way an adopter does, asserts the resolved door is an executable file and runs an arm on it, and exercises every grant against the installed guard from the resolved allowlist rather than the shipped template. -
context-kit/templates/session-context.sh,drift-kit/templates/kpi-deprecated-surface.sh— both templates now reach their arms by running the gate binary directly instead of spawning the shell front-end: the session-context hook drops itsRUN_GATESvariable and sourcesgate-sdk/lib/gate.shin-process (the library defines functions and runs nothing, so the oldbash -csubshell is gone), and the KPI example’sDRIFT_KIT_KIT_ROOTSwalk now locateslib/gate.shrather thanbin/run-gates.sh. If you vendored either template and retargeted its[EDIT ME]tool paths, retarget the library source line instead; a consumer copy of the session-context hook must propagate the newgate_native_bin_spelledcall orcheck-template-copy-parityreds. -
the
bashtool-floor audience — no longer a spelled kit list. The roster element isbash:4.3::derived, and every reader —checkwright doctor,--emit env-probe,check-install-toolchain, and the install page’s toolchain bullet — resolves it by evaluating a predicate over the kit roots in hand: a kit is on the bash floor when it ships a file your host runs with bash, meaning a file outsidegate-tests/andsmoke/that carries a bash shebang, or a settings template whose hookcommandis spawned with abashword. Prose telling a reader to type a bash command is deliberately not the predicate. delegation-kit and lifecycle-kit leave the audience and no kit joins it, so a host that met the old declaration meets the new one; if you selected either kit for its bash floor,doctornow skips thebashprobe where no other selected kit reaches it. A kit of your own that ships such a file joins the audience with no edit anywhere — which is the under-declaration this replaces.derivedis a sentinel and never a kit name; one that resolves to no kit root is reported undecided rather than not-owed, andcheck-install-toolchainexits 2 on it rather than comparing a page bullet against nothing. -
a packed kit README’s own-
SPEC.mdlink — where the packing tree setsGATE_SDK_SPEC_BASE_URL,--pack-installernow rewrites the extracted copy of eachpayload/<kit>/README.mdso a link whose target is exactlySPEC.md(orSPEC.md#<fragment>) points at<base>/<kit>/SPECinstead of theSPEC.mdthe payload withholds. The fragment passes through unchanged, the tracked README and its docs mirror are untouched, and an empty base rewrites nothing — so an unconfigured packer behaves exactly as before. The pack receipt gains a resolved-link count. Nothing to do; if you publish a payload and want the links to resolve, set the base. -
gate-sdk/templates/msg-patterns.list— gains the account-identification patterncheck-commit-msgandcheck-tree-termsnow read (see Tightened gates).initrewrites a seeded copy you never edited; if you edited yours, it is kept and now diverges from the kit’s: add the pattern’s line to your copy to take the guard. -
gate-sdk/templates/portability-patterns.list— gains a banned construct:cdonto agitcommand substitution with no fallback, which bash before 5.3 takes as a silent success when the substitution prints nothing.initdoes not seed this list; if you copied it out as yourGATE_SDK_PORTABILITY_PATTERNS, add the construct’s line to your copy. -
delegation-kit/bin/run-budget-guard-tests.sh,delegation-kit/bin/run-dispatch-guard-tests.sh— deleted; the guard cases they drove run as the gate binary’s own crate tests beside the--hookarms that replaced the guard templates. A script or permission grant of yours naming either path must drop it. -
delegation-kit/bin/usage-verdict.sh— deleted; the verdict rule is compiled into the gate binary and--hook agent-budget-guardcalls it in process, so nothing spawns a verdict tool. A script of yours that ran it must stop (DELEGATION_KIT_VERDICT_BIN’s removal is under Renamed knobs). -
doctrine-kit/bin/install-doctrine.sh— deleted; run the gate binary’s--install-doctrinearm instead, whichinitalso calls in process. Re-point any script or instruction file naming the old path. -
lifecycle-kit/templates/stages/build.md— the declaration paragraph now names removing a kit tool beside changing one, so a build that deletes a kitbin/tool declares it by path under Behavior changes. Nothing to change on your side; if you copied the template out, re-take the paragraph’s first sentence. -
run-gates.sh --enter-stage(boundary scratch wipe, report shape) — theboundary-wiped from <scratch>:note now names each wholly-removed immediate child once, never the nested paths deleted below it; a child left behind by a partial failure is absent from that note, and its failing nested path (or paths) still print on the separateboundary-wipe could not remove fromnote. A tool that parsed the wiped note for a nested path now finds only the immediate child’s own name. -
gate-sdk/lib/test-hermetic.sh— now unsetsGATE_SDK_TMP_DIRandGATE_SDK_WORKFLOW_DIRon source, so a sourcing bespoke test resolves both to their relative kit defaults against its own sandbox cwd instead of an ambient absolute value in the invoker’s environment; the unset runs before a test’s own explicit pin of either knob, since that pin sits after this library’s source line by construction, so it overrides no test’s deliberate choice. If a bespoke test of yours relied on inheriting an ambient absoluteGATE_SDK_TMP_DIRorGATE_SDK_WORKFLOW_DIR, pin the value explicitly after sourcing this library instead. -
guard-kit rule 12 — a
pgrep -f/pkill -fnow blocks when its pattern, read as the EREpgrepcompiles (case-insensitively under-i), matches the command’s own text, so a lone query or a loop-headed waiter that names the pattern once blocks where it passed; a quoted pattern is read whole across its blanks. A pattern that does not match its own text passes even when repeated, so a repeated bracket-trick literal no longer blocks, and-x/-vand an invalid ERE decline. Wait on the work’s own artifact orkill -0against a recorded PID instead; nothing to change in your config. -
doctrine-kit’s Re-verify volatile state before a git history rewrite and guard-kit rule 21 — the doctrine rule now has a session carry the commit message in the command (
-m, or-F -fed by a quoted heredoc) rather than in a scratch message file another session may have written, and read a file-borne message back withgit log -1 --format=%B; guard-kit rule 21’s advisory prints the same clause, on an unchanged trigger. Nothing to change unless you copied the doctrine out; re-vendor it. -
delegation-kit/templates/agent-execution.md— a call the harness moves to the background on its timeout is now the session’s own producer: size a foreground timeout above the command’s run, write its<key>.runrecord from any pid it names, and hold the turn and the tracked tree until its completion notification. If your agent definitions restate the waiting rule, propagate the sentence. -
subagent-stop-liveness— the turn-end hook also refuses while the payload’sbackground_tasksshows a runningshelltask, a call the harness moved to the background included, whatever the liveness reader said; the log grammar is unchanged, and such a refusal reads asdecision=refusebeside a non-refusing verdict. Nothing to configure; a session that ends its turn on a running shell task now meets the refusal. -
delegation-kit/templates/agent-execution.md— an isolated read-only dispatch prompt now names its return channel (its final message or the harness hand-back, never a peer send); isolation cost (4) gains a dispatcher half, so an oracle-running sweep has its arm run in your checkout and the output handed over as a file named absolute into the main checkout; a resumed isolated child is limited to re-emitting its report, since the resume runs in the main checkout, and an isolated child confirms its linked worktree at every start and resume. The header’s propagate list now names four passages: if your agent definitions restate isolation cost (3)’s child clause, propagate the resume check. -
lifecycle-kit/templates/lead.md— a stage session that reported and ended its journal withDONEyet still reads as active is now inspected rather than waited out: the lead checks its leftover processes (waiters, shells, worktrees) and reports them. Nothing to configure; if you copied the lead template out, re-take the paragraph after the undelivered-notification recovery. -
checkwright demo— a new adopter verb: it runs the adoption arc (install at thefullprofile, a green battery, a task marked done with no validate evidence caught, the claim withdrawn) from the installed package in a scratch repository of its own, and never touches the directory you run it from. It needs nothing from you. -
run-gates.sh --projection-witness— a new arm: for every gate carrying# projection:, it perturbs a scratch copy of your tracked tree (with its history) outside the gate’s declared trigger, one file per first-path-segment-and-extension class, and exits 1 naming any perturbation that turned the gate red, which means the gate reads a file itscouples=does not declare. It also printscoupled but inertlines as a report. It spawns each gate a few times per class, so run it as a validate suite rather than in the battery: addEVIDENCE_KIT_SUITES[] = projection_witnessandEVIDENCE_KIT_RUN_projection_witness = bash gate-sdk/bin/run-gates.sh --projection-witnessto your evidence-kit knobs to adopt it. -
context-kit/checks/check-surface-ratchet.gate— its pre-commit trigger now followsCONTEXT_KIT_RATCHET_PATHS: when you set that knob, a regenerated hook runs the ratchet on any commit touching those paths, so a surface regrown past its ceiling is refused at commit rather than at the next full battery. The verdict is unchanged; regenerate your hooks to take it. -
Every kit-shipped
.gatedescriptor naming a consumer path —couples=/trigger=literals such asTASK-QUEUE.md,CLAUDE.md,scripts/*.sh,scripts/gates.listand.workflow/*are nowknob:<NAME>tokens, or the new rooted formknob:<NAME>/<glob>under a directory knob or the gates-dir locator, so each gate’s hook trigger follows the path your knobs configure rather than this repository’s layout. Triggers only widen, since each token takes the covering*-led pattern. Regenerate your hooks after upgrading —bash gate-sdk/bin/run-gates.sh --emit git-hooks --write— orcheck-graphstays red. -
canon-kit/checks/check-deprecation-task.gate— now declares# armed-by: CANON_KIT_DEPRECATION_MARKERS, so where you registered it and left that roster empty,checkwright doctornames itdisarmeduntil you set your deprecation-marker regexes. The verdict and the exit status are unchanged. -
check-manifest-countandcheck-comment-tier’s count shape — the partitive exemption now reads across one line break: a total whose partitive marker (of,out of) ends the previous line of the same paragraph or comment block, with nothing but an article between it and the cardinal, no longer reds. Nothing new reds; amanifest-count-exempt:tag you added only to get past a wrapped partitive can now be deleted. -
--emit queue-index --icebox-candidates— arecurrence:line now holds an entry off the icebox only while its newest date is insideQUEUE_KIT_ICEBOX_AGE_DAYS; an older recurrence falls through to the live-slug test, so an entry pinned by one stale recurrence now lists•. The cause prints as[recurrence] re-filed <date> — live trigger(was[recurrence] dated re-filing — live trigger). If you parse the worklist’s recurrence rows, match the new text; no knob moves. -
check-queue-prose-precondition— each finding now prints an indentedfired on: "<clause>"row quoting the matched clause (lowercased, from the rewritten body), and the help text branches on the clause’s shape: a precondition the entry waits on takes a blocker tag, a Deferred move or a past-tense rephrase; a negated clause, or one naming the entry as what another waits on, takes[precondition-ok: <cause>]. The verdict is unchanged; if you match the finding text, allow the extra row. -
queue-kitqueue format — an entry is a### <slug>heading, a sub-task#### <slug>, with every bracketed tag on one tag line directly under the heading and the prose after it;recurrence:,roadmap-summary:andnot-icebox-eligible:body lines become the[recurrence: <date>, …]array,[roadmap-summary: <sentence>]and[not-icebox-eligible: <date> <grounds>]tags; a reference to a live entry is a same-file link and one to a retired slug stays in backticks; the deferred section’s###subsections are retired; Done stays a bare- <slug>bullet. Every queue gate and arm reads the new shape. Run--emit queue-migrate --write <queue-file>on the gate binary once, then delete any leftover deferred###subsection heading. -
--emit queue-migrate— a new arm converting a bullet-shape queue to the heading shape, refusing the whole file (nothing written) when the conversion would lose a slug, a tag or a done line, or when a declaration value holds a bracket. -
check-queue-entry-budget— the declaration-line discount is gone: an entry’s size is its whole extent, heading and tag line included; an icebox entry is its heading and one sentence, and a tag line on one reds; a retiredruled:line is now refused as a[ruled:]tag. -
--emit roadmap— each bullet now links to its queue entry, the queue path relative to the page, in place of the bold-code slug; regenerate your page. -
--emit queue-index --collapse-deferred— prints one(top): <n>tally, since the deferred section has no subsections. -
queue-kit/templates/TASK-QUEUE.md— the starter queue ships in the heading shape, unwrapped, one line per paragraph and every line within the default wrap budget, so eithercheck-md-unwrappedorcheck-queue-wrapholds it. -
check-queue-slug-liveness— a membership claim on a prose surface is now a markdown link into the queue file whose fragment is a slug; a bold-code token is plain emphasis and claims nothing. Rewrite a page’s claims as links. -
lifecycle-kit/templates/stages/scope.md,lifecycle-kit/templates/lead.md— scope now tests each shortlisted candidate for supersession, grepping the deferred pool and icebox by the names its deliverable edits, and the unit-set escalation’s Recommendation carriesSupersession:lines beside itsComposition:line (Supersession: none — <names searched>when nothing paired); the lead returns an escalation lacking either before routing it. A scope or lead binding that restates the escalation’s lines should take the templates’. -
lifecycle-kit/templates/lead.md— an answer that nothing changes is now relayed as one to be landed, naming the surface that recorded the question, and the stage session lands it there with its class and grounds; a question held in the gap inbox takes a resolution bullet through--emit file-gapnaming the bullet it resolves. A stage-session agent file or lead binding that restates the landing rule should add the no-change case. -
lifecycle-kit/templates/stages/spec.md— a delta whose act depends on whether a named sibling entry lands in the same build batch now states the act for each case and names the sibling, never one case in the unconditional voice. A spec binding that restates the authoring rules should take the template’s. -
doctrine-kit/DOCTRINE.md— gains methodology rule 13, Policy-as-choice: a kit ships a calibration as a consumer-selectable set,offamong them, and each consumer binds its own. The engineering-craft rules renumber from 13–26 to 14–27.check-doctrine-registrationreds your agent file until it carries the new digest bullet: re-run--install-doctrineafter re-vendoring. A citation of yours naming a craft rule by number now points one rule early; name the rule instead. -
doctrine-kit/DOCTRINE.mdProbe-before-assertion — the rule now binds a probe to the corpus its claim ranges over, and its digest reads “probed over the corpus the claim ranges over before it is asserted”.check-doctrine-registrationreds your agent file’s bullet until it matches the new digest: re-run--install-doctrineafter re-vendoring. -
gate-sdk/SPEC.md§The knob file — a knob that selects behavior now ships a working value (a bundled bare name, a kit--emitarm through the front-end, oroff), and a consumer command extends that set rather than being its only working member; a new kit-shipped adapter is an--emitarm. Nothing to change on your side. -
canon-kit/checks/check-measured-claim.gate,check-unmarked-claim.gate,check-prose-enum.gate,check-payload-claim.gate,check-install-claim.gate— each now declares# armed-by:its command knob (CANON_KIT_MEASURED_CLAIMS_CMD,CANON_KIT_CLAIM_CLASSES_CMD,CANON_KIT_ENUM_SETS_CMD,CANON_KIT_PAYLOAD_CLAIMS_CMD,CANON_KIT_INSTALL_TRANSPORTS_CMD), so where you registered one and left its knob empty,checkwright doctornames itdisarmeduntil you set the command. The verdict and the exit status are unchanged. -
CANON_KIT_MEASURED_SPAN— new canon-kit knob selecting the claim a full-linemeasured:marker binds, whichcheck-measured-claimarm C reads andcheck-unmarked-claimdischarges: the paragraph below it, its first sentence, oroff, which skips arm C for full-line markers and keeps arms A and B. The default is the paragraph span the gate shipped with, so no verdict moves on upgrade; an inline marker keeps binding its own sentence whatever the knob holds. Act only if your tree keeps markdown unwrapped and marks cardinal claims with full-line markers: setsentenceto bind each marker to its own sentence, then fix any marker it reds by moving the measured sentence first or marking it inline. Any other value refuses at exit 2. -
CANON_KIT_KNOB_CITATION_REACH— new canon-kit knob: how far a “default” marker may follow the knob tokencheck-knob-citationbinds it to. The default is the code-point reach the gate shipped with, so no verdict moves on upgrade. The alternatives are any other positive count,sentence(bind only within the token’s sentence) andoff(stop reading the default shape, keeping the=shape). Act only if your prose sits at a different distance; any other value refuses at exit 2. -
CANON_KIT_KNOB_CITATION_LITERAL_SPAN— new canon-kit knob: the bytes after the word “default” within whichcheck-knob-citationbinds it to a value literal. The default is the span the gate shipped with, so no verdict moves on upgrade; it takes any positive integer and has nooffor structural value, since the reach’soffalready stops the leg. Any other value refuses at exit 2. -
CANON_KIT_DEFAULT_COUPLING_WINDOW— new canon-kit knob: the code points after a knob’s name within whichcheck-knob-default-couplingreads its owning SPEC’s default statement. The default is the window the gate shipped with, so no verdict moves on upgrade. The alternatives are any other positive count andoff, which skips the SPEC comparison and keeps source self-agreement, its clean line saying the comparison was not run. Any other value refuses at exit 2. -
GATE_SDK_ASSERTION_STRENGTH_WINDOW— new gate-sdk knob: the lines after a guarded call thatcheck-assertion-strengthreads for failure text. The default is the window the gate shipped with, so no verdict moves on upgrade; it takes any positive integer and has nooff, since unregistering the gate is how a consumer wants none. Any other value refuses at exit 2. -
gate-sdk/templates/msg-patterns.list— the session-reference pattern’s value is now bounded by the token ([^ ]*, no space) rather than by the line, so it stops redding a prose lead-in that quotes a UUID later in its sentence and now also catches a URL-valued trailer. If you copied the template’smsg-patterns.listinto your gates dir, re-take the changed line. -
gate_harness_bin— newgate-sdk/lib/gate.shaccessor: inside a linked worktree with no gate binary of its own,run-gates.sh --hook/--statusline, itsrun-gates.ps1twin and guard-kit’s bash guard now dispatch to the main checkout’s binary, so an isolated agent’s hooks enforce rather than decline. Every verdict-bearing arm still resolves locally and fails closed. Nothing to do, unless the main checkout’s binary is stale against a worktree’s knob files: the bash guard then refuses there at exit 2, as it already does in a main checkout whose binary is stale. -
gate_path_rooted— newgate-sdk/lib/gate.shfunction, the shell’s one absoluteness test: a leading/or\, or a drive root (C:/,C:\).gate_native_bin_spellednow treats aGATE_SDK_NATIVE_BINopening with\as anchored rather than prefixing./, and guard-kit’s rule 24 now blocks a drive-rooted path in a grant’s path slot (bash C:/elsewhere/checks/check-x.sh) as it already blocked/elsewhere/…. Nothing to do unless you relied on either old reading. -
checkwright doctor— now namescheck-commit-msgandcheck-tree-termsdisarmed when no pattern fileGATE_SDK_MSG_PATTERN_FILESorGATE_SDK_MSG_PATTERN_FILES_LOCALnames carries a live line, reading their new# armed-by: content …declarations. The exit status is unchanged; act only if you emptied your pattern file on purpose, or if you parse doctor’s disarmed lines — the new form endscarries a live linerather thanis set. -
Fifteen kit
.gatedescriptors — their# graph: couples=triggers drop literals naming this project’s own layout for knob tokens and extension covers: thecheck-action-*gates couple*.yml,*.yaml;check-footprint-fresh,check-surface-ratchet,check-surface-duplicationandcheck-close-surfacestakeknob:CONTEXT_KIT_SURFACES,knob:CANON_KIT_DUP_SURFACESandknob:LIFECYCLE_KIT_CLOSE_SURFACE_GLOBS;check-install-claim,check-payload-claim,check-prose-tells,check-scratch-citation,check-graphandcheck-producer-livenessdrop transcribed or argv-supplied paths. Your hook now fires on your own configured files. Regenerate your hooks with--emit git-hooks --write. -
CONTEXT_KIT_FOOTPRINT_FILE,GATE_SDK_ENFORCEMENT_FILE— new knobs naming the committed pagescheck-footprint-freshandcheck-enforcement-freshcompare, which were fixed paths. The defaults are the old paths (docs/footprint.md,docs/enforcement.md), so nothing moves on upgrade; set them if your pages live elsewhere. An explicit positional still wins. -
check-graph— a descriptor whosecouples=expands to nothing because everyknob:token names a knob you left empty is no longer acouples= is emptyfinding; the finding now reads the authored field.check-prose-tellsis the stock instance: its trigger is its knob alone, and it scans nothing while that knob is empty. Nothing to do. -
# projection:— a projection line may name its output through a knob-path token,knob:<NAME>orknob:<NAME>/<glob>, resolved to the knob’s value verbatim, and the kit freshness gates (check-enforcement-fresh,check-footprint-fresh,check-graph,check-roadmap-fresh) now do, so relocating one of those outputs through its knob no longer redscheck-projection-roster. Akit:member on the line is a finding, and a line whose every member resolves empty declares nothing:check-roadmap-freshleaves the declaring set whileQUEUE_KIT_ROADMAP_FILEis empty, so drop a roster row you keyed to it on such a tree. -
check-enforcement-fresh— its trigger now covers every file underGATE_SDK_ENFORCE_SCAN_DIR, the monitor walk’s own root, in place of.github/workflows/*.yml; and a rootedknob:<NAME>/<glob>token over a.-valued knob now expands to the glob alone rather than to a pattern matching nothing. At the default.the gate fires on every commit. Regenerate your hooks. -
CANON_KIT_MIRROR_ROOT— new canon-kit knob, defaultdocs: the directory--emit docs-mirrorwrites under, the docs-mirror freshness comparator reads and the canonical-spec finder prunes, moved together. Nothing changes at the default. If your ownSPEC.mdsits atdocs/<dir>/, set the knob to a directory beneath your site root (docs/ref, say), regenerate the mirror there and delete the old pages. Empty,., absolute and..-bearing values are malformed config. -
CANON_KIT_PROSE_TELL_ABBR_MIN_LEN— new canon-kit knob, default3: the shortest all-caps tokencheck-prose-tells’ undefined-abbreviation tell reads, the length the gate shipped with, so no verdict moves on upgrade. Set an integer of at least2to recalibrate, oroffto drop that tell alone and keep the others; any other value refuses at exit 2. -
QUEUE_KIT_PRECONDITION_PAST_REGEX— new queue-kit knob whose default is the past-tense phrase setcheck-queue-prose-preconditionshipped with, stripped before its trigger matches, so no verdict moves on upgrade. If you added a forward verb toQUEUE_KIT_PRECONDITION_REGEX, add its past form here;offstrips nothing, an empty value is malformed config, and a pattern that does not compile exits 2. -
LIFECYCLE_KIT_AUDIT_ROSTER_LINE_CAP— now admitsoff, which dropscheck-audit-roster’s line-length assertion and keeps the grammar, class-uniqueness and stamp assertions. The default1500is unchanged. -
lifecycle-kit/templates/stages/— every stage template now reads its successor’s entry with--enter-stage --simulate <stage>after its last commit and before its journal step, so a refusal reaches the session that caused it;lifecycle-kit/templates/lead.md’s backstop sentence names that read with the journal. If you copied a stage template out, re-take it. -
lifecycle-kit/templates/lead.md— the lead holds a capture made while a dispatched stage session is live (a gap bullet, a survey block) in its own journal and files and commits it at the first moment none is live, so a batch’s clean-tree preconditions andgit addnever meet a lead write. If you copied the lead template out, re-take its capture paragraph. -
gate-sdk/lib/gate.shgate_verdict_bin,run-gates.sh/run-gates.ps1— inside a linked worktree with no gate binary of its own, a verdict-bearing arm now links the main checkout’s binary into the worktree’s door path and runs it, when that path is gitignored and, where the worktree tracks the crate source, the binary’s source stamp is the worktree’s; otherwise it refuses at 2 naming why and telling the session to run it in the main checkout, never to build.check-crate-armsin a linked worktree reads the main checkout’s green record on a local miss and refuses rather than runs cargo on a miss there. Nothing to do; a worktree that relied on the old refusal now gets a verdict. -
guard-kit ignored-target test (rules 16, 17, 19 B2, 25) — from a linked worktree it now asks the checkout that holds a main-checkout target, so a journal append into the main scratch dir is granted rather than blocked, and git’s stderr no longer leaks into a block message. Every non-block rule (the grants and rewrites of rules 4, 7, 16, 17, 18 and 19, and rule 21’s advise) now declines a call rule 27 refuses. Nothing to do outside a linked worktree.
-
delegation-kit/templates/agent-execution.md— isolation now charges five costs, as its list always held. An isolated sweep over an untracked or gitignored surface is delegable: the dispatcher names the surface absolute into the main checkout, and the child reads it with the read tool and searches it with a read-only pipeline. An oracle-running sweep runs its gates inside the worktree on the stamp-matched main binary. Every agent whose run an interruption could cost, a read-only sweep included, is granted a journal, which an isolated agent appends by shell. Re-read your consumer agent definitions’ copies of the cost (3) child clauses and the journal clause. -
guard-kit rule 2 — gains arm (d): the bash guard now blocks an
export NAME=value, a leadingNAME=valueor anenv NAME=valueprefix that sets a scalar kit knob to the value it already resolves to, or to another spelling of the same file, and names the command without the prefix. Drop the prefix; a differing value is an override and still falls through. -
guard-kit rule 27 — new, and inert outside a linked worktree: from a linked worktree, the bash guard blocks a command naming a main-checkout path outside the main checkout’s scratch dir unless it is a read-only pipeline of the read-only roster, the refusal naming the roster and the lawful routes. An isolated session reads a named main-checkout file with the harness’s read tool and appends its journal by shell under the main scratch dir; set
GUARD_KIT_WORKTREE_READS = offto refuse shell reads of the main checkout too. -
delegation-kit
agent-dispatch-guardD4 and D5 — new rules, each inert until configured. D4 blocks an unisolated dispatch of any type outside a non-emptyDELEGATION_KIT_MUTATING_TYPES. D5 is armed byDELEGATION_KIT_REQUIRE_TIER = onand blocks a dispatch naming nomodelwhose type has no definition underDELEGATION_KIT_AGENT_DIRstatingmodel:. To adopt them, bind the types that commit to your shared tree and dispatch every other type withisolation: worktree. With D5 on, name a model at each dispatch of a type that has no definition. -
subagent-stop-liveness— the task-view refusal now counts only the emitting session’s own shell tasks: a runningshellelement ofbackground_tasksrefuses when itsidoccurs as a whole token in the transcript the payload’sagent_transcript_pathnames, so a dispatched child is no longer refused on a shell task its dispatcher holds (a dispatcher’s recorded producer still refuses it through the record set). An absent or unreadable transcript keeps the unscoped refusal. The log grammar, the refusal text and the exit contract are unchanged; nothing to configure. -
guard-kit rules 14, 15 and 19 (B) — from a linked worktree, a relative
GUARD_KIT_SCRATCH_DIRSmember now resolves against the main checkout, the liveness record’s home: rule 14 holds a git write on a live record under the main checkout’s scratch dir, rule 15 counts a record written there and names that home in its corrective, and rule 19’s arm (B) grants the canonical recorded launch carrying it. A record written into the worktree’s own scratch dir is now refused. An isolated session records its producer under the main checkout’s scratch dir; nothing to configure. Outside a linked worktree the only change is that a record path is compared with ./ and .. folded. -
guard-kit knob load — a library whose knob-load list names a knob the gate binary does not declare (the library updated ahead of the binary) no longer blocks every command: the hook advises naming the undeclared knob and the rebuild command, runs no rule, and lets the call take the harness’s own permission path. Rebuild or re-install the binary to restore steering. A malformed or missing knob file still blocks with the refusal’s text.
-
guard-kit rules 18 and 20, and
templates/settings-allow.json— an allow entry whose only*is a closing space-led one (Bash(git show *)) now lends its head as a bare lead, which the harness already grants bare. So rule 20 blocks a decorated no-argument call such asgit show > out.txtorcargo test; makewith its run-it-bare steer, and rule 18 grants such a head piped into a read-only tail. A redirectedGUARD_KIT_APPEND_BINSemitter taken this way is left to rule 25. The template drops its three no-argument twins: the binary, the front end andls. Drop the no-argument twin beside each space-star entry in your own allowlist; the guard and the harness read the space-star entry alone the same way. -
subagent-stop-liveness— a harness helper’s firing now allows on every arm. A helper is the progress-summary firing the harness makes while a dispatched session runs, and the hook classes a firing as one only when all three marks hold:agent_typeempty,agent_transcript_pathnaming a path that does not exist, andagent_idnaming nosubagentelement ofbackground_tasks. The line keeps the reader’s verdict and recordsdecision=allow, soredorcorruptbesideallowmarks a helper, and a task-held refusal in the log is now always a dispatched session’s own. Every firing of a dispatched session decides as before. The log grammar, the refusal text and the exit contract are unchanged; nothing to configure. -
guard-kit’s
PreToolUse(Bash)hook (lib/guard.sh,templates/bash-guard.sh) — both deleted; the hook is now--hook shell-guard, a compiled member of the gate binary carrying every generic rule with its verdicts unchanged. Rewire your.claude/settings.json’sPreToolUse(Bash)command frombash <script>tobash gate-sdk/bin/run-gates.sh --hook shell-guard, the wiringtemplates/settings-hooks.jsonnow ships. Move any project rule out of your copiedbash-guard.shinto a command named by the newGUARD_KIT_CONSUMER_RULES_CMDknob — a plainPreToolUsehook command of your own, speaking the harness’s own protocol on stdin/stdout/exit code, with--guard-json view <view>handing it the same quote- and heredoc-inert match surface a copied rule read off the shell primitives — then delete the copiedbash-guard.sh. Honest limit: a consumer that upgrades without rewiring keeps a copied guard whose first line tests for the now-deletedlib/guard.shand exits 0; its guard fails open silently until you rewire, and this entry is the only notice. -
--emit enforcement-map— the Guards table now rows the command hooks of every event other thanSessionStart(aSubagentStoporStopregistration is no longer missing), gains aneventcolumn, and heads a--hook <member>row with the member’s name, credited to the member’s owning kit rather than to gate-sdk’s front-end path. Regenerate your committed page with the commandcheck-enforcement-freshprints. -
--hookdeclines — a hook member that cannot resolve its own knob now tells the session model onPreToolUse(anadditionalContextadvise envelope) and the operator on every other event (asystemMessagewarning), and a tree with no runnable gate binary now hasrun-gates.sh/run-gates.ps1 --hookwrite asystemMessagetelling the operator its hook guards are off. Before, both wrote only to stderr, which the harness keeps in its debug log. Nothing to do; a hook command of your own that wraps--hookand reads its stdout now meets that envelope on the decline paths. -
run-gates.sh --enter-stage --dispatch <stage> --waive <reason…>— new form: an operator-ruled audit waiver is declared with it by the dispatcher (a lead, or the session the operator instructs) and written by the entering stage’s own entry, as a<iter> <waiver-token> <id> <date> <head>line immediately before its stamp; the entry report prints abody:line carrying the reason, for the stamp commit’s body. A dispatch-marker line may now carry fields after its stage.check-stage-entry’s assertion-C recovery names this form, and every state-file line it prints names your configuredLIFECYCLE_KIT_STATE_FILErather than the scratch candidate--enter-stagehands it. If you copied the align or lead template out, re-take its waiver sentence; a hand-appended waiver line still satisfies assertion C. -
--hook workflow-state-guard(stamp-before-write) — with the newLIFECYCLE_KIT_STAGE_SESSION_TYPESknob set (default empty, so nothing changes until you set it), the workflow-state guard also refuses aWrite/Editfrom a dispatched stage session — a caller whose payloadagent_typeis on that roster — until a data line ofLIFECYCLE_KIT_STATE_FILEcarries that session’s id (itsagent_id, normalized as--emit session-idnormalizes it). A top-level session, a lead and a stage run by hand carry noagent_typeand are untouched. To adopt it, set the knob to the agent type your lead dispatches stage sessions as; no settings edit is needed, the guard’s existing registration carries it. -
--hook workflow-state-guard(state-file rule) and--rewrite— the direct-edit rule and--rewrite’s state-file refusal now resolve the state file throughLIFECYCLE_KIT_STATE_FILE, as the stamp-before-write rule and every stamp writer already did, in place ofGATE_SDK_WORKFLOW_DIR/WORKFLOW-STATE.txt. Nothing changes at the default, which derives fromGATE_SDK_WORKFLOW_DIR. If you setLIFECYCLE_KIT_STATE_FILEto another path, the guard now protects that path rather than the one it left. -
--hook shell-guard— now grants a recorded launch whose target, and steers a knob echo whose value, spellsSQorDQ, where it declined; and it blocks a command carrying a raw control byte other than tab, line feed or carriage return, naming the escape that spells it (printf '\x<hh>'). Act only if a command of yours carries such a byte raw: write it as that escape.--guard-json viewprints nothing for such a command and prints every placeholder as its two letters, as before. -
guard-kit/templates/settings-hooks.json— the shell guard’s matcher isBash|PowerShell. Re-merge it, and a call through the harness’sPowerShelltool then meets these generic rules (cd_compound,scratch_redirect,git_grep,git_mutation_under_producer,git_rewrite,rm_tracked,worktree_confinement) read through a PowerShell reader, takes no guard grant, and is logged when nothing decides it. -
GUARD_KIT_CONSUMER_RULES_CMD— under the widened matcher your consumer command also receivesPowerShellpayloads, and--guard-json viewreads them through the PowerShell reader. Readtool_namefirst in any rule written for bash grammar. -
--emit scan-prompts— PowerShell fall-throughs, logged asPowerShell, a tab, then the encoded command, print in their own advisory section keyed by command word, off the headline and--count; every Bash line and the KPI series read as before. -
--emit queue-migrate— no longer cuts a wrapped sentence at a line that begins with bold text: a continuation line opening with a bold span starts a paragraph only as a lead-in, its own span ending in.or:or the paragraph before it ending a sentence, and otherwise joins. A queue you already converted is returned as it stands, so any split the earlier arm left there is yours to join by hand. -
supported-platform roster —
aarch64-unknown-linux-gnujoined:initon an arm64 Linux host installs a published native gate binary where it refused the host before. -
supported-platform roster —
aarch64-pc-windows-msvcjoined:initon an ARM64 Windows host under Git for Windows’ bash installs a published native gate binary where it refused the host before. The host is resolved from the OS’s architecture, since Git’s shell runs emulated there and reportsx86_64. -
guard-kitrulebackground_no_record— now applies to thePowerShelltool: a PowerShell call backgrounded by the harness, or a detachedStart-Processwithout-Wait, is blocked unless it writes the LF-terminated record the corrective spells, aSet-Content -NoNewlineto<scratch-dir>/<key>.runwhose value ends in the`nescape, the command wrapped in atry/finallythat removes it; a plainSet-Contentor a>record reads as corrupt. An inlinewhile/dowait loop owes no record. On a native Windows build the liveness predicate now answers a Windows process id first, so a PowerShell-launched producer’s record reads held while it runs. -
lifecycle-kit/templates/stages/andlifecycle-kit/templates/lead.md— scope’s unit-set escalation states its push need against the close binding’s budget, the ruling lands a push line on each push-needing entry, build pushes under it, and close’s push needs no ask of its own. A copied template is re-taken. -
check-commit-msgrefusal help /gate-sdk/templates/msg-patterns.list— the refusal help text no longer argues against banning theCo-Authored-Bytrailer (it names the pattern set only now), and the template’s promo-URL comment states leaving the trailer unbanned as the shipped default rather than a rule the kit takes a side on. Banning the trailer is a consumer-selectable class (§check-commit-msg, Policy-as-choice): add your own pattern to your copy of the template for the ban, and note it also scans the tree throughcheck-tree-terms, since both gates share one pattern source. If you copied the template or quote the old help text, re-take the comment. -
--scratch-run— executes a snapshot of the body it echoed rather than re-reading the target, so a rewrite landing after the echo no longer runs unseen. The snapshot is a dot-led file beside the target, created per run and removed when the child exits, and the second header now readsexecuting <target> as <snapshot>.$0,BASH_SOURCEand$PSCommandPathname the snapshot: a script of yours that locates itself through them still finds its siblings, but not its own original name. -
GUARD_KIT_SCRATCH_POWERSHELL— new guard-kit knob, default empty (off). Set it topwshorpowershell, bare or as a path, and--scratch-runruns a.ps1body under that host with-NoLogo -NoProfile -NonInteractive -ExecutionPolicy Bypass -File, echoing it first; left empty, a.ps1is refused. A.shwhose shebang names a PowerShell host is now refused with the corrective to name it.ps1. Setting the knob widens what your front-end grant runs, so set it in your own knob file only if you want that. -
guard-kit rule
script_interpreter— now applies to thePowerShelltool and to a PowerShell host under Bash:& .tmp\x.ps1,.\.tmp\x.ps1, a dot-sourced or command-position scratch path,pwsh -File .tmp/x.ps1and a scratch path piped intoiexare blocked, as arebashand the interpreter roster on a scratch body through the PowerShell tool. The steer names the runner’s PowerShell path whenGUARD_KIT_SCRATCH_POWERSHELLis set and a bash body under the runner when it is empty. Run a scratch PowerShell body through the runner, or set the knob. -
context-kit/templates/session-context.sh— step 8, the craft-rule block, now prints one warning line namingCONTEXT_KIT_STAGE_RULESand the exit status when that command exits non-zero, where it used to drop the block silently; the hook still exits zero. Your copy of the hook keeps the old silent form until you re-copy step 8 from the template. -
capture writes from a linked worktree — every capture writer the gate binary carries (the guard’s fall-through log, the wakeup log, the turn-end liveness log, the wait-primitive evidence, the lesson sink’s fallback harvest file, the usage history, the overhead and stage-economics logs, the knowledge-friction log and the install-observation record) now resolves a relative path against the main checkout when it runs in a linked worktree, so an isolated agent’s capture reaches your close triage instead of dying with the worktree. An absolute knob value is used as written, and reads are not redirected. A capture writer of your own outside the binary meets the same rule with
git rev-parse --git-dir --git-common-dir. -
--emit capture-drainand the close triage templates — a new arm,--emit capture-drain [--done] [--] <log>, renames a capture log aside to<log>.drainbefore a close reads it and leaves the live log present and empty, so a line a concurrent session appends mid-triage is no longer erased.guard-kit/templates/close-triage.mdanddrift-kit/templates/close-knowledge.mdnow drain the friction, wakeup and knowledge-friction logs through it and remove the drain with--done, the shippedclose-surface:rows name it as their reclaim, and--emit scan-promptscloses its report with the drain command rather than a: >truncate. Gitignore.workflow/*.drainand.workflow/*.drain.part(the close-surface derivation folds them into their log’s row), re-take the two templates if you copied them out, and drop any exact-string: >grant for those logs from your settings. -
delegation-kit/templates/agent-execution.md— the in-turn liveness wait is now spelledwhile kill -0 <pid> 2>/dev/null; do sleep N; done,<pid>the literal number read out of the.runrecord, where it spelled"$pid", an expansion guard-kit refuses. If you copied the template out or restate its wait in an agent definition, respell the PID as a literal. -
--emit <name>— every--emitmember now refuses an argument outside its grammar at exit 2, where a surplus or misspelt one was dropped at exit 0: a member taking no argument refuses any, and one reading only flags refuses any other token. A member reading free-text operands —md-indexandpub-indexpaths, thestage-rulesstage,ruling-stalenessnames, theclose-surfacesscan root — refuses a dash-led one, which--admits, andclose-surfacesrefuses a second operand. Every--emitrefusal of an argument’s shape now prints the member’s usage block on stderr,--helpincluded; a refusal on anything else, such as a missing file, names its cause alone. Act only if a script or knob value of yours passes an--emitmember an argument it never read — drop the argument. -
--run-gate-tests— a named checks dir that does not exist is now exit 2 naming it, where it was dropped and every gate then reportedresolves in none of:; a dash-led argument,--helpincluded, is a refusal printing the usage at exit 2, and--admits a path beginning with-. Act only if a fixture-suite line of yours names a checks dir your tree does not have — drop that argument. -
--run-validate— any argument,--helpincluded, is now refused at exit 2 before the lock is claimed, where it was dropped and a full validate run started. Act only if a script of yours passes it an argument — drop the argument. -
--upgrade-smoke— runs from inside a linked git worktree, where it refused withnot a git repository;GATE_SDK_UPGRADE_REPOmust still name a work tree’s toplevel, so a subdirectory is refused. Nothing to reconcile. -
--emit docs-mirror,--emit roadmap,--emit queue-index,--emit entry-historyand--emit port-blockers—-h/--helpis now refused at exit 2 like any other unrecognized argument, its refusal printing the member’s usage on stderr, where it printed the usage on stdout at exit 0; forport-blockersthat holds in every position, where--helpfirst won over whatever followed it. Every--emitmember now answers--helpthe same way. Act only if a script of yours reads one of these members’ usage off--helpat exit 0 — read it off stderr from the refusal. -
--usage-poll,--statusline—--usage-pollnow refuses any argument,--helpincluded, at exit 2 before it polls, where the argument was dropped and a cycle ran.--statuslinestill ignores an argument and renders as before, and now names it on stderr. Act only if a timer, aDELEGATION_KIT_REFRESH_CMDvalue or astatusLinecommand of yours passes either arm an argument: drop the argument. -
--install-hooks— a positional argument, bare or after--, is now refused at exit 2 before any git config is written, where it was dropped and the full opt-in ran at its normal status; a dash-led one was already refused. Act only if a script of yours passes it an argument — drop the argument. -
lifecycle-kit/templates/stages/build.mdandclose.md— each now points at doctrine-kit’s Enforcement-first rule body at its discovery step: build before a mid-build defect or redundancy fix lands, close at step 1’s gap generalization. A copied template is re-taken. -
--enter-stagepre-flight refusal help — a refused entry’shelp:line no longer invites a hand-written stamp: it names resolving the finding at its source or escalating it, and states that a hand stamp is the operator’s override, which the workflow-state guard blocks from a session. Act only if a script of yours matches the old help text. -
check-stage-entryrefusal help andlifecycle-kit/templates/stages/spec.md— assertion C’s help now says that respelling an amendment body token so it stops resolving is not a remedy, and assertion D’s help says that a claim no delta rests on keeps its honest limit in prose when its marker goes. The spec template’s causal-completeness step carries the respelling line too. The verdicts are unchanged. A copied spec template is re-taken. -
doctrine-kit/DOCTRINE.mdAbsence statements — gains methodology rule 14, Absence statements: state an absence only where a reader must know it was considered, and then as a token; omit it elsewhere, so an empty section is its heading alone. The engineering-craft rules renumber from 14–27 to 15–28.check-doctrine-registrationreds your agent file until it carries the new digest bullet: re-run--install-doctrineafter re-vendoring. -
--emit roadmapempty horizon — an empty horizon is now its heading alone, with no placeholder line under it.check-roadmap-freshreds a page whose committed block still carries the old line: regenerate it with--emit roadmap --write. -
--install-doctrinelink paragraph — the digest block’s intro paragraph is now written as one line where it was hard-wrapped over three, so a tree registeringcheck-md-unwrappedstays green after an install. Nothing to do; a block you already rejoined is left as it is. -
--with-foreign-shells— new gate-sdk contributor arm, with two new knobs,GATE_SDK_FOREIGN_PWSH_IMAGEandGATE_SDK_FOREIGN_DASH_IMAGE, each defaulting to a digest-pinned image reference: on a Linux host with Docker it copiespwshanddashout of those images into your scratch directory and runs the command you hand it withpwsh,dashandsh(as dash) first onPATH, passing its exit status through; without Docker, or off Linux, it skips at exit 0. Nothing runs it unless you do, so nothing to do; to test a PowerShell or POSIXshchange before a push, wrap the suite that needs the shell in it. -
check-evidence-manifestassertion C remedy — the finding for a validate stamp with no evidence line now tells you to run--run-validateon the binaryGATE_SDK_NATIVE_BINnames, instead of naming this repository’sgate-sdk/bin/run-gates.sh, which an installed tree does not carry. The verdict is unchanged; nothing to do. -
init— seeds.github/workflows/gates.ymlwhere it is absent, a workflow running the battery through this project’s CI action at the release yourcheckwright.locknames and uploading each red as SARIF.updateseeds it into an existing install too. If you already run the battery from a workflow at another path, delete one of the two. -
GATE_SDK_SARIF_FILE— a new environment-only gate-sdk knob: set, the battery also writes its verdict as a SARIF 2.1.0 log to that path. Unset, nothing changes.
Upgrading
Replace the vendored kit directories wholesale at v0.26.0. Then retire each shell config the new kits replaced with a knob file: rewrite what you set in <gates-dir>/<stem>-config.sh, and in any <stem>-config.local.sh, into its .knobs file and delete it. A copy init seeded that you never edited is simply deleted. Regenerate your generated artifacts; each one’s freshness gate names its own regen command when it reds. Then run the full battery.
The allowed reds. Every gate under Tightened gates above may red, and its bullet names what clears it. They fall into two groups:
- A gate refusing at exit 2 on a left-behind
<gates-dir>/<stem>-config.shis the knob-file migration. The phase-A step above clears it. - Every other red is a finding the gate could not previously see, or a new gate you chose to register. Reconcile it as its bullet states. A new opt-in gate stays silent until you register or configure it.
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.