fix(pm): read YAML block-scalar run: bodies in dispatch-gates discovery - #8465
Merged
Merged
Conversation
…ry (#8410) `extractCheckInvocations` read only the text on the `run:` line itself, so a step written as a block scalar (`run: |`) contributed the string "|" and none of its commands. Six gate families are invoked exclusively that way and were absent from the derivation entirely -- not matched, and not in the "undetermined" bucket either, since a family that is never discovered has no entry to fall into it. That is the one output shape the script's contract forbids, and it cost PR #8399 a CI round: its declared-breaking changeset derived check-changeset-no-major (a one-line `run:`) but not check-adr-0087-registration (a block-scalar body), the gate that reddened. The fix is in discovery only. check-adr-0087-registration.mjs already names `.changeset` in its own source, so the ordinary watch-hint match fires as soon as the family is discovered; nothing downstream changed, and no list was added. Whole-line comments are stripped from bodies so prose about a gate cannot be mistaken for an invocation of it. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018WuTtyckQa1VcXwgd52JpN
|
The latest updates on your projects. Learn more about Vercel for GitHub. 1 Skipped Deployment
|
hotlong
marked this pull request as ready for review
August 13, 2026 14:27
hotlong
enabled auto-merge
August 13, 2026 14:28
hotlong
disabled auto-merge
August 13, 2026 14:29
hotlong
enabled auto-merge
August 13, 2026 14:29
hotlong
disabled auto-merge
August 13, 2026 14:29
hotlong
enabled auto-merge
August 13, 2026 14:30
This was referenced Aug 14, 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 #8410
What was actually wrong (both hypotheses in the card were refuted)
The card proposed that the
Check Changesetenforcement lives inline inpr-automation.ymlrun:blocks, so the watch-hint scan cannot see its.changeset/path literals. Measured onorigin/main: that is not the mechanism.The enforcement does not live inline at all. It is
scripts/check-adr-0087-registration.mjs, a real 162KB script file the scanner is perfectly able to read — and that file already names.changesetin its own source, so the watch-hint match would fire immediately. The matching layer was never broken.The defect is one layer earlier, in discovery.
extractCheckInvocationsused/^\s*run:\s*(.+)$/gm— it reads only the text on therun:line itself. A step written as a YAML block scalar puts|on that line and its commands on the following lines, so the extractor collected the string"|"and never saw the commands:Measured across the 24 workflow files, six gate families are invoked exclusively from block-scalar bodies and were absent from the derivation entirely — not matched, and not in the "repo-wide / undetermined" bucket either, because a family that is never discovered has no entry to fall into it:
check-adr-0087-registration,check-empty-changeset,check-shard-attestation,check-osv-exemptions,check-test-completeness,check-cross-package-test-inputsThat is precisely the one output shape the script's own header forbids (a gate the derivation cannot mention at all). PR #8399's symptom follows exactly: its declared-breaking changeset derived
check-changeset-no-major(written as a one-linerun:, line 842, therefore visible) but notcheck-adr-0087-registration(block-scalar body, therefore invisible) — and the second is the gate that reddened.So the scope is wider than the card's title: this was never a
.changeset/-specific bug..changeset/is just where it was first noticed.Route chosen, and why neither (a) nor (b)
The dispatch offered (a) teach the scanner to scan
run:blocks for path literals, or (b) extract the inline step into ascripts/file. Measurement rules out both:run:bodies for path literals would add a second, noisier source of truth for something already derived correctly.The fix is instead a one-concept change confined to discovery: read the whole
run:value, block-scalar bodies included. Everything downstream (resolve to script files, read watch hints, cover the input path) is untouched, and no list and no path table was added — the 裁决 constraint holds.Result for the card's own symptom,
node scripts/pm/dispatch-gates.mjs .changeset/any-name.md:.changeset/matchescheck-adr-0087-registration,check-empty-changeset)Comment stripping, and the over-match it prevents
Reading block bodies means reading the shell comments inside them, and this repo's workflow bodies discuss gates by name at length (ci.yml's shard job spells
check-shard-attestation.mjsinside a comment explaining that gate's own classifier). "Mentions a gate" is not "runs a gate". A naive any-token scan over these files invents four families that exist only in prose —check:adr-links,check:empty-changeset,check:platform-checklist,check:skill-frame-freshness— and the self-test now pins both directions of that.Only whole-line comments are dropped: a trailing
# noteafter a real command sits on a line whose command still has to be read. Measured both ways on this tree, stripping changes no family's discovery today; it is there so that stops being luck.The parser stays hand-written rather than adopting the
yamlpackage on purpose:dispatch-gates.mjsimports only node builtins, so a PM can run it in a fresh worktree beforepnpm install. That property is load-bearing and was used during this very task — the derivation ran before the worktree hadnode_modules.Tests
Self-test extended from 47 to 61 cases, all local (this file has no CI wiring — another card owns that):
pnpm --filtercheck inside a body, a blank line not ending a body, a dedented step ending one.runCommandTextsdirectly (one entry per step, body lines joined, one-liner verbatim).pr-automation.yml(a fixture proves the parser; only the live file proves this repo's changeset gate is reachable), including the end-to-end chain: a.changeset/path is covered by the ADR-0087 gate's own hints.Reverse verification, direction predicted before running: ablating body reading turned exactly the 7 predicted cases red and left the other 7 green, matching the written prediction case-for-case. The fix was committed first, so the restore came out of a real commit and
git diffconfirmed byte-identity afterwards.Gates
Named in the dispatch (all green):
check:changeset-gate-self-tests,check:node-version,check:required-contexts,check:shard-attestation,check:workflow-status-functions,node scripts/check-changeset-no-major.mjs(self-test plus a real--basescan),node scripts/pm/dispatch-gates.mjs --self-test,check:nul-bytes. Also raneslinton the changed file (clean).Re-derived against the actual diff (
node scripts/pm/dispatch-gates.mjs scripts/pm/dispatch-gates.mjs): no check family names this path in its own source, so the dispatch list — derived for thepr-automation.ymlsurface this PR ended up not needing to touch — is a strict superset. Nothing was added to the run.skip-changeset: this PR changes only PM tooling underscripts/pm/and releases nothing.Generated by Claude Code