Verify containers share cargo's package-cache lock: mount the shared volume as CARGO_HOME #43

Merged
eureka merged 3 commits from eureka-substrate/mutants-sccache into main 2026-11-03 01:37:08 +00:00
3 changed files with 29 additions and 5 deletions
Showing only changes of commit e1e7962238 - Show all commits

cargo-mutants.sh: a failed build under the image's rustc wrapper retries once without it

Stage containers sharing the eureka-sccache volume died mid-build with cargo's
"could not execute process ... sccache ... (never executed)" or a missing dep-info
file in their own target dir, though the image's sccache is present, executes, and
a lone container builds clean. The wrapper only caches, so a failed build with
RUSTC_WRAPPER set is retried once without it; the job summary carries a NOTE line
saying which way it went, the first attempt's log is kept, and a build dead either
way stays a red baseline (exit 4) with its cause. Container errors now tail 25
lines, not 5. Tests: dead wrapper recovers with NOTE; red with and without the
wrapper stays red.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Eureka 2026-11-03 01:19:30 +01:00

View file

@ -208,7 +208,7 @@ if [ "$1" = --host ]; then
container_error() { # container_error <label> <out dir>
local rc; rc=$(cat "$2/hostrc" 2>/dev/null)
sum "ERROR $1 container exited ${rc:-?} (4 is a red baseline: the unmutated tests failed there)"
tail -n 5 "$2/stdout" 2>/dev/null | sed "s|^|$SUMTAG: ERROR |"
tail -n 25 "$2/stdout" 2>/dev/null | sed "s|^|$SUMTAG: ERROR |"
}
# ---- stage 1: files whose filter selects tests (the plan container derived each file's filter and counted its tests)
@ -251,7 +251,7 @@ if [ "$1" = --host ]; then
while IFS= read -r l; do sum "$l"; done
fi
for n in $(seq 1 "$s1n"); do
o="$D/items/s1-$n/out"
o="$D/items/s1-$n/out"; [ ! -s "$o/note" ] || sum "NOTE stage 1 (${S1_FILE[$n]}): $(cat "$o/note")"
cat "$D/items/s1-$n.names" >>"$D/m/s1.names"
cat "$o/caught.txt" >>"$D/m/s1.caught"; cat "$o/unviable.txt" >>"$D/m/s1.unviable"
cat "$o/missed.txt" "$o/timeout.txt" >>"$D/m/s1.surv"
@ -286,7 +286,7 @@ if [ "$1" = --host ]; then
ts2=$(( $(now) - ts2 ))
bad=0
for k in $(seq 1 "$K2"); do
o="$D/items/s2-$k/out"
o="$D/items/s2-$k/out"; [ ! -s "$o/note" ] || sum "NOTE stage 2 (shard $k of $K2): $(cat "$o/note")"
if [ "$(cat "$o/hostrc" 2>/dev/null)" != 0 ]; then
[ -e "$D/q/s2-$k" ] || continue
container_error "stage 2 (shard $k of $K2)" "$o"; bad=1; continue
@ -378,10 +378,25 @@ else
case $CM_SHARD in */1) ;; *) args+=(--shard "$CM_SHARD") ;; esac
[ "${#targs[@]}" = 0 ] || tail_args=(-- -- "${targs[@]}")
fi
cargo "${args[@]}" "${tail_args[@]}" >"$OUT/cargo.log" 2>&1
rc=$?
run_cargo() { cargo "${args[@]}" "${tail_args[@]}" >"$OUT/cargo.log" 2>&1; rc=$?; }
run_cargo
# The image's rustc wrapper (sccache, one cache volume shared by sibling containers) is a cache, never an input. 2026-11-02:
# builds died mid-way in sibling containers, cargo reporting the wrapper "(never executed)" or a dep-info file of its own
# target dir missing (ENOENT), while the image's sccache runs fine alone and RUSTC_WRAPPER= builds clean. A failed build
# with a wrapper set is therefore retried once without it, and the job summary says which way it went. The failure itself
# is not diagnosed here: the first attempt's log is kept as cargo-wrapper.log in the job's output.
if [ "$rc" != 0 ] && [ "$rc" != 2 ] && [ "$rc" != 3 ] && [ -n "${RUSTC_WRAPPER:-}" ]; then
w=$RUSTC_WRAPPER; rc1=$rc; cp "$OUT/cargo.log" "$OUT/cargo-wrapper.log"
{ echo "DIAG wrapper=$w"; ls -l "$w"; "$w" --version; df -h /tmp /sccache; free -m; grep -m3 -E "never executed|No such file" "$OUT/cargo.log"; } >"$OUT/diag.txt" 2>&1
unset RUSTC_WRAPPER
run_cargo
case $rc in 0|2|3) echo "RUSTC_WRAPPER=$w: the build failed with it (exit $rc1) and passed without it; the run continued without it" >"$OUT/note" ;;
*) echo "RUSTC_WRAPPER=$w: the build failed with it (exit $rc1) and without it (exit $rc): the wrapper was not the cause" >>"$OUT/cargo.log" ;; esac
fi
for l in caught missed timeout unviable; do cp "$o/mutants.out/$l.txt" "$OUT/$l.txt" 2>/dev/null || : >"$OUT/$l.txt"; done
echo "$rc" >"$OUT/rc"
[ ! -s "$OUT/diag.txt" ] || cat "$OUT/diag.txt"
[ ! -s "$OUT/note" ] || cat "$OUT/note"
tail -n 30 "$OUT/cargo.log"
# 0 clean, 2 missed and 3 timeouts are normal; 4 (red baseline) and everything else are errors
case $rc in 0|2|3) exit 0 ;; *) exit "$rc" ;; esac

View file

@ -62,6 +62,8 @@ open=$(perl -MPOSIX -e '$n = 0; for (10 .. 40) { my $d = POSIX::dup($_); if (def
[ -z "${FAKE_CM_KILLS:-}" ] || touch "$FAKE_CM_KILLS" # a watchdog kill arriving while a run is going
echo "stage=$stage filter=$filter harness=${harness[*]} openfds=$open mult=$mult min=$mintimeout" >>"${FAKE_CM_LOG:?}"
[ "${FAKE_CM_RED:-}" != "$stage" ] || { echo "baseline failed" >&2; exit 4; }
# FAKE_CM_DEADWRAP=1: a run whose environment still holds RUSTC_WRAPPER dies like cargo with a wrapper that cannot execute.
[ -z "${FAKE_CM_DEADWRAP:-}" ] || [ -z "${RUSTC_WRAPPER:-}" ] || { echo " Caused by: could not execute process $RUSTC_WRAPPER rustc (never executed)"; exit 101; }
mkdir -p "$out/mutants.out/log"
col=3; [ "$stage" = 2 ] || col=2
for o in caught missed timeout unviable; do

View file

@ -343,6 +343,13 @@ if grep '^stage=2' "$cm_log" | grep -q 'mult=9 min=33$' && ! grep '^stage=2' "$c
# slot lease: the job's own slot is held by ygg-verify (an inherited descriptor), others by other jobs
cm A HOLD_OWN=1 HOLD_OTHERS=1; cmcheck lease-free 'containers=3 |'; cmlocks lease-free
cm A HOLD_OWN=1 HOLD_OTHERS=3; cmcheck lease-one-free 'containers=2 |'
# a rustc wrapper that cannot execute: the build retries once without it and the job summary says so; a wrapper-free failure is not blamed on it
cm C FAKE_CM_DEADWRAP=1 RUSTC_WRAPPER=/nonexistent/sccache
cmrc C-dead-wrapper 0
cmcheck C-dead-wrapper "NOTE stage 2 (shard 1 of 1): RUSTC_WRAPPER=/nonexistent/sccache: the build failed with it" "MUTANTS tested=2 caught=2"
cm C FAKE_CM_RED=2 RUSTC_WRAPPER=/nonexistent/sccache
[ "$cm_rc" != 0 ] || { echo "FAIL cargo-mutants C-red-with-wrapper: exit 0"; fail=1; }
cmcheck C-red-with-wrapper "ERROR stage 2 (shard 1 of 1)" "!MUTANTS"
cm A HOLD_OWN=1 HOLD_OTHERS=4; cmcheck lease-none-free 'containers=1 |' 'tested=16'; cmlocks lease-none-free
open_none=$(grep -o 'openfds=[0-9]*' "$cm_log" | sort -u | paste -sd, -)
cm A HOLD_OWN=1 HOLD_OTHERS=1; open_leased=$(grep -o 'openfds=[0-9]*' "$cm_log" | sort -u | paste -sd, -)