docs(decisions): fix D-202 self-contradiction on sea_level storage (#963)

Clerk caught it: D-202 line 928 said sea_level is 'carried alongside (not in
the PNG)' while line 930 + the implementation store it IN the PNG (tEXt chunk).
Update line 928 to match — sea_level is a tEXt chunk, with a caller default
fallback. D-202 is now internally consistent (resolution, sea_level, table-drop).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-23 09:36:02 +02:00
co-authored by Claude Opus 4.7
parent 6334b0ddbe
commit 399cd590e9
+1 -1
View File
@@ -925,7 +925,7 @@ Technical foundation decisions that constrain implementation: engine, client-ser
- **Naming fix:** the existing color hypsometric render (today's `heightmap.png`, 1024×512 RGB) is renamed **`reliefmap.png`** — it is a relief visualization, not elevation. Display-only.
- **Canonical elevation:** a new **`heightmap.png`** = 16-bit grayscale (luminance = normalized elevation), **1024×512** (2× per axis / 4× the cells of the old 512×256 sim grid — the PNG dimensions are unchanged from the prior canonical 1024×512 in D-201; only the *content* changed from an RGB relief to native 16-bit elevation). 1024×512 bounds install size (~190 MB across 267 inhabited bodies) while sub-pixel detail is synthesized by the lower cascade layers. Single source of truth — the reliefmap and all computed geography derive from it, so it is bit-identical/deterministic by construction.
- **Multi-resolution:** the stored heightmap is high-res for the lower layers (region/block/tile sample local detail); **Layer 1** (continental drainage/basins/mountain-ranges) calls `BodyHeightmap::downsample` to the `GRID_W×GRID_H = 512×256` working resolution first, decoupling continental compute cost (~45ms) from stored resolution.
- **Rust loader:** `heightmap.rs::load_heightmap_png` reads the 16-bit grayscale PNG (via the `png` crate), normalizes to f32 [0,1]; rejects RGB (a reliefmap can't be misread as elevation). `sea_level` becomes body metadata carried alongside (not in the PNG).
- **Rust loader:** `heightmap.rs::load_heightmap_png` reads the 16-bit grayscale PNG (via the `png` crate), normalizes to f32 [0,1]; rejects RGB (a reliefmap can't be misread as elevation). `sea_level` is stored **in the PNG** as a `tEXt` chunk (the heightmap is self-describing), with a caller-supplied default as fallback.
- **`atlas_body_heightmaps` is dropped**; `import_heightmaps.py` writes the PNG file instead of a DB row. The bake runs in the content pipeline (numpy/scipy) once; the runtime cascade is pure Rust loading the file.
- **Implementation status (#963):** Consumer done — `heightmap.rs::load_heightmap_png` reads the 16-bit grayscale PNG + `sea_level` tEXt chunk, rejects RGB, downsamples for Layer 1. Producer done — `import_heightmaps.py` is the bake (rename legacy `heightmap.png`→`reliefmap.png` for all bodies incl. Sol; for non-Sol inhabited bodies write a fresh clean `reliefmap.png` + 16-bit `heightmap.png` from `simulate()` at the bumped 1024×512 grid). `atlas_body_heightmaps` dropped via MIGRATION_SQL + removed from `systems-schema.sql`. Godot client (`atlas_viewer.gd`) loads `reliefmap.png` for display. Sim determinism guarded by `test_sim_determinism.py`.
- **Rationale:** Storing heightmaps in `systems.db` keeps the DB as the single source of truth for all generation inputs, avoids a separate file-fetching path in the Rust server, and allows the pre-push hook (asset pipeline rules) to detect stale heightmap data. The float32 LE layout matches what NumPy and PIL produce natively, minimizing conversion overhead in the Python pipeline. *(Superseded by the #963 amendment above — the file-based model won out because the DB-as-single-source goal conflicts with binary-merge-conflict avoidance and DB size; a per-body committed PNG is itself a queryable, diffable-by-render asset.)*