Skip to content

fix(scripts): derive check-changeset-no-major's level headline from the parsed declaration - #19163

Merged
os-try-charles merged 1 commit into
mainfrom
claude/issue-19008-headline-from-the-parsed-declaration
Sep 19, 2026
Merged

os-try-charles merged 1 commit into
mainfrom
claude/issue-19008-headline-from-the-parsed-declaration

Conversation

@os-try-charles

Copy link
Copy Markdown
Collaborator

Fixes #19008

Clause-②: no

What was wrong, as measured (not as assumed)

judgeLevel reaches the not-declared lane on value === 'no' && arm !== 'narrowing'. Past that lane the verdict is decided by refusable and offenders.length alone — declaration.value plays no further part. So a Clause-②: no (narrowing) declaration flows straight into enforce, discharged and clean, and every one of those headlines stated yes as a literal, while the readings rows two lines below printed the true value and arm.

That made the arm docblock's own rule false in the one line a reader quotes:

a PR that declares no (narrowing) must not be reported as having declared yes

The enumeration (the card named one branch; the tree has four literals in three lanes)

Every render branch reachable with value === 'no' && arm === 'narrowing', driven through the real declarationFromPullRequest / judgeLevel / renderLevel at 8b8258d91:

reachable branch channel what it said before verdict / exit
clean stdout "declares clause-② `yes`" 🔴 clean / 0
discharged stdout "declares clause-② `yes` … the declared widening is accounted for" 🔴 (two claims, both false) discharged / 0
enforce stderr "This PR declares clause-② YES" 🔴 enforce / 1
enforce check-run annotation title "clause-② declares YES while no moved package is graded `minor`" 🔴 — ⭐ a fourth literal the card did not name, and the only one that crosses out of the step log enforce / 1
unreadable-diff stderr makes no claim about the declaration — correct as written unreadable-diff / 1

And the two lanes the dispatch left open, now measured rather than assumed: not-measured-material and not-measured-moot are NOT reachable under a narrowing declaration. Both sit behind declaration?.value === null || undefined, and a narrowing declaration has value === 'no'; the enumeration run confirms every no (narrowing) row lands in enforce / discharged / clean / unreadable-diff and never in a not-measured-*. payload-unreadable and no-pull-request are likewise unreachable: payload: false is written by one place, which returns value: null beside it.

The fix

  1. The parsed declaration travels on the verdict as declared: { value, arm }, beside carrier and for the same stated reason: renderLevel must not assert a declaration it did not read.
  2. One exported speller, declaredClause2, renders all five headlines — the four that lied plus not-declared, which was already correct and stays byte-identical on every input that reaches it. ⛔ No literal is left in a headline, so the rule above is now structural rather than per-branch.
  3. The arm is carried through, so the headline is the declaration as written and a reader can grep the PR body for the string the gate printed (yes, yes (widening), no, no (narrowing)).
  4. The discharged sentence derives its noun too — a declared narrowing is no longer "accounted for" as a widening.
  5. value: null spells NOT MEASURED rather than guessing. The three carried lanes cannot be reached with a null value, so a result arriving without one is a caller that dropped the axis, and check:react-declaration-parity 是唯一没接进任何 workflow 的源码审计门禁,且无 MANIFEST 时静默 skip 退出 0 —— 它现在永远不可能红 #4690's direction is that such a run says so.
  6. The verdict table in the judgeLevel docblock stopped describing clean / discharged / enforce as "declared `yes`" — that was the same misstatement in the documentation half, in the same file.

No verdict and no exitCode moves. This is a reporting repair; that is pinned, not asserted — see below.

Both directions, pinned

New self-test battery #19008: the level headline is the parsed declaration, not a literal, floor 30 cases (roster floor 19 → 20). Three lanes × both directions, with the lane identity asserted first so a headline pin cannot read a row it does not name:

  • each lane reaches its own verdict on both a yes and a no (narrowing) declaration;
  • each lane's exit code is unchanged in both directions (the grading-is-untouched pin);
  • on a narrowing: the true declaration appears, and clause-② \yes`/clause-② YES` appears nowhere — stdout, stderr and the annotation title alike;
  • controls: a bare yes still renders yes on all three lanes (that is every other PR in this repo), and yes (widening) renders its arm;
  • the annotation title is pinned separately, still exactly one, still one line;
  • a bare no still stands the axis down at exit 0 on the very tree the narrowing refuses, and still prints the no it always printed;
  • declaredClause2 unit rows, including both NOT MEASURED spellings.

Reverse verification (ablation), at 4e3cbe10

One-line mutation of declaredClause2 back to the literal this card removes, with the mutation proved on disk before the run and the restore proved by blob hash:

HEAD blob = 4d72a0f731d517324cda96e077828ebed3076080
ON-DISK PROOF: removed-text count 1 -> 0 ; injected-text count 0 -> 1
mutated blob = aea6bdf92c0249d83e0714f7513f82322701e004 (differs from HEAD)
VERDICT ablation-exit=1        (12 failures)
restored blob = 4d72a0f731d517324cda96e077828ebed3076080
RESTORE PROVED: blob hash matches HEAD and `git diff HEAD` is empty
VERDICT restore-leg-exit=0

⭐ The shape of that red is the evidence, not the count: the 12 that fired are all reporting pins (the three lanes' narrowing rows, the three yes (widening) controls, the annotation title, the no lane, the speller). The LANE IDENTITY and GRADING IS UNTOUCHED pins stayed green through the mutation, and so did the bare-yes controls — which is exactly the claim this PR makes: the literal was reporting, and only reporting.

Acceptance notes

Observed while enumerating, ⛔ not changed here and ⛔ not filed as cards:

  • The enforce refusal's remedy prose still cites only the "purely additive widening takes AT LEAST `minor`" ruling and still says "raise the widened package to `minor`". Under a declared narrowing the reading that actually drove the verdict is the arm's launch-window breaking rule (the readings line says so: "a BREAKING change; during the launch window it ships `minor`"), and the package was narrowed, not widened. That is a different sentence from the headline this card governs, and correcting it is a judgement call about what the remedy should say — ⛔ not the mechanical derivation this card asked for. Reported to the PM with dedupe words rather than folded in here.
  • readClause2Line accepts yes (narrowing) (only no + widening is treated as a contradiction). The new speller renders it faithfully; whether that combination should be declarable at all is a parser question, not a reporting one.

Scope

  • One file: scripts/check-changeset-no-major.mjs, its --self-test included. No published surface, no runtime file, no workflow file.
  • skip-changeset: nothing published moves. scripts/** ships in no package's files[], so this PR releases nothing.

Generated by Claude Code

…he parsed declaration

Past the `not-declared` lane the level verdict is decided by `refusable` and
`offenders.length` alone — `declaration.value` plays no further part — so
`clean`, `discharged` and `enforce` are each reachable on a `Clause-②: no
(narrowing)` declaration. All three stated `yes` as a LITERAL, and `enforce`
did it twice: once on stderr and once in the check-run annotation title, which
is the only one of the three that crosses out of the step log. The rows
underneath printed the true value and arm the whole time.

That made the arm docblock's own rule false in the line a reader quotes:
"a PR that declares `no (narrowing)` must not be reported as having declared
`yes`".

The parsed declaration now travels on the verdict as `declared`, beside
`carrier` and for the same reason, and one exported speller (`declaredClause2`)
renders all four headlines plus the `not-declared` one from it. The arm is
carried through, so the headline is the declaration as written and a reader can
grep the PR body for it. The `discharged` sentence derives its noun too — a
declared narrowing is no longer "accounted for" as a widening.

⛔ No verdict and no exit code moves: 30 new pins assert the grade unchanged in
both directions on all three lanes, with the `yes` and `yes (widening)` rows as
the controls that matter — they are every other PR in the repo.

Claude-Session: https://claude.ai/code/session_017ef78bLdybu3AffehKkhfk
Co-authored-by: Claude <noreply@anthropic.com>
@os-try-charles os-try-charles added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Sep 19, 2026 — with Claude
@os-try-charles
os-try-charles marked this pull request as ready for review September 19, 2026 02:42
@os-try-charles
os-try-charles added this pull request to the merge queue Sep 19, 2026
Merged via the queue into main with commit 5d0ee8f Sep 19, 2026
37 checks passed
@os-try-charles
os-try-charles deleted the claude/issue-19008-headline-from-the-parsed-declaration branch September 19, 2026 03:06
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

2 participants