sots-re/verify/state-checksum/run_validation.sh
alex fdd0b72b7a state-checksum: whole-state diagnostic checksum harness (lane C)
The complement to the per-function compare harness. Instead of "did this
function's declared outputs match", it asks "is the entire simulation state
still identical" -- so no region-declaration mistake can hide from it.

Coverage is PROVED, not declared: the digest tree is re-serialised and compared
byte-for-byte against the inflated save on every run. When that reconstruction
reproduces the stream, the whole file is a function of the digest's inputs. A
run that cannot account for the file says so and exits non-zero. This is the
direct answer to B4's three hooks that printed "0 diverged" over an empty
region set.

It localises. The root is the fold of a per-subsystem / per-object tree with
named objects, so the known load->re-save delta reports as exactly five leaves
-- /Summary/Checksum and four /Sim/players/Player[...]/Status 4->0 -- naming the
two Singularity players by id where the raw byte diff could only say "1st of
two". One real End Turn reports as 108 fully attributed differences.

Float-parity policy is explicit and strict by default (STATE_CHECKSUM.md 3):
raw IEEE-754 bits; a `canonical` policy for signed zero and NaN payloads only;
and deliberately NO tolerant hashing mode, because quantisation moves the cliff
rather than removing it and destroys the roll-up. Tolerance lives in the differ
as --ulps, applied after localisation. Corpus census: 0 NaN, 0 -0.0, 0
subnormals across 4,474 float leaves, so the strict default costs nothing today
and a test fails the day that changes.

Validated on the real saves (verify/results/state-checksum/): 10 files, 4
distinct contents, all STABLE + COVERED; chain record/verify works on the real
turn1-3 saves. The VM-driven replay loop is designed (section 5) but UNRUN.

Section 3.5 names the one question the host side cannot settle -- whether the
turn pipeline depends on x87 intermediate precision -- and the experiment that
would: force fpu_cw to 0x027f / 0x127f / 0x137f across End Turn and checksum
the three autosaves.

Also recorded: Summary.Checksum is NOT a byte sum over the inflated stream nor
a sum over the int leaves (both ruled out), so nobody repeats those two.

38 tests; sots-engine untouched, clean_room_check.sh OK.
2026-09-08 03:46:34 -04:00

114 lines
3.8 KiB
Bash
Executable file

#!/usr/bin/env bash
# Regenerate verify/results/state-checksum/ from the saves on this host.
#
# Saves are read from $SOTS_SAVES_DIR when set, plus the in-repo
# verify/results/saves/. No .sav is copied anywhere. Skips cleanly with a
# message when there is nothing to read.
#
# verify/state-checksum/run_validation.sh
#
# Each gate is run separately and its exit status reported; nothing is chained
# with && so that a failure cannot skip a later step.
set -u
HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
VERIFY="$(dirname "$HERE")"
OUT="$VERIFY/results/state-checksum"
SC="uv run python3 $HERE/state_checksum.py"
mkdir -p "$OUT"
REPO_SAVES="$VERIFY/results/saves"
EXTRA="${SOTS_SAVES_DIR:-}"
if [ -n "$EXTRA" ] && [ ! -d "$EXTRA" ]; then
echo "note: \$SOTS_SAVES_DIR=$EXTRA is not a directory; ignoring"
EXTRA=""
fi
if [ -z "$EXTRA" ]; then
echo "note: \$SOTS_SAVES_DIR unset; using in-repo saves only"
fi
shopt -s nullglob
ALL=("$REPO_SAVES"/*.sav)
[ -n "$EXTRA" ] && ALL+=("$EXTRA"/*.sav)
if [ ${#ALL[@]} -eq 0 ]; then
echo "no saves available; nothing to validate"
exit 0
fi
rc=0
note() { echo "== $1 -> exit $2"; [ "$2" -eq 0 ] || rc=1; }
# 1. one root + subsystem digest set per distinct save content
{
echo "# state_checksum roots -- $(date -u +%Y-%m-%dT%H:%M:%SZ)"
echo
seen=""
for f in "${ALL[@]}"; do
h=$(sha256sum "$f" | cut -c1-16)
case " $seen " in *" $h "*) continue;; esac
seen="$seen $h"
echo "--- sha256:$h $(basename "$f")"
$SC "$f"
echo
done
} > "$OUT/roots.txt" 2>&1
note "roots" $?
# 2. identical bytes must give identical roots, and every save must be covered
uv run python3 "$HERE/stability_check.py" "${ALL[@]}" > "$OUT/identical-roots.txt" 2>&1
note "identical-roots" $?
# 3. the known load->re-save delta must LOCALISE, not read as a whole-state miss
A="$REPO_SAVES/turn2-state.sav"
B=""
for f in "${ALL[@]}"; do
[ "$(sha256sum "$f" | cut -c1-8)" = "bb4fd9ac" ] && B="$f" && break
done
if [ -n "$B" ] && [ -f "$A" ]; then
{
echo "# determinism-oracle.md: loading a post-turn autosave and re-saving it"
echo "# changes Player.Status (4->0) on the four turn-participating players"
echo "# plus the derived Summary.Checksum. Nothing else."
echo
echo "\$ state_checksum.py turn2-state.sav $(basename "$B")"
$SC "$A" "$B"
echo
echo "\$ state_checksum.py turn2-state.sav $(basename "$B") --mask resave"
$SC "$A" "$B" --mask resave
} > "$OUT/resave-localisation.txt" 2>&1
note "resave-localisation" 0
else
echo "== resave-localisation -> SKIPPED (the bb4fd9ac re-save form is not on this host)"
fi
# 4. a real turn transition, fully attributed
if [ -f "$REPO_SAVES/turn2-state.sav" ] && [ -f "$REPO_SAVES/turn3-state.sav" ]; then
{
echo "# one real End Turn (turn 2 -> turn 3), every difference named"
echo
$SC "$REPO_SAVES/turn2-state.sav" "$REPO_SAVES/turn3-state.sav" --ulps 2 --limit 500
} > "$OUT/turn2-to-turn3.txt" 2>&1
note "turn-transition" 0
fi
# 5. the recorded chain (host side of the replay loop; the VM side is unrun)
CH=("$REPO_SAVES/turn1-state.sav" "$REPO_SAVES/turn2-state.sav" "$REPO_SAVES/turn3-state.sav")
have=1
for f in "${CH[@]}"; do [ -f "$f" ] || have=0; done
if [ "$have" = 1 ]; then
$SC "${CH[@]}" --record-chain "$OUT/chain-turn1-3.json" > "$OUT/chain.txt" 2>&1
note "record-chain" $?
echo >> "$OUT/chain.txt"
echo "\$ state_checksum.py --chain chain-turn1-3.json turn1 turn2 turn3" >> "$OUT/chain.txt"
$SC --chain "$OUT/chain-turn1-3.json" "${CH[@]}" >> "$OUT/chain.txt" 2>&1
note "verify-chain" $?
fi
# 6. float census -- the evidence behind the float-parity policy
uv run python3 "$HERE/float_census.py" "${ALL[@]}" > "$OUT/float-census.txt" 2>&1
note "float-census" $?
echo
echo "wrote $OUT"
exit $rc