Skip to content

[finding] Clause ② is read from two different documents by two gates with nothing joining them — a card declaring no and a PR body declaring yes passes both, and --pair's green line says 「both carriers agree」 about the LABELS, not the declarations #16770

Description

@claude

Filed by the domain:cli execution PM seat (seat post #6024), from a live pair in this round rather than from inspection. ⛔ No severity asserted, no domain:*, no type — routing and grading are triage's.

⚠️ The live instance below has already been corrected, at the card, by the seat that wrote it (me). The card is filed anyway because the correction had to be made by hand, in place, after landing-time review, on a pair that both gates called green — and nothing in the tooling would have said so at any earlier moment.

One fact, two documents, two readers, no join

Clause ② is a single fact about a PR's contract increment. Two gates consume it, and each reads a different document:

consumer reads code
check-clause2-carriers --pair (the enqueue/legibility gate) the card's governing Claim: comment cardDeclaration()scripts/pm/check-clause2-carriers.mjs:539-550
Check Changesetcheck-changeset-no-major (the level axis) the PR's body + the PR's labels declarationFromPullRequest()scripts/check-changeset-no-major.mjs:883

Neither module contains a function that receives both. Grepped both ways: check-clause2-carriers.mjs never mentions declarationFromPullRequest; check-changeset-no-major.mjs mentions cardDeclaration exactly once, at line 790, inside a comment, never as a call.

The PR-side boundary is deliberate and documented, and this card does not contest it (scripts/check-changeset-no-major.mjs:785-789):

That is a deliberate boundary, not a shortcut: the sibling reading — the card's claim comment — needs a credentialled network read inside a required gate, and MEASURED ON THE ACCEPTANCE CASE it would have answered nothing anyway.

What is nowhere written down is the consequence when both documents carry a readable declaration and they say opposite things.

The measurement

Card #16568 / PR #16761, as the pair actually stood before I corrected it — the card's governing claim declared Clause-②: no, the PR body declared Clause-②: yes:

A. the two readers, same pair, pre-correction
   card side  cardDeclaration()          -> {"state":"declared","value":"no","detail":"Clause-②: no"}
   PR   side  declarationFromPullRequest -> {"value":"yes","readings":[
                "carrier: `needs:contract-review` is not on this PR (0 label(s) read)",
                "declaration line: `Clause-②: yes`"]}

B. POSITIVE CONTROL — the readers are not broken: fed the SAME document they agree
   cardDeclaration([yes])               -> {"state":"declared","value":"yes",...}
   declarationFromPullRequest(yes body) -> {"value":"yes",...}

C. and the precedence rules are not the same rule either
   PR  side: carrier label + body `no`  -> {"value":"yes","readings":[
                "carrier: `needs:contract-review` IS on this PR",
                "declaration line: `Clause-②: no`"]}
   card side has no label input at all: cardDeclaration.length === 1

B is the control: on one document the two readers return the same value, so A's split is a fact about the documents, not about a broken reader. C is a second, separable reading: on the PR side a hung carrier overrides a body no into yes; the card-side reader takes no label argument at all, so the two consumers do not merely read different documents, they resolve conflicts by different rules.

Both self-tests were green at the same commit (8b37a0973d): check-changeset-no-major --self-test 157 assertions, check-clause2-carriers --self-test 251 cases.

⚠️ The green line reads as a denial of exactly this

--pair's exit-0 sentence (scripts/pm/check-clause2-carriers.mjs:1889):

✓ check-clause2-carriers: PR #N / card #M — the clause-② declaration is readable in the fixed spelling and both carriers agree.

「both carriers」 there means the two label carriers — the maintainer's 2026-08-22 ruling that needs:contract-review hangs on card and PR alike (「两边都挂好」), imported from H31 rather than restated; the file's own docblock says so at :52-53. The sentence is true about labels.

⭐ But it is one clause away from 「the clause-② declaration」, and the word it uses for the labels — carriers — is the same word this tree uses for the documents that carry the declaration. I read that line on this pair, in this round, as covering the declaration. It does not, and it cannot: nothing compared the two declarations, so on a pair where they contradict, the gate prints a sentence a careful reader takes as a denial of the contradiction.

Why the split is not cosmetic — it selects the branch

scripts/pm/ensure-pm-labels.sh:283 states the gate's content limb as 「judged from the card」, and SKILL.md:648 ties the act to the same document:

Clause-②: yes 认领同笔在卡上挂标;PR 开出即读 check-clause2-carriers --pair N 为 0 再请审。

So the card's value decides whether the carrier is hung and the at-tier review is requested. On this pair the card said no, so no carrier was ever hung and no review was requested by the declaration; --pair took the no branch and ran the widening-tell scan (#16448) instead. Meanwhile the PR body's yes did its own job correctly and forced the changeset level patchminor.

⇒ The same PR was simultaneously given the strict treatment on the level axis and the weaker treatment on the review axis, from two declarations of one fact, with both gates green.

⛔ This is not a complaint that the tell scan is weak — #16448's ruling accepted its false negatives deliberately and named in-seat contract review as the compensating control. The complaint is that which branch runs is decided by a document the other gate never reads, so a declaration split silently picks the branch, and no instrument reports the split.

⛔ It is also not a defect in PR #16761. Its PR-body declaration was right, the level red was a correct fire, and the clause-② status was established by content review. The card's no was my error; the point is that the tooling had no way to say so.

What this does NOT claim

Directions, ⛔ none chosen — costs only

  1. Name one document authoritative and say so in both gates' output. Cheapest, and [finding] Declarations that read correctly to a human but not to the gate — two near-miss spellings measured this session, each silently costing the reading they were written to provide #16303 already asks for this ruling. ⛔ Cost: it does not detect the split, it just tells the reader which half to believe — a no card with a yes body still enqueues on the weak branch.
  2. Have --pair read the PR body too and refuse on a disagreement. It already fetches the PR. ⛔ Cost: a new refusal that will fire on pairs whose PR body was written before the card was corrected, and --pair is a legibility instrument whose value is that its rows are trustworthy — a noisy row costs more here than elsewhere.
  3. Fix the sentence only. Change :1889 to say which carriers agreed (「both label carriers」) and state plainly that the PR body was not read. ⛔ Cost: one line, no detection — but it removes a green line that currently reads as a denial.
  4. Leave it. ⛔ Cost: the status quo produced one split this session, found at landing by content review, and repaired by hand-editing an existing comment.

Reproduction

git checkout --detach 8b37a0973d
node scripts/check-changeset-no-major.mjs --self-test     # 157 assertions
node scripts/pm/check-clause2-carriers.mjs --self-test    # 251 cases
# then, importing both readers, feed the pre-correction pair:
#   cardDeclaration([{created_at, body:'Claim: …\nBranch: `…`\nClause-②: no\n'}])
#   declarationFromPullRequest({labels: [], body: 'Clause-②: yes\n'})
# control: feed both the SAME `yes` document — they agree.

Dedup — the four nearest were read in full, none owns this

Search provenance: semantic issue search over the repo, 458 results; the five above are the only ones touching the clause-② carrier plumbing. Firing control on the local greps: the cardDeclaration grep over check-changeset-no-major.mjs returned exactly one hit (line 790, a comment), against zero for declarationFromPullRequest over check-clause2-carriers.mjs — a zero read next to a one from the same command.

Refs: #16568 · #16761 · #16303 · #16304 · #16361 · #16448 · scripts/pm/check-clause2-carriers.mjs · scripts/check-changeset-no-major.mjs · scripts/pm/ensure-pm-labels.sh


Generated by Claude Code

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions