#!/usr/bin/env python3 """Determinism guard for planet_simulation.simulate() (#963). The 1024×512 elevation bump (D-202 amended) claims to be deterministic — the 271-body heightmap bake cannot be re-run cheaply, so a silent non-determinism means a full regeneration. This asserts that simulating the same body twice yields a bit-identical elevation array. Run: uv run python tooling/planet-gen/test_sim_determinism.py Exit: 0 = deterministic, 1 = drift detected, 2 = could not find a test body. """ import hashlib import sqlite3 import sys from pathlib import Path REPO = Path(__file__).resolve().parent.parent.parent sys.path.insert(0, str(REPO / "tooling" / "planet-gen")) import numpy as np # noqa: E402 from body_definition_parser import parse_system # noqa: E402 from planet_simulation import GRID_H, GRID_W, simulate # noqa: E402 def _elev_hash(terrain) -> str: arr = np.ascontiguousarray(terrain["elevation"], dtype=np.float32) return hashlib.sha256(arr.tobytes()).hexdigest() def main() -> int: conn = sqlite3.connect(str(REPO / "server" / "data" / "systems.db")) rows = conn.execute( "SELECT body_id, terrain_reference FROM bodies " "WHERE inhabited=1 AND terrain_reference IS NOT NULL AND population>0 " "AND system_id != 'GJ 0' ORDER BY body_id LIMIT 30" ).fetchall() checked = 0 for body_id, tref in rows: if checked >= 3: break sys_index = tref.split("/bodies/")[0] + "/index.md" try: defs = parse_system(sys_index) except Exception: continue bd = next((d for d in defs if d.get("id") == body_id), None) if bd is None: continue t1 = simulate(bd) t2 = simulate(bd) if not t1 or "elevation" not in t1: continue h1, h2 = _elev_hash(t1), _elev_hash(t2) ok = h1 == h2 and t1["elevation"].shape == (GRID_H, GRID_W) print(f" {body_id}: {'OK' if ok else 'DRIFT'} {h1[:16]} shape={t1['elevation'].shape}") if not ok: print(f"FAIL: {body_id} elevation is non-deterministic ({h1[:16]} != {h2[:16]})") return 1 checked += 1 if checked == 0: print("SKIP: no testable body found") return 2 print(f"PASS: {checked} bodies simulate deterministically at {GRID_W}×{GRID_H}") return 0 if __name__ == "__main__": sys.exit(main())