refactor(tooling): T-1288 — planet-gen becomes reach atlas planet

The 30-file tree moves under atlas as its third rung (D-243), ten verbs
fronting it. Each verb restates its module's options so `--help` describes
something; tooling/test_planet_router.py hands every declared option to the
module's own argparse and fails on drift, and now runs in make test-tooling.

The 2026-09-02 half of this move had converted the top-level imports and the
repo roots. Finishing it found what the half-move left:

- Lazy in-function imports, and all of sol_data/, still named siblings bare.
  They resolved only through sys.path.insert hacks, so under reach the first
  globe render in generate, batch or sol-import would have raised
  ModuleNotFoundError. Qualified; the hacks are gone.
- 247 print() calls and a stdout progress writer that fired once per 8 KB
  block. Report verbs (audit, quality) write through console.out, progress
  through console.event, and download progress is throttled to 10% steps
  so a job log is not tens of thousands of lines.
- Every error exit raises ReachError with a fix.

Two checks that could not fail:

- batch --verify-determinism printed a warning and exited 0 on a mismatch.
- import-provinces exited 0 with errors > 0.

Both now raise. The 271-body bake is only safe to re-run because the first
one holds.

sol-import --body is action="append" in the module but the router took one
value, so --body GJ0d --body GJ0e kept one. Now repeatable, and _flags repeats
list options.

test_conformance walked one level, so a nested group was reported as a verb
missing @command and its ten verbs were never checked. It recurses now;
proven by stripping @command from `planet quality` and watching it fail.

Stray PNGs from the 2026-09-03 runaway router-test run are parked in
.cache/t1288-stray-pngs/, not committed. Their reliefmaps differ from HEAD
while the heightmap regenerated byte-identical — filed as T-1291.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-09-23 16:08:02 +02:00
co-authored by Claude Opus 5.5
parent 201dabd19b
commit 668772075c
56 changed files with 1130 additions and 509 deletions
+71
View File
@@ -0,0 +1,71 @@
#!/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: .venv/bin/python tooling/test_planet_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
sys.path.insert(0, str(REPO))
import numpy as np # noqa: E402
from tooling.domains.atlas.planet.body_definition_parser import parse_system # noqa: E402
from tooling.domains.atlas.planet.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())