Re-measured 2026-09-09 at 5673d20. Both totals moved again, and the
drift is the same seven scripts. Twenty local, twenty-seven in CI, which is
every *.test.sh on disk. CONTRIBUTING.md moved from :182 to :212.
$ grep -oE 'tests/(release|e2e)/[a-z0-9-]+\.test\.sh' scripts/ci-local.sh | sort -u | wc -l
20
$ grep -rhoE 'tests/(release|e2e)/[a-z0-9-]+\.test\.sh' .github/workflows/ | sort -u | wc -l
27
$ ls tests/release/*.test.sh tests/e2e/*.test.sh | wc -l
27
CONTRIBUTING.md:212 asks for one thing before a PR:
Run scripts/ci-local.sh. A compile error in a crate your machine cannot build is still a compile error, and finding it costs a review round.
A green ci-local.sh does not mean a green board, in two independent ways.
1. The script list drifted from what CI runs
run_hygiene_group names twenty test scripts by hand (ci-local.sh:265-285).
CI runs twenty-seven. Seven run in CI and nowhere locally:
cassette-replay-parity.test.sh
codex-plugin-manifest.test.sh
grub-kargs-edit.test.sh
log-edit.test.sh
mount-edit.test.sh
no-secrets.test.sh
rmswap.test.sh
Four of those seven guard privileged helper scripts under packaging/, which is
the surface where a mistake costs the most.
This is the defect class this tracker keeps finding: a hand-maintained list that
drifted from what is on disk. STORIES=(1 2 3 4 5 6 7 8 9 10 11) against twelve
exec-*.sh files (#330) and six claim files against sixteen were both this.
2. A required check skips silently
run_postgres_contract_group records SKIP when neither docker nor podman is
installed:
if [[ -z "$runtime" ]]; then
record SKIP "${label} (no SYSKNIFE_TEST_POSTGRES_URL and no docker/podman found)"
return
fi
postgres-contract is one of the five required checks. A contributor with no
container runtime gets an all-green local board and a red required check on push,
with nothing in the local output saying which gate did not run.
Why it matters
Both failures point the same way: the contributor did what CONTRIBUTING.md
asked, believes the board is green, and finds out from CI. That is a review round
per occurrence, and it lands on the people least able to absorb it.
Scope
- Replace the hand-written list with a glob over
tests/release/*.test.sh and
tests/e2e/*.test.sh, with an explicit skip list for anything deliberately
excluded and a comment saying why. A new test then runs locally the day it
lands, rather than the day someone remembers.
- Make the Postgres skip loud: print, in the final summary, that a required
check did not run and name the two ways to satisfy it
(SYSKNIFE_TEST_POSTGRES_URL, or install podman). A SKIP line in the middle
of a long run is not a warning.
- Consider trying podman before docker. Docker's published ports reset the
connection on at least one maintainer machine, so the current preference order
picks the runtime that does not work and reports failure rather than falling
through.
This overlaps #331, which asks for a guard that every tests/release/*.test.sh
is invoked by a gate. That one is about CI; this one is about the command
contributors are told to run. Doing #331 first makes the glob here the obvious
implementation, so they are worth reading together.
Tests first
A guard that lists both sets and fails when they differ:
comm -13 <(grep -o 'tests/\(release\|e2e\)/[a-z-]*\.test\.sh' scripts/ci-local.sh | sort -u) \
<(grep -ro 'tests/\(release\|e2e\)/[a-z-]*\.test\.sh' .github/workflows/ | cut -d: -f2- | sort -u)
Prove it bites by deleting one run_step line and watching it name that file.
Assert the extraction found something first: a regex that matches nothing makes
comm report no difference and the guard passes over an empty comparison, which
is the same vacuity the guard exists to prevent.
Difficulty
medium. The glob is short. Deciding what belongs in the skip list, and proving
the guard cannot pass over an empty set, is the work.
Getting started
CONTRIBUTING.md
has the build and test commands. No CLA and no copyright waiver. The project is MIT.
CONTRIBUTING.md:212asks for one thing before a PR:A green
ci-local.shdoes not mean a green board, in two independent ways.1. The script list drifted from what CI runs
run_hygiene_groupnames twenty test scripts by hand (ci-local.sh:265-285).CI runs twenty-seven. Seven run in CI and nowhere locally:
Four of those seven guard privileged helper scripts under
packaging/, which isthe surface where a mistake costs the most.
This is the defect class this tracker keeps finding: a hand-maintained list that
drifted from what is on disk.
STORIES=(1 2 3 4 5 6 7 8 9 10 11)against twelveexec-*.shfiles (#330) and six claim files against sixteen were both this.2. A required check skips silently
run_postgres_contract_grouprecordsSKIPwhen neither docker nor podman isinstalled:
postgres-contractis one of the five required checks. A contributor with nocontainer runtime gets an all-green local board and a red required check on push,
with nothing in the local output saying which gate did not run.
Why it matters
Both failures point the same way: the contributor did what
CONTRIBUTING.mdasked, believes the board is green, and finds out from CI. That is a review round
per occurrence, and it lands on the people least able to absorb it.
Scope
tests/release/*.test.shandtests/e2e/*.test.sh, with an explicit skip list for anything deliberatelyexcluded and a comment saying why. A new test then runs locally the day it
lands, rather than the day someone remembers.
check did not run and name the two ways to satisfy it
(
SYSKNIFE_TEST_POSTGRES_URL, or install podman). ASKIPline in the middleof a long run is not a warning.
connection on at least one maintainer machine, so the current preference order
picks the runtime that does not work and reports failure rather than falling
through.
This overlaps #331, which asks for a guard that every
tests/release/*.test.shis invoked by a gate. That one is about CI; this one is about the command
contributors are told to run. Doing #331 first makes the glob here the obvious
implementation, so they are worth reading together.
Tests first
A guard that lists both sets and fails when they differ:
Prove it bites by deleting one
run_stepline and watching it name that file.Assert the extraction found something first: a regex that matches nothing makes
commreport no difference and the guard passes over an empty comparison, whichis the same vacuity the guard exists to prevent.
Difficulty
medium. The glob is short. Deciding what belongs in the skip list, and provingthe guard cannot pass over an empty set, is the work.
Getting started
CONTRIBUTING.md
has the build and test commands. No CLA and no copyright waiver. The project is MIT.