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
test(pm): pin the zero-branch claim state in both self-tests
H60's battery replays the measured inline spellings (2026-09-08/09 on one
card, and the four a second seat's template produced inside three seconds
on 2026-09-12) and pins that the branch reader's accept set did NOT move:
the state is the fix, so the next unrecognised spelling is loud on its
first occurrence instead of being bought one widening at a time.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MCLBsUgfykL74aU716rzVK
'the exit register is distinct in every direction it must be': 6,
621
622
'the argv contract and the board provenance (#16623)': 42,
622
623
'#17366: the correction comment — the self-solvable exit, and the three things it is not': 65,
624
+
'#17149: a claim that parses to ZERO branches — malformed, never absent': 26,
623
625
});
624
626
625
627
// DELETING an entry silences that battery's floor exactly as effectively as
626
628
// zeroing it, so the roster's own size is pinned too.
627
629
// Raised by exactly the one battery #16304 adds, again by exactly the one
628
630
// #17302 adds, and again by exactly the one #17366 adds, so the roster's
629
631
// existing slack is preserved rather than tightened or loosened as a side
630
-
// effect.
631
-
constSELF_TEST_BATTERY_FLOOR=17;
632
+
// effect, and once more by the one #17149 adds.
633
+
constSELF_TEST_BATTERY_FLOOR=18;
632
634
633
635
// The key an assertion is filed under when no battery is open. It is not a
634
636
// declared battery, so it reds by the same set difference rather than silently
@@ -4322,6 +4324,101 @@ export function selfTest() {
4322
4324
t('⛔ no new exit code was minted for the correction reading',newSet([EXIT_OK,EXIT_USAGE,EXIT_INCOMPLETE,EXIT_PREREQUISITE_NOT_MET,EXIT_PAIR_ADVERSE]).size===5);
4323
4325
t('…and a repaired pair answers with the SAME code a never-broken one does',pairRows(repairedPair).length===pairRows(pair({cardComments: [CLAIMED('Clause-②: no')]})).length);
4324
4326
4327
+
// -- #17149: a claim that parses to ZERO branches ---------------------------
4328
+
//
4329
+
// The declaration limb's carrier is the GOVERNING claim, and governance is
4330
+
// resolved by a branch parse. A newest claim comment naming no parseable
4331
+
// branch used to be discarded, and this file then read a declaration off a
4332
+
// comment the seat had already replaced — silently, and in BOTH directions:
4333
+
// wrong when the two disagreed, and right-for-the-wrong-reason when they
4334
+
// agreed. The fixtures below are the MEASURED bodies, quoted rather than
4335
+
// paraphrased, so a future widening of the branch reader cannot make this
4336
+
// battery pass by accident.
4337
+
battery('#17149: a claim that parses to ZERO branches — malformed, never absent');
4338
+
// Card #16322, comments 5593513389 (2026-09-08T23:46:51Z) and 5594909614
4339
+
// (2026-09-09T02:35:21Z) as posted: the branch named INSIDE the `Claim:`
4340
+
// sentence, with no `Branch:` line anywhere. The two declare OPPOSITE values,
4341
+
// which is what made the fallback visible at all.
t('⭐ the measured inline spelling reads CLAIM-BRANCH-UNPARSED — the carrier could not be resolved',unparsedDecl.state==='claim-branch-unparsed');
4372
+
t('⛔ …and NOT `declared`: the line that IS on the thread belongs to a comment this run cannot confirm is current',unparsedDecl.state!=='declared');
4373
+
t('⛔ …nor `absent`, which would say no claim comment was written — one was',unparsedDecl.state!=='absent');
4374
+
t('⛔ …nor `missing`, which would send the seat looking for a line that is there',unparsedDecl.state!=='missing');
4375
+
t('…and it carries NO value — an unclassified result is never a reading',unparsedDecl.value===undefined);
4376
+
t('the state names the comment it could not parse',unparsedDecl.malformedClaim?.id===5594909614);
4377
+
// The BEFORE-state, quantified rather than recalled: both comments carry a
4378
+
// readable line, and they DISAGREE. That is why reading the wrong one was a
4379
+
// wrong answer and not merely an unlucky one.
4380
+
t('⭐ the superseded comment carried a readable declaration, and the two DISAGREE',readClause2Line(INLINE_OLD.body)?.value==='no'&&readClause2Line(INLINE_NEW.body)?.value==='yes');
4381
+
// The reading PRINTS, and it is UNJUDGED (exit 2) rather than a verdict.
t('⭐ the pair is UNJUDGED and the reading prints in full — ⛔ never silence',typeofunparsedGap==='string'&&unparsedGap.length>0);
4385
+
t('…naming the comment id, so a reader can open it',says(unparsedGap,'5594909614'));
4386
+
t('…and the remedy, which is a `Branch:` line of its OWN',says(unparsedGap,'`Branch:` line of its OWN'));
4387
+
t('…and saying in as many words that this is not a declared `no`',says(unparsedGap,'never a declared `no`'));
4388
+
t('…and that a whole shift reading this way is a TEMPLATE fault rather than a typo',says(unparsedGap,'SEAT TEMPLATE fault'));
4389
+
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'));
4390
+
t('⛔ nor any other finding row on this pair',pairRows(unparsedPair).length===0);
4391
+
// The live specimen, and the fallback shape at its sharpest: the older claim
4392
+
// names a DIFFERENT branch, so every reader downstream probes the wrong ref.
t('⭐ the live 2026-09-12 specimen reads the same way',liveDecl.state==='claim-branch-unparsed');
4395
+
t('…and the state names the older claim governance would have fallen back to',liveDecl.governingClaim?.createdAt==='2026-09-06T06:19:06Z');
4396
+
t('⚠️ …whose branch is a DIFFERENT one, so the fallback is not even about the same work',liveDecl.governingClaim?.branches.join(',')==='claude/issue-16175-regen-sibling-stale-rules');
4397
+
t('…and the printed gap names that older claim rather than leaving the reader to guess',says(pairUnjudged(pair({cardComments: [LIVE_PARSES,LIVE_BRANCHLESS]})),'claude/issue-16175-regen-sibling-stale-rules'));
4398
+
// CONTROLS — the accept set did not move in either direction.
4399
+
t('⛔ CONTROL: a well-formed newest claim still governs, and its value is read',cardDeclaration([
t('⛔ CONTROL: a thread with no claim comment at all still reads ABSENT',cardDeclaration([{id: 1,body: 'a triage note',created_at: '2026-08-31T10:00:00Z'}]).state==='absent');
4411
+
t('⛔ CONTROL: an unreadable thread still reads UNREADABLE — never the new state',cardDeclaration(null).state==='unreadable');
4412
+
// The new state is nobody else's state: it is counted into neither not-read
4413
+
// population and it is not the #16304 fourth reading's `absent`.
4414
+
t('the tally counts it under NEITHER not-read population',declarationLimbTally([unparsedPair]).absent===0&&declarationLimbTally([unparsedPair]).missing===0);
4415
+
t('⛔ …and the fourth reading is unavailable on it — a sibling cannot answer a question this card could not ask',readsSiblingDeclaration(unparsedPair,[unparsedPair,pair({card: 999,cardComments: [CLAIM('Clause-②: yes')]})])===false);
4416
+
t('⛔ …nor is such a card a CARRIER for a sibling of its own',siblingDeclarations(pair({card: 999,pr: 13910}),[pair({card: 999,pr: 13910}),{pr: 13910,card: 13476,cardComments: INLINE_THREAD}]).length===0);
4417
+
// ⛔ The fix is the STATE, not a widening: the branch reader's accept set is
4418
+
// byte-identical, which is what keeps the next unrecognised spelling loud.
4419
+
t('⛔ the branch reader was NOT widened — the inline spelling still parses to zero',claimedBranches(INLINE_NEW.body).length===0);
4420
+
t('⛔ …and the claim marker still matches it, which is what makes the two-anchor split a STATE',CLAIM_COMMENT_MARKER.test(INLINE_NEW.body)===true);
4421
+
4325
4422
// -- The floor: every declared battery RAN, and ran its cases (#13489) -----
4326
4423
//
4327
4424
// Evaluated after every battery has had its chance and BEFORE the verdict, so
@@ -4382,7 +4479,9 @@ export function selfTest() {
4382
4479
'the correction comment that supersedes a claim declaration with the five measured prose '+
4383
4480
'spellings held out as negatives, '+
4384
4481
'the three read paths with their offline reader, the argv contract with its usage and its '
4385
-
+'refusal, the board provenance line, and the exit register).',
4482
+
+'refusal, the board provenance line, the claim whose `Branch:` line parses to ZERO '
4483
+
+'branches — reported as an unresolvable carrier rather than discarded — and the exit '
0 commit comments