Repository navigation
feat(scripts): check:pnpm-flag-spellings — no committed pnpm call spells -s, --prod=VALUE, --production=VALUE or --no-production, which a global pnpm 11+/12 frontend rejects - #23824
Merged
Conversation
Claude-Session: https://claude.ai/code/session_local_00307fb7-db7a-4ba8-84c3-65a062e8a14d Co-authored-by: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_local_1904ee85-9672-427b-bc91-7e31318013c7 Co-authored-by: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_local_1904ee85-9672-427b-bc91-7e31318013c7 Co-authored-by: Claude <noreply@anthropic.com>
This was referenced Oct 16, 2026
os-zhuang
approved these changes
Oct 16, 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.
Problem
#23777 removed every pnpm argv spelling that a contributor's global pnpm 11.x / 12.x
@pnpm/exefrontend rejects before it hands off to the pinned pnpm 10.31:-s, and--prod=falseon the objectui install. Nothing stops a script from bringing one back.CI cannot catch a regression. It gets pnpm through Corepack, which runs the real 10.31 binary with no frontend in front of it, and 10.31 accepts every one of these spellings. A regression stays green in CI and goes red only on a laptop, where it shows up as something other than a flag problem. Before #23777,
check:generatedread the frontend's exit 2 as "every artifact stale", the pre-commit regen gate refused every commit, andpnpm objectui:buildinstalled nothing. Only a scan of the committed source can see it.Change
scripts/check-pnpm-flag-spellings.mjs(new). It reds on any pnpm run in tracked source that uses one of these spellings in a pnpm option position:-s--silent--prod=VALUE,--production=VALUE--config.production=VALUE--no-production--config.production=false--silent,--reporter=silent,--no-prodand--config.production=…are accepted, and counted on the success line so that a zero is a measurement.check:pnpm-flag-spellingsroot script:--self-test, then the gate.lint.yml: one step in theLint · CI, release & engine gateslane, right after its siblingcheck:agent-test-spelling, with anid:andcontinue-on-error: truelike every gate there. The lane's verdict step keeps any red, and the requiredLint & Repo Gatesaggregate carries it.What it reads
Population. Tracked files only (
git ls-files, read from the working tree):scripts/**, everyscripts/directory underpackages/, and.githooks/**. JS/TS files are recognised by extension; shell files by extension or by ansh/bashshebang, because the hooks have no extension.scriptsvalues of every trackedpackage.json.Out of scope:
.github/workflows/**. CI's pnpm is Corepack's 10.31 binary, which no frontend fronts, so no workflow can hit this.Three source forms:
js-comment-mask.mjsand regex literals not read;spawnSync('pnpm', ['--filter', pkg, '-s', 'build'])and the tuple form['pnpm', '-s', 'build'].Judged positions. A flag is judged only where pnpm itself parses it:
installorlist;run/exec/dlxand its target.Anything after a script name, a bin, a run target or a bare
--is forwarded and never judged. Sopnpm build -sis green, and so isgit ls-files -s.Failure direction. If the gate meets a value-taking flag it doesn't know, the run goes unjudged. That's a miss, never a false red.
Refuses (exit 2) instead of passing when any of these holds:
git ls-filesfails;scripts;Misses, named in the header:
pnpm${s}, as inownerRunCommand, whose outputgit-merge-regen.mjs --self-testalready pins);-rs.Dispatch watch hints. The gate declares its population in the spellings
scripts/pm/dispatch-gates.mjscan match, so a card that adds a new script under one of these roots, or touches a manifest, is routed to it. Before this, the derivation read the'scripts/'label as a bare root no dispatch can name, and its battery said so. The header and a self-test pin cover the coverage measurements and both reconciliation directions.Evidence
All on
adf2ca745e, branched frommainat59f9763d3e, which already contains #23777.Green on main:
Red on a planted occurrence. I put the two spellings #23777 removed back into tracked files, ran the gate, restored both files from HEAD, and ran it again:
--self-test: 64 cases across 7 batteries pass, under a frozen roster with per-battery floors and a verdict handshake (shape copied fromcheck-agent-model-declared.mjs, not imported). Besides the positive and negative spelling cases, theTREEbattery runs the real sweep over throwaway git work trees on disk:file:line: a plantedpnpm -sin a trackedscripts/shell file, in apackage.jsonscript, in a JS spawn underpackages/*/scripts/, and in an extension-less git hook;Mutation probes on a throwaway copy, both red as intended:
battery "RED — …" registered 18 case(s), below its pinned floor of 19, exit 1;returnabove the floor →selfTest() returned without reaching its verdict, exit 1.Neighbouring gates run locally, all exit 0:
check:pnpm-filter-targetsandcheck:entry-guard;check:parse-guardandcheck-comment-mask-adoption;check-self-test-wiredandcheck-aggregator-roster;check-ci-filter-parityandcheck:doc-authoring;check:watch-hint-literalandcheck:declared-population-live;check:workflow-step-name-quoting,check:required-contextsandcheck:select-gate-families;bare-root-worklist --self-test,check:issue-citationsandcheck:pm-skill-id-lint;check:scripts-symbol-anchorsandcheck:ratchet-remedy-authority;check-workflow-status-functions;check:pm-dispatch-gates, with all fast-tier cases passing;check:agent-test-spellingis red locally only on.claude/settings.local.json, an untracked file that a global gitignore excludes. CI never has that file, and the red is unrelated to this diff.Notes
.github/workflows/lint.yml, a Tier H surface under AGENTS.md Prime Directive 14. The PR is a draft and the landing is the maintainer's.scripts/, the rootpackage.jsonscripts block and a workflow change. None of them ships in a published package, so the PR carriesskip-changeset.pnpm testrun. The diff touches no workspace package; the gate's own--self-testis its test.Generated by Claude Code