Repository navigation
fix(benchmarks): run bench_regression.sh under macOS bash 3.2 and sweep the shell scripts - #696
Conversation
…set, not when it fires bench_regression.sh set its subshell EXIT trap with a single-quoted body that expands the function-local wt_dir when the trap fires. Under macOS /bin/bash 3.2.57 and bash -c, the function's locals are already gone then, so the trap died on 'wt_dir: unbound variable' under set -u: the baseline worktree was left behind and the runner's exit status was replaced by 1 (#690). The trap body is now built at the point it is set, with printf %q quoting. The tests run the library under every distinct bash a user has (/bin/bash and the first on PATH) and add a repository path with spaces and quotes. Fixes #690 Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DXMXvHLm94B6pA9FkWWmzu Signed-off-by: cdeust <cdeust@icloud.com>
Refs #690 Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DXMXvHLm94B6pA9FkWWmzu Signed-off-by: cdeust <cdeust@icloud.com>
Keeps _run under the method-size cap after the bash parameter. Refs #690 Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DXMXvHLm94B6pA9FkWWmzu Signed-off-by: cdeust <cdeust@icloud.com>
… bash An empty first argument behaved differently per bash, measured on this Mac: /bin/bash 3.2.57 ran mutmut with one empty test name and exited 0, bash 5.3 expanded to no tests and exited 1 after 'failed to collect stats'. It is now a usage error with exit 2 and a message, the same on both. Found by the bash 3.2 sibling search. Refs #690 Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DXMXvHLm94B6pA9FkWWmzu Signed-off-by: cdeust <cdeust@icloud.com>
|
ZETETIC-REVIEW: REQUEST_CHANGES Scope: PR #696 (Fixes #690). Code and tests are correct. Two small text defects inside the diff block approval; neither needs code logic changes. Blocking (text only)
Q1 root cause and trap (verified)
Q2 sibling search (independently re-run)
Q3 mutation_check.shBase measured on this Mac: /bin/bash exit 0 with Q4 tests
Q5 craftsmanship and PR body
Not verifiedThe 3.2 source line behind the locals drop; the long Docker/dataset benchmark scripts beyond Cleanup: review worktree removed (git worktree list shows none); the disk-hygiene register call refused the detached worktree, so I removed it with git directly; no processes of mine remain. |
…e mutation_check change shellcheck 0.11.0 could not parse 'disable=SC2064 -- reason' (SC1072, SC1073); the reason moves to its own comment line, as in scripts/lib/setup_py_step.sh. The cd in the same subshell now exits on failure (SC2164, present on the base). The changelog claimed no other script changed; it now records the mutation_check.sh usage error. Refs #690 Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DXMXvHLm94B6pA9FkWWmzu Signed-off-by: cdeust <cdeust@icloud.com>
|
ZETETIC-REVIEW: APPROVE Delta review of PR #696 against the previous verdict (982e6f8, two text defects). Both are fixed; nothing new found. Checks
Not verifiedCI. Behaviour under brew bash 5.3 in this delta (verified earlier on 982e6f8; the delta is a comment line, HousekeepingWorktree .claude/worktrees/review-696b: disk_hygiene register-worktree refused it (detached head), so I removed it with |
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DXMXvHLm94B6pA9FkWWmzu Signed-off-by: cdeust <cdeust@icloud.com>
Symptom
benchmarks/lib/bench_regression.shfails under the macOS system bash 3.2.57 withbash: wt_dir: unbound variable, sotests_py/benchmarks/test_bench_regression_datasets.pypasses on a Mac only when a newer bash comes first onPATH(macos-latest run https://github.com/cdeust/Cortex/actions/runs/38008915302: 2 failures; with Homebrew bash 5 first onPATH, run 38015387291: 5 passed).Measured here with the real library under
/bin/bash(3.2.57): the failing runner case returns 1 instead of the runner's 17, and the missing-dataset case leaves its baseline worktree registered.Root cause
benchmarks/lib/bench_regression.shline 76 (before): the subshell that runs the baseline benchmarks setstrap '... "$wt_dir" ...' EXITwith a single-quoted body.wt_dirislocaltorun_baseline_benchmarks, and the body is only expanded when the trap fires. Reduced to a library of 8 lines (f() { local wt_dir; wt_dir="$(mktemp -d)"; ( trap 'echo "trap sees: [${wt_dir-UNSET}]"' EXIT; /usr/bin/false ); local status=$?; }) sourced bybash -c 'set -euo pipefail; source ./lib-src.sh; f':So under
bash -cbash 3.2.57 has already dropped the function's locals when the subshell's EXIT trap fires after a failing command;$wt_diris unset,set -uaborts the trap beforegit worktree removeruns, and the shell's status becomes 1. The tests drive the library throughbash -c, so they hit the failing mode.Fix
The trap body is built where the trap is set:
trap "$(printf 'git -C %q worktree remove --force %q ...' "$REPO_ROOT" "$wt_dir")" EXIT.printf %qkeeps a path with spaces or quotes intact through the re-parse the trap does, so the trap no longer depends on any variable being alive when it fires.Sibling search result that needed a change:
scripts/mutation_check.shtook an empty first argument into"${TEST_ARR[@]}"(a different result per bash, measured below); it is now a usage error with exit 2.Failing before, passing after
The test now runs the library under every distinct bash a user can have (
/bin/bashand the firstbashonPATH), and a third test uses a repository path with spaces, a quote and a$.Before (the new parametrization against the old library, this Mac,
/bin/bash3.2.57 and Homebrew 5.3.15):After (head 11704b5, same machine,
/bin/bash3.2.57 and Homebrew 5.3.15 both exercised):tests_py/benchmarks/test_bench_regression_datasets.pyandtest_mutation_check_arguments.py: 14 passed.shellcheck 0.11.0 on the two changed scripts (CI's shellcheck covers only workflow run blocks): on the base,
bench_regression.shreports78:9 SC2164(info level); on the previous head 982e6f8 it reportedSC1073andSC1072errors for the directive# shellcheck disable=SC2064 -- early expansion ..., which shellcheck cannot parse. The directive now sits alone on its own line with the reason on the line above, as inscripts/lib/setup_py_step.sh, and thecdthat SC2164 flagged exits on failure. On 11704b5 both scripts print nothing and exit 0;mutation_check.shprints nothing on base and head.Other gates on 11704b5:
uvx ruff@0.16.6 checkandformat --checkexit 0,check_craftsmanship.py --base origin/mainprintsOK,check_project_wiki.pyexit 0,/bin/bash -nexits 0. pyright overmcp_server/(untouched by this PR) was 0 errors on 982e6f8.The full local pytest was NOT run for this PR: the machine was loaded by other sessions, and the diff changes two shell scripts and two test files. The nine test files that execute these scripts passed on 982e6f8 (62 passed,
/bin/bashfirst onPATH); the later commit changes a comment line, one|| exit 1and the changelog. The first complete full run is CI.Empty test list in
scripts/mutation_check.sh, before:/bin/bash:assert 0 == 2(mutmut ran with one empty test name and exited 0); Homebrew bash 5.3:assert 1 == 2("failed to collect stats"). After: both exit 2 witherror: the test list (first argument) is empty.(tests_py/scripts/test_mutation_check_arguments.py, 2 passed).Completion Ledger
test_first_runner_failure_is_preserved_and_cleans_worktree[bash=...](exit 17 kept, one worktree left)test_missing_dataset_fails_before_runner_and_cleans_worktree[bash=...]test_baseline_uses_exact_selected_ignored_inputs[...][bash=...]$test_cleanup_trap_quotes_a_repository_path_with_spaces_and_quotes[bash=...]test_an_empty_test_list_is_a_usage_error[bash=...]Sibling search
Scope: every shell file in the repository, found by extension or by a bash/sh/zsh shebang over
git ls-files(22 files, list in the first command), the 13 hook and install commands of.claude-plugin/plugin.json, the Codex plugin hooks, and.github/workflows.Command 1, files and syntax under bash 3.2.57:
Command 2, construct scan (grep -E over the 22 files, comments excluded). Zero hits for each of:
declare/local/typeset -A,local -n/declare -n,declare -g,${v,,}${v^^}${v,}${v^},${v@Q}and the other@transforms,mapfile,readarray,|&,&>>,coproc,;∧;&,[-N]array indices,${v: -N}negative offsets,[[ -v ]],wait -n,read -i/-N, fractionalread -t,shopt -s globstar|lastpipe|inherit_errexit|compat*,exec {fd}>,$BASHPID$EPOCHSECONDS$EPOCHREALTIME$SRANDOM$BASH_ARGV0,printf '%(..)T',{01..10},$'\u....'.Hits that needed a decision (every other class above had none):
benchmarks/lib/bench_regression.sh:76localscripts/mutation_check.sh:25,86"${TEST_ARR[@]}"underset -u, empty when the first argument is emptybenchmarks/lib/bench_only.sh:42"${raw[@]}"underset -uONLYis non-empty there (the function returns above on empty) and an empty token is rejectedbenchmarks/reproduce.sh:320,362"${entry[@]}"benchmarks/reproduce.sh:344,351"${V4_MECHANISMS[@]}","${mech_args[@]}"mech_argsfilled by the loopbenchmarks/reproduce.sh:516-525${lm_args[@]+"${lm_args[@]}"}and siblingsbenchmarks/reproduce.sh:527"${be_args[@]}"(--split 100K)at line 509benchmarks/reproduce.sh:504,benchmarks/repro_longmemeval.sh:130,scripts/mutation_check.sh:22trap <function> EXITLOCK_DIR,started_container,CONTAINER,BAK,PY,RUN_LOG,ROOT), none a function localbenchmarks/energy/run.sh#!/bin/zsh,print -u2docker/entrypoint.sh,docker/run.shdocker, not the host/bin/bash; no flagged construct anyway.claude-plugin/plugin.json(11bash -chook commands)$(command -v ...),${VAR:-},[ -z ]PATH=/bin:..., each stops at its own plugin-root guard message and exits 1, no syntax errorplugins/hypermnesia-mcp-codex/hooks/hooks.jsonpython3 ...direct.github/workflows/*.ymlgrep -rn "macos|macOS" .github/workflows/*.ymlprints nothing)commandstrings of.claude-plugin/plugin.json(13), the Codex and deprecatedhooks.json(14), and therun:blocks of the workflows and composite actions (84)/bin/bash -n(3.2.57) after replacing${{ }}with a literal, plus a regex for associative arrays,mapfile/readarray,${v,,}${v^^},&>>, `The empty-array hazard itself, on this Mac, to show the class is real:
Command 3, execution under the system bash. The nine test files that run these scripts, with
/binfirst onPATH:Adjacent, not changed here: BSD versus GNU userland differences (for example
sed -i) are a separate class from bash versions;git grep -n "sed -i" -- '*.sh'prints nothing.What could not be verified
reproduce.sh,repro_longmemeval.sh,trust_factor_sweep.sh,docker_smoke.sh,bench_variance.sh) need Docker, a database and datasets; for them the evidence isbash -nplus the construct scan, not a run.bash -c; I did not find the bash 3.2 source line responsible.Decision points for the ADR register
None. The trap fix and the usage error follow ADR-0067 and ADR-0770 unchanged.
Fixes #690
🤖 Generated with Claude Code
https://claude.ai/code/session_01DXMXvHLm94B6pA9FkWWmzu