feat(phase-b): sweep [--boot] — corpus-scale VM+state validation harness

Runs every SC/SP scene through GameSession (fresh or booted-from-snapshot) and
reports halt distribution + line counts. Unbooted matches the vm0.py A0 baseline
(294 exit + the same 3 LOOP scenes) — cross-validates the C# VM at scale.
FINDING: booting the *INIT data tables gives byte-identical results (regression-
free) but does NOT change ADV dialogue flow — *INIT feeds gameplay; ADV branches
key on story-state flags (chapter/form/choices) from the progression layer, not
*INIT. So story-state seeding (e.g. the Lily form flag) is the ADV-unlock lever.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
gamer147
2026-07-07 00:28:36 -04:00
parent f6d1384b00
commit d46940158c

View File

@@ -103,6 +103,42 @@ if (args[0] == "play")
return 0; return 0;
} }
if (args[0] == "sweep")
{
// sweep [--boot] — run every SC/SP scene through GameSession (each from a fresh or booted-from-snapshot
// baseline) and report halt distribution + line counts. Validates the VM + state substrate at scale and
// surfaces how booted real data affects the corpus. Headless.
var sceneRe = new Regex(@"^S[CP]\d{4}\.BIN$");
var scripts = Paths.Scripts();
var names = scripts.Keys.Where(n => sceneRe.IsMatch(n)).OrderBy(n => n, StringComparer.Ordinal).ToList();
bool boot = args.Contains("--boot");
string? baseline = null;
if (boot)
{
var bootSession = new GameSession();
foreach (var s in new[] { "SKINIT.BIN", "ITINIT.BIN", "EBINIT.BIN", "CGINIT.BIN", "MPINIT.BIN",
"AFINIT.BIN", "CCINIT.BIN", "STINIT.BIN", "STINIT2.BIN" })
bootSession.RunScene(Sys4Loader.Load(scripts[s], table), table, new CaptureHost());
baseline = bootSession.ToJson();
Console.WriteLine($"[boot] baseline = {bootSession.Globals.Count} globals; running {names.Count} scenes from it.");
}
var haltDist = new SortedDictionary<string, int>(StringComparer.Ordinal);
long totalLines = 0; var anomalies = new List<string>();
foreach (var name in names)
{
var session = baseline != null ? GameSession.FromJson(baseline) : new GameSession();
var r = session.RunScene(Sys4Loader.Load(scripts[name], table), table, new CaptureHost());
var halt = r.Halt ?? "null";
haltDist[halt] = haltDist.GetValueOrDefault(halt) + 1;
totalLines += r.Emitted.Count;
if (halt != "exit") anomalies.Add($"{name}: {r.Emitted.Count} lines, halt={halt}");
}
Console.WriteLine($"swept {names.Count} scenes{(boot ? " (booted)" : "")}: {totalLines} total lines");
Console.WriteLine("halt distribution: " + string.Join(", ", haltDist.Select(kv => $"{kv.Key}={kv.Value}")));
if (anomalies.Count > 0) { Console.WriteLine($"non-exit halts ({anomalies.Count}):"); foreach (var a in anomalies) Console.WriteLine(" " + a); }
return 0;
}
if (args[0] == "trace") if (args[0] == "trace")
{ {
var scene = new Regex(@"^S[CP]\d{4}\.BIN$"); var scene = new Regex(@"^S[CP]\d{4}\.BIN$");