You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Commit 7d493ad
Browse filesBrowse the repository at this point in the historyBrowse files
fix(pm): claim-branch-unparsed remedy names the whole shape its own rule requires (#19454)
Fixes#19414
Clause-②: no
## What moved
Only the `claim-branch-unparsed` remedy sentence in
`claimBranchUnparsedGap`, the one docblock line that restates it, and
ONE self-test case. The reader is untouched: `CLAIM_SELECTION_RULE`, row
C8 and the retraction channel read exactly as they did at `57ceb9d`. Net
+21 lines in `scripts/pm/check-clause2-carriers.mjs` (26 insertions / 5
deletions), against the dispatch's ceiling of +30.
Placeholder note: the literal in the source spells its two placeholders
in angle-bracket form. They are written as `N` and `slug` everywhere in
this body, because the body sanitizer eats short angle-bracket
fragments, fenced or not.
### Before — `57ceb9d`, the sentence at :4913–:4915
> Remedy — the CLAIMING SEAT, with one comment: name the branch on a
`Branch:` line of its OWN (`` Branch: `claude/issue-N-slug` ``), ⛔ not
inside the `Claim:` sentence, which no reader parses.
The rule sentence printed in the SAME output (`pair.1.claim.rule`)
requires both lines:
> the GOVERNING claim — the NEWEST comment whose body carries a line
beginning `Claim:`/`Claimed:` … AND whose `Branch:` line parses at least
one protocol-shaped branch
A `Branch:` line alone carries no claim marker, so the comment the old
sentence prescribed is not a claim comment at all: `claimGovernance`
never sees it, `newest` stays the unparsed claim, and the state does not
move.
### After
> Remedy — the CLAIMING SEAT, with ONE comment carrying BOTH lines: a
line beginning `Claim:` AND a `Branch:` line of its OWN (`` Branch:
`claude/issue-N-slug` ``). ⛔ Not the branch named inside the `Claim:`
sentence, which no reader parses, and ⛔ not a `Branch:` line posted
ALONE in a comment of its own, which carries no claim marker and is
therefore not a claim comment at all — that comment leaves this state
exactly as it is. ⚠️ Already holding a LIVE claim on this card? Post
`Release:` FIRST, so the new comment is the only claim standing — a
second `Claim:` under a live one is row C8, ⛔ not a repair.
The old warning is kept verbatim in substance — the defect is what the
sentence OMITTED, not what it said — and the phrase the existing
self-test pins (`` `Branch:` line of its OWN ``) is unmoved.
## The filer's four steps, reproduced on this tree
Offline through `--pair-json` (fixtures only, no board read), each exit
captured before any pipe:
| step | the card thread | exit |
|---|---|---|
| 1 | one live claim naming its branch INSIDE the `Claim:` sentence |
**2** — `claim-branch-unparsed` |
| 2 | …the OLD remedy followed: a `Branch:` line of its own, in a
comment of its own | **2** — unchanged, the remedy did nothing |
| 3 | …`Claim:` + `Branch:` added under the still-live claim | **4** —
row C8 |
| 4 | …`Release:` then ONE fresh claim | **0** |
That is the filer's measured path (2 → 2 → 4 → 0), reproduced before the
edit and unchanged after it: the sentence moved, the reader did not.
Following the sentence as it NOW reads, from the same step-1 thread —
`Release:` first, then ONE comment carrying both lines — reaches **exit
0 in one act** (2 → 0).
## The self-test case is the sentence's own proof
Four assertions, beside the existing `#17149` battery:
1. a `Branch:` line posted ALONE leaves the thread at
`claim-branch-unparsed` — the old remedy's own outcome, pinned;
2. the comment the sentence now prescribes (both lines, the live claim
released first) IS the governing claim — `cardDeclaration(...).state ===
'declared'` and zero finding rows;
3. CONTROL: post that same comment WITHOUT the `Release:` and row C8
answers — which is why the sentence names it;
4. the printed sentence carries the whole shape: `ONE comment carrying
BOTH lines`, `` `Release:` FIRST `` and `row C8`.
`node scripts/pm/check-clause2-carriers.mjs --self-test` → **exit 0**,
1075 cases pass (was 1071).
### Reverse verification — the sentence assertion really can fail
Through `scripts/ablation-replace.mjs` (anchor must hit; the write is
verified against the disk, and the restore against `HEAD`), from the
committed state:
```
ablation-replace: replaced 1 occurrence(s)
ablation-replace: ok mutation landed: anchor 1 -> 0, blob de6a171 -> efcc146d09eb
✗ …and the sentence itself carries the whole shape: both lines, the `Release:` before a second claim, and the row one earns
✗ check-clause2-carriers self-test: 1 of 1075 case(s) failed.
ablation-replace: ok restored: blob == HEAD (de6a171) and `git diff HEAD` is empty
```
Assertions 1–3 pin the READER, which this diff does not touch; assertion
3 is their non-vacuity control (same thread, one thing changed, C8
instead of silence).
## Verification — all at `5a5b381`
- Derived union: `node scripts/pm/dispatch-gates.mjs --commands --repo
objectstack-ai/objectstack` (no paths) → 35 families. Every one run,
exit captured before any pipe; reconciled with `--ran`: `35 derived, 35
run, 0 NOT-MEASURED, 0 UNRUN`, all exit 0 (`a DERIVED zero — all 35
recorded an exit code and none of them is 3`).
- `pnpm check:pm-clause2-carriers` :: exit 0 · `pnpm
check:pm-dispatch-gates` :: exit 0 (993s on this box) · `pnpm
check:nul-bytes` :: exit 0.
- The edited file is a tool script, so its own suite is owed beyond the
derived families: its `--self-test` IS that suite (exit 0). The sibling
readers that name it also ran green: `check-half-states`,
`check-widening-tells`, `check-governed-merges`,
`check-governed-queue-guard`, `check-expected-skips` — each
`--self-test` :: exit 0.
- Lint: not narrowed — the repo-wide `eslint . --no-inline-config` ran
here in full, **6947 files, 0 errors, 0 warnings, exit 0** (population
read from `--format json`, not estimated).
- Control-character scan beyond the gate: `grep -naP` over the edited
file → 0 hits.
- `node scripts/pm/check-governed-merges.mjs --pr` — `scripts/pm/**`
carries no row in `GOVERNED_SURFACES`, so NOT governed is expected.
## Acceptance notes
- noted, not filed: the card's wider ask — ONE check over every
`scripts/pm/*` remedy text, so a remedy that does not satisfy its own
tool's rule fails mechanically — is recorded by the lane grading as a
seat item and is deliberately out of this card's scope. Carrier: the
`domain:skills` seat's item list.
- noted, not filed: `check-harness-current.mjs`'s STALE remedy text is
the filer's second instance of the same shape. Not touched here, not
re-measured here; it is the other half of the seat item above. Carrier:
the same seat item.
---
_Generated by [Claude
Code](https://claude.ai/code/session_017ETYWqMQD4qMtZzAGovWNi)_
Co-authored-by: Claude <noreply@anthropic.com>
Copy file name to clipboardExpand all lines: scripts/pm/check-clause2-carriers.mjs
+26-5Lines changed: 26 additions & 5 deletions
Original file line number
Diff line number
Diff line change
@@ -4886,7 +4886,9 @@ export function declarationLimbTally(pairs) {
4886
4886
* whether it is the current one. Reporting it as `missing` would send the seat
4887
4887
* looking for a line that is there; reporting it as a `no` would manufacture a
4888
4888
* decision nobody made. The sentence names the comment, says what governance
4889
-
* did instead, and gives the one remedy — a `Branch:` line of its own.
4889
+
* did instead, and gives the one remedy — ONE comment carrying a `Claim:` line AND
4890
+
* a `Branch:` line of its own, with a `Release:` first when the seat already holds
4891
+
* a live claim here.
4890
4892
*
4891
4893
* ⛔ Nothing here widens the branch reader. The remedy is on the WRITE side,
4892
4894
* which is the same call the sibling script's H34 makes for the claim marker
@@ -4910,10 +4912,14 @@ export function claimBranchUnparsedGap(pair, decl) {
4910
4912
`parses to ZERO branches, so the carrier this limb reads cannot be resolved. ${instead}. ` +
4911
4913
'An unparsed claim is an UNCLASSIFIED result, ⛔ never an absent declaration and ⛔ never a ' +
4912
4914
'declared `no` — this pair is missing from the readings above, not clean in them and not ' +
4913
-
'adverse in them. Remedy — the CLAIMING SEAT, with one comment: name the branch on a ' +
4914
-
'`Branch:` line of its OWN (`` Branch: `claude/issue-<n>-<slug>` ``), ⛔ not inside the ' +
4915
-
'`Claim:` sentence, which no reader parses. ⚠️ A whole shift of claims reading this way is a ' +
4916
-
'SEAT TEMPLATE fault, not a typo. ' +
4915
+
'adverse in them. Remedy — the CLAIMING SEAT, with ONE comment carrying BOTH lines: a line ' +
4916
+
'beginning `Claim:` AND a `Branch:` line of its OWN (`` Branch: `claude/issue-<n>-<slug>` ``). ' +
4917
+
'⛔ Not the branch named inside the `Claim:` sentence, which no reader parses, and ⛔ not a ' +
4918
+
'`Branch:` line posted ALONE in a comment of its own, which carries no claim marker and is ' +
4919
+
'therefore not a claim comment at all — that comment leaves this state exactly as it is. ' +
4920
+
'⚠️ Already holding a LIVE claim on this card? Post `Release:` FIRST, so the new comment is ' +
4921
+
'the only claim standing — a second `Claim:` under a live one is row C8, ⛔ not a repair. ' +
4922
+
'⚠️ A whole shift of claims reading this way is a SEAT TEMPLATE fault, not a typo. ' +
4917
4923
NEVER_WRITES
4918
4924
);
4919
4925
}
@@ -8174,6 +8180,21 @@ export async function selfTest() {
8174
8180
t('…and that a whole shift reading this way is a TEMPLATE fault rather than a typo', says(unparsedGap, 'SEAT TEMPLATE fault'));
8175
8181
t('⛔ and it raises NO C2 finding — an unclassified result must never be rendered as an adverse verdict', pairRows(unparsedPair).every((r) => r.code !== 'C2'));
8176
8182
t('⛔ nor any other finding row on this pair', pairRows(unparsedPair).length === 0);
8183
+
// #19414 — the REMEDY is its own proof. The sentence used to name ONE line of
8184
+
// the shape the rule requires, so a seat that followed it walked exit 2 → exit 2
8185
+
// → C8's exit 4 before reaching 0 (measured on card #19306 / PR #19411). The
8186
+
// case below WRITES the comment the sentence now prescribes and reads it back
t('⭐ #19414: a `Branch:` line posted ALONE carries no claim marker, so the OLD remedy left the thread in this SAME state', cardDeclaration([U14_HELD, U14_BRANCH_ONLY]).state === 'claim-branch-unparsed');
8195
+
t('⭐ …and the comment the sentence NOW prescribes is the governing claim — both lines in one comment, the live claim released first', cardDeclaration([U14_HELD, U14_BRANCH_ONLY, U14_RELEASE, U14_CLAIM]).state === 'declared' && U14_CODES([U14_HELD, U14_BRANCH_ONLY, U14_RELEASE, U14_CLAIM]).length === 0);
8196
+
t('⛔ CONTROL: post that same comment WITHOUT the `Release:` and row C8 answers instead — which is why the sentence names it', U14_CODES([U14_HELD, U14_BRANCH_ONLY, U14_CLAIM]).includes('C8'));
8197
+
t('…and the sentence itself carries the whole shape: both lines, the `Release:` before a second claim, and the row one earns', says(unparsedGap, 'ONE comment carrying BOTH lines') && says(unparsedGap, '`Release:` FIRST') && says(unparsedGap, 'row C8'));
8177
8198
// The live specimen, and the fallback shape at its sharpest: the older claim
8178
8199
// names a DIFFERENT branch, so every reader downstream probes the wrong ref.
0 commit comments