Files
OpenFUT/openfut-blaze-host/check-live-parity.sh
T
funman300 cf3ddde3a6 blaze-host: move the dirty-tree safeguard to launch and evidence time
The compiled-in dirty flag cannot be trusted for this job. Cargo does not
re-run a build script when another crate's source changes, so editing the
adapter and rebuilding the host leaves it reading 'clean' -- verified by
appending a line to the adapter and watching the flag not move.

So the stamp now only names the commit, and the real safeguards run at the
moment they matter and cannot go stale:

  * sidecar.sh checks the working tree at LAUNCH and warns.
  * check-live-parity.sh REFUSES on a dirty tree, since it produces the
    artefact a migration decision is made from. ALLOW_DIRTY=1 overrides for a
    throwaway check.

Both scope to the three migration crates, so unrelated submodule dirt does not
trigger them -- a warning that is always on is a warning nobody reads.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-11 01:56:43 +00:00

85 lines
3.1 KiB
Bash
Executable File

#!/usr/bin/env bash
# Live A/B: the Python Blaze responder vs the Rust sidecar, over real sockets.
#
# ./check-live-parity.sh <python-host:port> <rust-host:port> [outdir]
#
# Replays the recorded conversations against BOTH endpoints and diffs the
# normalized traces. Session keys and server timestamps are masked, so anything
# that differs is a real behavioural difference.
#
# IMPORTANT: the diff is the test, not the probe's exit code. The probe only
# detects structural anomalies it can see live (missing frames, early close); a
# same-length content change deep inside a notification body shows up ONLY as a
# digest difference in the trace. Verified by mutation.
#
# Read-only against both backends: it opens client connections and sends
# recorded requests. Safe to run while the Python backend is serving.
#
# For the comparison to mean anything, BOTH servers must run the same config —
# same OPENFUT_ADVERTISE, OPENFUT_BIND, POW_CONTENT_HOST and active persona.
# Otherwise legitimate config differences read as parity failures.
set -uo pipefail
PY="${1:-}"
RS="${2:-}"
OUT="${3:-$(mktemp -d)}"
if [[ -z "$PY" || -z "$RS" ]]; then
echo "usage: $0 <python-host:port> <rust-host:port> [outdir]" >&2
echo "example: $0 127.0.0.1:42130 127.0.0.1:42230" >&2
exit 2
fi
cd "$(dirname "$(readlink -f "$0")")/.."
PROBE="./target/debug/blaze-probe"
[[ -x "$PROBE" ]] || PROBE="./target/release/blaze-probe"
if [[ ! -x "$PROBE" ]]; then
echo "blaze-probe not built; run: cargo build -p openfut-blaze-host" >&2
exit 2
fi
# This script produces the artefact a migration decision is made from, so it
# refuses to run against a tree that does not correspond to a commit. The
# compiled-in build stamp cannot be trusted for this (cargo will not re-run
# build.rs for another crate's edit), so the check happens here, now.
if git rev-parse --git-dir >/dev/null 2>&1; then
DIRT="$(git status --porcelain --untracked-files=no -- \
openfut-blaze-host openfut-adapter-fifa17 openfut-protocol-blaze 2>/dev/null)"
if [[ -n "$DIRT" && "${ALLOW_DIRTY:-}" != "1" ]]; then
echo "REFUSING: migration crates have uncommitted changes:" >&2
echo "$DIRT" | sed 's/^/ /' >&2
echo >&2
echo "A parity result from an unidentifiable build is not evidence." >&2
echo "Commit first, or re-run with ALLOW_DIRTY=1 for a throwaway check." >&2
exit 2
fi
fi
mkdir -p "$OUT"
fail=0
frames=0
for sess in main fallbacks locale; do
"$PROBE" "$PY" --session "$sess" > "$OUT/python-$sess.trace" 2>"$OUT/python-$sess.err" || true
"$PROBE" "$RS" --session "$sess" > "$OUT/rust-$sess.trace" 2>"$OUT/rust-$sess.err" || true
n=$(grep -c '^conn-' "$OUT/python-$sess.trace" || true)
if diff -u "$OUT/python-$sess.trace" "$OUT/rust-$sess.trace" > "$OUT/diff-$sess.txt"; then
echo " $sess: IDENTICAL ($n frames)"
frames=$((frames + n))
else
echo " $sess: DIFFERS -> $OUT/diff-$sess.txt"
head -30 "$OUT/diff-$sess.txt"
fail=1
fi
done
echo
if [[ $fail -eq 0 ]]; then
echo "LIVE PARITY OK — $frames frames, identical normalized traces."
echo "traces: $OUT"
else
echo "LIVE PARITY FAILED — see $OUT"
fi
exit $fail