#!/usr/bin/env python3 """Compare composed owner hashes and resolved graph identity at W1/W8/W12.""" from __future__ import annotations import json import re import subprocess import time from pathlib import Path ROOT = Path(__file__).resolve().parents[4] OUT = ROOT / "Saved/Linux/l139/determinism" DATA = ROOT / "Standalone/data/owner_world.json" STAMP = "b8603b6cb3975ca0f9669759e4e2464561c557fdb7aa6836acef123ecf0b99d1" BINARIES = { "clang": ROOT / "Saved/Linux/l139/bin/VoxelForgeCoreHeadless-l139-clang", "gcc": ROOT / "Saved/Linux/l139/bin/VoxelForgeCoreHeadless-l139-gcc", } CAMERA = "-20.062500,-5.068359,-900.353516,0,0" HASH_RE = re.compile( r"^\[Pipeline(?:FullDetailHash|WholeViewHash|MaterialHash|LODHash|ExactQueryHash)\].*$", re.M) STAMP_RE = re.compile(r"^\[VoxelForgeSourceStamp\] sha256=([0-9a-f]+)$", re.M) def main() -> int: if any(not path.is_file() for path in (DATA, *BINARIES.values())): raise SystemExit("missing L139 determinism binary or composed owner fixture") OUT.mkdir(parents=True, exist_ok=True) rows = [] reference_hashes: tuple[str, ...] | None = None reference_layout_identity: str | None = None for compiler, binary in BINARIES.items(): for workers in (1, 8, 12): name = f"determinism-{compiler}-w{workers}" log, layout = OUT / f"{name}.log", OUT / f"{name}.json" command = ["taskset", "-c", "0-11", "prlimit", "--as=6442450944", "--", "timeout", "1740s", str(binary), str(DATA), "--world-assembler-prototype", "--stream-benchmark", "--stream-pipeline", f"--workers={workers}", "--clip-radius=3", "--max-clip-level=8", "--max-level=0", f"--camera={CAMERA}", "--stream-hash", "--force-generate", "--seed=0", "--recipe=surface-world", "--render-distance-chunks=0", "--density-dispatch-report", f"--resolved-layout-output={layout}"] started = time.monotonic() with log.open("w", encoding="utf-8") as output: proc = subprocess.run(command, cwd=ROOT, stdout=output, stderr=subprocess.STDOUT, check=False, timeout=1740) content = log.read_text(encoding="utf-8", errors="replace") stamp = STAMP_RE.search(content) hashes = tuple(HASH_RE.findall(content)) current_layout = json.loads(layout.read_text(encoding="utf-8")) stable_identity = current_layout.get("stable_identity") dispatch_ok = bool(re.search( r"^\[DensityDispatch\] strate=3 generator=VerticalShafts " r"recipe=Core\.Caves\.PrimitiveField version=1 " r"bound_path=Caves-native adapter=FCavesFieldAdapter$", content, re.M)) passed = (proc.returncode == 0 and stamp is not None and stamp.group(1) == STAMP and len(hashes) >= 4 and dispatch_ok and bool(stable_identity)) if reference_hashes is None and passed: reference_hashes = hashes reference_layout_identity = stable_identity else: passed = (passed and hashes == reference_hashes and stable_identity == reference_layout_identity) row = {"compiler": compiler, "workers": workers, "exit": proc.returncode, "stamp": stamp.group(1) if stamp else None, "hash_lines": len(hashes), "hashes_match_first": hashes == reference_hashes, "layout_identity": stable_identity, "layout_matches_first": stable_identity == reference_layout_identity, "shaft_dispatch": dispatch_ok, "passed": bool(passed), "elapsed_s": round(time.monotonic() - started, 3), "log": str(log.relative_to(ROOT)), "layout": str(layout.relative_to(ROOT))} rows.append(row) print("[L139DeterminismRun] " + json.dumps(row, sort_keys=True), flush=True) (OUT / "runs-partial.json").write_text(json.dumps(rows, indent=2) + "\n") if not passed: raise SystemExit(f"composed owner determinism mismatch; see {log}") (OUT / "summary.json").write_text(json.dumps({"status": "PASS", "stamp": STAMP, "layout_identity": reference_layout_identity, "runs": rows}, indent=2) + "\n") print(f"[L139DeterminismSummary] runs={len(rows)} source_stamp={STAMP} status=PASS") return 0 if __name__ == "__main__": raise SystemExit(main())