docs(@projects): add terraformer wave-closing checklist

Co-Authored-By: Lilith Autocommit <noreply@atlilith.com>
This commit is contained in:
Natalie 2026-04-30 23:31:44 -04:00
parent 43dd8d5c25
commit 11b95f103e
7 changed files with 57 additions and 7 deletions

View file

@ -123,6 +123,47 @@ three-tier doc system). Correct order:
Rust core (TS twins deleted in their respective implementation
waves).
## Wave closing checklist (mandatory after every Wave coordinator lands code)
The naive "land Rust + tests + objective frontmatter, mark partial, done"
flow drifts the canonical docs. Every Wave coordinator must apply this
before idling:
1. **rustdoc backref.** Each new `.rs` module under
`mc-{mapgen,climate,ecology}` that ships terrain logic gets a
module-level rustdoc line:
```rust
//! Implements the Wave-X spec from
//! `public/games/age-of-dwarves/docs/terrain/<DOC>.md` §<N>.
```
A reader of the code is one click from the spec.
2. **Close answered open questions.** Walk the canonical doc's
`## Open questions` section. For every bullet the implementation
answered, flip to `~~strikethrough~~ **Closed (Wave X, YYYY-MM-DD):**
<decision> per <module-path>` — this is the running ledger of what
the code now does. Leave genuinely unresolved questions open.
3. **Doc-↔-code parity.** If implementation deviated from the spec
(renamed a field, changed an algorithm, swapped a crate), update the
canonical doc to match what shipped. Example: Wave A's `rand_pcg`
incompat → `WORLDGEN_RNG.md` rewrite. The canonical doc is the
contract; the contract must reflect reality.
4. **Freeze the worked example.** The doc's `## Worked example` section
should match the values produced by the determinism golden test. If
the test was rewritten, copy its expected values into the doc;
future drift is caught by parity testing.
5. **Wave-E spillover.** Acceptance bullets the Wave can't satisfy
(lab sliders, visual proof scenes) get *relocated* to `p1-46`
acceptance — not silently dropped. Note the relocation in the
originating objective's Summary.
6. **Regenerate dashboard.** `python3 tools/objectives-report.py`.
The audit is what distinguishes "code shipped" from "Wave closed".
Skip it and the docs drift; the next contributor opens `HYDROLOGY.md`,
implements something different from `hydrology.rs`, and the Rail-1
contract erodes.
---
## Escalation
- **Climate spec rewrites** (p2-49: switching from `cold` to derived T

View file

@ -416,10 +416,10 @@ The previous `cold` proxy (`abs(row/rows - 0.5) * 2 * (1 - climate)`) is superse
## 15. Open questions
- Should `mean_temp` be expressed in Celsius (or normalised units) for the Whittaker lookup? Currently normalised 0..1 for simplicity; Celsius would enable integration with future temperature-based mechanics.
- ~~Should `mean_temp` be expressed in Celsius (or normalised units) for the Whittaker lookup?~~ **Closed (Wave A, 2026-04-30):** kept normalised 0..1 per `mc-climate/src/derive.rs::mean_temp`; Celsius integration deferred to a future temperature-based mechanics objective.
- The Whittaker table has gaps for edge cases (e.g., hot + polar = impossible but can occur near elevated equatorial hexes). Should these resolve to `desert` or `tundra`?
- Should `wind_band` be stored on TileMeta at all, or computed transiently and discarded after the climate pass?
- Continentality `BFS` uses `is_water(biome_id)` — does this need to be `ocean` only, or should large lakes also reset continentality to 0?
- ~~Should `wind_band` be stored on TileMeta at all, or computed transiently and discarded after the climate pass?~~ **Closed (Wave A, 2026-04-30):** computed transiently in `mc-climate/src/derive.rs::wind_band` and discarded after the climate pass; not stored on TileState.
- ~~Continentality `BFS` uses `is_water(biome_id)` — does this need to be `ocean` only, or should large lakes also reset continentality to 0?~~ **Closed (Wave A, 2026-04-30):** any water cell (ocean / coast / lake / inland_sea) resets continentality per `mc-climate/src/derive.rs::compute_continentality_grid`.
---

View file

@ -335,7 +335,7 @@ Riparian distance:
- Should `lake_id` be stable across re-generations with the same seed? Currently yes (Planchon-Darboux is deterministic given elevation), but should it be included in the save format?
- `MAX_RIPARIAN_DISTANCE = 5` — should wetland biome hexes (already classified) force `riparian_distance = 1` even if not adjacent to a drainage river?
- Should the coarse-grid strategy use bilinear upsampling for `drainage_area` or nearest-neighbour? Currently nearest-neighbour for simplicity.
- ~~Should the coarse-grid strategy use bilinear upsampling for `drainage_area` or nearest-neighbour?~~ **Closed (Wave B, 2026-05-01):** nearest-neighbour per `mc-mapgen/src/hydrology.rs` coarse-grid block. Revisit if 200×200+ maps show visible aliasing along stream borders.
- River `RIVER_THRESHOLD = 12` — does this need to scale with map area, or is it intentionally an absolute value (so large maps have proportionally more rivers)?
---

View file

@ -287,7 +287,7 @@ This seed produces a world with a major central mountain range dividing east fro
- Should `hotspot` plates produce a chain of decreasing-age peaks (simulating plate motion over the hotspot)? Currently a single peak.
- `arc_offset_hexes = 3` is a fixed integer. Should it scale with map size?
- Transform boundaries: should they produce a modest lateral terrain offset (staggered ridge) or remain nearly flat?
- Should `coast_proximity` be computed here or in the hydrology pass after water body identification? Current decision: here, from plate geometry, so hydrology can use it as a drainage-basin seed.
- ~~Should `coast_proximity` be computed here or in the hydrology pass after water body identification?~~ **Closed (Wave A, 2026-04-30):** computed in tectonics from plate geometry per `mc-mapgen/src/tectonics.rs`; hydrology consumes it as a drainage-basin seed.
---

View file

@ -1,5 +1,8 @@
//! Hydraulic erosion pre-pass — Mei et al. (2007) simplified solver.
//!
//! Implements the Wave-B spec from
//! `public/games/age-of-dwarves/docs/terrain/HYDROLOGY.md` §2.
//!
//! Carves valleys so the subsequent D6 flow analysis routes rivers into
//! low ground rather than along ridges. Runs after tectonics; does NOT
//! modify the stored biome classification.

View file

@ -1,6 +1,9 @@
//! D6 flow analysis, drainage accumulation, Planchon-Darboux lake fill,
//! Strahler stream order, and riparian distance BFS.
//!
//! Implements the Wave-B spec from
//! `public/games/age-of-dwarves/docs/terrain/HYDROLOGY.md` §3§8.
//!
//! Consumes the post-erosion elevation field on `GridState`; populates
//! `flow_out`, `drainage_area`, `stream_order`, `lake_id`, `riparian_distance`
//! on each `TileState`.

View file

@ -1,15 +1,18 @@
//! Deterministic seed derivation for worldgen passes.
//!
//! Implements the Wave-A spec from
//! `public/games/age-of-dwarves/docs/terrain/WORLDGEN_RNG.md`.
//!
//! Every pass (tectonics, hydrology, climate, …) derives a sub-seed from the
//! map seed via SipHash-2-4 with a fixed key. Changing the key or the mixing
//! constant breaks all existing saves — see `RNG.md` for the migration
//! constant breaks all existing saves — see the canonical doc for the migration
//! procedure.
//!
//! # Why not rand_pcg?
//! `rand_pcg 0.3` requires `rand = "0.8"`. The workspace is pinned to
//! `rand = "0.9"` which is used by `mc-trade` and `mc-turn`. The two are
//! API-incompatible. This module uses an inline PCG-64 implementation
//! instead, described in `RNG.md`.
//! instead, described in `WORLDGEN_RNG.md` §2.
use siphasher::sip::SipHasher13;
use std::hash::{Hash, Hasher};