#!/usr/bin/env python3 """Check L25, 24 m crossing and upper-SW fixture determinism for L36.""" import csv import re import subprocess import time from pathlib import Path ROOT = Path(__file__).resolve().parents[4] OUT = ROOT / "Saved/Linux/l36" OWNER = ROOT / "Standalone/data/owner_world.json" FIXTURE = ROOT / "Saved/Linux/l33/fixtures/sw-upper-tunnel-network-style0.json" BINARIES = { "clang": OUT / "bin/VoxelForgeCoreHeadless-l36-final-clang", "gcc": OUT / "bin/VoxelForgeCoreHeadless-l36-final-gcc", } HASH = re.compile(r"^\[Pipeline(?:FullDetailHash|WholeViewHash|LODHash|ExactQueryHash)\].*$", re.M) STAMP = re.compile( r"^\[WorldAssemblerRecipeAudit\] requested=([^ ]+) actual=([^ ]+).*status=([^ ]+)$", re.M) LAYOUT = re.compile( r"^\[ResolvedLayoutSnapshot\] schema=\d+ stable_identity=([^ ]+) strata=\d+ bytes=\d+ round_trip=PASS$", re.M) PLAN = re.compile( r"^\[WorldAssemblerPlanSerialization\].*canonical_round_trip=true .*" r"plan_hash=([0-9a-f]+) manifest_hash=([0-9a-f]+) status=PASS$", re.M) ROUTE = re.compile( r"^\[WorldAssemblerRouteAccepted\] arrival_xy_m=\([^)]*\) " r"departure_xy_m=\([^)]*\) endpoint_proximity_cost=\d+ average_grade_q16=\d+$", re.M) rows = [] failed = False references = {} def run(kind, recipe, compiler, workers, data, passage_audit=False, crossing=False): global failed binary = BINARIES[compiler] name = f"determinism-{kind}-{compiler}-{recipe}-w{workers}" if kind == "upper-fixture": name = f"determinism-upper-fixture-{compiler}-w{workers}" log = OUT / f"{name}.log" command = [ "taskset", "-c", "0-11", "prlimit", "--as=6442450944", "--", "timeout", "1800s", str(binary), str(data), f"--workers={workers}", "--world-assembler-prototype", "--stream-benchmark", "--stream-pipeline", "--force-generate", "--clip-radius=3", "--max-clip-level=8", "--max-level=-1", f"--recipe={recipe}", ] if passage_audit: command.append("--audit-resolved-layout-passages") else: command.append("--stream-hash") if crossing: command.extend(("--camera-step=24,0,0", "--region-crossing")) started = time.monotonic() try: with log.open("w", encoding="utf-8") as stream: result = subprocess.run(command, cwd=ROOT, stdout=stream, stderr=subprocess.STDOUT, timeout=1800, check=False) except subprocess.TimeoutExpired: result = None elapsed = time.monotonic() - started output = log.read_text(encoding="utf-8", errors="replace") stamps = STAMP.findall(output) stamp_ok = stamps == [(recipe, recipe, "PASS")] if passage_audit: signature = (tuple(LAYOUT.findall(output)), tuple(PLAN.findall(output)), tuple(ROUTE.findall(output))) expected = references.get((kind, recipe)) stable = expected is None or signature == expected if expected is None and all(signature): references[(kind, recipe)] = signature valid = (result is not None and result.returncode == 0 and stamp_ok and len(signature[0]) == len(signature[1]) == len(signature[2]) == 1 and re.search(r"^\[ResolvedPassageAuditSummary\].*status=PASS$", output, re.M) and re.search(r"^\[PassageRippleAuditSummary\].*status=PASS$", output, re.M) and stable) hashes = () detail = f"layout={signature[0][0] if signature[0] else 'MISSING'} stable={stable}" else: hashes = tuple(HASH.findall(output)) key = (kind, recipe) expected = references.get(key) stable = expected is None or hashes == expected if expected is None and hashes: references[key] = hashes valid = (result is not None and result.returncode == 0 and stamp_ok and "hash=on" in output and len(hashes) == 12 and stable) detail = f"hashes={len(hashes)}/12 stable={stable}" code = result.returncode if result is not None else "TIMEOUT" rows.append((kind, recipe, compiler, workers, elapsed, code, valid)) failed |= not valid print(f"[L36DeterminismRun] kind={kind} recipe={recipe} compiler={compiler} " f"workers={workers} elapsed={elapsed:.1f}s {detail} " f"{'PASS' if valid else 'FAIL'} log={log}", flush=True) for kind in ("l25", "crossing24"): for recipe in ("surface-world", "floating-islands"): for compiler in BINARIES: for workers in (1, 8, 12): run(kind, recipe, compiler, workers, OWNER, crossing=(kind == "crossing24")) for compiler in BINARIES: for workers in (1, 8, 12): run("upper-fixture", "floating-islands", compiler, workers, FIXTURE, passage_audit=True) summary = OUT / "determinism-l36.csv" with summary.open("w", newline="", encoding="utf-8") as stream: writer = csv.writer(stream) writer.writerow(("kind", "recipe", "compiler", "workers", "elapsed_seconds", "exit_code", "status")) for row in rows: writer.writerow((*row[:-1], "PASS" if row[-1] else "FAIL")) print(f"[L36DeterminismSummary] runs={len(rows)} pass={sum(row[-1] for row in rows)} " f"fail={sum(not row[-1] for row in rows)} summary={summary}", flush=True) raise SystemExit(1 if failed or len(rows) != 30 else 0)