Files
settled-reach/tooling/planet-gen/populate_terrain_reference.py
T
jpmschweitzerandClaude Fable 5 346d87df7a chore(meta): docs/build sweep + tooling test gate (T-1069, T-1066)
- make test-tooling: planet-gen determinism guard + import_economics
  --dry-run, wired into pre-push on TOOLING_CHANGED; ruff widened to
  E4/E7/E9/F/W (90 safe auto-fixes applied; E402/E702/F841 ignored with
  documented counts)
- one-generator reality fixed in DEVOPS.md, asset-pipeline rule, CLAUDE.md
  (import_economics sole generator since #951/D-223); dead check-protocol
  target deleted; DEVOPS hook/config sections rewritten from the actual
  hook sources; team-patterns gate description updated (client+tooling)
- project.yaml: 0.2.0 → 0.4.0 per the 0.{phase}.{n} scheme, description
  refreshed from the v0.1 Sova narration to cascade reality
- stale comment sweep: voxel.rs stub claims (all 8 families implemented),
  cascade.rs TODO recited to T-1044, main.rs D-192 handshake claim,
  relationships.rs/chunk_streaming.rs version targets → phase language
- gitignore: client/settings.db* e2e-run artifacts

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-12 16:22:55 +02:00

140 lines
4.5 KiB
Python

#!/usr/bin/env python3
"""
Batch populate terrain_reference column in systems.db bodies table.
For each inhabited body with NULL terrain_reference:
1. Construct expected wiki heightmap path:
wiki/star-systems/{system_slug}/bodies/{body_id}/heightmap.png
where system_slug = system_id with spaces replaced by hyphens.
2. Verify the file exists.
3. Update terrain_reference to the relative path.
Bodies with missing heightmaps are logged to stdout for remediation.
This is the prerequisite for the atlas importers (import_heightmaps.py, #901).
Usage:
python3 tooling/planet-gen/populate_terrain_reference.py
python3 tooling/planet-gen/populate_terrain_reference.py --dry-run
python3 tooling/planet-gen/populate_terrain_reference.py --db path/to/systems.db
Decisions: D-191 (atlas pipeline prerequisites)
"""
import argparse
import sqlite3
from pathlib import Path
SCRIPT_DIR = Path(__file__).resolve().parent
REPO_ROOT = (SCRIPT_DIR / ".." / "..").resolve()
DB_PATH = REPO_ROOT / "server" / "data" / "systems.db"
WIKI_DIR = REPO_ROOT / "wiki" / "star-systems"
def system_slug(system_id: str) -> str:
"""Convert a system_id to its wiki directory slug.
'GJ 71' → 'GJ-71'
'GJ 244A' → 'GJ-244A'
'GJ 559B' → 'GJ-559B'
"""
return system_id.replace(" ", "-")
def expected_heightmap_path(system_id: str, body_id: str) -> Path:
"""Return the expected absolute heightmap path for a body."""
return WIKI_DIR / system_slug(system_id) / "bodies" / body_id / "heightmap.png"
def relative_terrain_reference(system_id: str, body_id: str) -> str:
"""Return the terrain_reference value to store in the DB.
Stored as a repo-root-relative path so it is portable across checkouts.
"""
return f"wiki/star-systems/{system_slug(system_id)}/bodies/{body_id}/heightmap.png"
def main():
parser = argparse.ArgumentParser(
description="Populate terrain_reference column in systems.db bodies table"
)
parser.add_argument("--db", default=str(DB_PATH), help="Path to systems.db")
parser.add_argument(
"--dry-run",
action="store_true",
help="Report without writing changes",
)
args = parser.parse_args()
db_path = Path(args.db)
if not db_path.exists():
print(f"error: {db_path} not found")
raise SystemExit(1)
conn = sqlite3.connect(str(db_path))
conn.execute("PRAGMA foreign_keys=ON")
# Fetch all inhabited bodies with NULL terrain_reference.
rows = conn.execute("""
SELECT b.body_id, b.system_id
FROM bodies b
WHERE b.terrain_reference IS NULL
ORDER BY b.system_id, b.body_id
""").fetchall()
print("\n terrain_reference population pass")
print(f" DB: {db_path}")
if args.dry_run:
print(" Mode: DRY RUN")
print(f"\n {len(rows)} bodies with NULL terrain_reference\n")
found = []
missing = []
for body_id, system_id in rows:
path = expected_heightmap_path(system_id, body_id)
if path.exists():
found.append((body_id, system_id))
else:
missing.append((body_id, system_id, str(path)))
# Report missing heightmaps before writing — helps flag gaps early.
if missing:
print(f" MISSING heightmaps ({len(missing)} bodies — no update for these):")
for body_id, system_id, path in missing:
print(f" {body_id} ({system_id}) → {path}")
print()
if found:
print(f" Updating {len(found)} bodies with terrain_reference:")
for body_id, system_id in found:
ref = relative_terrain_reference(system_id, body_id)
print(f" {body_id} ({system_id}) → {ref}")
if not args.dry_run:
conn.execute(
"UPDATE bodies SET terrain_reference = ? WHERE body_id = ?",
(ref, body_id),
)
if not args.dry_run:
conn.commit()
print(f"\n Committed {len(found)} terrain_reference updates.")
else:
print("\n Dry run — no changes written.")
conn.close()
# Summary
print("\n Summary:")
print(f" Updated: {len(found)}")
print(f" Missing: {len(missing)}")
print(f" Total: {len(rows)}\n")
if missing:
print(f" Action required: generate heightmaps for {len(missing)} bodies "
f"before running the atlas importers (#901).")
print(" Use: make generate-terrain (or run generate.py per body)\n")
if __name__ == "__main__":
main()