fix(pm): name PLACEMENT, not spelling, when a Clause-② key sits mid-line - #17201
Merged
Merged
Conversation
check-clause2-carriers read a claim header like `Domain: X · Clause-②: no` as `missing` and shipped a remedy naming only spelling -- so a seat was sent to hunt a typo on a line spelled exactly right. Both existing patterns anchor at `^`, so the line reached neither the declaration reader nor the near-miss reporter whose whole job is to stop a near miss reading as an absence. Adds a reporting-only detector for the fixed key preceded by something other than line-start decoration. The near miss now carries a reason, and the C2 row picks its remedy sentence from it: placement, with the offending line quoted and an explicit "there is no typo to find". CLAUSE2_KEY_LINE is untouched and the state union is unchanged -- the shape still reads `missing`, carries no value, and keeps its exit. What moved is the sentence, not the accept set: this reader decides "is this a declaration?" by position alone, so loosening position here would promote merely-describing prose into candidate declarations in the opposite direction. Claude-Session: https://claude.ai/code/session_012GKcPZbMoGq7WPzKLfRBTU Co-authored-by: Claude <noreply@anthropic.com>
baozhoutao
marked this pull request as ready for review
September 9, 2026 16:36
baozhoutao
enabled auto-merge
September 9, 2026 16:36
baozhoutao
deleted the
claude/issue-16931-clause2-inline-key-diagnostic
branch
September 9, 2026 17:11
This was referenced Sep 9, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #16931
Domain:
domain:devx· Type: Bug · Route: A (change what the tool SAYS, not what it ACCEPTS)Clause-②: no — diagnostic text only. The accept set, the state union, the values, the tallies and the exit register are unchanged, and that is measured below rather than argued.
The defect
check-clause2-carriersread a compact claim header likeas
missingand shipped a remedy naming only spelling — so a seat was sent to hunt a typo on a line spelled exactly right. Both existing patterns anchor at start-of-line and tolerate only line-start decoration before the key, so the line was invisible twice: not read as a declaration (correct), and not quoted back as a near miss either — which is the whole job of the mechanism that exists so a near miss is not silently read as an absence.What changed
One reporting-only detector: the fixed key followed by its colon, at a position no line-start decoration explains. The near miss now carries a
reason, and the C2 row picks its remedy sentence from it.reason: 'inline-key'— the key is spelled exactly right and simply not at the start of a line. The row names PLACEMENT, quotes the offending line, says in as many words that the spelling is not the defect and that there is no typo to find, and sends the seat to put the line on one of its own.reason: 'spelling'— everything the near-miss reporter already caught. Sentence unchanged.CLAUSE2_KEY_LINEis untouched. The standing red line is preserved verbatim in the file and in the row it still prints: 「a predicate that reads prose is a heuristic, and the measured terminus of that direction is a check that can barely fail」.⭐ Both direction controls, measured before and after
This reader decides "is this line a declaration?" by position alone, so #16931 and #17098 are the same regex from opposite directions, and any change that loosened position here would make #17098 worse. Both directions were measured on the same harness, against
origin/mainc3756ff096and against this branch.Forward — this card's shape
readClause2Linenull(invisible to both patterns){kind: 'near-miss', reason: 'inline-key', line: …}cardDeclaration{state: 'missing'}, no detail{state: 'missing', detail: THE_LINE, nearMissReason: 'inline-key'}⭐ The state is the same in both columns. The line is exactly as unread as it was; only the sentence moved.
Reverse control — #17098's direction, ⛔ not fixed here and ⛔ not regressed
Input: a key-INITIAL bullet that merely describes,
- **Clause-②: yes/Clause-②: no** — the value alone on its line, machine-read.readClause2Line{kind: 'declared', value: 'yes', …}{kind: 'declared', value: 'yes', …}cardDeclaration{state: 'declared', value: 'yes', …}{state: 'declared', value: 'yes', …}Byte-identical — the diff of the two harness runs shows no line for this control at all. Today that reading is #17098's defect; ⛔ this PR neither fixes it nor moves it. Structurally it cannot: the declaration reader returns on the first key-line match before the reporter is consulted, and the detector is written to fire only where the key is NOT at line start. That property is pinned by a case of its own (a key-initial line is never reasoned
inline-key), rather than by pinning what the defective direction currently reads — pinning today'sdeclaredwould put a fixture in #17098's way.Neighbours held
Clause-②: nostill declares; the #12297 reasoning-after-value allowance (Clause-②: yes — widens the accept set) still declares; the existing prose near miss still prints the same row text and only gains itsreasonfield.A side effect measured, not glossed
A claim comment that merely DESCRIBES with prose before the key (the
:2272fixture's shape) also carries the key mid-line, so it now takes the placement sentence too. That is why the sentence is worded to state only what is measurable — the thread carries the key, not at the start of a line — and never that the judgement was made. Its state is unchanged (missing), and the remedy it now gives (put the declaration on a line of its own) is correct for that shape as well.End-to-end, on this card's own thread
Running the reader over the real comment thread of #16931: before, the row carried no quotation at all; after, it quotes the triage bullet that spells the key mid-line. The state is
absentin both readings, unchanged.Ablation
Fix committed first. Mutating the detector's single decision (
return truefor a key preceded by non-decoration) toreturn false, proved on disk by blob hash60b7562c…→71d6a50b…:missing, no value, tally still one not-read card, the standing refusal still printed. Those hold in both worlds, which is what makes them controls.git checkout HEAD -- PATH; blob back to60b7562c…,git diff HEADempty,git status --porcelainempty, self-test exit 0 / 319 pass.Test evidence
pnpm check:pm-clause2-carriers— exit 0, 319 cases (was 299 onorigin/main; 20 added across the two existing batteries, which carry floors rather than equalities, soSELF_TEST_BATTERIESis untouched).node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstackderived 35 commands; all 35 run; reconciled with--ran:35 derived famil(ies) accounted for — 35 run, 0 NOT-MEASURED, exit 0.pnpm installhad not run in this worktree). That is NOT MEASURED, not a finding; all seven were re-run after install and returned 0.pnpm check:pm-half-states(0),pnpm check:pm-widening-tells(0). Their reference is to this file's decoration tolerance as a precedent; that tolerance is unchanged.--self-test, wired ascheck:pm-clause2-carriers.eslint . --no-inline-config --format jsonat59adc6d0: 6438 files, 0 errors, 0 warnings. Whole population, not a narrowing.Changeset
None.
scripts/pm/**ships in no package'sfiles[]and the repo root package is private, so nothing published moves.lint.ymlstates the case in its own words: "this PR edits a CI-internal script" is the textbookskip-changesetcase.验收备注 — noted, not filed
readClause2Line,cardDeclaration's return object, themissingbranch ofc2DeclarationUnreadable, and two self-test batteries — no overlap, andSELF_TEST_BATTERIESis not edited. ⛔ [finding] check-clause2-carriers T2 fires on a replaced string property value as "a new member of a closed set", and the C5 row it raises cannot be cleared except by declaring Clause-② yes on a change that does not widen #16943 is not addressed here and remains open.`Claim:`, andCLAIM_COMMENT_MARKERis a line BEGINNINGClaim:(blockquote tolerated, backticks and bold not). So [finding] aClause-②:key that is not at the start of its own line is invisible to BOTH of check-clause2-carriers' regexes — read asmissing, with a remedy that names only spelling #16931's thread readsabsentrather thanmissing. Measured, not inferred. That strictness is deliberate and documented in this file, so this is a note about the carrier, not a defect in the reader — the seat that wrote the claim is the one who can move it. ⛔ Not filed, ⛔ not edited by this seat, and ⛔ the declaration was not filled in on anyone's behalf.absentrow's own remedy sentence is deliberately left alone: what that thread owes is the claim comment, which is correct whatever the near miss looked like. It gains only the quotation it never had.🤖 Generated with Claude Code
https://claude.ai/code/session_012GKcPZbMoGq7WPzKLfRBTU
Generated by Claude Code