From 97a571550eb534df1b2134cb43e5c9245150bff8 Mon Sep 17 00:00:00 2001 From: Kyle Sexton <153232337+kyle-sexton@users.noreply.github.com> Date: Mon, 19 Oct 2026 07:30:22 -0400 Subject: [PATCH] fix(ci): select suites for the files they read (#8410) The selection audit (shard 4/7, run 39240292374) traced six suites reading 28 files whose one-file diff did not select them. Each suite reaches those files through a path built from parts, a directory glob, or the launcher hooks.json names, which the selector cannot see from text, so each now declares them in its `# test-scope:` header (R8), the selector's existing mechanism for that case. scripts/affected-tests-live.sh gains a live case per (suite, file) pair; it failed 28 of 28 before the declarations and passes after. Selection only widens: for each of the 28 files the selection at the base commit is a subset of the new one, which adds exactly the declared suite. Bump-none changelog fragments for the six fragment-mode plugins whose suites changed; nothing a plugin ships changes. Co-Authored-By: Claude Opus 5.5 --- ...ected-tests-selector-gaps-8410-45db118f.md | 5 +++ ...ected-tests-selector-gaps-8410-687124da.md | 5 +++ ...ected-tests-selector-gaps-8410-d5f89308.md | 5 +++ ...ected-tests-selector-gaps-8410-5f025871.md | 5 +++ ...ected-tests-selector-gaps-8410-7f1657a5.md | 5 +++ ...ected-tests-selector-gaps-8410-9a321634.md | 5 +++ .../hooks/biome-format-end-of-turn.test.sh | 2 +- .../scripts/audit-complexity.test.sh | 2 +- .../git-hooks/index-check.test.sh | 2 +- plugins/planning/shared/tests/test_session.py | 1 + plugins/ruff-format/hooks/ruff-format.test.sh | 2 +- .../work-items/tests/set-dimensions.test.sh | 1 + scripts/affected-tests-live.sh | 44 +++++++++++++++++++ 13 files changed, 80 insertions(+), 4 deletions(-) create mode 100644 .changes/biome-format/fix-affected-tests-selector-gaps-8410-45db118f.md create mode 100644 .changes/code-metrics/fix-affected-tests-selector-gaps-8410-687124da.md create mode 100644 .changes/instruction-placement/fix-affected-tests-selector-gaps-8410-d5f89308.md create mode 100644 .changes/planning/fix-affected-tests-selector-gaps-8410-5f025871.md create mode 100644 .changes/ruff-format/fix-affected-tests-selector-gaps-8410-7f1657a5.md create mode 100644 .changes/work-items/fix-affected-tests-selector-gaps-8410-9a321634.md diff --git a/.changes/biome-format/fix-affected-tests-selector-gaps-8410-45db118f.md b/.changes/biome-format/fix-affected-tests-selector-gaps-8410-45db118f.md new file mode 100644 index 0000000000..3b9cec2951 --- /dev/null +++ b/.changes/biome-format/fix-affected-tests-selector-gaps-8410-45db118f.md @@ -0,0 +1,5 @@ +--- +bump: none +--- + +Test-only: a suite's test-scope header now declares files it reads that the pull-request test selection could not see, so a change to one of them runs the suite; no shipped behavior changes. diff --git a/.changes/code-metrics/fix-affected-tests-selector-gaps-8410-687124da.md b/.changes/code-metrics/fix-affected-tests-selector-gaps-8410-687124da.md new file mode 100644 index 0000000000..3b9cec2951 --- /dev/null +++ b/.changes/code-metrics/fix-affected-tests-selector-gaps-8410-687124da.md @@ -0,0 +1,5 @@ +--- +bump: none +--- + +Test-only: a suite's test-scope header now declares files it reads that the pull-request test selection could not see, so a change to one of them runs the suite; no shipped behavior changes. diff --git a/.changes/instruction-placement/fix-affected-tests-selector-gaps-8410-d5f89308.md b/.changes/instruction-placement/fix-affected-tests-selector-gaps-8410-d5f89308.md new file mode 100644 index 0000000000..3b9cec2951 --- /dev/null +++ b/.changes/instruction-placement/fix-affected-tests-selector-gaps-8410-d5f89308.md @@ -0,0 +1,5 @@ +--- +bump: none +--- + +Test-only: a suite's test-scope header now declares files it reads that the pull-request test selection could not see, so a change to one of them runs the suite; no shipped behavior changes. diff --git a/.changes/planning/fix-affected-tests-selector-gaps-8410-5f025871.md b/.changes/planning/fix-affected-tests-selector-gaps-8410-5f025871.md new file mode 100644 index 0000000000..3b9cec2951 --- /dev/null +++ b/.changes/planning/fix-affected-tests-selector-gaps-8410-5f025871.md @@ -0,0 +1,5 @@ +--- +bump: none +--- + +Test-only: a suite's test-scope header now declares files it reads that the pull-request test selection could not see, so a change to one of them runs the suite; no shipped behavior changes. diff --git a/.changes/ruff-format/fix-affected-tests-selector-gaps-8410-7f1657a5.md b/.changes/ruff-format/fix-affected-tests-selector-gaps-8410-7f1657a5.md new file mode 100644 index 0000000000..3b9cec2951 --- /dev/null +++ b/.changes/ruff-format/fix-affected-tests-selector-gaps-8410-7f1657a5.md @@ -0,0 +1,5 @@ +--- +bump: none +--- + +Test-only: a suite's test-scope header now declares files it reads that the pull-request test selection could not see, so a change to one of them runs the suite; no shipped behavior changes. diff --git a/.changes/work-items/fix-affected-tests-selector-gaps-8410-9a321634.md b/.changes/work-items/fix-affected-tests-selector-gaps-8410-9a321634.md new file mode 100644 index 0000000000..3b9cec2951 --- /dev/null +++ b/.changes/work-items/fix-affected-tests-selector-gaps-8410-9a321634.md @@ -0,0 +1,5 @@ +--- +bump: none +--- + +Test-only: a suite's test-scope header now declares files it reads that the pull-request test selection could not see, so a change to one of them runs the suite; no shipped behavior changes. diff --git a/plugins/biome-format/hooks/biome-format-end-of-turn.test.sh b/plugins/biome-format/hooks/biome-format-end-of-turn.test.sh index 836af43559..0970d04abe 100755 --- a/plugins/biome-format/hooks/biome-format-end-of-turn.test.sh +++ b/plugins/biome-format/hooks/biome-format-end-of-turn.test.sh @@ -5,7 +5,7 @@ # keeps it from blocking twice in one turn; the plugin kill switch wins. The # spawn budget case fences the cost every user pays per turn with the option # off: the node launcher only. -# test-scope: plugins/biome-format/hooks/hooks.json plugins/biome-format/git-hooks/biome-check.sh plugins/biome-format/.claude-plugin/plugin.json +# test-scope: plugins/biome-format/hooks/hooks.json plugins/biome-format/git-hooks/biome-check.sh plugins/biome-format/.claude-plugin/plugin.json plugins/biome-format/hooks/exec-bash.mjs set -uo pipefail unset GIT_DIR GIT_WORK_TREE GIT_CONFIG GIT_INDEX_FILE BIOME_CONFIG_PATH CLAUDE_PLUGIN_OPTION_BIOME_FORMAT_END_OF_TURN CLAUDE_PLUGIN_OPTION_BIOME_FORMAT_ENABLED diff --git a/plugins/code-metrics/skills/audit-complexity/scripts/audit-complexity.test.sh b/plugins/code-metrics/skills/audit-complexity/scripts/audit-complexity.test.sh index 1ede4e811f..df071d13e5 100755 --- a/plugins/code-metrics/skills/audit-complexity/scripts/audit-complexity.test.sh +++ b/plugins/code-metrics/skills/audit-complexity/scripts/audit-complexity.test.sh @@ -6,7 +6,7 @@ # PATH carries fake `lizard`, `radon`, `multimetric`, `gocognit` and # `shellmetrics` replaying the committed captures under # fixtures/tool-output/ (design T13; nothing executable is committed). -# test-scope: plugins/code-metrics/scripts/collectors/*.py plugins/code-metrics/scripts/fixtures/* +# test-scope: plugins/code-metrics/scripts/collectors/*.py plugins/code-metrics/scripts/fixtures/* plugins/code-metrics/scripts/yaml_subset.py set -uo pipefail unset GIT_DIR GIT_WORK_TREE GIT_CONFIG diff --git a/plugins/instruction-placement/git-hooks/index-check.test.sh b/plugins/instruction-placement/git-hooks/index-check.test.sh index f814c1ab2f..c8a6d80d05 100755 --- a/plugins/instruction-placement/git-hooks/index-check.test.sh +++ b/plugins/instruction-placement/git-hooks/index-check.test.sh @@ -8,7 +8,7 @@ # the entry so `git commit` runs it from a flat installed copy. # Expected values come from the requirement: a path-scoped rule the index block # does not list is drift, and the block `render-index.sh write` produces is not. -# test-scope: plugins/instruction-placement/git-hooks/entries.json plugins/instruction-placement/scripts/render-index.sh plugins/instruction-placement/scripts/lib/discover.sh plugins/instruction-placement/lib/git-hooks/check-lib.sh plugins/instruction-placement/lib/git-hooks/install.mjs +# test-scope: plugins/instruction-placement/git-hooks/entries.json plugins/instruction-placement/scripts/render-index.sh plugins/instruction-placement/scripts/lib/discover.sh plugins/instruction-placement/lib/git-hooks/check-lib.sh plugins/instruction-placement/lib/git-hooks/install.mjs plugins/instruction-placement/.claude-plugin/plugin.json set -uo pipefail unset GIT_DIR GIT_WORK_TREE GIT_CONFIG GIT_INDEX_FILE CLAUDECODE AI_AGENT diff --git a/plugins/planning/shared/tests/test_session.py b/plugins/planning/shared/tests/test_session.py index f8ad7b3de0..12d92482c0 100644 --- a/plugins/planning/shared/tests/test_session.py +++ b/plugins/planning/shared/tests/test_session.py @@ -1,3 +1,4 @@ +# test-scope: plugins/planning/shared/schema/*.schema.json plugins/planning/surface/schema/*.schema.json plugins/planning/shared/tests/fixtures/*.json """session.py holds the shared interview session's domain rules; each test names one invariant. Expected values come from the Design's Contracts (state shape, error codes, round transitions, diff --git a/plugins/ruff-format/hooks/ruff-format.test.sh b/plugins/ruff-format/hooks/ruff-format.test.sh index aa24e5726f..9d94d73d31 100755 --- a/plugins/ruff-format/hooks/ruff-format.test.sh +++ b/plugins/ruff-format/hooks/ruff-format.test.sh @@ -18,7 +18,7 @@ # # Requires a real Ruff binary: $RUFF_TEST_BIN if set, else `ruff` on PATH. # Without one the behavioral assertions cannot run, so the suite skips. -# test-scope: plugins/ruff-format/.claude-plugin/plugin.json plugins/ruff-format/hooks/hooks.json plugins/ruff-format/prerequisites.json +# test-scope: plugins/ruff-format/.claude-plugin/plugin.json plugins/ruff-format/hooks/hooks.json plugins/ruff-format/prerequisites.json plugins/ruff-format/lib/prerequisites.mjs plugins/ruff-format/lib/git-hooks/install.mjs set -uo pipefail diff --git a/plugins/work-items/tests/set-dimensions.test.sh b/plugins/work-items/tests/set-dimensions.test.sh index bbaf1af57c..bc64c20e8a 100755 --- a/plugins/work-items/tests/set-dimensions.test.sh +++ b/plugins/work-items/tests/set-dimensions.test.sh @@ -7,6 +7,7 @@ # listing holds the fixture's ids. # # bash plugins/work-items/tests/set-dimensions.test.sh +# test-scope: plugins/work-items/tools/work-item-tracker/adapters/github/capabilities.json plugins/work-items/tools/work-item-tracker/adapters/github/common.sh plugins/work-items/tools/work-item-tracker/adapters/github/set-fields.sh plugins/work-items/tools/work-item-tracker/lib/id.sh plugins/work-items/tools/work-item-tracker/lib/lease.sh set -uo pipefail PLUGIN_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" || exit 2 diff --git a/scripts/affected-tests-live.sh b/scripts/affected-tests-live.sh index 0fe564b234..aef0df88d5 100755 --- a/scripts/affected-tests-live.sh +++ b/scripts/affected-tests-live.sh @@ -226,4 +226,48 @@ for probe in 'plugins/github/skills/advise/S*.md|plugins/github/github.test.sh' fi done +# --- LIVE repo: files a suite reads select that suite (#8410) ------------------ +# The selection audit traced each suite reading these files while a one-file +# diff to the file did not select it: each suite reaches them through a path +# built from parts, a directory glob, or a launcher hooks.json names, so its +# `# test-scope:` header declares them (R8). +s_session=plugins/planning/shared/tests/test_session.py +s_dims=plugins/work-items/tests/set-dimensions.test.sh +gh_adapter=plugins/work-items/tools/work-item-tracker/adapters/github +tracker_lib=plugins/work-items/tools/work-item-tracker/lib +pl_fix=plugins/planning/shared/tests/fixtures +read_pairs=( + "$s_session|plugins/planning/shared/schema/event.schema.json" + "$s_session|plugins/planning/shared/schema/question-shape.schema.json" + "$s_session|plugins/planning/surface/schema/event.schema.json" + "$s_session|plugins/planning/surface/schema/ops.schema.json" + "$s_session|plugins/planning/surface/schema/responses.schema.json" + "$s_session|plugins/planning/surface/schema/visual.schema.json" + "$s_dims|$gh_adapter/capabilities.json" + "$s_dims|$gh_adapter/common.sh" + "$s_dims|$gh_adapter/set-fields.sh" + "$s_dims|$tracker_lib/id.sh" + "$s_dims|$tracker_lib/lease.sh" + "plugins/ruff-format/hooks/ruff-format.test.sh|plugins/ruff-format/lib/git-hooks/install.mjs" + "plugins/ruff-format/hooks/ruff-format.test.sh|plugins/ruff-format/lib/prerequisites.mjs" + "plugins/biome-format/hooks/biome-format-end-of-turn.test.sh|plugins/biome-format/hooks/exec-bash.mjs" + "plugins/code-metrics/skills/audit-complexity/scripts/audit-complexity.test.sh|plugins/code-metrics/scripts/yaml_subset.py" + "plugins/instruction-placement/git-hooks/index-check.test.sh|plugins/instruction-placement/.claude-plugin/plugin.json" +) +for fixture in events-v1 invalid-device-scope-on-prototype invalid-reaction-agree \ + invalid-recommendation-on-choice old-page-defaults state-v0-prototype state-v2-mentions \ + state-v3 state-v4 state-v5 wire-heartbeat wire-presence; do + read_pairs+=("$s_session|$pl_fix/$fixture.json") +done +for pair in "${read_pairs[@]}"; do + suite="${pair%%|*}" file="${pair#*|}" + out="$(cd "$REPO_ROOT" && bash scripts/affected-tests.sh "$file" 2>/dev/null)" + RC=$? + if [[ -e "$REPO_ROOT/$file" && "$RC" -eq 0 ]] && has_line "$out" "$suite"; then + ok "LIVE: $file selects $suite" + else + fail "LIVE: $file did not select $suite (rc=$RC): $out" + fi +done + test_harness::report