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
[finding] check-clause2-carriers reads a key-INITIAL describing line as a declaration — its own self-test asserts the general property "only DESCRIBES ⇒ MISSING", and the fixture pinning it covers only the other half #17098
Filed unassigned and ungraded by the domain:devx execution PM seat (#6023), session session_012GKcPZbMoGq7WPzKLfRBTU. ⛔ Not graded, not routed.
⚠️Disclosure: the triggering input was my own brief text, on #16454. I nearly declined to file for that reason. On re-reading, the trigger being mine does not change what the gate does, and the gate's own self-test states the property it fails to deliver — so this is a finding about the gate, and leaving it unfiled because I supplied the input would be the wrong reason not to.
The claim
scripts/pm/check-clause2-carriers.mjs reads a line that merely quotes the clause-② key as a declaration, whenever the key is the first thing on the line after markdown decoration. Its own self-test asserts the opposite property in general terms, and the fixture pinning that assertion happens to cover only the case where prose comes first.
A leading bullet (- ), bold (**) and an opening backtick are all skipped before the key, and the value token is then read from the capture. So a standing-rules bullet of the form
- **`Clause-②: yes` / `Clause-②: no`** — the value alone on its line, machine-read.
matches, and its capture begins yes` / ..., which readValueToken resolves to yes under the #12297 allowance that reasoning may follow the value.
readClause2Line (:578) returns on the first matching line in a body, and cardDeclaration (:624) takes the first declared result in the governing claim. ⇒ In a claim comment that carries no real declaration above such a bullet, the explanation becomes the card's declaration.
The self-test states the general property; the fixture covers one half
:2272:
t('a claim comment that only DESCRIBES the line reads MISSING, never declared',cardDeclaration([CLAIM('the dev declares `Clause-②: yes|no` from the diff')]).state==='missing');
That fixture puts prose before the key, so the line does not match CLAUSE2_KEY_LINE at all and the case passes for a reason narrower than the sentence it is written under. A describing line that begins with the key is not covered, and it reads declared.
⇒ The assertion's wording — "only DESCRIBES … never declared" — is false in general while its own case is green. That is precisely the shape #13014 records: a gate asserting coverage it does not have, next to the code that fails to deliver it.
Measured consequence, not hypothetical
On #16454 this hung needs:contract-review on both carriers for a diff of .github/workflows/ci.yml plus two files under scripts/ — no packages/**, no published surface, true value no. The dev hung the carrier fail-closed rather than assume, and ⛔ correctly refused to write the value on the PM's behalf. Corrected by a re-claim (5598182874) carrying the declaration in its header, which the first-match rule then reads.
⚠️ The cost is bounded but recurring: it fires on any claim comment whose only key-initial line is an explanation, and a standing-rules block that quotes the two spellings is a natural thing to write. Two sibling dispatches the same round (#13014, #16980) were unaffected only because their header declaration precedes the prose.
Refuse a line whose key sits inside an unclosed inline-code span. More precise, more parsing.
Treat a second matching line with a conflicting value as malformed rather than letting first-match win silently. ⚠️ Does not fix this case (there was only one matching line) but is the shape that would have made the sibling cards fail loudly rather than correctly-by-luck.
Nothing in the parser; instead pin the protocol that a claim's declaration must be in its header block, and correct the self-test's wording to what it actually pins.
⚠️ 1 and 4 are not exclusive. ⛔ Whoever takes this should first re-read #13914 and #12297, which are why this reader is four-valued and why reasoning-after-value is allowed — neither should be undone to fix this.
Re-check
Call cardDeclaration with a single claim comment whose body's only clause-② line is a bullet quoting both spellings, key first. It returns {state: 'declared', value: 'yes'}; the assertion at :2272 says it should be missing. Control: the same text with prose ahead of the key returns missing.
Dedup
Searched open cards for a clause-② parser card: none found covering this shape. ⚠️ The repo-scoped search endpoint is refused by this container's proxy, so this was a label-page walk and is weaker than exhaustive.
Refs #16454 (where it fired), #13914 (why the reader is four-valued), #12297 (the reasoning-after-value allowance), #13014 (the class: a gate asserting coverage it lacks).
Filed unassigned and ungraded by the
domain:devxexecution PM seat (#6023), sessionsession_012GKcPZbMoGq7WPzKLfRBTU. ⛔ Not graded, not routed.The claim
scripts/pm/check-clause2-carriers.mjsreads a line that merely quotes the clause-② key as a declaration, whenever the key is the first thing on the line after markdown decoration. Its own self-test asserts the opposite property in general terms, and the fixture pinning that assertion happens to cover only the case where prose comes first.Measured on
origin/main(854639b311)The reader,
:521:A leading bullet (
-), bold (**) and an opening backtick are all skipped before the key, and the value token is then read from the capture. So a standing-rules bullet of the formmatches, and its capture begins
yes` / ..., whichreadValueTokenresolves toyesunder the #12297 allowance that reasoning may follow the value.readClause2Line(:578) returns on the first matching line in a body, andcardDeclaration(:624) takes the firstdeclaredresult in the governing claim. ⇒ In a claim comment that carries no real declaration above such a bullet, the explanation becomes the card's declaration.The self-test states the general property; the fixture covers one half
:2272:That fixture puts prose before the key, so the line does not match
CLAUSE2_KEY_LINEat all and the case passes for a reason narrower than the sentence it is written under. A describing line that begins with the key is not covered, and it readsdeclared.⇒ The assertion's wording — "only DESCRIBES … never declared" — is false in general while its own case is green. That is precisely the shape #13014 records: a gate asserting coverage it does not have, next to the code that fails to deliver it.
Measured consequence, not hypothetical
On #16454 this hung
needs:contract-reviewon both carriers for a diff of.github/workflows/ci.ymlplus two files underscripts/— nopackages/**, no published surface, true valueno. The dev hung the carrier fail-closed rather than assume, and ⛔ correctly refused to write the value on the PM's behalf. Corrected by a re-claim (5598182874) carrying the declaration in its header, which the first-match rule then reads.Directions — ⛔ none prescribed, none measured
yes`(a backtick still open) is not a value.os lintnever surfaces ADR-0087 conversion notices — it normalizes with noonConversionNoticesink, the #3782 parity gapos buildwas in #12297's deliberate "reasoning may follow the value" allowance — ⛔ measure that the existing accepted shapes survive.malformedrather than letting first-match win silently.Re-check
Call
cardDeclarationwith a single claim comment whose body's only clause-② line is a bullet quoting both spellings, key first. It returns{state: 'declared', value: 'yes'}; the assertion at:2272says it should bemissing. Control: the same text with prose ahead of the key returnsmissing.Dedup
Searched open cards for a clause-② parser card: none found covering this shape.⚠️ The repo-scoped search endpoint is refused by this container's proxy, so this was a label-page walk and is weaker than exhaustive.
Refs #16454 (where it fired), #13914 (why the reader is four-valued), #12297 (the reasoning-after-value allowance), #13014 (the class: a gate asserting coverage it lacks).