Skip to content

tooling(pm): split the clause-② declaration limb's NO READING into two readings - #15735

Merged
os-steve merged 2 commits into
mainfrom
claude/issue-15693-clause2-no-reading-split
Sep 5, 2026
Merged

tooling(pm): split the clause-② declaration limb's NO READING into two readings#15735
os-steve merged 2 commits into
mainfrom
claude/issue-15693-clause2-no-reading-split

Conversation

@claude

@claude claude Bot commented Sep 5, 2026

Copy link
Copy Markdown
Contributor

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

cardDeclaration now returns two members of the same enum where it returned one:

  • ABSENT — no comment on the card's thread is a claim comment: nothing carries a line beginning 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.
  • MISSING — a claim comment is there and carries no line matching the anchored ^Clause-②:\s*(yes|no)\s*$. The carrier exists; what the card owes is the line.

misplaced, malformed, declared and unreadable are untouched.

The sentences, before → after

Before — one sentence for both, and it asserts a claim comment that may not exist:

card #15588 (delivering open PR #15720 (draft)) — NO READING on the declaration limb: the card's claim comment carries no Clause-②: line in the fixed spelling. …

After, ABSENT:

card #15588 (delivering open PR #15720 (draft)) — NO READING on the declaration limb, and the CLAIM COMMENT is what is missing: no comment on the card's thread is a claim comment, so the carrier this limb reads does not exist and no line could have been read from it. Remedy: write the claim comment with a first line beginning Claim:, then the Clause-②: yes|no line; the fixed spelling is Clause-②: yes or Clause-②: no, exactly those two. A heading-style claim (## Claim — …) is not a claim comment to this predicate, however complete the reasoning under it. …

After, MISSING:

card #15393 (delivering open PR #15721 (draft)) — NO READING on the declaration limb, and the DECLARATION LINE is what is missing: the card's claim comment is there and carries no Clause-②: line in the fixed spelling. Remedy: add the line to that claim comment — the fixed spelling is Clause-②: yes or Clause-②: no, exactly those two. …

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:

check-clause2-carriers: 41 card/PR pair(s) derived from 36 open PR(s) in objectstack-ai/objectstack — 22 clause-② finding(s), 0 pair(s) UNJUDGED. Report-only: findings are patrol input, not a gate verdict.

After:

check-clause2-carriers: 39 card/PR pair(s) derived from 33 open PR(s) in objectstack-ai/objectstack — 23 clause-② finding(s), 0 pair(s) UNJUDGED. Declaration limb not read: 11 with NO CLAIM COMMENT (a line beginning `Claim:` is the whole set) and 9 with a claim comment but NO DECLARATION LINE — two readings, two remedies, ⛔ never one number. Report-only: findings are patrol input, not a gate verdict.

--json carries the same pair as declarationLimb: { absent, missing }. The tally reads the same cardDeclaration the 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:

before (1c1421401, 04:18Z) after (555e10e9b, 05:07Z)
pairs / open PRs 41 / 36 39 / 33
clause-② findings 22 (3 C1 + 19 C2) 23 (3 C1 + 20 C2)
declaration limb, not read 19 NO READING — one number 11 NO CLAIM COMMENT + 9 NO DECLARATION LINE
pairs UNJUDGED 0 0

⚠️ The board moved between the two runs (36 → 33 open PRs), so the totals are not a controlled before/after and the row counts are not comparable one-to-one. What is comparable is the shape: on the 04:26Z run of the same board that produced 19 C2 rows, the split read 9 + 10 = 19 and every row's own sentence agreed with the summary's label, and grep -c 'NO READING on the declaration limb: ' (the old folded sentence) returned 0.

--pair on one card of each kind, named, both still exit 4 — the limb's exit code is unchanged:

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:

  • a thread of prose only → ABSENT;
  • a thread whose only "claim" is a ## Claim — … heading → ABSENT (the motivating shape), and it produces the same row as the prose thread, remedy sentence included;
  • a Claim: comment with no declaration line → MISSING;
  • a Claim: comment with Clause-②: yes → readable, no row;
  • a Claim: comment carrying the key only inside prose (a sentence of the form "the dev declares Clause-②: yes|no from the diff") → MISSING, never readable, and carries no value — the reader is line-anchored, so a description of a declaration is not one;
  • the two rows are asserted to be different strings, and both are asserted to keep the shared tail;
  • the tally: two not-read states counted apart, with declared, unreadable and misplaced each counted into neither.

Battery floors updated: C2, the row this file exists for 14 → 26, and the 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_MARKER stays exactly as it is, and scripts/pm/check-half-states.mjs is not edited — git diff origin/main -- scripts/pm/check-half-states.mjs is 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 literal Claim:, 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.
  • No exit code changes. Both not-read states keep the code the limb has always returned; the exit table is a contract other tools read. Asserted live above: --pair on an ABSENT card and a MISSING card both exit 4.
  • Still writes nothing. No label, ever — the row's own closing sentence says so, and every new case asserts it.

Verification — every verdict line, all at head 555e10e9b

Gate 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:

Run reconciliation — 29 derived, 29 run, 0 NOT-MEASURED, 0 UNRUN.
✓ dispatch-gates --ran: 29 derived famil(ies) accounted for — 29 run, 0 NOT-MEASURED.

Named verdicts:

✓ check-clause2-carriers self-test: 190 cases pass (fixed-spelling reader, the declaration
  states with the two not-read readings kept apart — no claim comment, and a claim comment
  with no line — the 2026-08-31 seven-pair replay, …)                            exit 0
✓ check-half-states self-test: 2223 cases pass.                                   exit 0
✓ dispatch-gates self-test: 1445 cases pass.                                      exit 0
✓ check-self-test-wired: every one of the 172 script(s) CI runs that ship a
  `--self-test` has that self-test run by CI.                                     exit 0
✓ check:entry-guard: 215 scripts/ file(s) — every entry guard goes through
  invoked-as.mjs; 159 export bindings, 159 of them inert on import               exit 0
check-nul-bytes: OK (scanned 7594 text file(s); no raw ASCII control bytes).       exit 0
os-verify-lock: VERDICT command-exit 0 · held the lock 100s   ← `pnpm lint`, whole repo

pnpm lint is the repo-wide eslint . --no-inline-config, run whole through the shared verification lock — no narrowing, nothing to declare.

Note on the base: origin/main advanced by 5 commits under this branch mid-run, and three files the gate derivation reads changed in that range — dispatch-gates said so (STALE TREE) rather than answering about a tree nobody is on. origin/main was 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 against origin/main is the one file.

Not governed; no changeset

Nothing is published from any package — scripts/pm/** only — so this carries skip-changeset.

🤖 Generated with Claude Code

https://claude.ai/code/session_019RfFHiRCSs3JXLK4cwcfox


Generated by Claude Code

…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
@claude claude Bot added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Sep 5, 2026
@github-actions github-actions Bot added the size/m label Sep 5, 2026

os-steve commented Sep 5, 2026

Copy link
Copy Markdown
Collaborator

ACCEPT — in-seat review of PR #15735, head 555e10e9b (skills seat, 2026-09-05T05:3xZ).

Implemented-by: claude/issue-15693-clause2-no-reading-split (os-dev subagent)
Reviewed-by: session_019RfFHiRCSs3JXLK4cwcfox (skills seat)

Verified in a detached compare worktree at the PR head, three-dot against origin/main (eca504724), not from the report: one file, scripts/pm/check-clause2-carriers.mjs, +133 / −25 — the head is the route-1 commit plus one merge of main, and the branch's own diff is unchanged by the merge. cardDeclaration returns missing when a comment on the thread matched the imported CLAIM_COMMENT_MARKER and none of the claim rows carries the anchored line, and absent when no comment matched — decided on the same claimRows the reading itself used, so the two readings cannot disagree with the rows. Every consumer of the state was read at the head: the C2 sentence switch gains a missing case and keeps absent as its default, naming the heading-style claim as the shape that does not count; the declared/yes predicate is untouched; the new declarationLimbTally counts only the two not-read states, keeps declared, misplaced, malformed and unreadable out, and feeds the summary line and the --json declarationLimb pair from the same reader. CLAIM_COMMENT_MARKER is not redefined (it stays the sibling's constant); no exit code changed; check-half-states.mjs untouched; route 2 refused, not deferred, under the 2026-08-11 ruling. No model names in the diff or the PR body. Not governed (check-governed-merges --test exit 0); tier read: no path-derived mandate.

Seat gate runs on this head in the compare worktree: check-clause2-carriers --self-test 190 cases (174 on main, +16, with the dev's observed red while the roster lagged the cases), check-half-states --self-test 2223, governed exit 0. The dev's evidence beyond that: 29 derived families all exit 0 and reconciled 29 of 29 after the merge; whole-repo lint through the lock; the two live --pair demos (a thread with no claim comment → the ABSENT sentence, a claim comment without the line → the MISSING sentence, both still exit 4); the controlled 04:26Z sweep where 9 + 10 = 19 and every row agreed with its label. CI on 555e10e9b: 34 check runs, 23 success, 11 skipped, none failing, Lint & Repo Gates among the successes; mergeable_state: clean.

Landing regime: pure code ⇒ ready + auto-merge in this same act (the queue's SQUASH governs whatever method the tool reports); Fixes #15693 closes the card on merge.


Generated by Claude Code

@os-steve
os-steve marked this pull request as ready for review September 5, 2026 05:32
@os-steve
os-steve added this pull request to the merge queue Sep 5, 2026
Merged via the queue into main with commit ae7b7f1 Sep 5, 2026
36 checks passed
@os-steve
os-steve deleted the claude/issue-15693-clause2-no-reading-split branch September 5, 2026 06:02
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

Development

Successfully merging this pull request may close these issues.

[finding] A claim comment headed ## Claim — … is invisible to CLAIM_COMMENT_MARKER, so its Clause-② declaration reads as never made

2 participants