Skip to content

Commit 42f8df1

Browse files
os-justinclaude
andauthored
fix(pm): a decorated Claim: enters the governing-claim pool, through the sibling's one reading (#18824)
Fixes #18764 Clause-②: no ## The defect `scripts/pm/check-clause2-carriers.mjs` built the governing-claim POOL, and indexed retractions, by testing the imported `CLAIM_COMMENT_MARKER` against the RAW comment body. That constant anchors the bare word at line start and tolerates leading whitespace and one blockquote marker — nothing else — so a claim a seat wrote as a bolded or backticked `Claim:` was not SUPERSEDED here, it was never a candidate: not listed, not rejected, not named anywhere in the record. Meanwhile `claimGovernance`, imported from the same sibling, has read both ownership markers through `markerMatches` since #18680, so ONE FUNCTION held both answers at once — governance saw the bolded claim and the pool beside it did not. ## The before-reading, re-derived here and not taken from the card Taken through this file's own offline reader (`--pair-json`), on `origin/main` `e7eb4e9184` — the before leg was run in the shared checkout, whose copy of both `scripts/pm/check-clause2-carriers.mjs` (blob `ccd5ad7c9a`) and `scripts/pm/check-half-states.mjs` (blob `153d10a015`) is byte-identical at `e7eb4e9184` and at `a7bafc29af`, so the reading is a reading of this branch's base. | fixture | BEFORE (`e7eb4e9184`) | AFTER (this branch) | |---|---|---| | a bolded `Claim:` carrying its own `Branch:` and `Clause-②: no` | exit **4**, row **C2 — MISPLACED**; `claim.selected: none — no comment on this thread carries a line beginning \`Claim:\``; `claim.clause2-line: (no carrier, so no line was read from one)` | exit **0**; `claim.selected: 1 comment(s) in the pool`; `claim.clause2-line: DECLARED \`no\`` | | the backticked spelling, same lines | exit **4**, row **C2 — MISPLACED**, identical record | exit **0**, `DECLARED \`no\`` | | a BARE older claim declaring `yes` beneath a DECORATED newer one declaring `no` | exit **4**, row **C3**; the OLD claim governs; `claim.clause2-line: DECLARED \`yes\`` | exit **0**; the decorated newer claim governs; the older is listed `rejected: 1 … a SUPERSEDED claim`; `claim.clause2-line: DECLARED \`no\`` | The third row is the expensive direction and it is why this is not merely a missing reading: the value the declaration limb hands every downstream reader FLIPS, and the wrong value produced an adverse C3 row about a contract-review gate that was never owed. ### One premise of the dispatch is falsified, and it is stated rather than smoothed over The escalation's two live bodies (objectui#9660 comment `5721120402`, objectui#9717 comment `5720184809`, read 2026-09-17T22:02Z) carry **no `Branch:` directive line at all**. Driven through the pool verbatim, both read `claim-branch-unparsed` and exit **2** on BOTH sides of this change — `claim.selected: NONE — the newest claim comment (5721120402 at 2026-09-17T20:57:09Z) parses ZERO branches`. That state is already correct on `main`, because it is resolved by the sibling's governance leg, which already reads decorated claims. So the fixtures in the table above ADD the `Branch:` / `Clause-②` lines: the defect this PR repairs is the one that only becomes visible once a claim is otherwise complete. Neither shape ever read `absent`. ## The repair: one path, and it is the sibling's Both former raw tests now read through `markerMatches(CLAIM_COMMENT_MARKER, body)`, imported from `check-half-states.mjs` — the pool (`claimCarrierSelection`) and the retraction indexer (`claimRetractions`). The bare marker is tried first inside `markerMatches`, so the change is provably additive: no body that matched yesterday stops matching. - No `\*\*` was added to `CLAIM_COMMENT_MARKER`. Decoration is an open set, so admitting one spelling buys exactly that spelling; the constant is the protocol's spelling and every reader imports it rather than restating it. - No second undecorator was written in this file. That would give this file a private definition of "decorated" for the sibling to drift from, which is the failure the card names. - The near-miss vocabulary (`OWNERSHIP_MARKER_NEAR_MISS_FORMS`) is the sibling's and is not re-declared here. - `scripts/pm/check-half-states.mjs` is untouched. ## The retraction stripper, measured against that path — it STAYS, and that is a reading `undecorateRetractionLine` (this file) and the sibling's `undecorateProseLine`-through-`markerMatches` were run over one fixture set, with the retraction stripper extracted from the shipped source text rather than retyped. **5 of 12 fixtures read differently:** | fixture | `undecorateRetractionLine` | `markerMatches` (shared) | same? | |---|---|---|---| | bare `Claim:` | true | true | yes | | bold | true | true | yes | | backticks | true | true | yes | | **underscore emphasis** `__Claim:__` | true | **false** | **NO** | | leading blockquote | true | true | yes | | blockquote + bold | true | true | yes | | **list item (hyphen)** `- Claim:` | true | **false** | **NO** | | **list item (asterisk)** `* Claim:` | true | **false** | **NO** | | **sigil prefix** `🚨 Claim:` | true | **false** | **NO** | | a line that is NOT a marker but starts with the word | false | false | yes | | inflected word `Claiming:` | false | false | yes | | **heading** `## Claim:` | true | **false** | **NO** | Per the dispatch, the retraction stripper is **kept as is** and is ⛔ NOT unified by hand. The divergence is load-bearing in both directions, which is why: the #18373 retraction this file's own battery replays opens with a leading sigil, and narrowing the retraction path to the shared reading would stop reading the specimen #18719 landed for; widening the shared path the other way would make a list item a claim, which H20 pins as not one. Two strippers, two jobs — now stated in the file, and pinned, rather than discovered again. The unification question is for the seat to route; it is not folded in here. ## The pins A new self-test battery, `#18764: a DECORATED claim ENTERS the pool — ONE reading, and it is the sibling's`, 24 cases, with `SELF_TEST_BATTERY_FLOOR` raised by exactly the one battery it adds (30 → 31). It pins: a bold and a backticked claim ENTER the pool and GOVERN, with their `Branch:` and `Clause-②` lines read from them; a decorated NEWER claim supersedes a BARE older one and the value the limb reads moves with it; the older record is listed SUPERSEDED rather than dropped; the retraction index sees a decorated claim as retractable by its own author; the input record names the decorated row it selected, by id and by date. The controls are the other half: the constant itself still refuses those same bodies; a list item, a heading and an underscore-emphasis line are still not claims; the `Clause-②-correction:` comment does not enter the pool through the new door either; a bare claim reads exactly as before; and the two undecoration paths are pinned as the two jobs they are. The bare-constant pins that assert on the CONSTANT (`CLAIM_COMMENT_MARKER.test(...)` in the #17366 and #17149 batteries) are byte-untouched. No network in the self-test. ## Census — report-only, over THIS gate's own population The population is the one this gate derives: the open PRs of one board and the cards they deliver, by this file's own `derivePairs`. ⛔ This is NOT the half-states population the triage scanned (46 cards / 253 comments over two boards). - **`objectstack-ai/objectstack`, read 2026-09-17T22:43:06Z** — 26 open PRs, 24 derived pairs, 24 distinct cards, 147 comments read, 0 unread. [LIT CTRL] bare-marker claim comments in today's pool: **29**. Decorated claims the shared reading sees and today's pool does not: **0**. - **`objectstack-ai/objectui`, read 2026-09-17T22:44:02Z** (the board a seat reaches with `PM_SWEEP_REPO`, named because the escalation's instances live there) — 14 open PRs, 12 derived pairs, 12 distinct cards, 69 comments read. [LIT CTRL]: **13**. Decorated claims invisible to today's pool: **2**. - card objectui#9629, comment `5721993574` (`os-sales`, 2026-09-17T22:19:38Z), bolded — the card's ONLY claim. Before: pool empty, declaration `misplaced no` (an adverse C2). After: pool = that comment, declaration `declared no`. - card objectui#9317, comment `5653084747` (`claude[bot]`, 2026-09-13T11:51:39Z), backticked — the card's ONLY claim. Before: pool empty, `claim-branch-unparsed`. After: in the pool, still `claim-branch-unparsed` — the gate now names the carrier by id instead of reading the thread as unclaimed. ⚠️ Every instance above carries its reading time because it may have left this state since. ⛔ No state was written by this census. ## Ablation, from the committed fix Two legs, each mutating on disk from the committed state, each proven to have reached disk by blob hash, each restored under a `trap` and verified by blob hash plus an empty `git diff HEAD`. | leg | mutation | blob before → after | self-test | |---|---|---|---| | the POOL predicate back to the raw `.test` | `claimCarrierSelection` | `f7ee45d4ef` → `ae548569fd` | exit **1** — **8 of 889** cases red, all 8 from the new battery, nothing pre-existing red | | the RETRACTION indexer predicate back to the raw `.test` | `claimRetractions` | `f7ee45d4ef` → `708893dc5c` | exit **1** — **2 of 889** cases red, both from the new battery, nothing pre-existing red | Both restorations: `RESTORED: blob f7ee45d, git diff HEAD empty`. ⚠️ Worth recording: with the fix in place and the new battery removed from the picture, the pre-existing 865 cases pass **unchanged** on both sides of the repair. The existing suite could not see this defect, which is exactly why the battery is the deliverable and not an extra. ## Self-test `node scripts/pm/check-clause2-carriers.mjs --self-test` — 865 cases before, **889 cases pass** after (865 + 24), exit 0; also green as `pnpm check:pm-clause2-carriers` on the final head. ## Derived gates, with exit codes Derived from this worktree with `node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack` (no hand-fed path list) at `984a93a173`: change set 1 path, `scripts/pm/check-clause2-carriers.mjs`, three-dot against merge base `a7bafc29a`. **34 derived commands, 34 run, all exit 0**, reconciled with `--ran` recording each exit code: `34 derived famil(ies) accounted for — 34 run, 0 NOT-MEASURED (a DERIVED zero)`. `node scripts/check-adr-0087-registration.mjs --base origin/main` · `--self-test` · `node scripts/check-changeset-no-major.mjs --base origin/main` · `--self-test` · `node scripts/check-ci-filter-parity.mjs` · `node scripts/check-closing-keyword-parity.mjs` · `--self-test` · `node scripts/check-comment-mask-corpus.mjs` · `node scripts/check-declaration-mirrors.mjs` · `--self-test` · `node scripts/check-scripts-symbol-anchors.mjs` · `--self-test` · `node scripts/check-self-test-wired.mjs` · `--self-test` · `node scripts/check-self-test-workflow-commands.mjs` · `--self-test` · `node scripts/check-whole-set-label-write.mjs` · `--self-test` · `node scripts/pm/bare-root-worklist.mjs --self-test` · `pnpm check:agent-test-spelling` · `pnpm check:bash32-floor` · `pnpm check:changeset-gate-self-tests` · `pnpm check:cli-command-ids` · `pnpm check:cross-package-test-inputs` · `pnpm check:driver-memory-census` · `pnpm check:entry-guard` · `pnpm check:nul-bytes` · `pnpm check:parse-guard` · `pnpm check:pm-clause2-carriers` · `pnpm check:pm-dispatch-gates` · `pnpm check:pnpm-filter-targets` · `pnpm check:ratchet-remedy-authority` · `pnpm check:refd-timer-probe` · `pnpm check:watch-hint-literal` — each exit 0. `pnpm check:pm-dispatch-gates` was run DETACHED with output to a file and read from that file: 1809 cases pass, 747.5s on this box, exit 0. ⛔ It was never run under a foreground timeout, so no reading here is a SIGTERMed run. Repo-wide `pnpm lint` (`eslint . --no-inline-config`): exit 0, run on the final head `984a93a173`. ## Scope `skip-changeset`: the only changed file is `scripts/pm/check-clause2-carriers.mjs`, which no package ships — nothing published moves. #18807 (`listOpenPulls`'s bare page cap, behind this card on the same file) was read and is not addressed here: its lines are untouched by this diff. PR #18799's `pagedListRead` ladder and PR #18770's `claimRetractions` were read for the words the record and the selector use, and neither was touched. ## Acceptance notes - The two undecoration paths in this file diverge on 5 of 12 fixtures (table above). Whether the protocol should converge them — and in which direction — is a real question and is deliberately left to the seat rather than answered by a grep. Noted, not filed by the dev. - On a thread whose newest claim is decorated and parses zero branches, `claim.clause2-line` now reads from that comment instead of printing `(no carrier, so no line was read from one)`, because the pool is no longer empty on it. This makes the decorated case render exactly as the bare case already did; `claim.selected` still reports `NONE … parses ZERO branches` and the pair is still UNJUDGED. Stated as a measured rendering delta, not a verdict change. --- _Generated by [Claude Code](https://claude.ai/code/session_01Gqi43smmqjJ5sUrhfoPeKu)_ --------- Co-authored-by: Claude <noreply@anthropic.com>
1 parent fbe5e1e commit 42f8df1

1 file changed

Lines changed: 166 additions & 12 deletions

File tree

‎scripts/pm/check-clause2-carriers.mjs‎

Lines changed: 166 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -683,6 +683,7 @@ import {
683683
isGateSemanticLabel,
684684
labelNames,
685685
latestMarkedComment,
686+
markerMatches,
686687
prDeliversCard,
687688
proxyRearmPlan,
688689
resolveSweepRepo,
@@ -781,6 +782,7 @@ const SELF_TEST_BATTERIES = Object.freeze({
781782
'#18701: ONE thread set -- what the template STATES is what the queue guard READS': 16,
782783
'#18719: a RETRACTED claim leaves the pool — a withdrawn claim never governs': 36,
783784
'#18683: the card-comment read pages to a cap — past 100 is UNJUDGED, ⛔ never a truncated pool': 27,
785+
'#18764: a DECORATED claim ENTERS the pool — ONE reading, and it is the sibling\'s': 24,
784786
});
785787

786788
// DELETING an entry silences that battery's floor exactly as effectively as
@@ -792,8 +794,8 @@ const SELF_TEST_BATTERIES = Object.freeze({
792794
// one #17915 adds, by the one #17959 adds, by the one #18042 adds, and by the
793795
// one #18174 adds, and by the one #18141 adds, and by the one #17919 adds, and
794796
// by the one #16833 adds, and by the one #18456 adds, and by the one #18719
795-
// adds, and by the one #18683 adds.
796-
const SELF_TEST_BATTERY_FLOOR = 30;
797+
// adds, and by the one #18683 adds, and by the one #18764 adds.
798+
const SELF_TEST_BATTERY_FLOOR = 31;
797799

798800
// The key an assertion is filed under when no battery is open. It is not a
799801
// declared battery, so it reds by the same set difference rather than silently
@@ -1756,7 +1758,7 @@ export function claimRetractions(commentRows) {
17561758
});
17571759
const out = new Map();
17581760
for (const claim of indexed) {
1759-
if (!CLAIM_COMMENT_MARKER.test(String(claim.row?.body ?? ''))) continue;
1761+
if (!markerMatches(CLAIM_COMMENT_MARKER, String(claim.row?.body ?? ''))) continue;
17601762
// Fail closed, twice: an unattributable claim cannot be matched against an
17611763
// author, and an unattributable candidate cannot be the seat that wrote it.
17621764
if (claim.author === null) continue;
@@ -1791,12 +1793,82 @@ export function claimRetractions(commentRows) {
17911793
*/
17921794
export const CLAIM_SELECTION_RULE =
17931795
'the GOVERNING claim — the NEWEST comment whose body carries a line beginning `Claim:`/`Claimed:` '
1796+
+ '(read through the sibling reader\'s ONE reading, `markerMatches`: the bare marker first, then the '
1797+
+ 'shared stripper per line, with a markdown LIST ITEM refused — so a decorated `**Claim:**` is the '
1798+
+ 'same record as a bare one and ⛔ the two readers of this thread cannot answer differently) '
17941799
+ 'AND whose `Branch:` line parses at least one protocol-shaped branch (newest by `created_at`; an '
17951800
+ 'unreadable stamp or a tie falls back to thread order, later row wins). The pool is every claim '
17961801
+ 'comment sharing that `created_at`; when NO claim names a branch at all, every claim comment is '
17971802
+ 'the pool. ⛔ Not earliest, ⛔ not a session match, ⛔ not the one whose body mentions the key. '
17981803
+ `MEMBERSHIP comes first: ${CLAIM_RETRACTION_RULE}`;
17991804

1805+
// ---------------------------------------------------------------------------
1806+
// #18764 — a DECORATED claim ENTERS the pool. ONE reading, and it is the
1807+
// sibling's.
1808+
//
1809+
// The pool and the retraction indexer each tested `CLAIM_COMMENT_MARKER`
1810+
// against the RAW body. The constant anchors the bare word at line start and
1811+
// tolerates leading whitespace and one `>` — nothing else — so a claim a seat
1812+
// wrote as `**Claim:** …` or `` `Claim:` … `` was not SUPERSEDED here, it was
1813+
// never a candidate: not listed, not rejected, not named anywhere in the
1814+
// record. Meanwhile `claimGovernance`, imported from the same sibling, had
1815+
// already been reading both markers through `markerMatches` since #18680, so
1816+
// ONE FUNCTION held both answers at once — governance saw the bolded claim and
1817+
// the pool beside it did not.
1818+
//
1819+
// Measured on the two live records the #18764 escalation named (read
1820+
// 2026-09-17T22:02Z; ⚠️ both cards have since left that state and the reading
1821+
// is stated with its time for that reason), replayed through `--pair-json`:
1822+
//
1823+
// a bolded/backticked claim carrying its own `Branch:` and `Clause-②: no`
1824+
// → `claim.selected: none — no comment on this thread carries a line
1825+
// beginning `Claim:``, the limb read MISPLACED and `--pair` exited 4,
1826+
// prescribing a `Clause-②-correction:` for a line the seat had already
1827+
// written in the right place.
1828+
// a BARE older claim declaring `yes` beneath a DECORATED newer one declaring
1829+
// `no` → the OLD claim governed the declaration, the reading answered
1830+
// `DECLARED yes`, and the newer record was not even listed as rejected.
1831+
// ⭐ That is the expensive direction: not a missing reading but a WRONG
1832+
// value, reported with every appearance of having been read.
1833+
//
1834+
// ⛔ The repair is NOT a `\*\*` added to `CLAIM_COMMENT_MARKER`. Decoration is
1835+
// an OPEN set (#18680 settled that), so admitting one spelling buys exactly
1836+
// that spelling and replays this card on the next one — and the constant is
1837+
// the PROTOCOL's spelling, which is why every reader imports it rather than
1838+
// restating it. ⛔ Nor is it a second undecorator written here: this file
1839+
// would then own a definition of "decorated" that the sibling could drift
1840+
// from, which is the very failure the card names. What both raw tests do
1841+
// instead is READ THROUGH `markerMatches` — the sibling's one reading, bare
1842+
// test first (so the change is provably additive: no body that matched
1843+
// yesterday stops matching) and the shared stripper after it, with the list
1844+
// item refused there and the near-miss vocabulary
1845+
// (`OWNERSHIP_MARKER_NEAR_MISS_FORMS`) kept where it lives. ⛔ That vocabulary
1846+
// is the sibling's and is not re-declared here.
1847+
//
1848+
// ## The OTHER undecorator in this file stays where it is, and that is MEASURED
1849+
//
1850+
// `undecorateRetractionLine` looks like the same job one section up, and the
1851+
// card asked whether the file should end up with one undecoration path. It
1852+
// should not, and the two paths were run over one fixture set to find out:
1853+
// 5 of 12 fixtures read DIFFERENTLY. `undecorateRetractionLine` strips `_` and
1854+
// then every leading non-letter/non-digit character, so it reads
1855+
// `__Claim:__`, `- Claim:`, `* Claim:`, `## Claim:` and `🚨 Claim:` as the
1856+
// directive; `markerMatches` reads none of those, deliberately — the list item
1857+
// and the heading are NAMED refusals with pins behind them, and the underscore
1858+
// form is a named near miss.
1859+
//
1860+
// ⭐ The divergence is load-bearing in BOTH directions, which is why unifying
1861+
// by hand would be a regression whichever way it went. The #18373 retraction
1862+
// this file's own battery replays opens `🚨 **撤回上一条认领…`, and the leading
1863+
// sigil is exactly what the prose channel must strip before the anchor can
1864+
// OPEN the line — narrowing the retraction stripper to the shared one would
1865+
// stop reading the measured specimen #18719 landed for. Widening the shared
1866+
// one the other way would make `- Claim:` a claim, which H20 pins as not one.
1867+
// ⇒ two strippers, two jobs, and the difference is stated here rather than
1868+
// discovered again. ⛔ Not unified from here: it is filed, with the fixture
1869+
// table, for the seat to route.
1870+
// ---------------------------------------------------------------------------
1871+
18001872
/**
18011873
* WHICH claim comment this reading is built from, and which it is not — the
18021874
* input half of the declaration limb (#18456).
@@ -1837,7 +1909,7 @@ export function claimCarrierSelection(commentRows) {
18371909
// ⭐ The full claim listing KEEPS the retracted rows: the record names them
18381910
// RETRACTED below. A pool that silently shrank would replace one invisible
18391911
// fact with another.
1840-
const claims = commentRows.filter((row) => CLAIM_COMMENT_MARKER.test(String(row?.body ?? '')));
1912+
const claims = commentRows.filter((row) => markerMatches(CLAIM_COMMENT_MARKER, String(row?.body ?? '')));
18411913
const live = claims.filter((row) => !retracted.has(row));
18421914
const governing = governance.governing;
18431915
const matched = governing ? live.filter((row) => (row?.created_at ?? null) === governing.createdAt) : [];
@@ -1898,13 +1970,17 @@ const CLAUSE2_CORRECTION_KEY_TEXT = 'Clause-②-correction';
18981970
* because the older claim happened to agree.
18991971
*
19001972
* The predicate that separates them is `CLAIM_COMMENT_MARKER`, imported rather
1901-
* than restated: a claim comment is one whose body carries a LINE BEGINNING
1902-
* `Claim:` (or `Claimed:`, optionally blockquoted), and that one spelling is
1903-
* the whole set — so a heading-style claim (`## Claim — …`) is not a claim
1904-
* comment here, however complete the reasoning under it, and its thread reads
1905-
* `absent`. ⛔ Widening the predicate is not this file's to do: it is the
1906-
* sibling's constant precisely so the two readers cannot drift, and the remedy
1907-
* for a thread that reads `absent` is a comment in the fixed spelling.
1973+
* than restated, and OFFERED through `markerMatches` — the sibling's one
1974+
* reading (#18764), imported for the same reason the constant is. A claim
1975+
* comment is one whose body carries a LINE BEGINNING `Claim:` (or `Claimed:`,
1976+
* optionally blockquoted), read bare first and then with the shared
1977+
* decoration stripped, so `**Claim:**` and `` `Claim:` `` are that same line
1978+
* and ⛔ not a second spelling this file admits on its own. A heading-style
1979+
* claim (`## Claim — …`) is still not a claim comment here, however complete
1980+
* the reasoning under it, and its thread reads `absent`. ⛔ Widening the
1981+
* predicate is not this file's to do: the constant AND the reading are the
1982+
* sibling's precisely so the two readers cannot drift, and the remedy for a
1983+
* thread that reads `absent` is a comment in the fixed spelling.
19081984
*
19091985
* @param {{ body?: string, created_at?: string }[]|null} commentRows — the REST
19101986
* comment rows, or `null` when the thread could NOT be read.
@@ -8108,6 +8184,82 @@ export async function selfTest() {
81088184
})());
81098185
t('⛔ CONTROL: the diagnosis KEY is unchanged, so every sentence already keyed to `comments` still finds it', readDiagnosisKey('comments', 770017) === 'comments:770017');
81108186

8187+
// -- #18764: a DECORATED claim ENTERS the pool -----------------------------
8188+
//
8189+
// The two live records the escalation named, replayed OFFLINE and ⛔ never
8190+
// re-graded: they are another repository's cards and another seat's work.
8191+
// Ids, stamps and the load-bearing LINES are the real ones, read from the
8192+
// REST rows at 2026-09-17T22:02Z — ⚠️ both cards have since left the state
8193+
// they were read in, which is why the reading carries its time. The bodies
8194+
// below ADD the `Branch:` / `Clause-②` lines the real comments did not carry:
8195+
// without them the thread reads `claim-branch-unparsed` on BOTH sides of this
8196+
// change (measured), and the defect this battery pins is the one that only
8197+
// shows once a claim is otherwise complete.
8198+
battery('#18764: a DECORATED claim ENTERS the pool — ONE reading, and it is the sibling\'s');
8199+
const D64 = (id, at, body, login = 'os-sales') => ({ id, created_at: at, user: { login }, body });
8200+
const D64_BOLD = D64(5721120402, '2026-09-17T20:57:09Z', [
8201+
'**Claim:** card objectui#9660, by the `domain:spec` @ objectui execution seat, session `session_01UanLVj6xvbS6puBCewLr8L`.',
8202+
'Branch: `claude/issue-9660-named-test-invocation`',
8203+
'Clause-②: no',
8204+
].join('\n'));
8205+
const D64_TICK = D64(5720184809, '2026-09-17T19:41:36Z', [
8206+
'`Claim:` card objectui#9717, by the `domain:spec` @ objectui execution seat, session `session_01UanLVj6xvbS6puBCewLr8L`.',
8207+
'Branch: `claude/issue-9717-doc-component-types`',
8208+
'Clause-②: no',
8209+
].join('\n'));
8210+
// The older BARE claim, declaring the OPPOSITE value — so "the wrong carrier
8211+
// governs" is a WRONG VALUE here and not merely a missing one.
8212+
const D64_BARE_OLD = D64(5700000001, '2026-09-17T18:00:00Z', [
8213+
'Claim: the older BARE claim',
8214+
'Branch: `claude/issue-9660-older-bare`',
8215+
'Clause-②: yes',
8216+
].join('\n'));
8217+
const D64_POOL = (rows) => claimCarrierSelection(rows).pool.map((r) => r.id).join(',');
8218+
const D64_RECORD = (rows) => {
8219+
const rec = pairInputRecord({ pr: 9999, card: 9660, cardComments: rows, headSha: 'offline' });
8220+
return { selected: [rec['claim.selected']].flat().join('\n'), rejected: [rec['claim.rejected']].flat().join('\n') };
8221+
};
8222+
8223+
t('⭐ a BOLD claim ENTERS the pool — the state it could not reach at all before', D64_POOL([D64_BOLD]) === String(D64_BOLD.id), D64_POOL([D64_BOLD]));
8224+
t('…and GOVERNS: the branch resolved is the one IT names', (claimCarrierSelection([D64_BOLD]).governing?.branches ?? []).join() === 'claude/issue-9660-named-test-invocation');
8225+
t('…and the declaration limb reads the `Clause-②` line OFF IT', cardDeclaration([D64_BOLD]).state === 'declared' && cardDeclaration([D64_BOLD]).value === 'no');
8226+
t('⛔ CONTROL — the CONSTANT is NOT widened: the raw marker still refuses that same body', CLAIM_COMMENT_MARKER.test(D64_BOLD.body) === false);
8227+
t('⭐ the BACKTICKED spelling is the same record, by the same reading', D64_POOL([D64_TICK]) === String(D64_TICK.id));
8228+
t('…with its own `Branch:` line resolved', (claimCarrierSelection([D64_TICK]).governing?.branches ?? []).join() === 'claude/issue-9717-doc-component-types');
8229+
t('…and its own declaration read', cardDeclaration([D64_TICK]).value === 'no');
8230+
t('⛔ CONTROL: the raw marker refuses the backticked body too', CLAIM_COMMENT_MARKER.test(D64_TICK.body) === false);
8231+
t('⭐ a DECORATED NEWER claim SUPERSEDES a BARE older one — the pool is the newest, not the readable one', D64_POOL([D64_BARE_OLD, D64_BOLD]) === String(D64_BOLD.id), D64_POOL([D64_BARE_OLD, D64_BOLD]));
8232+
t('…and the older record is LISTED, as SUPERSEDED rather than dropped', says(D64_RECORD([D64_BARE_OLD, D64_BOLD]).rejected, 'a SUPERSEDED claim') && says(D64_RECORD([D64_BARE_OLD, D64_BOLD]).rejected, String(D64_BARE_OLD.id)));
8233+
t('⭐ …and the VALUE the limb reads is the newer one', cardDeclaration([D64_BARE_OLD, D64_BOLD]).value === 'no');
8234+
t('⛔ CONTROL: the older record declares the OPPOSITE, so selecting the wrong carrier is a WRONG value, ⛔ not a missing one', cardDeclaration([D64_BARE_OLD]).value === 'yes');
8235+
t('the input record NAMES the decorated row it selected — by id and by date', says(D64_RECORD([D64_BOLD]).selected, String(D64_BOLD.id)) && says(D64_RECORD([D64_BOLD]).selected, '2026-09-17T20:57:09Z'));
8236+
t('⛔ CONTROL: the same thread read the other way says nobody claimed at all', says(D64_RECORD([D64(1, '2026-09-17T20:57:09Z', 'no claim on this line')]).selected, 'no comment on this thread carries'));
8237+
8238+
// The retraction index reads the SAME predicate, so a decorated claim is
8239+
// retractable by its own author — ⛔ never a record that can be written but
8240+
// never withdrawn.
8241+
const D64_RELEASE = D64(5721120999, '2026-09-17T21:30:00Z', 'Release: session `session_01UanLVj6xvbS6puBCewLr8L` — 去向 `pm:queue`');
8242+
t('⭐ the retraction index SEES a decorated claim — it is retractable by its own author', claimRetractions([D64_BOLD, D64_RELEASE]).has(D64_BOLD));
8243+
t('…and the pool then says every claim on the thread is RETRACTED, ⛔ not that none was written', says(D64_RECORD([D64_BOLD, D64_RELEASE]).selected, 'RETRACTED'));
8244+
t('⛔ CONTROL: a DIFFERENT author\'s release retracts nothing, decorated or not', claimRetractions([D64_BOLD, { ...D64_RELEASE, user: { login: 'os-other' } }]).size === 0);
8245+
8246+
// The refusals are the SIBLING's and are pinned here as still-refused: this
8247+
// file admits no spelling of its own, so a form the sibling names as a NEAR
8248+
// MISS must not become a claim by arriving through this door.
8249+
t('⛔ a markdown LIST ITEM is still not a claim — the shape the shared reading refuses to undecorate through', D64_POOL([D64(2, '2026-09-17T20:00:00Z', '- Claim: seat.\nBranch: `claude/issue-1-x`')]) === '');
8250+
t('⛔ a HEADING-style claim is still not one', D64_POOL([D64(3, '2026-09-17T20:00:00Z', '## Claim: seat.\nBranch: `claude/issue-1-x`')]) === '');
8251+
t('⛔ UNDERSCORE emphasis is still a NAMED near miss, ⛔ not a claim', markerMatches(CLAIM_COMMENT_MARKER, '__Claim:__ seat.') === false);
8252+
t('⛔ and the `Clause-②-correction:` comment does not enter the pool through the new door either', D64_POOL([FIXED_CORRECTION('no')]) === '' && markerMatches(CLAIM_COMMENT_MARKER, FIXED_CORRECTION('no').body) === false);
8253+
t('⛔ provably ADDITIVE: a bare claim this file already read reads exactly as before', claimCarrierSelection([CLAIM('Clause-②: no')]).pool.length === 1);
8254+
8255+
// ⭐ The file keeps TWO undecoration paths, and that is a measurement rather
8256+
// than an oversight: `undecorateRetractionLine` strips `_` and then every
8257+
// leading non-letter/non-digit character, which the shared stripper does not.
8258+
// 5 of 12 fixtures read differently. Both directions are load-bearing, so the
8259+
// pair below pins the divergence instead of quietly closing it.
8260+
t('⭐ the RETRACTION path still reads the sigil-led #18373 line — narrowing it to the shared reading would unland #18719', claimRetractions(RTX_18373).has(RTX_18373.find((r) => r.id === RTX_WITHDRAWN)));
8261+
t('⭐ …while the SHARED reading does not strip a leading sigil, so the two paths are ⛔ NOT interchangeable', markerMatches(CLAIM_COMMENT_MARKER, '🚨 Claim: PM loop round 1') === false);
8262+
81118263
// -- The floor: every declared battery RAN, and ran its cases (#13489) -----
81128264
//
81138265
// Evaluated after every battery has had its chance and BEFORE the verdict, so
@@ -8176,7 +8328,9 @@ export async function selfTest() {
81768328
+ 'line that QUOTES the spelling held apart from one that declares a value in BOTH halves '
81778329
+ 'of that property, the input record whose field roster is the same on exit 0, on exit 4 '
81788330
+ 'and on a refusal — with the selected carrier, its body fingerprint and the rejected '
8179-
+ 'candidates each stated — and the exit register).',
8331+
+ 'candidates each stated, the DECORATED claim that enters the pool and governs through '
8332+
+ 'the sibling\'s one reading — the constant unwidened, and the file\'s two undecoration '
8333+
+ 'paths pinned as the two jobs they are — and the exit register).',
81808334
);
81818335

81828336
selfTestReachedVerdict = true;

0 commit comments

Comments
 (0)