The determinism harness moves into deploy/ for real
deploy/verify-ledgers.sh fetches every production ledger and strictly replays it against the local engine (any refusal or crash fails; a lobby that never dealt is trivially clean). Run from the repo root before deploying engine changes — the check both of tonight's replay breaks would have caught. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0138A8CjeQRpvzKxuMfz1Bqc
This commit is contained in:
co-authored by
Claude Fable 5
parent
c87b8cb28d
commit
1cf5d0a68d
@@ -0,0 +1,21 @@
|
|||||||
|
// Strict full-ledger replay: ANY refused command is a hard failure.
|
||||||
|
import { readFileSync } from "fs";
|
||||||
|
import { createGame, applyCommand } from "../packages/engine/src/game.ts";
|
||||||
|
const lines = readFileSync(process.argv[2], "utf8").trim().split("\n").map((l) => JSON.parse(l));
|
||||||
|
const meta = lines.find((l) => l.kind === "meta");
|
||||||
|
const start = lines.find((l) => l.kind === "start");
|
||||||
|
if (!start) {
|
||||||
|
console.log(`OK ${process.argv[2].split("/").pop()}: lobby only, nothing to replay`);
|
||||||
|
process.exit(0);
|
||||||
|
}
|
||||||
|
const joins = lines.filter((l) => l.kind === "join");
|
||||||
|
const playerIds = [...new Set([meta.hostId, ...joins.map((j) => j.name)])];
|
||||||
|
let { state } = createGame({ playerIds, seed: meta.seed, sets: start.expansion ? ["basic", "expansion1"] : ["basic"], colors: start.colors, deckRev: start.deckRev });
|
||||||
|
let n = 0;
|
||||||
|
for (const l of lines) {
|
||||||
|
if (l.kind !== "command") continue;
|
||||||
|
const r = applyCommand(state, l.playerId, l.command);
|
||||||
|
if (!r.ok) { console.log(`FAIL ${process.argv[2].split("/").pop()} seq ${l.seq}: ${r.error}`); process.exit(1); }
|
||||||
|
state = r.state; n++;
|
||||||
|
}
|
||||||
|
console.log(`OK ${process.argv[2].split("/").pop()}: ${n} commands replay clean`);
|
||||||
Executable
+19
@@ -0,0 +1,19 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# Pre-deploy determinism check: fetch every production ledger and strictly
|
||||||
|
# replay it against the LOCAL engine. Any refused command is a hard failure.
|
||||||
|
# Run from the repo root before deploying any engine change.
|
||||||
|
set -euo pipefail
|
||||||
|
HOST="${1:-104.236.96.198}"
|
||||||
|
TMP=$(mktemp -d)
|
||||||
|
trap 'rm -rf "$TMP"' EXIT
|
||||||
|
scp -q "root@$HOST:/var/lib/wizwar/rooms/*.jsonl" "$TMP/"
|
||||||
|
fails=0
|
||||||
|
for f in "$TMP"/*.jsonl; do
|
||||||
|
out=$(npx tsx deploy/replay-verify.mjs "$f" 2>&1 | tail -1)
|
||||||
|
case "$out" in
|
||||||
|
FAIL*) echo "$out"; fails=$((fails+1));;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
count=$(ls "$TMP" | wc -l | tr -d ' ')
|
||||||
|
echo "--- $count ledgers checked, $fails failures"
|
||||||
|
[ "$fails" -eq 0 ]
|
||||||
Reference in New Issue
Block a user