tooling(pm): split the clause-② declaration limb's NO READING into two readings - #15735
Conversation
…o readings The declaration limb returned one `absent` state for two different facts: a card whose thread carries no claim comment at all, and a card whose claim comment carries no `Clause-②:` line. One sentence, one count, and two different things owed -- a report could say "15 NO READING" about two populations and a seat reading its own row could not tell which remedy was being asked for. `cardDeclaration` now returns `absent` (no comment on the thread is a claim comment -- no line beginning `Claim:`) and `missing` (a claim comment is there and carries no declaration line) as two members of the same enum, under the same exit code the limb has always returned. `c2DeclarationUnreadable` writes a sentence per state: the ABSENT one names the fixed first-line spelling as its remedy and says in one clause that a heading-style claim is not a claim comment to this predicate; the MISSING one sends the remedy to the claim comment already on the thread. The sweep's per-repo summary counts them as two numbers under two labels, from the same reader the rows use, and `--json` carries the same pair. `CLAIM_COMMENT_MARKER` is unchanged -- it is imported from `check-half-states.mjs` so the two readers cannot drift, and the spelling it accepts is a maintainer ruling. No exit code changes. Self-test: 174 -> 190 cases. New cases cover a prose-only thread (ABSENT), a `## Claim --` heading thread (ABSENT, with the remedy sentence), a `Claim:` comment with no line (MISSING), a `Claim:` comment carrying the key only inside prose (MISSING, never readable -- the reader is line-anchored), and the summary tally over all of them. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019RfFHiRCSs3JXLK4cwcfox
…ause2-no-reading-split
|
ACCEPT — in-seat review of PR #15735, head Implemented-by: Verified in a detached compare worktree at the PR head, three-dot against Seat gate runs on this head in the compare worktree: Landing regime: pure code ⇒ ready + auto-merge in this same act (the queue's SQUASH governs whatever method the tool reports); Generated by Claude Code |
Fixes #15693
The declaration limb of the clause-② sweep returned one state,
absent, for two different facts, and printed one sentence and one count over both. A round report could therefore say "15 NO READING" about two populations that owe different things, and a seat reading its own row could not tell which of the two it was in.This splits the reading in two — same limb, same exit code, one file.
The two readings
cardDeclarationnow returns two members of the same enum where it returned one:Claim:, which is the whole of the predicate. The carrier the limb reads does not exist, so no line could have been read from it. What the card owes is the claim comment.^Clause-②:\s*(yes|no)\s*$. The carrier exists; what the card owes is the line.misplaced,malformed,declaredandunreadableare untouched.The sentences, before → after
Before — one sentence for both, and it asserts a claim comment that may not exist:
After, ABSENT:
After, MISSING:
The tail both sentences share (not a declared
no, ⛔ do not fill the line in, ⛔ do not relax the spelling to prose, report-only) is unchanged.The summary line, before → after
Before:
After:
--jsoncarries the same pair asdeclarationLimb: { absent, missing }. The tally reads the samecardDeclarationthe rows read, so a count can never disagree with the rows printed under it — asserted in the self-test.Live readings (read-only; the sweep writes nothing, ever)
Whole-repo sweep, both runs from this container, exit 0 both times:
1c1421401, 04:18Z)555e10e9b, 05:07Z)NO READING— one numbergrep -c 'NO READING on the declaration limb: '(the old folded sentence) returned 0.--pairon one card of each kind, named, both still exit 4 — the limb's exit code is unchanged:node scripts/pm/check-clause2-carriers.mjs --pair 15720→ card plugin-auth: both remedies in theno_sign_in_account_at_bootreport are unexecutable as written — and one of them silences the report #15588, thread carries no claim comment → ABSENT sentence, exit 4.node scripts/pm/check-clause2-carriers.mjs --pair 15721→ card [finding] Theos package publishexample set is maintained twice — CLIexamplesandcontent/docs/deployment/cli.mdx— with no parity gate, and they had drifted #15393, thread carries aClaim:comment with no declaration line → MISSING sentence, exit 4.Before this change both printed the same sentence, and the one it printed asserted a claim comment that #15588's thread does not have.
Self-test: 174 → 190 cases
New cases, both directions:
## Claim — …heading → ABSENT (the motivating shape), and it produces the same row as the prose thread, remedy sentence included;Claim:comment with no declaration line → MISSING;Claim:comment withClause-②: yes→ readable, no row;Claim:comment carrying the key only inside prose (a sentence of the form "the dev declaresClause-②: yes|nofrom the diff") → MISSING, never readable, and carries no value — the reader is line-anchored, so a description of a declaration is not one;declared,unreadableandmisplacedeach counted into neither.Battery floors updated:
C2, the row this file exists for14 → 26, andthe card-level declaration: four states, none collapsed into another(9) →the card-level declaration: every state, none collapsed into another(13). The battery was renamed because its old name asserted a count that this change makes wrong — the floor mechanism caught the rename itself and red until the roster agreed, which is the mechanism working.SELF_TEST_BATTERY_FLOOR(13 batteries) is unchanged: no battery was added or removed. The self-test's own count line names the split.What is deliberately NOT changed
CLAIM_COMMENT_MARKERstays exactly as it is, andscripts/pm/check-half-states.mjsis not edited —git diff origin/main -- scripts/pm/check-half-states.mjsis empty on this head. The marker is imported precisely so the two readers cannot drift, and the spelling it accepts is a maintainer ruling of 2026-08-11: a claim comment's first line begins with the literalClaim:, the patrol predicate accepts that one spelling and stays strict, and a fleet writing another form converges to the documented one. The card's route 2 (widening the predicate to## Claim — …) is refused by that ruling, not deferred.--pairon an ABSENT card and a MISSING card both exit 4.Verification — every verdict line, all at head
555e10e9bGate family derived mechanically from the change set, not from a hand-written list:
node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack→ 29 families. All 29 run, exit 0, then reconciled:Named verdicts:
pnpm lintis the repo-wideeslint . --no-inline-config, run whole through the shared verification lock — no narrowing, nothing to declare.Note on the base:
origin/mainadvanced by 5 commits under this branch mid-run, and three files the gate derivation reads changed in that range —dispatch-gatessaid so (STALE TREE) rather than answering about a tree nobody is on.origin/mainwas merged in (555e10e9b) and the whole union above was re-derived and re-run on the merged head; the derived family set was byte-identical to the pre-merge one. This branch's only change againstorigin/mainis the one file.Not governed; no changeset
Nothing is published from any package —
scripts/pm/**only — so this carriesskip-changeset.🤖 Generated with Claude Code
https://claude.ai/code/session_019RfFHiRCSs3JXLK4cwcfox
Generated by Claude Code