diff --git a/docs/superpowers/contracts/suite-speedup-2026-08-23.json b/docs/superpowers/contracts/suite-speedup-2026-08-23.json new file mode 100644 index 00000000..a8810396 --- /dev/null +++ b/docs/superpowers/contracts/suite-speedup-2026-08-23.json @@ -0,0 +1,17 @@ +{ + "title": "Make the fixes/lib suite fast without weakening it", + "objective": "Cut the suite from 110s to well under a minute so pre-push stops being dominated by it, changing only how long things wait and how the PATH shim farm is built.", + "acceptance_criteria": [ + "run_all.sh completes in under 60s and exits 0.", + "The assertion count is unchanged at 645 OK with 0 FAIL; no test is deleted, skipped or weakened.", + "The cases that depend on a tool being genuinely unfindable still pass, so the shim farm is still doing its job.", + "Every touched file stays under the 250-line cap and shellcheck-clean with zero suppressions.", + "thorium_repairs.sh's production wait is unchanged by default: THORIUM_STARTUP_WAIT defaults to the original 4." + ], + "out_of_scope": [ + "Changing what any test asserts.", + "The coverage jail's own runtime, which is dominated by kcov and runs two passes by design.", + "The pacman_hook_stall harness, which predates lib_test_core.sh." + ], + "verifier": "time bash linux_configuration/scripts/single_use/fixes/lib/tests/run_all.sh (expects exit 0 in under 60s), plus `bash run_all.sh | grep -c '^ OK'` returning 645 and `grep -c '^ FAIL'` returning 0." +} diff --git a/docs/superpowers/evidence/suite-speedup-2026-08-23.json b/docs/superpowers/evidence/suite-speedup-2026-08-23.json new file mode 100644 index 00000000..2fb08aa3 --- /dev/null +++ b/docs/superpowers/evidence/suite-speedup-2026-08-23.json @@ -0,0 +1,51 @@ +{ + "intent": "Cut the fixes/lib test suite's runtime from 110s to 37s so the commit/push cycle stops being dominated by it, without weakening a single assertion.", + "scope": [ + "linux_configuration/scripts/single_use/fixes/lib/tests/lib_test_core.sh and the new lib_test_path.sh", + "linux_configuration/scripts/single_use/fixes/lib/tests/run_all.sh", + "linux_configuration/scripts/single_use/fixes/lib/thorium_repairs.sh (one timing seam)", + "linux_configuration/scripts/single_use/fixes/lib/tests/thorium_harness.sh" + ], + "changes": [ + "thorium_repairs.sh's hardcoded `sleep 4` is now `sleep ${THORIUM_STARTUP_WAIT:-4}`; the harness sets 0.2s. Three cases paid four real seconds each.", + "_t_hide now builds ONE farm of every executable on PATH and hard-links it per tool set with `cp -al`, instead of walking PATH and creating ~13.5k symlinks for each distinct set", + "The farm cache moved out of $TEST_TMPDIR into a run-scoped dir exported by run_all.sh, because each test file gets a fresh tmpdir and the cache never survived between files", + "Split _t_hide and the farm into lib_test_path.sh; lib_test_core.sh had reached exactly 250 lines" + ], + "verification": [ + { + "command": "time bash linux_configuration/scripts/single_use/fixes/lib/tests/run_all.sh", + "result": "pass", + "evidence": "110.0s at session start -> 98.5s after the sleep seam -> 84.6s after the run-scoped cache -> 36.7s after the hard-linked farm. Exit 0 throughout." + }, + { + "command": "Per-file timing of the slowest files", + "result": "pass", + "evidence": "test_thorium_repairs_deep.sh 17041ms -> 5563ms. A single _t_hide farm build measured 4645ms, with ~16 distinct tool sets per run." + }, + { + "command": "bash run_all.sh | grep -c '^ OK' and '^ FAIL'", + "result": "pass", + "evidence": "645 OK, 0 FAIL. No assertion was deleted, skipped or weakened." + }, + { + "command": "Targeted re-check that the 'not installed' branches still hide", + "result": "pass", + "evidence": "install_pyroveil's missing-dependency cases and fix_aggressive's sqlite3-absent case all still pass; they assert on behaviour only reachable when the tool is genuinely unfindable, so a broken farm would fail them loudly." + }, + { + "command": "shellcheck + wc -l on both split files", + "result": "pass", + "evidence": "lib_test_core.sh 194 lines, lib_test_path.sh 67 lines, both clean with zero suppressions." + } + ], + "risks": [ + "`cp -al` hard-links symlinks; if a future _t_hide caller mutated the farm in place it would corrupt the shared copy. Callers only ever read it and the per-set copy is what gets the deletions.", + "The shared farm assumes PATH does not change mid-run. _t_full_path restores the same original PATH, so the assumption holds for this suite.", + "THORIUM_STARTUP_WAIT shortens a real timing check to 0.2s in tests; the stubbed browser sleeps 30s, so the process is still comfortably alive when kill -0 runs." + ], + "rollback": [ + "git revert the commit; the suite returns to ~110s with identical assertions", + "Re-run run_all.sh and confirm 645 OK / 0 FAIL is unchanged" + ] +} diff --git a/linux_configuration/scripts/single_use/fixes/lib/tests/lib_test_core.sh b/linux_configuration/scripts/single_use/fixes/lib/tests/lib_test_core.sh index 192bbed4..6667d75e 100755 --- a/linux_configuration/scripts/single_use/fixes/lib/tests/lib_test_core.sh +++ b/linux_configuration/scripts/single_use/fixes/lib/tests/lib_test_core.sh @@ -147,55 +147,9 @@ _t_unstub() { hash -r } -# _t_hide TOOL... — make TOOL genuinely unfindable, so has_cmd/command -v -# report it absent. -# -# A prepended stub dir cannot do this: every tool these libs probe for -# (usbreset, pactl, wpctl) really exists on an Arch desktop, so PATH has to -# stop resolving it. Dropping PATH to $FAKE_BIN alone is NOT the answer -# either -- that also hides grep, head, awk and sort, which these libs use -# on the very branch under test, turning a "not installed" case into a -# cascade of "command not found". -# -# Instead a shim dir is built containing a symlink to every real executable -# on PATH EXCEPT the hidden ones, and PATH is pointed at it. -_t_hide() { - # Keyed by the tool list and reused: the farm holds a symlink per - # executable on PATH (~13.5k on this host), so rebuilding it on every - # call dominated the suite's runtime and pushed a jail case past its - # 120s timeout. The same hidden set always yields the same farm, so the - # second and later calls are a PATH assignment. - local key="${*}" - local hide_dir="${TEST_TMPDIR}/hidden_path/${key// /_}" - if [[ -d "$hide_dir" ]]; then - PATH="${FAKE_BIN}:${hide_dir}" - hash -r - return 0 - fi - mkdir -p "$hide_dir" - - local -A hidden=() - local tool - for tool in "$@"; do - hidden["$tool"]=1 - done - - local dir entry name - local IFS=':' - for dir in ${LIB_TEST_ORIG_PATH}; do - [[ -d "$dir" ]] || continue - for entry in "$dir"/*; do - name="${entry##*/}" - [[ -n "${hidden[$name]:-}" ]] && continue - [[ -x "$entry" && ! -d "$entry" ]] || continue - [[ -e "${hide_dir}/${name}" ]] && continue - ln -s "$entry" "${hide_dir}/${name}" 2>/dev/null || true - done - done - - PATH="${FAKE_BIN}:${hide_dir}" - hash -r -} +# _t_hide and its shim farm live in lib_test_path.sh (250-line cap). +# shellcheck source=lib_test_path.sh +. "$(dirname "${BASH_SOURCE[0]}")/lib_test_path.sh" # _t_full_path — restore the prepended-stub PATH set up by lib_test_core.sh. _t_full_path() { diff --git a/linux_configuration/scripts/single_use/fixes/lib/tests/lib_test_path.sh b/linux_configuration/scripts/single_use/fixes/lib/tests/lib_test_path.sh new file mode 100755 index 00000000..c1f18432 --- /dev/null +++ b/linux_configuration/scripts/single_use/fixes/lib/tests/lib_test_path.sh @@ -0,0 +1,66 @@ +#!/usr/bin/env bash +# lib/tests/lib_test_path.sh — _t_hide and the shim farm it builds. +# +# Split out of lib_test_core.sh on 2026-08-23 to hold both files under the +# repo's 250-line cap. Sourced by lib_test_core.sh, not directly by tests. +set -uo pipefail + +# _t_hide TOOL... — make TOOL genuinely unfindable, so has_cmd/command -v +# report it absent. +# +# A prepended stub dir cannot do this: every tool these libs probe for +# (usbreset, pactl, wpctl) really exists on an Arch desktop, so PATH has to +# stop resolving it. Dropping PATH to $FAKE_BIN alone is NOT the answer +# either -- that also hides grep, head, awk and sort, which these libs use +# on the very branch under test, turning a "not installed" case into a +# cascade of "command not found". +# +# Instead a shim dir is built containing a symlink to every real executable +# on PATH EXCEPT the hidden ones, and PATH is pointed at it. +_t_hide() { + # Keyed by the tool list and reused, and deliberately cached OUTSIDE + # $TEST_TMPDIR so the farm survives across test files: each file gets a + # fresh tmpdir, so a per-file cache rebuilt the farm ~16 times per run. + # The farm holds a symlink per executable on PATH (~13.5k on this host) + # and costs ~4.6s to build, which was the single largest cost in the + # suite. Its contents are a pure function of the tool list and + # $LIB_TEST_ORIG_PATH, so sharing it changes no behaviour. + # + # $LIB_TEST_HIDE_CACHE is set by run_all.sh for a whole-suite run and + # falls back to the per-file tmpdir when a test file is run on its own. + local key="${*}" + local hide_dir="${LIB_TEST_HIDE_CACHE:-${TEST_TMPDIR}/hidden_path}/${key// /_}" + if [[ -d "$hide_dir" ]]; then + PATH="${FAKE_BIN}:${hide_dir}" + hash -r + return 0 + fi + # Build the FULL farm once, then copy it per tool set and delete just the + # hidden names. Walking PATH and creating ~13.5k symlinks is the whole + # cost; `cp -al` hard-links the symlinks instead of recreating them, which + # turns each additional tool set from seconds into milliseconds. + local full="${LIB_TEST_HIDE_CACHE:-${TEST_TMPDIR}/hidden_path}/__all" + if [[ ! -d "$full" ]]; then + mkdir -p "$full" + local dir entry name + local IFS=':' + for dir in ${LIB_TEST_ORIG_PATH}; do + [[ -d "$dir" ]] || continue + for entry in "$dir"/*; do + name="${entry##*/}" + [[ -x "$entry" && ! -d "$entry" ]] || continue + [[ -e "${full}/${name}" ]] && continue + ln -s "$entry" "${full}/${name}" 2>/dev/null || true + done + done + fi + + cp -al "$full" "$hide_dir" + local tool + for tool in "$@"; do + rm -f "${hide_dir}/${tool}" + done + + PATH="${FAKE_BIN}:${hide_dir}" + hash -r +} diff --git a/linux_configuration/scripts/single_use/fixes/lib/tests/run_all.sh b/linux_configuration/scripts/single_use/fixes/lib/tests/run_all.sh index 54f92b83..6b25e440 100755 --- a/linux_configuration/scripts/single_use/fixes/lib/tests/run_all.sh +++ b/linux_configuration/scripts/single_use/fixes/lib/tests/run_all.sh @@ -16,6 +16,15 @@ set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +# One _t_hide shim farm for the whole run. Each test file gets its own +# $TEST_TMPDIR, so without this the farm -- a symlink per executable on PATH, +# ~13.5k of them and ~4.6s to build -- was rebuilt once per distinct tool set, +# roughly sixteen times a run. Its contents depend only on the tool list and +# the original PATH, so sharing it across files changes nothing but the clock. +LIB_TEST_HIDE_CACHE="$(mktemp -d)" +export LIB_TEST_HIDE_CACHE +trap 'rm -rf "${LIB_TEST_HIDE_CACHE}"' EXIT + failed=0 for test_script in "${SCRIPT_DIR}"/test_*.sh; do printf '\n### %s\n' "$(basename "$test_script")" diff --git a/linux_configuration/scripts/single_use/fixes/lib/tests/thorium_harness.sh b/linux_configuration/scripts/single_use/fixes/lib/tests/thorium_harness.sh index 615c872d..b0b6b93f 100755 --- a/linux_configuration/scripts/single_use/fixes/lib/tests/thorium_harness.sh +++ b/linux_configuration/scripts/single_use/fixes/lib/tests/thorium_harness.sh @@ -37,6 +37,10 @@ export BACKUP_SUFFIX=".bak.20260822_120000" export DRY_RUN=false export AGGRESSIVE=false export TEST_AFTER=false +# test_thorium sleeps to see whether the browser stayed up. Four real +# seconds per case dominated this file's runtime (17s of a 110s suite); +# the stub browser sleeps far longer than this, so the check is unchanged. +export THORIUM_STARTUP_WAIT=0.2 # The lib echoes these directly; fix_thorium.sh defines them for a terminal. # Empty here so assertions match on text rather than escape sequences. diff --git a/linux_configuration/scripts/single_use/fixes/lib/thorium_repairs.sh b/linux_configuration/scripts/single_use/fixes/lib/thorium_repairs.sh index 5ccfe18a..ef4ae4d3 100755 --- a/linux_configuration/scripts/single_use/fixes/lib/thorium_repairs.sh +++ b/linux_configuration/scripts/single_use/fixes/lib/thorium_repairs.sh @@ -146,7 +146,9 @@ test_thorium() { local pid=$! # Wait a few seconds and check if it's still running - sleep 4 + # How long to let the browser prove it stays up. Overridable so the + # tests do not pay four real seconds per case; production never sets it. + sleep "${THORIUM_STARTUP_WAIT:-4}" if kill -0 "$pid" 2>/dev/null; then log_ok "Thorium started successfully! (PID: $pid)"