Skip to content

Commit 1ed9df2

Browse files
committed
ci(lint): a test under a package scripts/ that no gate wiring names skips the PM self-test
The PM dispatch-gates discovery opens a file under a workspace package's scripts/ only as a gate source, which is a file a check:* command in a manifest or a workflow step spells; it follows no import into a package's scripts/. A test there that no package.json and nothing under .github/ names is therefore read only by the two whole-tree censuses, as a test under src/ is, and it now skips the step on pull_request and merge_group. A basename either place spells still runs it (superset grep, fail-open on any git grep error). Self-test: three more cases, floor 71 cases / 369 checks. Claude-Session: https://claude.ai/code/session_01VF48aw8RPG6wzDnMgp6rtw Co-authored-by: Claude <noreply@anthropic.com>
1 parent 3bf0e98 commit 1ed9df2

2 files changed

Lines changed: 82 additions & 7 deletions

File tree

‎scripts/ci/select-gate-families.selftest.sh‎

Lines changed: 39 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,10 @@
2525
# scripts/ and agent prose outside the pm-dispatch rulebook skip it, while
2626
# scripts/pm/** whole, the rulebook, a `.claude/**` shell script, a data file a
2727
# relative specifier names and a scripts/ file of an unlisted kind still run
28-
# it; a pull request touching only packages/*/src/** runs no PM self-test, and
29-
# `schedule` and `push` still run it over the very changes the PR path skips.
28+
# it; a test under a package's scripts/ skips it unless a manifest or a
29+
# workflow names it; a pull request touching only packages/*/src/** runs no PM
30+
# self-test, and `schedule` and `push` still run it over the very changes the
31+
# PR path skips.
3032
#
3133
# Since #19753 it covers migration_registry, the one family that ADDS a gate
3234
# to the PR path: an entry, the generated registry, the generator and the two
@@ -85,13 +87,17 @@ mkdir -p "$UP/packages/a/scripts" "$UP/packages/a/src" "$UP/apps/site/src" "$UP/
8587
"$UP/packages/spec/src/migrations/entries/semantic" "$UP/packages/spec/scripts"
8688
printf '{"name":"fixture","private":true}\n' > "$UP/package.json"
8789
printf 'packages:\n - packages/*\n' > "$UP/pnpm-workspace.yaml"
88-
printf '{"name":"a"}\n' > "$UP/packages/a/package.json"
90+
printf '{"name":"a","scripts":{"check:gate":"vitest run scripts/gate.test.ts"}}\n' > "$UP/packages/a/package.json"
8991
printf 'export const a = 1;\n' > "$UP/packages/a/src/index.ts"
9092
printf 'export const t = 1;\n' > "$UP/packages/a/src/index.test.ts"
9193
printf '{"rows":[]}\n' > "$UP/packages/a/src/data.json"
9294
printf '#!/usr/bin/env bash\necho foo\n' > "$UP/packages/a/foo.sh"
9395
printf 'dist/\n' > "$UP/packages/a/.gitignore"
9496
printf 'console.log(1);\n' > "$UP/packages/a/scripts/build.mjs"
97+
# Two tests under a package's scripts/: one a check:* command in its manifest
98+
# names (a gate source), one nothing names (#22076).
99+
printf 'export const g = 1;\n' > "$UP/packages/a/scripts/gate.test.ts"
100+
printf 'export const b = 1;\n' > "$UP/packages/a/scripts/build.test.ts"
95101
printf 'export const site = 1;\n' > "$UP/apps/site/src/page.tsx"
96102
printf '# guide\n' > "$UP/docs/guide.md"
97103
printf '# page\n' > "$UP/content/docs/page.mdx"
@@ -128,6 +134,7 @@ printf 'export const registry = [];\n' > "$UP/packages/spec/src/migrations/regis
128134
printf 'export const entry = 1;\n' > "$UP/packages/spec/src/migrations/entries/semantic/17.x.ts"
129135
printf 'export const gen = 1;\n' > "$UP/packages/spec/scripts/build-migration-registry.ts"
130136
printf 'export const schemas = 1;\n' > "$UP/packages/spec/scripts/build-schemas.ts"
137+
printf 'export const merge = 1;\n' > "$UP/packages/spec/scripts/conversions-merge.test.ts"
131138
git_q -C "$UP" add -A
132139
git_q -C "$UP" commit -q -m 'C0: root'
133140
C0=$(git_q -C "$UP" rev-parse HEAD)
@@ -544,6 +551,20 @@ run_case 'merge_group: a package-local script is a gate source (the derivation f
544551
expect_rc 0
545552
expect_verdicts comment_mask_corpus pm_dispatch_gates declared_population_live bare_root_worklist self_test_workflow_commands
546553

554+
S=$(scenario M:packages/a/scripts/build.test.ts)
555+
run_case 'merge_group: a test under a package scripts/ that no manifest or workflow names is product test code to the PM self-test, which skips (#22076)' "$REPO" merge_group '' "$C0"
556+
expect_rc 0
557+
expect_warnings '' ''
558+
expect_verdicts slot_lookup query_options_erasure comment_mask_corpus declared_population_live bare_root_worklist self_test_workflow_commands
559+
expect_reason pm_dispatch_gates 'no changed path is in its read-set'
560+
561+
S=$(scenario M:packages/a/scripts/gate.test.ts)
562+
run_case 'merge_group: a test under a package scripts/ that a check script names is a gate source and still runs the PM self-test' "$REPO" merge_group '' "$C0"
563+
expect_rc 0
564+
expect_warnings '' ''
565+
expect_verdicts slot_lookup query_options_erasure comment_mask_corpus pm_dispatch_gates declared_population_live bare_root_worklist self_test_workflow_commands
566+
expect_reason pm_dispatch_gates 'packages/a/scripts/gate.test.ts (M, workspace)'
567+
547568
S=$(scenario M:scripts/pm/os-verify-lock.sh)
548569
run_case 'merge_group: the lock script runs its own self-test and every family that reads scripts/' "$REPO" merge_group '' "$C0"
549570
expect_rc 0
@@ -763,6 +784,20 @@ expect_warnings '' ''
763784
expect_verdicts entry_guard pm_dispatch_gates declared_population_live bare_root_worklist self_test_workflow_commands
764785
expect_reason pm_dispatch_gates 'scripts/pm/README.md (M, scripts)'
765786

787+
# The shape the card measured paying the step: a spec source, tests under
788+
# packages/spec/scripts/ that nothing wires as a gate, and a changeset.
789+
git_q -C "$REPO" checkout -q -B feature-22076-spec-tests "$C0"
790+
printf 'export const merge = 2;\n' > "$REPO/packages/spec/scripts/conversions-merge.test.ts"
791+
printf 'export const index = 3;\n' > "$REPO/packages/spec/src/index.ts"
792+
printf -- '---\n"spec": patch\n---\nthe shared entry\n' > "$REPO/.changeset/shared-entry.md"
793+
git_q -C "$REPO" add -A
794+
git_q -C "$REPO" commit -q -m 'F6: a spec source, an unwired test under packages/spec/scripts, a changeset'
795+
run_case 'pull_request: a spec source, an unwired test under packages/spec/scripts and a changeset run no PM self-test (#22076)' "$REPO" pull_request main ''
796+
expect_rc 0
797+
expect_warnings '' ''
798+
expect_verdicts slot_lookup query_options_erasure comment_mask_corpus declared_population_live bare_root_worklist self_test_workflow_commands
799+
expect_reason pm_dispatch_gates 'no changed path is in its read-set'
800+
766801
git_q -C "$REPO" checkout -q -B feature-19753 "$C0"
767802
printf 'export const entry = 2;\n' > "$REPO/packages/spec/src/migrations/entries/semantic/17.x.ts"
768803
git_q -C "$REPO" commit -q -am 'F3: an entry edited on a feature branch, registry not regenerated'
@@ -867,7 +902,7 @@ pin_step migration_registry 'pnpm --filter @objectstack/spec check:migration-reg
867902

868903
# ── Verdict ─────────────────────────────────────────────────────────────────
869904
# #4690: a battery that ran nothing is a failure, never a pass.
870-
if [ "$cases" -lt 68 ] || [ "$checks" -lt 354 ]; then
905+
if [ "$cases" -lt 71 ] || [ "$checks" -lt 369 ]; then
871906
echo "SELFTEST FAILED: only $cases case(s) / $checks check(s) ran -- the battery is short"
872907
exit 1
873908
fi

‎scripts/ci/select-gate-families.sh‎

Lines changed: 43 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -210,9 +210,20 @@
210210
# can change verdict. What moves from PR time to push-on-main and the hourly
211211
# run is the NAME half -- an ADDED file in these two classes, which the
212212
# tracked-name sweep sees and which, like an added file in every other class
213-
# since #19498, is judged here by its class and not its status. A deletion or
214-
# a rename still runs every family. Everything else the arm ran on, it still
215-
# runs on: scripts/pm/**, every code file under any scripts/, the rulebook,
213+
# since #19498, is judged here by its class and not its status.
214+
#
215+
# A third class takes #19498's weaker claim, and only that one: a TEST file
216+
# under a workspace package's scripts/ that no package manifest and nothing
217+
# under .github/ names. The discovery opens a package's scripts/ file only as
218+
# a gate source, and a gate source is a file a check:* command or a workflow
219+
# step spells; such a test is spelled by neither, so the one battery reader
220+
# left is the pair of whole-tree censuses -- which read it exactly as they
221+
# read a test under src/, a class that has skipped this family since #19498.
222+
# That census coverage is what moves for it.
223+
#
224+
# A deletion or a rename still runs every family. Everything else the arm ran
225+
# on, it still runs on: scripts/pm/**, every code file under the root
226+
# scripts/, every non-test file under a package's scripts/, the rulebook,
216227
# every `.claude/**` code file (the hooks, which the shell-mask census reads),
217228
# the workflow tree and every package manifest.
218229
#
@@ -451,6 +462,23 @@ named_by_relative_specifier() {
451462
return 0
452463
}
453464

465+
# named_in_gate_wiring <path> -- exit 0 when this path's basename is spelled
466+
# anywhere in a package manifest or anywhere under .github/ in the HEAD tree,
467+
# and ALSO when git grep cannot answer: fail-open. A file under a workspace
468+
# package's scripts/ is a gate source only when a check:* command in a
469+
# manifest or a workflow step names it (`resolveCheckToFiles` reads the
470+
# command text; the discovery follows no import into a package's scripts/),
471+
# so a basename spelled in neither place names no gate source. A comment, a
472+
# lookalike name, a step that is no gate: every extra hit answers "named".
473+
named_in_gate_wiring() {
474+
local base rc
475+
base=${1##*/}
476+
rc=0
477+
git grep -q -F -e "$base" HEAD -- '*package.json' '.github/' > /dev/null 2>&1 || rc=$?
478+
if [ "$rc" -eq 1 ]; then return 1; fi
479+
return 0
480+
}
481+
454482
# reads_gate_tree <path> <class> -- exit 0 when this change is inside the
455483
# read-set the dispatch derivation shares with the gates built on it: the
456484
# workflow tree it discovers (.github/**, workflows and composite actions),
@@ -516,6 +544,18 @@ family_reads() {
516544
;;
517545
esac
518546
;;
547+
workspace)
548+
# A test under a package's scripts/ is product test code to this
549+
# battery -- the two whole-tree censuses read it as they read every
550+
# source file -- unless gate wiring names it. A package manifest and
551+
# every other file under a scripts/ keep running it below.
552+
case "$path" in
553+
*/scripts/*.test.ts|*/scripts/*.test.tsx|*/scripts/*.test.mts|*/scripts/*.test.cts|*/scripts/*.test.js|*/scripts/*.test.mjs|*/scripts/*.test.cjs)
554+
if named_in_gate_wiring "$path"; then return 0; fi
555+
return 1
556+
;;
557+
esac
558+
;;
519559
esac
520560
if reads_gate_tree "$path" "$class"; then return 0; fi
521561
return 1

0 commit comments

Comments
 (0)