Skip to content

Commit e9efc40

Browse files
claude[bot]claude
andauthored
fix(pm): give the clause-② declaration limb a self-solvable exit (#17738)
Fixes #17366 ## The defect: a carrier a seat could write into and not get out of The clause-② declaration limb had one carrier — the `Clause-②:` line inside the card's governing `Claim:` comment — and repairing a line already written there was not an act every seat can perform. The MCP GitHub tool set carries no edit-an-issue-comment call; the claim protocol forbids a second `Claim:`; and this gate's own refusal forbids the checker filling the line in ("the declaration IS the judgement"). Three closed doors, and a seat that wrote the line as prose was left waiting for somebody outside the repository to retype it. That was measured five times in one shift across two roles, and the fifth instance was still holding a PR with 38 checks and 0 failures out of the queue when the card was filed. ## The fix: one correction comment, read by the same reader A dedicated comment whose FIRST line is a fixed key naming, in digits, the claim comment it corrects: ```text Clause-②-correction: 5642248126 Clause-②: no Session: `session_01MCLBsUgfykL74aU716rzVK` ``` The newest correction naming the card's governing claim supersedes that claim's declaration, in both directions — so a wrong VALUE is repaired by the same act as an unreadable one. The declaration inside it is read by the SAME `CLAUSE2_KEY_LINE` through the SAME `readClause2Line`, so what moved is WHICH COMMENT may carry the declaration, never what counts as an answer. That is the move #16304 already made when it asked a sibling CARD. Attribution is the `Session:` line the claim protocol already makes mandatory (SKILL.md 〈模板与表〉, 「session ID 不可省」, and 「`mode:subagent` 的 dev 与 PM 同会话同 ID」 — so the session is exactly the granularity of "the claiming seat"). A correction is attributed when its `Session:` equals the governing claim's. That is a DECLARED identity, never a verified one: the value is copyable text and this fleet writes under one GitHub login, so the comparison is on what the comments SAY — the same ceiling C4 already works at. ⛔ No branch of it may become a new one-way door, which is the defect being removed. A correction naming another comment, declaring a different session, carrying no `Session:` line, or carrying a prose declaration is IGNORED WITH A PRINTED REASON that names an act the claiming seat can perform. And a governing claim that carries no `Session:` line at all leaves nothing to compare: the correction APPLIES, with a note saying attribution could not be verified and why. Refusing there would have rebuilt the door one room over. The C2 remedy text was rewritten to name WHO can act and HOW, in three parts: the claim template in SKILL.md 〈模板与表〉 that already carries the literal `Clause-②: yes | no` line and should be copied rather than composed; the fact that an already-posted claim comment is not editable from every seat; and the one comment that repairs it. It replaces "add the line to that claim comment", which named an act the claiming seat may have no tool for. ## What deliberately did not move - **The accept set.** `CLAUSE2_KEY_LINE`, `readValueToken` and `CLAUSE2_VALUES` are untouched. The card's five measured prose spellings are pinned as negatives in the self-test. - **The exit register.** The correction is a new INPUT to C2, not a new verdict family. 0/1/2/3/4 keep their meanings and their numbers. - **`check-half-states.mjs`.** `CLAIM_COMMENT_MARKER` is still imported, not restated, and not widened. A correction is not a claim comment and never enters the claim pool. - **SKILL.md.** The template already carries the fixed line; this PR points at it and does not restate it. - **The writes.** This script still writes nothing, hangs no label, and reads no verdict word. ## Acceptance, all four from the card 1. **A seat writing per the template gets a machine-readable declaration.** Pinned by importing the reader over the template's own key with each value substituted, plus the new remedy text that sends the seat to the template rather than to a regex. 2. **The negative control holds.** All five measured spellings from the card's table are pinned as not-declared, from the line reader and from a claim comment. The `#1` spelling is reported as a SPELLING near miss; the `#2`–`#5` spelling reaches no pattern at all, because 条款② carries no `Clause` token — pinned as a measured fact. 3. **Self-solvability is pinned.** A card whose claim declaration is unreadable earns a C2 finding; adding ONE correction comment clears it, with the claim comment byte-identical across the two threads, no second `Claim:`, and the governing claim unmoved. Demonstrated end to end through the offline `--pair-json` path: `--pair` exit 4 with the broken claim, exit 0 with the one comment added. 4. **Ablation.** Deleting the correction reading reds 22 of 465 self-test cases (every criterion-3 case); deleting the template pointer and the who-can-act remedy reds 7 (criterion 1's new half). Both legs were mutated on disk, proved to have landed, then restored to a blob hash equal to HEAD's. ## Acceptance notes - ⚠️ Measured and pinned as a CONTROL, not endorsed and not fixed here: the template line copied UNFILLED — `Clause-②: yes | no` — reads as a declared `yes`, because `readValueToken` takes the first token after the colon and treats the rest as the seat's argument. That is an instance of the population #17098 is already open against (a key-INITIAL DESCRIBING line read as a declaration), so it is ⛔ not filed again here. The case carries a pre-registered FLIP TRIGGER: when #17098 lands, the expectation becomes `kind !== 'declared'` and the case flips with it in that PR. ⛔ It is not to be deleted and its green today is not an endorsement. - The PR-body carrier of `Clause-②:` is read by `scripts/check-changeset-no-major.mjs`, not by this gate: `--pair` reads the PR side for LABELS (C1) only, and no `readClause2Line` call here takes a PR body. The card-side correction shape therefore has no PR-side counterpart to add, and the PR-body carrier is editable by the seat anyway — which is exactly the asymmetry the card names. - `check-scripts-symbol-anchors`, `check-self-test-wired` and `check-self-test-workflow-commands` all pass unchanged: the `check:pm-clause2-carriers` step in `lint.yml` already runs the self-test, and no second step was added. ## Gates, on head `dbbfbb596` `node scripts/pm/dispatch-gates.mjs --commands` derives 35 families for this one-path diff; all 35 ran and all 35 exited 0 (`--ran` reconciliation: "35 derived famil(ies) accounted for — 35 run, 0 NOT-MEASURED (a DERIVED zero — all 35 recorded an exit code and none of them is 3)"). Lint is the declared narrowing rather than the repo-wide run CI owns: the receiving population is `eslint.config.mjs`'s base block (`files: ['**/*.{ts,tsx,mts,cts,js,jsx,mjs,cjs}']`), `--format json` reports 1 file linted with 0 errors and 0 warnings, and the config "never enables type-aware linting (no `parserOptions.project`, no typed `@typescript-eslint` rules) for ANY file" (`eslint.config.mjs`, its own words) — so this diff cannot move the verdict on any file it does not touch. `node scripts/pm/check-governed-merges.mjs --test scripts/pm/check-clause2-carriers.mjs` prints "✅ NOT governed — ordinary queue landing applies". `--pair 17738` exits 0. --- _Generated by [Claude Code](https://claude.ai/code/session_01MCLBsUgfykL74aU716rzVK)_ --- _Generated by [Claude Code](https://claude.ai/code)_ --------- Co-authored-by: Claude <noreply@anthropic.com>
1 parent 396eae3 commit e9efc40

1 file changed

Lines changed: 578 additions & 23 deletions

File tree

0 commit comments

Comments
 (0)