fix(gates): close six PR #135 review findings in gates and their tests
B1: check-skill-version-bump.sh resolves every merge-base with `git merge-base
--all` instead of the single base git happens to pick. A criss-cross history has
two, so the verdict turned on that choice: a skill byte-identical to main's tip
could still be reported "not above merge-base" / "not above main tip" and fail a
push that should pass. A skill now counts as changed only when it differs from
EVERY base, and its version must exceed the version at every base it exists at
as well as at the main tip; with more than one base the failure names which one.
Case 40 in tests/test-skill-version-bump.sh builds the criss-cross fixture and
pins both directions.
B2: check-apm-current.sh no longer assumes the remote default branch is `main`
when origin/HEAD is unset. A checkout whose default is `master` was standing on
its default branch and being told "this is a feature branch, so discard it" --
to throw away a real lock update. With origin/HEAD unset nothing is asserted and
the neutral advice stands. tests/test-apm-current-hook.sh covers the unset case
on both `main` and `master`.
#4: the required-frontmatter checks folded into skill-size-check.sh by c8a7c9e
were untested apart from the leading-zero shape -- mutating the missing-version
ERROR into a no-op left every suite green. tests/test-adr0020-frontmatter.sh now
pins name presence and non-emptiness, metadata.version presence and semver
shape, and the four grep defects the deleted test-skill-frontmatter.sh named.
#5: nothing asked whether a Vale rule still MATCHES anything -- rewriting
CompositionNote.yml's tokens to match nothing left test-vale-wrap.sh at 63/63.
Case 35 enumerates the rule files under the Kyberforge* style directories at run
time, requires an alert from each on its own fixture, and fails when a
discovered rule has no fixture row. The stale comment at case 31 is corrected.
#6: tests/run-tests.sh --strict exited 0 when discovery found no test-*.sh at
all; strictness only ever acted on skips, and with no suites there were none. It
now cross-checks the git index the way run-bats.sh does and fails
unconditionally on an empty set, naming the search root.
N9: the skill-size-check hook description in .pre-commit-config.yaml covered
only the size, context-budget and boundary-target gates. It now also names the
required frontmatter fields, matching docs/spec/gates.md.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NwD8Egs5r4ndqeFLmhusX2
This commit is contained in:
@@ -169,6 +169,67 @@ done < <(
|
||||
| sort
|
||||
)
|
||||
|
||||
# Discovering NOTHING is never a clean run, and it used to be the quietest
|
||||
# possible pass: the loops below iterate zero times, nothing is printed between
|
||||
# the bats block and the summary, and `Summary: 0 passed, 0 failed` exits 0 --
|
||||
# under --strict too, because strictness only ever turned SKIPS into failures
|
||||
# and there were no suites to skip. A wrong TEST_DIR, a mistyped `find` pattern,
|
||||
# an exclusion that grew to swallow tests/, and a gutted checkout all land here.
|
||||
# tests/run-bats.sh has carried this guard for its own .bats discovery; this is
|
||||
# the same guard one file over, and the run-tests pre-push hook is the caller
|
||||
# that needs it.
|
||||
#
|
||||
# Two checks, in the same order and for the same reasons as run-bats.sh's.
|
||||
# First, the derived one: every test-*.sh in the git index must have been
|
||||
# discovered. The direction matters -- a discovered file need NOT be tracked
|
||||
# (work in progress is ordinary), and a file removed with `git rm` leaves the
|
||||
# index, so a deliberate removal passes while an accidental disappearance
|
||||
# fails. It only runs when SEARCH_ROOT is itself the git worktree root, which
|
||||
# is what keeps it off the mktemp fixture trees in tests/test-run-tests.sh --
|
||||
# those hold one or two test-*.sh files by design and git resolves no worktree
|
||||
# for them. The same exclusions are reapplied to the index listing so both
|
||||
# sides cover the same universe.
|
||||
EXPECTED_SCRIPTS=()
|
||||
GIT_TOPLEVEL="$(git -C "$SEARCH_ROOT" rev-parse --show-toplevel 2> /dev/null || true)"
|
||||
if [[ -n "$GIT_TOPLEVEL" && "$GIT_TOPLEVEL" == "$SEARCH_ROOT" ]]; then
|
||||
while IFS= read -r f; do
|
||||
[[ -n "$f" ]] && EXPECTED_SCRIPTS+=("$SEARCH_ROOT/$f")
|
||||
done < <(
|
||||
git -C "$SEARCH_ROOT" ls-files -- 'test-*.sh' '*/test-*.sh' \
|
||||
| grep -Ev '(^|/)\.claude/worktrees/|(^|/)apm_modules/|(^|/)\.claude/skills/' \
|
||||
| sort || true
|
||||
)
|
||||
fi
|
||||
|
||||
if [[ ${#EXPECTED_SCRIPTS[@]} -gt 0 ]]; then
|
||||
MISSING_SCRIPTS=()
|
||||
for expected in ${EXPECTED_SCRIPTS[@]+"${EXPECTED_SCRIPTS[@]}"}; do
|
||||
found=false
|
||||
for actual in ${SCRIPTS[@]+"${SCRIPTS[@]}"}; do
|
||||
if [[ "$actual" == "$expected" ]]; then
|
||||
found=true
|
||||
break
|
||||
fi
|
||||
done
|
||||
[[ "$found" == true ]] || MISSING_SCRIPTS+=("${expected#"$SEARCH_ROOT"/}")
|
||||
done
|
||||
if [[ ${#MISSING_SCRIPTS[@]} -gt 0 ]]; then
|
||||
echo "Error: ${#MISSING_SCRIPTS[@]} of ${#EXPECTED_SCRIPTS[@]} tracked test-*.sh file(s) were not discovered under $SEARCH_ROOT — they were deleted without being removed from the index, or the search path/exclusions above no longer reach them:" >&2
|
||||
for m in ${MISSING_SCRIPTS[@]+"${MISSING_SCRIPTS[@]}"}; do
|
||||
echo " $m" >&2
|
||||
done
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
# Second, unconditional and separate: a tree with nothing tracked (a tarball
|
||||
# export, a fresh scaffold) still must not run on an empty set and call it
|
||||
# green.
|
||||
if [[ ${#SCRIPTS[@]} -eq 0 ]]; then
|
||||
echo "Error: found 0 test-*.sh file(s) under $SEARCH_ROOT — the search path is wrong or the suite has been gutted" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Each test-*.sh is independent (fixtures live under its own mktemp dir, none
|
||||
# write back into the live repo tree -- verified before adding this), so they
|
||||
# run concurrently in fixed-size batches instead of one at a time. Dispatch and
|
||||
|
||||
Reference in New Issue
Block a user