fix(devx): check-self-test-workflow-commands declares the scripts/** population it scans - #15590
Conversation
…population it scans (#15509) Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012zGPuVVX3deAx9LdjK8jCk
|
ACCEPT — PM seat Reviewed against the three-dot diff What I checked in the diff:
Dev's verification quoted (on Flipping ready + enabling auto-merge. Fixes #15509. Generated by Claude Code |
Fixes #15509
check-self-test-workflow-commandsscans the real stdout+stderr of every self-test CI runs, so a card editing any script that carries a--self-testmoves its verdict. It was derived onto none of them.Why it declared nothing
The gate imports its population from
check-self-test-wired.mjs(collectPopulation), which is a runtime coupling;scripts/pm/dispatch-gates.mjsderives families from source text. Neither end of that call spells a path:join(ROOT, 'scripts')— a bare single-segment word, no separator, soextractWatchHintsrecovers nothing from it;ROOT_DIR_WATCH_HINTSover either: the follow deliberately refuses a module that is itself a discovered gate file, and the sibling is one. Measured: a change set namingscripts/check-self-test-wired.mjsderived this gate just as little as one naming any other root script.So the only literals the extractor could recover from this file were
.github/workflowsand the handful of individual scripts its self-test fixtures cite by name — an artifact roster, not a population.The change
One constant plus its docblock, and one new self-test battery. No roster, no behaviour change.
Set-equal to the sibling's declaration, which is what the walk it imports really covers.
check-declared-population-live's doctrine — an inherited population belongs to the module it was declared in and is judged there — is satisfied rather than dodged: the population is still imported from the gate that owns it, and what is re-declared here is only the hints this gate consumes, judged here. The.github/workflowsderivation the gate already had is untouched and still pinned againstread.workflowDirinmain().The new battery
the scripts/ population is declared here(6 cases) pins: the constant exists and is non-empty; every entry is a multi-segment glob; it is not the bare subtree or the repo root; the sibling's declaration is readable as exactly one literal statement (a#4690floor, so the equality case cannot pass against nothing); it is set-equal to that declaration; and it is spelled as a literal array of quoted strings in this file's own code. The sibling's constant is not exported and this PR does not edit that file to export it — it is read with the samecodeOf+ declaration-statement read the gate already uses, statement-scoped because a whole-file search finds the copies the sibling's docblock spells and passes on a computed declaration.Derivation, before and after
node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack scripts/check-nul-bytes.mjs(a one-filescripts/change set), both legs at the same base:3d3f60e01, baseline worktree)21910edc4)The whole diff of the two command lists is two added lines:
Dispatch cost (the card's policy question)
(a) Derivation for a one-file
scripts/change set: 24 to 26 commands, the two lines above. Nothing else moved.(b) The gate's wall time on this tree:
node scripts/check-self-test-workflow-commands.mjsexits 0 in 33.9s. Measured while holdingscripts/pm/os-verify-lock.sh— that lock excludes other locked runs only, not unlocked sibling gate work on the same cores, so this is a SHARED-BOX reading, not an idle-box one. It spawns 17 of the 171 self-tests in the population; the population's own scope line is unchanged by this PR.(c) Open PRs that would newly derive it: of the 33 open PRs (REST
/pulls?state=open, then/filesper PR; the one 192-file PR paged to exhaustion), 10 touch ascripts/**/*.{mjs,mts,sh}file. 2 of those already derive this gate because they also edit.github/workflows/, so 8 of 33 open PRs would newly derive it — each paying the 33.9s above, once, on a card whose edit really can change what this gate reads.Verification
Exit codes captured before any pipe. Ran at
21910edc4(after the final commit).node scripts/check-self-test-workflow-commands.mjs --self-test... 8 declared batteries, 37 cases registered, every battery at or above its pinned floor.node scripts/check-self-test-workflow-commands.mjs✓ check-self-test-workflow-commands: no self-test CI runs prints a line the Actions runner would parse as a workflow command.3d3f60e01pnpm check:watch-hint-literal✓ ... 57 declaration(s) across 4 rostered name(s) -- ROOT_DIR_WATCH_HINTS 36 ... every one an array of quoted literals inside its own statementpnpm check:declared-population-live✓ check:declared-population-live — 211 of 258 famil(ies) declare a path population, and every one of them reaches this tree's 7562 tracked file(s).node scripts/check-self-test-wired.mjs(+--self-test)✓ check-self-test-wired: every one of the 171 script(s) CI runs that ship a --self-test has that self-test run by CI.pnpm check:pm-dispatch-gates✓ dispatch-gates self-test: 1415 cases pass.(no case edited)pnpm check:nul-bytescheck-nul-bytes: OK (scanned 7555 text file(s) ... no raw ASCII control bytes).dispatch-gates --changed --commandsemitsAblation of the new battery — trap-guarded, restore proved by blob hash, at
21910edc4:--self-testexitROOT_DIR_WATCH_HINTS = []fd616ffvs HEAD7aa9fa5this gate declares no scripts/ population ...and... declares a different scripts/ population than the walk whose population it importsROOT_DIR_WATCH_HINTS = ['scripts/**']7925050vs HEAD7aa9fa5the bare subtree or the repo root was declared ...and the set-equality caseRestore verified:
git hash-objectback to7aa9fa5(equal to the HEAD blob),git diff HEAD0 lines,git status --porcelainempty, and--self-testback to exit 0.Lint — a declared narrowing, not a skip.
npx eslint --no-inline-config --format jsonover the one edited file: exit 0,--format jsonreports 1 file linted, 0 errors, 0 warnings. The receiving population is read from eslint's own config rather than guessed —ESLint#isPathIgnoredover the tracked listing says 5956 files are lintable, and the edited file is one of them (not ignored).eslint.config.mjsenables no type-aware linting (noparserOptions.project, no typed rules), so this one-file diff cannot move the verdict on any file it does not contain. The repo-wide sweep is CI's run.No changeset:
scripts/**only, publishes nothing from any package.skip-changesetapplied.🤖 Generated with Claude Code
https://claude.ai/code/session_012zGPuVVX3deAx9LdjK8jCk
Generated by Claude Code