feat(simulation): basin-outlet course wiring — the endorheic cue (D-227, T-1185)

extend_river_network_with_basin_outlets threads each Overflow basin's
resolved outlet_path into RiverNetwork as real D8 downstream
continuations (spill cell skipped as lake interior; Sea target ends at
RIVER_DOWNSTREAM_MOUTH with a seaward entry, Basin/OpenSpillway at
RIVER_DOWNSTREAM_EDGE_DRAIN); Endorheic basins contribute nothing —
the ruled zero-bit cue is outflow-course PRESENCE (D-227 amendment
(4)): a lake with no outgoing course reads as closed. Additive per
T-1170 Ruling 7b; no wire migration, no new zone, no endorheic bit.

Wired in run_layer1_with_moisture strictly AFTER attractor extraction
so outlet cells never perturb settlement placement (tested). Edge
identity is the existing pack_cell_id (row,col) convention; wiring
determinism proven by three independent double-solve byte-identity
tests. 13 new tests across hydrology_equilibrium and layer1.

Goldens: cascade_layer1.json re-pinned (third deliberate re-pin,
documented in cascade_golden.rs) — river_cells 93->143 on GJ1c,
append-only prefix byte-identical, 51/53 real basins Overflow with
short OpenSpillway stubs (the dominant honest pattern: most basins
spill onto adjacent open ground, not a long channel to sea).
window_derivation_golden and river_course_golden verified structurally
unreachable and unchanged.

Known scope boundary (documented in-code): outlet cells carry
river_class 0 (stream) — outlet-channel classification/meander width
scaled to catchment is a named follow-up, not guessed at here.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-25 08:40:07 +02:00
co-authored by Claude Fable 5
parent e0a3ab35cf
commit 58cb1fec71
4 changed files with 1131 additions and 2 deletions
+27
View File
@@ -56,6 +56,33 @@
//! bug/fix story). `river_cells`/`mouths`/`attractors` counts unchanged by
//! this second re-pin (93/3/256) — purely the new parallel array, 3 non-
//! placeholder entries (one per real mouth).
//!
//! **Third deliberate re-pin (T-1185, D-227 amendment (4) — basin-outlet →
//! D8 river-network wiring):** `run_layer1`/`run_layer1_with_moisture` now
//! extends the D8-extracted `RiverNetwork` with every `BasinOutcome::
//! Overflow` basin's `outlet_path` as new river cells (the endorheic cue:
//! outflow-course PRESENCE). On this fixture (GJ1c, 256×128 downsample,
//! `moisture_q=55` — `run_cascade_from_heightmap`'s `body_params: None`
//! path), 51 of the working grid's 53 real basins classify `Overflow`;
//! their outlets add exactly **50 new river cells** (`river_cells`
//! 93→143 — one basin's single new cell coincides with a cell another
//! basin's outlet already added, correctly deduplicated). `attractors`
//! (256) and `drainage_basins` are UNCHANGED — the extension runs strictly
//! after `features::extract_attractors`, by design, so basin-outlet cells
//! never perturb geographic attractor placement. `mouths`/`confluences`
//! also unchanged (T-1185 never rewrites those arrays, only appends to
//! `river_cells`/`river_class`/`river_downstream`/`river_seaward`). Every
//! appended cell on this real body carries `river_downstream =
//! RIVER_DOWNSTREAM_EDGE_DRAIN` (9) — verified separately (a scratch probe,
//! not committed) that all 51 real `Overflow` basins here have a
//! length-2 `outlet_path` (`[spill_cell, terminus]`) resolving to
//! `DownstreamTarget::OpenSpillway`, the dominant real-world pattern on
//! this body (most basins spill onto immediately-adjacent open ground
//! rather than carving a long channel to the sea) — not a bug or an
//! unexercised code path; the interior-D8-direction branch (0–7) and the
//! `RIVER_DOWNSTREAM_MOUTH` terminus branch are both exercised by the
//! dedicated `hydrology_equilibrium`/`layer1` unit tests instead, which use
//! synthetic fixtures shaped to hit those specific branches.
use std::path::PathBuf;
+501 -1
View File
@@ -8151,6 +8151,206 @@
[
124,
239
],
[
1,
100
],
[
1,
138
],
[
7,
195
],
[
7,
204
],
[
10,
69
],
[
14,
28
],
[
14,
48
],
[
14,
173
],
[
19,
180
],
[
25,
152
],
[
21,
166
],
[
17,
200
],
[
17,
6
],
[
20,
181
],
[
16,
46
],
[
17,
93
],
[
17,
127
],
[
19,
224
],
[
21,
232
],
[
33,
255
],
[
27,
104
],
[
29,
15
],
[
31,
61
],
[
27,
236
],
[
30,
138
],
[
31,
10
],
[
34,
136
],
[
35,
155
],
[
37,
72
],
[
39,
63
],
[
41,
235
],
[
44,
122
],
[
51,
242
],
[
52,
1
],
[
50,
108
],
[
57,
41
],
[
56,
64
],
[
57,
216
],
[
62,
42
],
[
70,
232
],
[
74,
229
],
[
74,
231
],
[
92,
213
],
[
88,
38
],
[
96,
88
],
[
101,
214
],
[
114,
41
],
[
115,
59
],
[
117,
221
],
[
124,
24
]
],
"river_class": [
@@ -8246,6 +8446,56 @@
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0
],
"river_downstream": [
@@ -8341,7 +8591,57 @@
5,
9,
2,
8
8,
9,
9,
9,
9,
9,
9,
9,
9,
9,
9,
9,
9,
9,
9,
9,
9,
9,
9,
9,
9,
9,
9,
9,
9,
9,
9,
9,
9,
9,
9,
9,
9,
9,
9,
9,
9,
9,
9,
9,
9,
9,
9,
9,
9,
9,
9,
9,
9,
9,
9
],
"river_seaward": [
[
@@ -8715,6 +9015,206 @@
[
125,
240
],
[
0,
0
],
[
0,
0
],
[
0,
0
],
[
0,
0
],
[
0,
0
],
[
0,
0
],
[
0,
0
],
[
0,
0
],
[
0,
0
],
[
0,
0
],
[
0,
0
],
[
0,
0
],
[
0,
0
],
[
0,
0
],
[
0,
0
],
[
0,
0
],
[
0,
0
],
[
0,
0
],
[
0,
0
],
[
0,
0
],
[
0,
0
],
[
0,
0
],
[
0,
0
],
[
0,
0
],
[
0,
0
],
[
0,
0
],
[
0,
0
],
[
0,
0
],
[
0,
0
],
[
0,
0
],
[
0,
0
],
[
0,
0
],
[
0,
0
],
[
0,
0
],
[
0,
0
],
[
0,
0
],
[
0,
0
],
[
0,
0
],
[
0,
0
],
[
0,
0
],
[
0,
0
],
[
0,
0
],
[
0,
0
],
[
0,
0
],
[
0,
0
],
[
0,
0
],
[
0,
0
],
[
0,
0
],
[
0,
0
],
[
0,
0
]
]
}