fix(scripts): render an unread clause-② carrier as NOT MEASURED, and stop routing it to the remedy that clears the carrier - #18577
Conversation
…as absent
`declarationFromPullRequest` rendered every non-matching label list the same
way — ``carrier: `needs:contract-review` is not on this PR (N label(s) read)``
— including N = 0. A zero-label read is not an absence: the event payload is a
snapshot taken when the run fired, so an empty list is equally consistent with
"this PR carries no labels" and "nothing had been labelled yet", and nothing
inside the payload separates them. This file already owns the right word for
that state and uses it verbatim in its own payload block ("the `opened` run at
21:40Z would have read NOT MEASURED"); it just did not spell it here.
The string was not the damage. `renderLevel`'s `enforce` message printed the
unread carrier beside the `Clause-②:` line under "The two declarations
disagree", and then offered remedy 2 — "correct it at the producer: the
carrier is the review seat's to place and to clear". Pointed at a carrier the
run never read, that is an instruction to strip a review requirement in order
to clear a red whose real cause was remedy 1. This file's own text says the
two remedies are not interchangeable.
So the reader now returns a three-valued `carrier` axis (`present` / `absent`
/ `not-measured`) beside `value` and `arm`, `judgeLevel` carries it through,
and `renderLevel` softens the header and remedy 2 only on a positive
`not-measured`. A measured absence keeps the original verdict, the original
routing and the original bytes; every verdict keeps its exit code.
⛔ The payload boundary is untouched: no API call, no token, no live label
read. The `labeled`/`unlabeled` triggers remain the mitigation.
A new self-test battery pins both directions from one harness, plus the
fixture control the card asks for (a PR carrying the carrier must report it
PRESENT).
Claude-Session: https://claude.ai/code/session_017ef78bLdybu3AffehKkhfk
Co-authored-by: Claude <noreply@anthropic.com>
复核:ACCEPT —— 它同时更正了卡面的证据和分诊的框架,两处都用读数,⇒ 因此做得比框架更少
围栏一:⛔ 不加 API 调用、不加令牌 —— 本席带对照自己验的⇒ ⛔ 零网络、零令牌。 ⭐ 围栏二被真正量了出来,而它更正了卡面的证据卡面写:「Reproducible, not a one-off: the same PR failed identically in two separate workflow runs」。承接者去读了触发时刻;本席自己又独立核了一遍( ⇒ 第一次运行的载荷快照里那个标签还不存在,所以它打印了那条假行;第二次运行的日志读作「carrier: ⇒ 卡面那句话对"失败"成立,对"那条载体行"不成立 —— 只有较早那一次打印了它。⭐ 而这意味着底下没有第二个缺陷:脚本文档里记载的 ⭐ 它还把分诊的框架收窄了一格,并因此少改了东西分诊(和卡面)都把 ⇒ 那个标题是含糊,不是错。 ⇒ 它因此让那条路径逐字未动,只在载体确实什么都没贡献的那一种情况下消歧 —— 因为伤害在 remedy 2 那句话,不在标题。 ⭐ 这是本班最值得留存的一次"做得更少":框架说 A 坏了,它去量,量出坏的是 A 的一半,于是只修那一半。 ⛔ 照单转录一个更宽的框架,会让一条本来正确的路径被改掉。 修了什么零标签读出不再渲染成「carrier is not on this PR」,而是 NOT MEASURED,并写明「零标签既像一张没带标签的 PR,也像一张在快照取走之后才被打标的 PR」。 三个方向都测了,⛔ 不是一个
⭐ 并且它给自己写的新电池做了阳性对照两次:把新分支改成 其余放行判据
Generated by Claude Code |
Fixes #17229
Clause-②: no
What was wrong
declarationFromPullRequestrendered every non-matching label list the same way:including
N = 0. A zero-label read is not an absence. The event payload is a snapshot takenwhen the run fired, so an empty list is equally consistent with this PR carries no labels and
nothing had been labelled yet, and nothing inside the payload separates the two. The file
already owns the right word for that state and uses it verbatim in its own payload block — "the
openedrun at 21:40Z would have read NOT MEASURED" — it simply did not spell it at this callsite. That is
declared ≠ enforcedinside one file.The string was not the damage.
renderLevel'senforcemessage printed the unread carrierbeside the
Clause-②:line and then offered remedy 2 — "correct it at the producer: theneeds:contract-reviewcarrier is the review seat's to place and to clear". Pointed at acarrier the run never looked at, that reads as an instruction to strip a review requirement in
order to clear a red whose real cause was remedy 1 (a
patchthat owedminor). The file's owntext says the two remedies are "not interchangeable".
What changed
scripts/check-changeset-no-major.mjs, one file, no new inputs.declarationFromPullRequestreturns a three-valuedcarrieraxis —present/absent/not-measured— besidevalueandarm, and renders an empty or unreadable label list asNOT MEASURED(still printing the count it read).judgeLevelcarries the axis through to the renderer on all nine verdicts.renderLevel'senforcebranch softens its header and its remedy 2 only on a positivenot-measured: it names which two things disagree (the clause-② declaration and the changesetlevel), says the carrier is not evidence either way, and withdraws the carrier half of remedy 2
with an explicit ⛔. Remedy 1 is untouched, and so is the exit code.
⛔ The payload boundary is untouched: no API call, no token, no live label read. The
labeled/unlabeledtriggers remain the documented mitigation, and the fixed message nowpoints a reader at them.
Measured, both directions, end to end
Real CLI, real
--eventpayloads, on a throwaway probe commit that movedpackages/cli/src/**under a
patchchangeset (scaffold removed afterwards; the branch carries only the one file).Each direction was run against the pre-fix script (extracted from the merge base) and the fixed
one, on byte-identical input.
yesdiffreports 0 differing linesdiffreports 0 differing linesExit code 1 in all six runs: the refusal is repaired in its diagnosis, not spent.
The check has a positive control
A new self-test battery (
#17229: an UNREAD carrier is NOT MEASURED, never an absent one,25 assertions, roster floor raised 17 → 18) pins both directions from one harness plus the
fixture control the card asks for — a PR carrying
needs:contract-reviewmust make the carrierline report present.
It was proved able to fail, twice, each mutation verified on disk by occurrence count and blob
hash and restored against
HEAD:} else if (labels.length === 0) {→} else if (false) {const carrierUnread = result?.carrier === 'not-measured';→= false;The trigger types the card left open — measured
The card said the PR "failed identically in two separate workflow runs". That is true of the
failure, and not of the carrier line. Measured from the runs API and the PR timeline:
needs:contract-reviewwas applied at2026-09-09T19:39:17Z; the other four labels at19:39:30Z/19:39:41Z.34396338801(job102616882441) was created at19:39:13Z— 4 s before the carrierwas applied. Its payload snapshot could not have carried it, and its log is the false line.
34396350963(job102616922544) was created at19:39:20Z— 3 s after. Its logreads carrier: needs:contract-review IS on this PR.
⇒ There is no second defect underneath: the
labeledrun's payload did carry the carrier andthe documented mitigation held. Only the earlier run printed the false line. Both runs' event name
is
pull_request(the runs API exposes the name, not the action type; the timestamps are whatseparate them).
That second log also settles what the original header meant: it printed "The two declarations
disagree" while carrier and line agreed, so "the two declarations" is the clause-② declaration
versus the changeset level. This PR leaves that path byte-identical and only disambiguates the one
case where the carrier contributed nothing.
Acceptance notes
skip-changeset, measured rather than assumed:scripts/check-changeset-no-major.mjsliesoutside every package directory (0 package dirs contain it), no package manifest's
files[]names a
scriptspath, and the touched symbols have 0 hits anywhere underpackages/. Firingcontrols for both readings:
packages/lint'sfiles[]does shipCHANGELOG.md, and the samegrep finds
defineStackunderpackages/spec/src. The root manifest isprivate: true.two separate workflow runs" is inaccurate about the carrier line — only the first run printed it.
An observation about a card's evidence, not a defect in any file; corrected above so the next
reader of that thread is not sent looking for a second instance. Successor: this PR's reader.
🤖 Generated with Claude Code
Generated by Claude Code