Skip to content

fix(pm): a decorated Claim: enters the governing-claim pool, through the sibling's one reading - #18824

Merged
os-justin merged 3 commits into
mainfrom
claude/issue-18764-decorated-claim-enters-the-pool
Sep 17, 2026
Merged

os-justin merged 3 commits into
mainfrom
claude/issue-18764-decorated-claim-enters-the-pool

Conversation

@os-justin

Copy link
Copy Markdown
Collaborator

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 f7ee45d4efae548569fd exit 18 of 889 cases red, all 8 from the new battery, nothing pre-existing red
the RETRACTION indexer predicate back to the raw .test claimRetractions f7ee45d4ef708893dc5c exit 12 of 889 cases red, both from the new battery, nothing pre-existing red

Both restorations: RESTORED: blob f7ee45d4ef734fb21d50662470c340cc43210b1d, 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

os-justin and others added 3 commits September 17, 2026 22:39
…h the sibling's one reading

The governing-claim pool and the retraction indexer each tested the imported
`CLAIM_COMMENT_MARKER` against the RAW comment body, so a claim written
`**Claim:**` or `` `Claim:` `` was never a candidate for governance -- not
superseded, not listed, not named. `claimGovernance`, imported from the same
sibling, has read both ownership markers through `markerMatches` since #18680,
so one function held both answers at once.

Both raw tests now read through `markerMatches(CLAIM_COMMENT_MARKER, body)`,
imported from `check-half-states.mjs`: the bare marker first (provably
additive), then the shared stripper per line with the list item refused. The
constant is not widened and no second undecorator is written here.

Claude-Session: https://claude.ai/code/session_01Gqi43smmqjJ5sUrhfoPeKu
Co-authored-by: Claude <noreply@anthropic.com>
… retractable

A new self-test battery (24 cases, the roster floor raised by exactly the one
battery it adds) 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 retraction index sees a decorated claim as retractable by its own author;
the input record names the decorated row it selected.

The controls are the other half: the constant itself still refuses those
bodies, a list item / heading / underscore-emphasis line is still not a claim,
the `Clause-②-correction:` comment does not enter the pool through the new
door, and the two undecoration paths this file holds are pinned as the two
jobs they are -- the sigil-led #18373 retraction is read by one and not by the
other.

Claude-Session: https://claude.ai/code/session_01Gqi43smmqjJ5sUrhfoPeKu
Co-authored-by: Claude <noreply@anthropic.com>
@os-justin os-justin added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Sep 17, 2026 — with Claude
@os-justin
os-justin marked this pull request as ready for review September 17, 2026 23:26
@os-justin
os-justin added this pull request to the merge queue Sep 17, 2026
Merged via the queue into main with commit 42f8df1 Sep 17, 2026
37 checks passed
@os-justin
os-justin deleted the claude/issue-18764-decorated-claim-enters-the-pool branch September 17, 2026 23:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/m skip-changeset PR has no user-facing published change; bypasses the changeset gate

Projects

None yet

2 participants