feat(simulation): lakes from settled hydrology (D-227, T-1184) #200

Closed
jpmschweitzer wants to merge 0 commits from t1184-hydrology into main
Owner

Summary

Productionizes the T-1177 equilibrium solver and sources MorphologyZone::Lake from it, per the D-227 lakes amendment and D-255(f) mechanism B. run_layer1 solves hydrology once per body (~24ms) and carries it as TerrainAnalysis.hydrology; run_layer1_with_moisture threads the real body moisture ceiling. At derive time a gridunit is Lake when the bilinear-sampled settled water surface exceeds the bilinear-sampled ground — the continuous comparison, so lake edges refine with rung like coastlines. The old ocean-fraction heuristic survives byte-identically as the no-solve fallback.

Scope notes

  • The keep-always rung-0 tier does not exist until T-1181 — hydrology rides TerrainAnalysis and lands in that tier for free (lead-accepted deviation, recorded on the ticket).
  • No endorheic bit: the drains-vs-closed cue is T-1185 outlet-course presence (honest sequencing per D-227 amendment (4)). Basin spill points are computed and currently discarded — cheap to extend at the same call site.
  • Zero new wire bytes; static classification, distinct from the sim-state flooded plane.
  • Known merge seam with the parallel t1181-step-canvas branch: TerrainAnalysisCache::get_or_derive gained a body_params parameter (second-to-land rebases).

Verification

  • Acceptance: lake_classification_cache_hit_equals_cache_miss (independent double-solve, byte-identical zones, non-vacuous Lake hit) + hydrology determinism tests.
  • Golden fidelity hardened in lead review: the window golden fixture now builds TerrainAnalysis through the production entry point per body, and a dedicated lake_bowl golden body pins the hydrology-sourced Lake path (morphology 1 at ocean_fraction_q 0 — provably not the heuristic). The 108 pre-existing golden rows are byte-identical (pure append). believability.json moved one lake-shaped line (GJ338Bd voxel_relief_m 27->28, traced). river_course + derivation-harness goldens unchanged.
  • Full gate green: fmt, clippy -D warnings, 1904 lib + all integration binaries, deny. Paired-set screenshot eyeball (incl. a lake-targeted window capture) in flight — merge waits on its PASS.

Unblocks T-1185 (basin-outlet -> course-network wiring).

🤖 Generated with Claude Code

## Summary Productionizes the T-1177 equilibrium solver and sources MorphologyZone::Lake from it, per the D-227 lakes amendment and D-255(f) mechanism B. run_layer1 solves hydrology once per body (~24ms) and carries it as TerrainAnalysis.hydrology; run_layer1_with_moisture threads the real body moisture ceiling. At derive time a gridunit is Lake when the bilinear-sampled settled water surface exceeds the bilinear-sampled ground — the continuous comparison, so lake edges refine with rung like coastlines. The old ocean-fraction heuristic survives byte-identically as the no-solve fallback. ## Scope notes - The keep-always rung-0 tier does not exist until T-1181 — hydrology rides TerrainAnalysis and lands in that tier for free (lead-accepted deviation, recorded on the ticket). - No endorheic bit: the drains-vs-closed cue is T-1185 outlet-course presence (honest sequencing per D-227 amendment (4)). Basin spill points are computed and currently discarded — cheap to extend at the same call site. - Zero new wire bytes; static classification, distinct from the sim-state flooded plane. - Known merge seam with the parallel t1181-step-canvas branch: TerrainAnalysisCache::get_or_derive gained a body_params parameter (second-to-land rebases). ## Verification - Acceptance: lake_classification_cache_hit_equals_cache_miss (independent double-solve, byte-identical zones, non-vacuous Lake hit) + hydrology determinism tests. - Golden fidelity hardened in lead review: the window golden fixture now builds TerrainAnalysis through the production entry point per body, and a dedicated lake_bowl golden body pins the hydrology-sourced Lake path (morphology 1 at ocean_fraction_q 0 — provably not the heuristic). The 108 pre-existing golden rows are byte-identical (pure append). believability.json moved one lake-shaped line (GJ338Bd voxel_relief_m 27->28, traced). river_course + derivation-harness goldens unchanged. - Full gate green: fmt, clippy -D warnings, 1904 lib + all integration binaries, deny. Paired-set screenshot eyeball (incl. a lake-targeted window capture) in flight — merge waits on its PASS. Unblocks T-1185 (basin-outlet -> course-network wiring). 🤖 Generated with [Claude Code](https://claude.com/claude-code)
jpmschweitzer added 2 commits 2026-07-25 02:28:37 +02:00
Productionizes the T-1177 equilibrium solver: run_layer1 now solves
hydrology once per body (~24ms, mirrors drainage::analyze) and carries
it as TerrainAnalysis.hydrology; run_layer1_with_moisture threads the
real body moisture ceiling (extracted derive_moisture_ceiling_q), with
the T-1177 population-survey default as fallback. The resident rung-0
global tier does not exist yet (T-1181's scope) — hydrology rides
TerrainAnalysis and lands in that tier for free when it is built
(deviation recorded on the ticket).

MorphologyZone::Lake is now sourced from the settled solver at derive
time: a gridunit is Lake when bilinear-sampled filled surface exceeds
bilinear-sampled original elevation at the sample's own (px, py) — the
continuous comparison, so lake edges refine with rung like coastlines;
never a discrete basin-cell projection. The gate sits strictly between
OpenOcean (>= 80) and the old ocean_fraction heuristic (>= 60), which
survives as the derive-fresh fallback when no solve is attached —
byte-identical to pre-T-1184 output in that case. Static
classification, distinct from the sim-state flooded plane; no
endorheic bit (the drains-vs-closed cue is T-1185's outlet-course
presence, per the D-227 amendment (4) sequencing). Zero new wire
bytes.

Acceptance: lake_classification_cache_hit_equals_cache_miss (solve
twice independently, byte-identical zones, non-vacuous Lake hit) plus
hydrology determinism tests. Golden fidelity: the window golden
fixture now builds TerrainAnalysis through the production entry point
(run_layer1_with_moisture, per-body), and a dedicated lake_bowl golden
body pins the hydrology-sourced Lake path (morphology 1 at
ocean_fraction_q 0 — provably not the heuristic); the 108 pre-existing
golden rows are byte-identical (pure append). believability.json moved
by one lake-shaped line (GJ338Bd voxel_relief_m 27->28, a correctly
reclassified lake district leaving the dry-relief sample set).
river_course and derivation-harness goldens unchanged. Full suite:
2114 passed.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
jpmschweitzer added 2 commits 2026-07-25 02:44:04 +02:00
Hoshe finding 1: dropping HydrologySample.elevation was PROVEN unsafe
(TerrainAnalysis.elev_pct is a rank percentile, not raw elevation;
HydrologyResult carries no elevation) — the copy stays, and the truth
moves into the docs instead: gen_queue's TerrainAnalysisCache sizing
comment corrected to real 512x256 working-grid numbers (~1.57 ->
~2.62 MB/entry, capacity-8 worst case ~21 MB), clone-on-hit cost
documented, byte-safety proof recorded on HydrologySample itself.
Arc<TerrainAnalysis> follow-up filed as T-1187.

Hoshe finding 2: the endorheic-split test now asserts the bowl basin's
BasinOutcome actually diverges (Endorheic at moisture 0, Overflow at
100, straddling ENDORHEIC_MOISTURE_CEILING=60) plus basin-count sanity
— mutation-verified by stubbing is_endorheic and watching it fail.

Doc/test-only round: goldens byte-unchanged, full suite 2114 green.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Author
Owner

Review: t1184-hydrology -> main (type: code)

Tyre (Architecture): APPROVE

Full D-record conformance verified directly: the continuous filled-surface comparison with no discrete basin-cell lookup anywhere, D-239 §6 vocabulary not widened, no endorheic bit or wire change leaked from the superseded workshop drafts (grepped), static classification with no TTL coupling, D-255(f) mechanism B shape exact, and the one-derive-core (D-256) respected — batch inherits the lake gate through the shared core, no second sampling path. The lead-accepted scope deviation (solve inside run_layer1, resident tier deferred to T-1181) ruled architecturally sound and correctly recorded. The golden-fixture change is a pure strengthening of the T-1162 charter. Independently re-ran the new tests and both golden regressions. No comments.

Hoshe (Code Quality): REQUEST_CHANGES (2 findings — both fixed, see author response)

Core work verified solid under direct inspection: gate ordering (OpenOcean >= 80 untouched, lake strictly ahead of the >= 60 heuristic), None-fallback byte-identity, moisture threading byte-identical, D-010 determinism (bilinear comparison mirrors the solver's own strict test), and the lake_bowl fixture "genuinely rigorous" (pure-append golden, non-vacuous Lake/rim boundary).

# File Issue
1 server/src/atlas/features.rs (HydrologySample.elevation) + gen_queue.rs:205-212, :716 Unbudgeted footprint: full elevation copy stored per TerrainAnalysis, deep-cloned on every cache HIT; the LRU's load-bearing sizing comment left materially wrong.
2 server/src/atlas/layer1.rs (endorheic-split test) Test name promises "changes endorheic split" but only asserts extent equality — the split itself never checked; a regression making is_endorheic dead code would pass silently.

Author response — both fixed in 4ef79b6b4 + b222cec9b (fmt)

Finding 1: the preferred fix (drop the redundant copy) was investigated and PROVEN unsafe — TerrainAnalysis.elev_pct is a rank-percentile transform, not raw elevation, and HydrologyResult carries no elevation field; comparing filled against any existing TA field would be a silent unit mismatch. The copy therefore stays, with the truth moved into the docs: the gen_queue sizing comment corrected to real 512x256 working-grid numbers (~1.57 -> ~2.62 MB/entry, x1.67; capacity-8 worst case ~21 MB), clone-on-hit documented, and the byte-safety proof recorded on HydrologySample itself. The Arc refactor Hoshe's finding points toward is filed as T-1187.

Finding 2: the test now re-solves and asserts the bowl basin's BasinOutcome diverges — specifically Endorheic at moisture 0 and Overflow at 100 (straddling ENDORHEIC_MOISTURE_CEILING=60), plus basin-count sanity. Mutation-verified: stubbing is_endorheic makes the test fail loudly; the stub was cleanly reverted (zero residual diff).

Round was doc/test-only: all three goldens byte-unchanged, full suite 2114 green, gate green on re-push.

Verdict: CHANGES REQUESTED -> resolved; merge pending the lake-targeted screenshot eyeball (in flight)

Process context: full pre-push gate green twice (initial + fix round); paired-set screenshot protocol running with a dedicated lake-window capture on a known filled basin.

## Review: t1184-hydrology -> main (type: code) ### Tyre (Architecture): APPROVE Full D-record conformance verified directly: the continuous filled-surface comparison with no discrete basin-cell lookup anywhere, D-239 §6 vocabulary not widened, no endorheic bit or wire change leaked from the superseded workshop drafts (grepped), static classification with no TTL coupling, D-255(f) mechanism B shape exact, and the one-derive-core (D-256) respected — batch inherits the lake gate through the shared core, no second sampling path. The lead-accepted scope deviation (solve inside run_layer1, resident tier deferred to T-1181) ruled architecturally sound and correctly recorded. The golden-fixture change is a pure strengthening of the T-1162 charter. Independently re-ran the new tests and both golden regressions. No comments. ### Hoshe (Code Quality): REQUEST_CHANGES (2 findings — both fixed, see author response) Core work verified solid under direct inspection: gate ordering (OpenOcean >= 80 untouched, lake strictly ahead of the >= 60 heuristic), None-fallback byte-identity, moisture threading byte-identical, D-010 determinism (bilinear comparison mirrors the solver's own strict test), and the lake_bowl fixture "genuinely rigorous" (pure-append golden, non-vacuous Lake/rim boundary). | # | File | Issue | |---|------|-------| | 1 | server/src/atlas/features.rs (HydrologySample.elevation) + gen_queue.rs:205-212, :716 | Unbudgeted footprint: full elevation copy stored per TerrainAnalysis, deep-cloned on every cache HIT; the LRU's load-bearing sizing comment left materially wrong. | | 2 | server/src/atlas/layer1.rs (endorheic-split test) | Test name promises "changes endorheic split" but only asserts extent equality — the split itself never checked; a regression making is_endorheic dead code would pass silently. | ## Author response — both fixed in 4ef79b6b4 + b222cec9b (fmt) **Finding 1**: the preferred fix (drop the redundant copy) was investigated and PROVEN unsafe — TerrainAnalysis.elev_pct is a rank-percentile transform, not raw elevation, and HydrologyResult carries no elevation field; comparing filled against any existing TA field would be a silent unit mismatch. The copy therefore stays, with the truth moved into the docs: the gen_queue sizing comment corrected to real 512x256 working-grid numbers (~1.57 -> ~2.62 MB/entry, x1.67; capacity-8 worst case ~21 MB), clone-on-hit documented, and the byte-safety proof recorded on HydrologySample itself. The Arc<TerrainAnalysis> refactor Hoshe's finding points toward is filed as **T-1187**. **Finding 2**: the test now re-solves and asserts the bowl basin's BasinOutcome diverges — specifically Endorheic at moisture 0 and Overflow at 100 (straddling ENDORHEIC_MOISTURE_CEILING=60), plus basin-count sanity. Mutation-verified: stubbing is_endorheic makes the test fail loudly; the stub was cleanly reverted (zero residual diff). Round was doc/test-only: all three goldens byte-unchanged, full suite 2114 green, gate green on re-push. ### Verdict: CHANGES REQUESTED -> resolved; merge pending the lake-targeted screenshot eyeball (in flight) *Process context: full pre-push gate green twice (initial + fix round); paired-set screenshot protocol running with a dedicated lake-window capture on a known filled basin.*
Author
Owner

Screenshot eyeball: PASS — merge clear

Paired-set protocol (cold release server, main vs branch, fixed scripted navigation), capture sets at .cache/screenshots/t1184-{main,eyeball}/:

Pair Surface Diff (AE) Verdict
a Cold-start staged frames x3 0 clean start, tiles arrive
b GJ380c continuity: orbital x2 + district/quarter windows at (1695,-1844) 0 no drift where no basin exists
c GJ338Bd lake window at true DistrictPos (13652,4360), district + quarter 1,967,180 (99.997%) the feature: entire 65.5 km / 16.4 km window flips dry plains (main) -> water (branch), with ~2,600 distinct colors of real bathymetric shading (not a flat fill); zoom refinement coherent across the rung boundary
d GJ338Bd whole-body orbital 20,936 (1.06%) new lake dots appear across multiple continents — global lake coverage, not just the probed basin

Lake coordinates were resolved from an aliveness_probe hit at ocean_fraction_q=0 (heuristic provably cannot fire there — hydrology-only classification) via the D-256 survey-to-district bridge. T-1186 (known latitude bug, ticketed) is shared identically by both runs and cannot pollute the pair diff. Both checkouts verified clean post-run; temp drivers deleted; no lingering processes.

Merging.

## Screenshot eyeball: PASS — merge clear Paired-set protocol (cold release server, main vs branch, fixed scripted navigation), capture sets at `.cache/screenshots/t1184-{main,eyeball}/`: | Pair | Surface | Diff (AE) | Verdict | |---|---|---|---| | a | Cold-start staged frames x3 | 0 | clean start, tiles arrive | | b | GJ380c continuity: orbital x2 + district/quarter windows at (1695,-1844) | 0 | no drift where no basin exists | | c | **GJ338Bd lake window at true DistrictPos (13652,4360), district + quarter** | 1,967,180 (99.997%) | **the feature**: entire 65.5 km / 16.4 km window flips dry plains (main) -> water (branch), with ~2,600 distinct colors of real bathymetric shading (not a flat fill); zoom refinement coherent across the rung boundary | | d | GJ338Bd whole-body orbital | 20,936 (1.06%) | new lake dots appear across multiple continents — global lake coverage, not just the probed basin | Lake coordinates were resolved from an `aliveness_probe` hit at `ocean_fraction_q=0` (heuristic provably cannot fire there — hydrology-only classification) via the D-256 survey-to-district bridge. T-1186 (known latitude bug, ticketed) is shared identically by both runs and cannot pollute the pair diff. Both checkouts verified clean post-run; temp drivers deleted; no lingering processes. Merging.
jpmschweitzer closed this pull request 2026-07-25 03:11:56 +02:00

Pull request closed

This pull request cannot be reopened because the branch was deleted.
Sign in to join this conversation.
No Reviewers
No labels
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: jpmschweitzer/settled-reach#200