Uh oh!
There was an error while loading. Please reload this page.
feat(pm): give the contract-review independence clause a machine carrier (C4) - #14216
Merged
Merged
Conversation
os-zhuang
approved these changes
Sep 2, 2026
os-zhuang
marked this pull request as ready for review
September 2, 2026 14:01
os-zhuang
enabled auto-merge
September 2, 2026 14:01
Uh oh!
There was an error while loading. Please reload this page.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for freeto join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Part of #14209 — direction A's guard half. #14209 stays open: its template half is deferred on a
governance blocker named under "What is NOT in this PR", and merging this alone must not close the card.
Ruling being implemented (maintainer, 2026-09-01, verbatim and untranslated): 「同意 A」 — the
contract-review verdict template carries an
Implemented-by:/Reviewed-by:session-ID pair, and theguard refuses to recognise a verdict whose two IDs are the same session.
What changed
One file:
scripts/pm/check-clause2-carriers.mjs, one new finding row C4, report-only like everyother row. No existing row is weakened or reordered, no label is ever written (the file's standing
NEVER_WRITESrule), and no sibling script is touched.C4 reports a pair whose governing contract-review verdict names the SAME session on both authorship
lines — a self-review, which does not count as an independent review. The clause it finally carries is
references/contract-review.md's own: the in-seat path is scoped to 「低档实现者的契约增量,非自身产物」,and its isolation sub-rule will not feed a reviewer even 「派发席自己的结论(污染即失独立性)」.
Four states, exactly as the card's scope sets them:
The four design choices worth reviewing
VERDICT:key line, picked from the live corpus rather than invented: realverdicts open a fenced block whose first line is
VERDICT: PASS, besideREVIEWED-HEAD:andCLAUSE-2-PATH:. The same board supplies the near miss that makes the colon load-bearing — an os-devreport writes
`VERDICT command-exit 0`in prose, repeatedly. Both are pinned as self-testfixtures, so a discriminator that matched the bare WORD would read a build log as a review verdict.
Clause-②:reader one section up: case-sensitive key, the sessiontoken immediately after the colon, trailing reasoning tolerated, the same markdown decoration allowed.
One convention for machine spellings in this file, not two. Its residual hole is stated in the row
rather than hidden: both IDs are SELF-DECLARED, and this file compares them to each other without
cross-checking either against the implementation claim — it catches the honest self-review.
independent re-review is precisely the remedy the row asks for, so judging every verdict ever posted
would leave a remediated pair red on every later sweep — the defect [finding]
check-clause2-carriers.mjs --pairanswers C3 / exit 4 on a LEGITIMATELY cleared clause-② pair — the completed state (declaration outlives the label) is indistinguishable from the fail-open it hunts #14155 had to repair in C3, wherea row that could never clear made the landing check's own precondition unsatisfiable.
The file header's boundary sentence was narrowed to match, not quietly broken: it read "it does not read
verdict comments"; it now reads "it reads no verdict VALUE", with a starred paragraph saying that the
authorship pair is the one thing read out of a verdict and that no PASS or FAIL token is read to reach
it. The PASS half of the recovery rule stays human, exactly as before.
What is NOT in this PR, and why — please read before reviewing scope
The dispatched surface was two files. The second,
.claude/skills/pm-dispatch/references/contract-review.md(the template lines plus one sentence about the guard), is not here, and could not be added inside the
dispatched surface. Measured, not assumed:
check-skill-line-ratchet.mjspins that file at 60 lines, and it is 60 lines — the gate's ownverdict line is
contract-review.md is 60 lines (ceiling 60; headroom 0). Any net growth is red.densify to buy lines is 筹行, banned by the maintainer's 2026-08-17 ruling as recorded in
SKILL.md:「⛔ re-wrap(折行合并)不得用作筹行 …… 新增以删减付账;密度优化仅随净减内容的 PR 顺带」. Deleting a
ruled clause is refused on the state-machine precedent, recorded twice in this very file's own ceiling
comments.
60): raise the ceiling, with the maintainer ruling quoted in the raising PR body — which means
editing
scripts/pm/check-skill-line-ratchet.mjs, a third file the dispatch did not authorize andexplicitly said to stop on rather than improvise.
governance control, unilaterally, is the same act #14209 exists to record. So the guard ships and the
template waits for an authorization only the dispatching seat or the maintainer can give.
Consequence if this merges alone: none adverse. A verdict carrying neither line is silent by mandate,
so C4 simply does not fire until seats start writing the pair — the row is forward-compatible and inert
on today's board. The template half is what turns it on.
To finish the card on this branch: authorize the ceiling raise (60 to about 66), add the template
lines plus the guard sentence to the review-checklist section, record the raise above the CEILINGS entry
in the established comment form, and flip this PR's first line to the closing keyword.
Gates run
All readings at the pushed head
57f23063f(the final commit), every exit captured byredirect-then-capture, never across a pipe.
node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstackEXIT=0, repo assertion held,1 path vs merge base
b992b1d64, three-dot, 199 families discovered, 13 matched plus 2convention-triggered (adds or edits a GATE SCRIPT).
check:pm-clause2-carriers,check:pm-dispatch-gates,bare-root-worklist --self-test,check:agent-test-spelling,check:bash32-floor,check:cli-command-ids,check:cross-package-test-inputs,check:entry-guard,check:parse-guard,check:pnpm-filter-targets,check:watch-hint-literal,check-cross-package-test-inputs.mjs,check-ci-filter-parity.mjs,check-shard-attestation.mjs.check-test-completeness.mjsEXIT=3, its own text — "The log comes froma test RUN. This gate does not run tests and cannot produce one … the local reading for this gate is
NOT MEASURED." CI covers it.
check-ci-filter-parity.mjsandcheck-shard-attestation.mjsfirst returned EXIT=3 PREREQUISITENOT MET ("the dependency
yamlis not installed") because the worktree had nonode_modulesyet;both were re-run after
pnpm installand are the EXIT=0 readings above. Recorded because a 3 read as apass would have been the false green.
eslint . --no-inline-config --format jsonEXIT=0 — 5,644 files, 0 errors,0 warnings, with the edited file confirmed present in the linted set by its own JSON row.
check-nul-bytes.mjsEXIT=0 (7,766 files). Control-character self-scan over the edited file withgrep -naPreturned rc=1, no matches.check-skill-line-ratchet.mjsEXIT=0 — unchanged, since no ceilinged file is touched.Ablation — the new cases can actually fail
Run from the committed implementation, so the restore leg had something true to restore to. The C4
comparison was neutered (
if (implementedBy !== reviewedBy)replaced byif (true), marker appended).Mutation confirmed ON DISK before running, not from the editor's exit code: the original anchor's
grep -cFcount went 1 to 0 and the injected marker's 0 to 1. Ablated run: EXIT=1, 11 of 138 casesfailed, including "a same-session verdict FIRES C4" and "a self-reviewed pair is adverse even when
every carrier reading is clean". Restore by
git checkout HEAD -- (absolute path)under an EXIT/INT/TERMtrap, then proved rather than assumed:
git diff HEADempty, marker count back to 0, and the worktreeblob hash equal to the HEAD blob hash (
2ea30125…both sides). Self-test green again at 138.No rebuild leg applies and none is claimed: this script is plain ESM executed from source, with no
distbetween the edit and the run.
Landing shape
Draft, and it stays draft —
.claude/-adjacent PM tooling under the governed four-step, which thedispatching seat runs after this report. No auto-merge, no ready flip from here.
skip-changesetappliesand is set: the diff is confined to
scripts/pm/**, which publishes from no package.Generated by Claude Code