fix(refresh): refuse to promote an empty capture over a good snapshot

ssh exiting 0 is not proof the capture is usable — the inspect script can emit
nothing and both refresh scripts would mv that over a good system-details.txt and
report 'ok (0 bytes)'. Every reader tests the snapshot with -s, so the writer was
producing an artifact its own readers call invalid: a guard whose test disagrees
with its writer's contract has quietly stopped guarding. Prompted by
brokkr-smithy-dev hitting the same shape from the other side (a -s test against a
sentinel written with touch, a precondition that could never pass).

- empty capture -> refused, previous snapshot kept, host counted as failed (exit 1)
- capture under 1/4 of the previous -> promoted but flagged, since a host can
  legitimately shed services and the script should not guess
- header + CLAUDE.md contract lines corrected to say what is actually guaranteed
- verified red (empty inspect -> FAIL, snapshot intact, rc=1) then green (real host
  -> ok 6727 bytes)
This commit is contained in:
vh
2026-09-09 16:58:25 -07:00
parent 5a3db132aa
commit 9b9f0625c9
4 changed files with 163 additions and 45 deletions
+30 -3
View File
@@ -13,7 +13,9 @@
# For each host:
# 1. Run scripts/server_inspect.sh on the remote via `ssh <target> 'bash -s'`.
# 2. Write output atomically to `servers/<host>/system-details.txt`.
# A failed SSH/run never clobbers the previous good snapshot.
# A failed SSH/run never clobbers the previous good snapshot — and neither
# does a SUCCEEDED run that produced nothing (ssh exit 0 is not proof of a
# usable capture; an empty one is refused and counted as a failure).
#
# Exit status is non-zero if any host failed.
#
@@ -241,10 +243,35 @@ for host in "${HOSTS[@]}"; do
mkdir -p "$SERVERS_DIR/$host"
if ssh -o BatchMode=yes -o ConnectTimeout=10 -o StrictHostKeyChecking=accept-new "$target" 'bash -s' < "$INSPECT" > "$tmp" 2> "$tmp.err"; then
# ⚠ ssh exiting 0 is NOT proof the capture is usable. The inspect script can
# emit nothing (a shell that dies before its first write, output swallowed by
# a remote wrapper) and this would then promote an EMPTY file over a good
# snapshot and report "ok (0 bytes)" — the readers below all test the
# snapshot with `-s`, so the writer must not produce something they consider
# invalid. A guard whose test disagrees with its writer's contract has
# quietly stopped guarding. Refuse the promotion, keep the old snapshot,
# and count it as a failure so the exit code carries it.
new_bytes=$(wc -c < "$tmp" 2>/dev/null || echo 0)
if [ "$new_bytes" -eq 0 ]; then
rm -f "$tmp" "$tmp.err"
printf 'FAIL (empty capture — previous snapshot kept)\n'
failed+=("$host")
[ "${#warnings[@]}" -gt 0 ] && print_warnings " " "${warnings[@]}"
continue
fi
# A capture that collapses to a fraction of the previous one is suspicious
# but not provably wrong (a host really can shed services), so this WARNS and
# still promotes — the operator sees it rather than the script guessing.
shrink=""
if [ -s "$out" ]; then
old_bytes=$(wc -c < "$out")
if [ "$old_bytes" -gt 0 ] && [ $((new_bytes * 4)) -lt "$old_bytes" ]; then
shrink=" ⚠ shrank from ${old_bytes}B — check before trusting"
fi
fi
mv "$tmp" "$out"
rm -f "$tmp.err"
bytes=$(wc -c < "$out")
printf 'ok (%s bytes)\n' "$bytes"
printf 'ok (%s bytes)%s\n' "$new_bytes" "$shrink"
else
rc=$?
rm -f "$tmp"