Checkwright v0.27.0

2026-09-28

Checkwright is the verification layer under agent orchestration, and this release fits the prose profile to spec trees that Spec Kit or OpenSpec writes, and adds a static Linux gate binary beside the glibc one so the installer serves any Linux.

In brief

  • If Spec Kit or OpenSpec writes your specs, each now has a tested recipe for the prose profile, and Spec Kit gets an extension attached to this release as checkwright-companion-0.27.0.zip. The Spec Kit and OpenSpec page walks both.
  • Alpine, and any Linux whose glibc is older than 2.39, is now served: a static build ships beside the glibc one, and the installer takes the glibc build wherever it runs and the static one everywhere else. An install that runs today keeps its binary.
  • Installs now check the minimum versions of the tools they rely on, such as git 2.15, and name the floor a host is below instead of failing later.
  • New gates ship for docs pages, catching a repeated sentence or link, a section citation left unlinked, and a collapsible region the Pages parser would print raw. Each arms only where you register it.
  • You have one step to take after upgrading. Register each new gate your kits carry, or declare it unregistered; your first battery names them. Then regenerate the pages it reports stale.

Tightened gates

  • check-survey-record — a survey block’s corpus must now be the literal none or space-separated git pathspecs, single-quoted where one carries a quote, a shell metacharacter, a glob character or pathspec magic, and in bare mode each pathspec must match a path at the block’s rev. A block whose corpus is prose, carries an unquoted glob, or names nothing reds; rewrite its corpus to the pathspecs the survey read (scoping prose moves to finding), or none for a survey over no tree corpus.
  • check-docs-page-repeat — new canon-kit gate: no page declared in CANON_KIT_PAGE_REPEAT_PAGES states a relative link target, or a sentence of CANON_KIT_PAGE_REPEAT_MIN_WORDS words or more, twice. It arms only where you set the corpus knob; register it and set the knob to hold your docs pages, then make each later repeat plain text or an in-page anchor.
  • check-gate-substrate-parity — reds after upgrading through assertion I, which holds every gate the binary carries for a kit you vendor to be registered in your gates.list or declared # unregistered: there. If you vendor canon-kit, the new check-docs-page-repeat and check-citation-link are such gates, and if you vendor site-kit, the new check-docs-collapsible is: register each, or declare # unregistered: <gate> — <reason>.
  • check-citation-link — new canon-kit gate: on a page declared in CANON_KIT_CITATION_LINK_PAGES, every section citation (<path> §<heading>, or a bare §<heading>) sits in a link’s text whose target carries that section’s anchor; a later mention of a section the page already linked stays plain text. It arms only where you set the corpus knob; register it, set the knob to your hand-authored pages, and turn each unlinked citation into a link to its section.
  • check-docs-collapsible — new site-kit gate: every <details> region on a tracked docs page opens with markdown="1", carries a <summary>, hides no heading and closes. Register it where your docs site builds with the Pages parser, and add markdown="1" to any region the Pages parser was printing raw.

Renamed knobs

None. Knobs were added this cycle, and none was renamed or removed.

Behavior changes

  • --emit file-survey — the arm now refuses at exit 2, filing nothing, a corpus outside the grammar above or naming a pathspec that matches no path tracked at HEAD, and names each unmatched pathspec. File the pathspecs the survey read, single-quoted where needed, or none; a none corpus’s witness hint prints the oracle re-run alone.
  • --emit file-gap and --emit file-survey — both now refuse at exit 2, writing nothing, when run in a linked worktree, where the tracked line would be lost with an uncommitted worktree. An isolated child hands the finding back to its dispatcher, who files it from the main checkout; a session that works and commits in a linked worktree appends the line by hand in the record’s grammar.
  • --hook workflow-state-guard — with LIFECYCLE_KIT_STAGE_SESSION_TYPES set, a dispatched stage session whose stage the cursor has left is now refused Write and Edit outside the scratch dir GATE_SDK_TMP_DIR names; its resume journal there stays writable. Such a session answers through its report and the live stage session lands the change. With the knob empty, nothing changes.
  • --enter-stage and --install queue-source — on native Windows, the iteration-boundary wipe report (boundary-wiped from <tmpdir>: …, and each residue path it could not remove) and the queue-source record now join each name onto its directory with /, the declared dialect, where they joined with \. Nothing to do; a reader splitting these lines on / now reads them.
  • --emit enforcement-map — a harness settings file at the default path that does not parse now drops the hook sections, as for an absent file, where it refused at exit 2 and reddened check-enforcement-fresh. An explicitly set CONTEXT_KIT_SETTINGS_FILE that does not parse still refuses. Nothing to do.
  • --emit enforcement-map and --emit footprint — the generated pages’ prose changed: the enforcement map names the repository it is generated from where it said “this repo” and states what the (consumer) group holds, and the footprint page states what earns a row. check-enforcement-fresh and check-footprint-fresh red on your committed pages until you regenerate them with the command each prints.
  • CANON_KIT_COMMENT_ACTIONS — new knob, off or on; set to on, it extends check-comment-tier, check-spec-pointer, check-todo-task-liveness and check-deprecation-task to every actions-shaped YAML file (a top-level jobs: or runs: key), so your CI workflows’ comments are governed like a script’s. It defaults to off, so nothing changes until you set it; set it in your canon-config.knobs once your workflows’ comments are directives.
  • check-comment-tier — the gh-repo-exempt: and action-permissions-exempt: valves and the enforce: monitor marker are now blessed directives, so a governed workflow may carry them. Nothing to do.
  • init — a re-run now writes the hooks and the coupling graph where your GATE_SDK_HOOKS_DIR and GATE_SDK_GRAPH_ARTIFACT put them, and records those paths, where it wrote the graph to the default <gates-dir>/CHECK-GRAPH.html and recorded both at the default layout whatever the knobs said. Nothing to do; delete a default-path graph an earlier run left behind if your knob moved it.
  • uninstall — now removes the installed gate binary even when it no longer matches the hash init recorded, where it kept it and reported it as yours. Nothing to do.
  • doctor, and so init — now hold git ≥ 2.15 on every profile, curl ≥ 5.9 where delegation-kit is selected and shellcheck ≥ 0.6.0 where a registered gate needs it. A host below refuses at doctor and names the floor, and --emit env-probe renders the same floors (jq ≥ 1.5 among them, contributor-only); upgrade the tool.
  • The Linux gate binary — now published twice per architecture: the glibc build, x86_64-unknown-linux-gnu and aarch64-unknown-linux-gnu, and beside it a build statically linked against musl, x86_64-unknown-linux-musl and aarch64-unknown-linux-musl, which runs on any Linux kernel 3.2 or later (4.1 on arm64) whatever the host’s C library. The installer takes the glibc build where it runs and the musl build everywhere else, and asks no question about the host’s C library. A musl host such as Alpine, or a glibc below 2.39, where the glibc build alone could not run, is now served. An install on a host where the glibc build runs keeps it. Nothing to do.
  • The per-target Release archives — gain the two *-linux-musl archives beside the *-linux-gnu ones, whose names are unchanged.
  • lifecycle-kit/templates/lead.md — the lead now writes nothing into the checkout or a linked worktree while a dispatched stage session is live, gitignored scratch included, keeping only its resume journal, its session-role marker and what the arms it runs write for it; a probe that must write runs after the stage or in a clone outside the checkout. It also reads a linked worktree’s provenance (branch and lock, dirtiness, commits the main checkout lacks, the journal or dispatch naming it) before calling it stale. Nothing to do.
  • The gate scratch directory — .tmp unless GATE_SDK_TMP_DIR says otherwise, now carries a .gitignore holding *, written by init and by the battery when absent, so a battery run no longer leaves an untracked file; an existing .gitignore there is never rewritten, and the iteration-boundary wipe and the session-start scratch sweep spare it. An adopter who already added a root ignore line may keep it. If you copied context-kit’s session-context.sh template, add ! -name .gitignore beside ! -name .gitkeep in your copy’s step-6 scratch sweep, which otherwise deletes the file once it is a day old.
  • LIFECYCLE_KIT_AMENDMENT_GLOB — a value carrying / now matches a file’s repo-relative path component by component, * inside one component and ** across any number, so a tree can mark its in-flight specs by location; check-stage-entry and check-reads-couples both read it so. A value with no / matches the basename as before. Nothing to do.

Upgrading

Replace the vendored kit directories wholesale at v0.27.0, or run checkwright update. Regenerate your generated artifacts: the enforcement map and the footprint page red until you do, and each freshness gate prints its own regen command. If you copied context-kit’s session-context.sh template, add the scratch-sweep exclusion the scratch-directory change above names. Then run the full battery.

The allowed reds. Each is a gate named above, and each clears differently:

  • check-gate-substrate-parity — reds once for each new gate your vendored kits carry and your gates.list does not name. Register it, or declare it # unregistered: with a reason.
  • check-survey-record — reds on a survey block whose corpus is prose, an unquoted glob, or nothing. Rewrite the corpus to the pathspecs the survey read, or none.
  • check-docs-page-repeat, check-citation-link and check-docs-collapsible — red only once registered, and the first two only once their corpus knob is set. Each red names the line to fix.

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.