test(gates): pin hook wiring and enforce the bats TAP plan

The repo's gates were not pinned to their wiring. Deleting the
check-skill-version-bump block from .pre-commit-config.yaml left the
whole suite green; deleting eight blocks at once, run-tests among them,
also left it green. Only 4 of 20 hook ids had their wiring pinned
anywhere, so a merge conflict resolved badly could stop the suite
running at pre-push forever while every test still reported green.

test-adr0020-contract now derives the repo-authored hooks from the
repo: local entries and pins each one's id, entry and stages against an
explicit expected set, both directions, with the same non-vacuity
guards the file already applies to its own fixtures. Upstream hooks and
their rev: values are untouched, so a rev bump does not churn the test.
Mutation-checked: a removed block, a repointed entry and a hook moved
off pre-push each go red; a rev bump, a comment edit and reordering
stay green. 29 -> 44 assertions.

run-bats computed each file's TAP plan and then discarded it, so a
process printing "1..10", three ok lines and exit 0 was counted as
"3 tests, 0 failures" with seven tests silently gone. That is exactly
the wrapper-swallows-the-status case the runner's own comment puts in
its threat model, and the plan was the only surviving signal. The plan
is now enforced in both directions when a file emits exactly one.

Also: test-no-pipefail-early-exit-grep's live-tree floor goes from 20 to
50 against an actual 57, matching test-vale-wrap's per-glob discipline,
and test-vale-wrap's header names the real path to vale-wrap.sh.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NwD8Egs5r4ndqeFLmhusX2
This commit is contained in:
2026-09-20 12:34:07 +00:00
parent 8cfd54f925
commit 384756b343
5 changed files with 271 additions and 10 deletions

View File

@@ -204,7 +204,14 @@ while IFS= read -r rel; do
[[ -f "$REPO_ROOT/$rel" ]] && FILES+=("$REPO_ROOT/$rel")
done < <(git -C "$REPO_ROOT" ls-files -- '*.sh' '*.bats' '*.bash')
if [[ "${#FILES[@]}" -lt 20 ]]; then
# Floored at 50 against a real 57 (58 tracked `*.sh`/`*.bats`/`*.bash` files, less
# this one, which excludes itself above). Same discipline as the per-glob floors in
# tests/test-vale-wrap.sh: a guard against a broken `git ls-files` invocation or a
# moved search root resolving to a fraction of the tree, not a headcount to keep in
# step. Seven files of slack is one deliberate multi-file deletion -- a plugin's
# whole tests/ directory is three or four .bats files -- and nowhere near enough to
# absorb a discovery that degraded to a single directory.
if [[ "${#FILES[@]}" -lt 50 ]]; then
fail "only ${#FILES[@]} tracked shell files found — the scan is looking in the wrong place"
else
LIVE_HITS="$(scan ${FILES[@]+"${FILES[@]}"})"