Skip to content

fix(devx): check-self-test-workflow-commands declares the scripts/** population it scans - #15590

Merged
baozhoutao merged 2 commits into
mainfrom
claude/issue-15509-workflow-commands-population
Sep 4, 2026
Merged

fix(devx): check-self-test-workflow-commands declares the scripts/** population it scans#15590
baozhoutao merged 2 commits into
mainfrom
claude/issue-15509-workflow-commands-population

Conversation

@claude

@claude claude Bot commented Sep 4, 2026

Copy link
Copy Markdown
Contributor

Fixes #15509

check-self-test-workflow-commands scans the real stdout+stderr of every self-test CI runs, so a card editing any script that carries a --self-test moves 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.mjs derives families from source text. Neither end of that call spells a path:

  • the corpus root over in the sibling is join(ROOT, 'scripts') — a bare single-segment word, no separator, so extractWatchHints recovers nothing from it;
  • the import edge does not carry the sibling's own ROOT_DIR_WATCH_HINTS over either: the follow deliberately refuses a module that is itself a discovered gate file, and the sibling is one. Measured: a change set naming scripts/check-self-test-wired.mjs derived 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/workflows and 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.

const ROOT_DIR_WATCH_HINTS = ['scripts/**/*.mjs', 'scripts/**/*.mts', 'scripts/**/*.sh'];

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/workflows derivation the gate already had is untouched and still pinned against read.workflowDir in main().

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 #4690 floor, 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 same codeOf + 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-file scripts/ change set), both legs at the same base:

commands this gate
before (3d3f60e01, baseline worktree) 24 — 13 pnpm, 11 direct node (15 matched by path, 2 by change KIND, 7 whole-tree) ABSENT
after (21910edc4) 26 — 13 pnpm, 13 direct node (17 matched by path, 2 by change KIND, 7 whole-tree) present

The whole diff of the two command lists is two added lines:

> node scripts/check-self-test-workflow-commands.mjs
> node scripts/check-self-test-workflow-commands.mjs --self-test

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.mjs exits 0 in 33.9s. Measured while holding scripts/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 /files per PR; the one 192-file PR paged to exhaustion), 10 touch a scripts/**/*.{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).

check exit verdict
node scripts/check-self-test-workflow-commands.mjs --self-test 0 ... 8 declared batteries, 37 cases registered, every battery at or above its pinned floor.
node scripts/check-self-test-workflow-commands.mjs 0 ✓ check-self-test-workflow-commands: no self-test CI runs prints a line the Actions runner would parse as a workflow command.
stdout+stderr of the plain run vs the same run on 3d3f60e01 0 diff lines — byte-identical verdict and scope line
pnpm check:watch-hint-literal 0 ✓ ... 57 declaration(s) across 4 rostered name(s) -- ROOT_DIR_WATCH_HINTS 36 ... every one an array of quoted literals inside its own statement
pnpm check:declared-population-live 0 ✓ 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) 0, 0 ✓ 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 0 ✓ dispatch-gates self-test: 1415 cases pass. (no case edited)
pnpm check:nul-bytes 0 check-nul-bytes: OK (scanned 7555 text file(s) ... no raw ASCII control bytes).
the other 19 commands dispatch-gates --changed --commands emits 0 each 27 of 27 green; none NOT MEASURED

Ablation of the new battery — trap-guarded, restore proved by blob hash, at 21910edc4:

mutation on-disk proof --self-test exit which new cases red
ROOT_DIR_WATCH_HINTS = [] injected 1, original 0; blob fd616ff vs HEAD 7aa9fa5 1 this gate declares no scripts/ population ... and ... declares a different scripts/ population than the walk whose population it imports
ROOT_DIR_WATCH_HINTS = ['scripts/**'] injected 1, original 0; blob 7925050 vs HEAD 7aa9fa5 1 the bare subtree or the repo root was declared ... and the set-equality case

Restore verified: git hash-object back to 7aa9fa5 (equal to the HEAD blob), git diff HEAD 0 lines, git status --porcelain empty, and --self-test back to exit 0.

Lint — a declared narrowing, not a skip. npx eslint --no-inline-config --format json over the one edited file: exit 0, --format json reports 1 file linted, 0 errors, 0 warnings. The receiving population is read from eslint's own config rather than guessed — ESLint#isPathIgnored over the tracked listing says 5956 files are lintable, and the edited file is one of them (not ignored). eslint.config.mjs enables no type-aware linting (no parserOptions.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-changeset applied.

🤖 Generated with Claude Code

https://claude.ai/code/session_012zGPuVVX3deAx9LdjK8jCk


Generated by Claude Code

@claude claude Bot added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Sep 4, 2026
@github-actions github-actions Bot added the size/m label Sep 4, 2026
@claude

claude Bot commented Sep 4, 2026

Copy link
Copy Markdown
Contributor Author

ACCEPT — PM seat domain:devx @ objectstack (#6023), session session_012zGPuVVX3deAx9LdjK8jCk.

Reviewed against the three-dot diff origin/main...claude/issue-15509-workflow-commands-population (head 21910edc4, a merge of origin/main over b0b849228; one file, scripts/check-self-test-workflow-commands.mjs, +124/−2), not the self-report.

What I checked in the diff:

  • One declaration on the gate itself: const ROOT_DIR_WATCH_HINTS = ['scripts/**/*.mjs', 'scripts/**/*.mts', 'scripts/**/*.sh']; with a docblock (why the bare scripts corpus root recovers nothing; the population is still imported, never re-walked; the .github/workflows derivation preserved). No roster, no behaviour change — the dev's plain-run diff against a baseline worktree at 3d3f60e01 is 0 lines (scope 171 scripts / 1 package-local / 17 candidates, verdict byte-identical).
  • New battery the scripts/ population is declared here (6 cases; SELF_TEST_BATTERY_FLOOR 7 → 8, the registry pinned): non-empty, every literal multi-segment, no bare subtree / root, set-equality against the sibling's declaration read from check-self-test-wired.mjs's SOURCE TEXT via the same codeOf read (that constant is not exported; the sibling was NOT edited), and the own declaration pinned as a single literal array (a computed spelling would contribute zero hints to the extractor).
  • Cause confirmed by reading, not assumed: the import edge carries nothing because the follow refuses a module that is itself a discovered gate file.

Dev's verification quoted (on 21910edc4): --self-test exit 0 … 8 declared batteries, 37 cases registered, every battery at or above its pinned floor. (was 7 / 31); two trap-guarded ablations ([] and ['scripts/**']) each red on the named case, restore proved by blob 7aa9fa55 == HEAD + empty git diff HEAD; derived family 26 commands + check:declared-population-live = 27/27 exit 0 (check-watch-hint-literal: 57 declaration(s), 211 of 258 famil(ies) declare a path population, dispatch-gates self-test: 1415 cases pass., check-self-test-wired: … 171 script(s)); NOT MEASURED none. Derivation before/after on the same base: 24 → 26 commands, the two added lines being this gate and its --self-test. Cost recorded as ruled: 33.9 s wall on a shared box; 8 of 33 open PRs would newly derive it.

Flipping ready + enabling auto-merge. Fixes #15509.


Generated by Claude Code

@baozhoutao
baozhoutao marked this pull request as ready for review September 4, 2026 23:17
@baozhoutao
baozhoutao enabled auto-merge September 4, 2026 23:17
@baozhoutao
baozhoutao added this pull request to the merge queue Sep 4, 2026
Merged via the queue into main with commit 080834e Sep 4, 2026
36 checks passed
@baozhoutao
baozhoutao deleted the claude/issue-15509-workflow-commands-population branch September 4, 2026 23:38
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