Commit Graph
599 Commits
Author SHA1 Message Date
jpmschweitzerandClaude Fable 5 de8bcf4ebb fix(simulation): PR #215 review fixes — hop-unit surcharge, D-210 amendment, citation + gap
The surcharge is now COASTAL_ACCESS_SURCHARGE_HOPS_PER_RING=1 added
directly to length_cells (a pure hop count) — the old cost-unit
constant div_ceil'd through MIN_CELL_COST silently produced 4 hops per
ring, worst-case +24 (double the waypoint threshold) for physically
short edges; worst case is now 6. A formula-pinning test asserts both
the arithmetic and the constant. GJ251c's repro tightened to the
documented 2 edges. The always-land citation now points at the real
guarantee (features.rs::extract_attractors, D-209) — and checking the
D-211 Phase-4 synthetic-overflow path exposed a real gap: it has no
ocean-mask guard at all (T-1206 filed); documented, not papered over.
D-210 gains a dated amendment recording the surrogate-anchor-at-cost
carve-out and the relaxation-over-nudge adjudication. The bare 100
dependency dissolved with the unit fix. Edge counts on both repro
bodies verified unchanged (reachability was never affected).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-26 13:34:43 +02:00
jpmschweitzerandClaude Fable 5 0039bda184 style(simulation): cargo fmt
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-26 13:19:02 +02:00
jpmschweitzerandClaude Fable 5 1ec5cb4fd5 fix(simulation): clippy — erasing_op row-major literals, range-contains in T-1116 tests
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-26 13:16:54 +02:00
jpmschweitzerandClaude Fable 5 8247ba1ded fix(simulation): coastal-cell routing relaxation — roads return to water-heavy bodies (T-1116)
A routing cell folds up to 64 native pixels, so a coastal settlement's
own land pixel (placement always filters !ocean_mask) can sit inside a
water-majority cell that RouteGrid marks IMPASSABLE — and astar()
hard-returned None for every pair touching it, zeroing whole road
graphs (GJ251c: all 3 placements; GJ380c: Sethvale). The fix relaxes
only the start/goal anchor lookup: nearest_passable_cell (ring BFS,
deterministic row-major tie-break, bounded at COASTAL_ANCHOR_MAX_RING=3)
finds a surrogate anchor and prices it via COASTAL_ACCESS_COST_PER_RING
— a short, honestly-costed access road, never a free water crossing.
IMPASSABLE semantics untouched everywhere else (D-210 transit costs,
open-ocean). The placement-nudge alternative was rejected: it would
move Layer-3 state D-211 promises is seed-derived, for no gain.

Boundary semantics pinned by test: exactly-half-water cells stay
passable (strict-majority rule); a settlement with no passable cell
within the search ring degrades to an isolated 0-edge node, never a
panic or fabricated route. Failing-first repro on real bodies
(GJ251c 0->2 edges, GJ380c 0->1) via the real cascade entry point,
plus same-seed determinism. Full cargo test green; believability and
cascade goldens verified unaffected (Layer-2-only change).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-26 13:05:35 +02:00
jpmschweitzerandClaude Fable 5 493cd716b6 style(simulation): gate bounce — cargo fmt in fix-round fixture
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-25 19:49:56 +02:00
jpmschweitzerandClaude Fable 5 5d1935f8fc style(simulation): gate bounce — clippy identity_op in drainage fixtures
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-25 19:45:18 +02:00
jpmschweitzerandClaude Fable 5 b165c8038d fix(simulation): PR #210 review round — guard boundary, live oasis pinning, unreachability proof (T-964)
Guard becomes land_districts <= 1 (both reviewers converged — a lone
island definitionally cannot show two distinct directions; same
nothing-to-vary condition one value short), with a lone-island vacuous-
pass fixture; golden confirmed untouched. Oasis scaling adjudicated as
LIVE, not future — GRID_W is already 1024 on main, so ring iterations
change 2/4 -> 4/8 today: extracted a pure oasis_ring_iterations()
helper pinned by tests at both 512 and 1024, and traced exactly why the
determinism hash stayed green (it reads only elevation; the rings touch
only biome — a genuinely different array, not a coincidence). The
drainage merge-logic question answered byte-precisely: zero logic
changed vs main (comment-only diff) — and the deeper dig PROVED the
'isolated basin with another basin to escape to' branch is
mathematically unreachable for any connected grid (contracting vertex
groups of a connected graph cannot disconnect it), so the comment now
states that instead of narrating a divergence that never fires; two
direct merge-target tests added regardless. Wrap test renamed to what
it actually pins (non-wrap-awareness). D-010 docstring softened to
same-process purity, naming the cascade golden as the cross-run layer.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-25 19:35:09 +02:00
jpmschweitzerandClaude Fable 5 272d3781d8 style(simulation): gate bounce — clippy unnecessary_cast in test fixture
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-25 19:04:47 +02:00
jpmschweitzerandClaude Fable 5 b929aa27b0 style(simulation): gate bounce — cargo fmt
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-25 19:01:51 +02:00
jpmschweitzerandClaude Fable 5 e141a595b1 feat(simulation): believability gate learns basin-direction variety (T-964, D-245)
A real D-245 gate-shape strengthening, not just a test: the D-256/T-1174
finding proved the believability golden byte-identical under a total
all-North basin_direction collapse — every scalar contrast field is
structurally blind to the one field that regressed. ContrastMetrics
gains land_districts and basin_directions_distinct (both over ALL
districts, no new derive calls — the evidence-backed pick over the
voxel-transect proxy, which washes out at production sample density),
and evaluate_criteria gains 'basin direction variety': pass when
land_districts == 0 (the drained-body guard — an all-ocean body has no
cells that can cast a D8 vote per the aggregator's own exclusion rule,
so a uniform default is legitimate, mirroring the file's existing
nothing-to-vary idiom) or distinct >= 2. Negative test proves the
criterion catches the land-bearing all-North regression; vacuous-pass
test proves the waterworld guard. Golden regenerated and rerun-stable;
both validation bodies (Arbour, Edict) pass at distinct=2.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-25 18:59:13 +02:00
jpmschweitzerandClaude Fable 5 f81622bbf0 test(simulation): Phase-4 hardening — deferred #953/#963 review gaps (T-964)
The verified-still-open coverage list: per-type attractor reachability
fixtures (LakeShore via enclosed depression, PassEntrance via crafted
saddle, PlainCenter via flat terrain, RiverCrossing via confluence) plus
thin_by_spacing behavior (collision, strict-< boundary, equirectangular
column wrap); heightmap 8-bit decode, sea_level passthrough, downsample
identity and zero-target early-return; drainage area_pct bit-for-bit
determinism plus the isolated-basin-fallback divergence comment (Tyre
N1, citing the pre-#953 behavior it deliberately departs from); the
layer1 mountain-branch pairing test (investigated first — the cascade
test supplies a mountain pool but only ever asserted river counts, a
genuine gap); an importer idempotency test covering atlas_city_names
AND atlas_feature_names plus the Sol exemption, wired into
make test-tooling; and the oasis_water dilation radius scaled by
GRID_W/512 (Tyre N2, hash-stable). One stale item dropped per the
refinement trim (test_sim_determinism wiring — already done).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-25 18:58:53 +02:00
jpmschweitzerandClaude Fable 5 077d787c4a fix(simulation): one shared invent_coastal_position — PR #208 review round (T-1160)
Hoshe found the concrete residual: the hand-copied driver block called
derive_temperature_c unconditionally where invent_primitives prefers the
lapse-adjusted region baseline on non-airless bodies — driver_temp feeds
glaciation/moisture into the warp magnitude, so orbital displacement
could still differ from District at the same position (the ticket's
defect class, one step upstream); the copy structurally couldn't branch
right because region_baseline_at_district was computed after it. Tyre
demanded the structural cure: steps 1-3 now live in ONE shared helper
(invent_coastal_position -> warped position + CoastCharacter);
invent_primitives composes helper + detail-scatter; the orbital path
hoists the baseline and makes a single helper call. The audit test's own
'District-style' side turned out to be a THIRD copy carrying the same
bug — rewired to the real helper (raw pre-fix side untouched as the
historical baseline; refreshed: 5.01% disagreement, mean 5,957.9 m,
748.9 ns/cell). Golden verified byte-identical under forced regen, with
the reason traced: the wire temperature never flowed through the buggy
internal branch, and the fixture's probe positions cross no discrete
boundary — the 267-body audit is the instrument that sees the drift.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-25 17:22:16 +02:00
jpmschweitzerandClaude Fable 5 71f70f035e style(simulation): gate bounce — cargo fmt
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-25 16:53:41 +02:00
jpmschweitzerandClaude Fable 5 8da9670e0f feat(simulation): feature-name pipeline wired + legacy window_granularity u32 retired (T-1169, T-1159)
One commit for two tickets whose changes share the bridge/plugin
plumbing files. T-1169 connects the three dormant feature-name pieces:
atlas_feature_names populated at regen (17,891 rows — 15,190 mountain,
2,701 river — via populate_atlas_feature_names mirroring the city-names
importer; systems.db regenerated, stamp fresh), attach_feature_names
wired into the cascade's Topography block with name pools threaded
DB-free through AnalyzeBody (D-225 pattern) and assignments stored on
Layer1Output/BodyWorldState for future consumers, and a
FeatureNamesRequest/Response read proxy as the bridge's 7th tagged
envelope (D-236 pattern, both SimBridge impls). Client label DRAW is
deliberately NOT here — implementation proved both river and mountain
labels need a wire-carried position (the pool is position-free; course
polylines aren't correlated with the named attractors by construction) —
deferred to T-1195's single design pass. cascade_layer1 golden re-pinned
(additive feature_names field).

T-1159 retires the legacy u32 granularity field fully shadowed by
window_granularity_v2: AtlasLayerRequest.window_granularity,
DistrictWindowLayer.granularity echo, the u32::MAX sentinel, and
resolve_window_granularity are gone server-side; client encode paths and
the caller-less atlas_window_cache legacy key component dropped;
msgpack fixtures regenerated; the T-1150 aliasing regression test now
drives through the surviving enum field. The district_window carrier
itself survives byte-compatible per D-255(c).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-25 16:10:27 +02:00
jpmschweitzerandClaude Fable 5 befdb689c1 fix(simulation): orbital rung applies coast_warp_px — one coastline at every rung (T-1160)
The Global/Region rungs sampled the heightmap ocean mask raw while every
finer rung samples it at the coast-warped position — a structurally
different coastline at the orbital-to-district seam. Audited on all 267
real body heightmaps at region spacing, coastal band only: 5.01%
land/ocean classification disagreement (2,911 of 58,073 cells), mean
displacement ~6.0 km, max ~18.9 km. Fork taken: APPLY the warp —
derive_orbital_at_metres now runs invent_primitives' steps 1-3 (driver
climate -> coast character -> coast_warp_px) before sampling, still
skipping detail-scatter (its octave ceiling, 32.8 km, is below region
spacing; the WARP's octaves reach 262 km, which is why skipping it was
wrong). Cost measured: ~784 ns/cell added (~15 ms on an Earth-class
Global canvas; low hundreds of ms parallel at the 8.3M-cell ceiling).
The ignored audit test preserves the pre-fix baseline for the record.
Golden re-pinned — region rows only, district/quarter byte-identical.
project.yaml 0.4.2 -> 0.4.3: orbital canvas bytes changed, client disk
caches must miss. Awaiting Araminta's review-seat sign-off per ticket.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-25 16:09:46 +02:00
jpmschweitzerandClaude Fable 5 4a9567c669 style(simulation): gate bounce — fmt wrap + clippy needless_range_loop
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-25 14:24:45 +02:00
jpmschweitzerandClaude Fable 5 39f0fd8c51 fix(simulation): lake_margin_q normalizes per basin — full-range depth gradient (T-1188)
The PR #206 eyeball caught what every numeric gate passed: the depth
signal was visually flat on both test lakes (GJ1c lmq=0 across the whole
basin; GJ338Bd 0-13 of 100). Two compounding causes: a fixed absolute
ceiling (one body's p90 cell depth) compressing skewed depth
distributions into single digits, and heightmap-pitch depth variation
being sub-texel-tiny within most basins. lake_margin_q is now
depth / the basin's own maximum settled depth: HydrologyResult grows
basin_max_depth_scaled (computed in solve() from existing basin_cells
membership, broadcast per basin), threaded through
HydrologySample.basin_max_depth, normalized in lake_from_hydrology_at
with a degenerate-basin epsilon guard (a genuinely uniform pond shades
flat — honest, not forced). Lake EXISTENCE (filled > original) is
untouched — only tone changes. Measured at district spacing:
GJ1c min=0 p50=33 max=84; GJ338Bd min=8 p50=38 max=70 — full-range
shore-to-deep ramps on both. No perceptual curve added: the linear
per-basin ramp is already well-quartiled. project.yaml 0.4.1 -> 0.4.2
(0.4.1-tagged canvases carrying flat-lmq semantics reached real disk
caches during eyeball runs and must miss). Acceptance gates green;
zero golden churn (lake_margin_q not captured by either golden shape).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-25 14:23:11 +02:00
jpmschweitzerandClaude Fable 5 b39dd49950 docs(simulation): update step_canvas row-space doc — T-1186 is fixed (PR #206 review)
Hoshe's review finding: the build_step_canvas row-space convention block
still described region_centre_latitude_deg as pole-anchored/bugged and
said 'T-1186 stays open' — both false after this PR's own first commit.
Rewritten to reflect the fixed state; the deliberate signed-convention
rationale and the layer_proxy deferral (still true, still T-1181's scope)
are preserved.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-25 13:44:35 +02:00
jpmschweitzerandClaude Fable 5 dec5b0bc43 feat(simulation): lake_margin_q depth band — lake shorelines gain gradient vocabulary (T-1188)
Lake edges rendered as hard step-edges while ocean coasts got multi-tone
transition bands: every coastal-transition morphology gate keys on
ocean_fraction_q, definitionally 0 inside a lake basin (hypothesis (b)
of the ticket; (a) disproven first — a shoreline-crossing sweep at
2048/512/128m plus a 10m fine sweep all land on the same continuous
crossing, so positional refinement was never broken). New
DistrictProfile.lake_margin_q (0-100 settled-hydrology depth band, from
the same bilinear filled/elevation pair the lake test already samples;
ceiling calibrated just above the observed p90 depth on GJ338Bd's 5,043
flooded cells), threaded through both derive paths onto
EncodedStepCanvas (serde-default for shape tolerance) and down the
client: protocol decode, terrain-layer plane, colorize shades Lake cells
by depth band instead of elev_q (bedrock-under-water, the wrong signal).
project.yaml 0.4.0 -> 0.4.1: the new wire field must invalidate the
client disk cache via its version tag (T-1183's D-192 mechanism).
Acceptance gates green with the new field (lossless round-trip,
cache-hit==cache-miss, every rung).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-25 13:08:44 +02:00
jpmschweitzerandClaude Fable 5 07f0fa307f fix(simulation): region baseline latitude — equator-anchored signed rows (T-1186)
region_centre_latitude_deg mapped row 0 to the north pole with lat_frac
clamped [0,1] while the derive core floor-divides equator-anchored signed
world metres — every northern-hemisphere region clamped to +90 (polar
everywhere) and the southern hemisphere read as compressed northern
tropics. Now mirrors the derive core's exact inverse mapping (lat_frac =
centre_y/meridian clamped [-0.5,0.5], lat = -frac*180). The ticket's
in-the-wild datapoint flips as predicted: GJ338Bd region (136,43), old
baseline +13.94N/26.8C -> new -76.06S/10.3C; the 76S district cell now
derives Lake/2.07C/Light glaciation. Goldens regenerated (believability +
window derivation, stable on rerun); two region_profile unit tests
repositioned — their probe coordinates meant different places under the
old convention. step_canvas rung-0 already used the correct signed
convention; layer_proxy's pole-anchored pseudo-grid stays deferred to
T-1181's rung-0 rebuild per D-256(f).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-25 13:08:26 +02:00
jpmschweitzerandClaude Fable 5 1d2cac9e65 fix(simulation): PR #202 review round — spill cell always wired + golden truth
Hoshe finding 1 (live-firing on GJ1c: 2 spill collisions + 1 i==1
collision among 51 Overflow basins): adjacency adjudicated
INSUFFICIENT for the cue — a course's visible anchor is its upstream
cell, so nothing pre-existing belongs to the lake unless wired. The
spill cell (outlet_path[0]) now always gets a real entry: appended
when new, OVERWRITTEN IN PLACE when it collided with an existing river
cell (append would duplicate edge_id; the hydrology solve is the more
authoritative downstream answer for that cell than flat D8
extraction). Interior stop-on-collision stays, now provably safe.
Internal lookup is a dense Vec<Option<usize>>, never iterated (D-010).
Two non-vacuous regression tests prove the cue through build_edges
output; end-to-end on GJ1c all 51 Overflow basins now build a readable
edge (was: one silently missing).

Hoshe finding 2: both doc sites now state the fallback-vs-production
split explicitly (fallback moisture 55: 51/2; production GJ1c moisture
80: 53/53 all-Overflow) — the golden's Endorheic pair is a
fallback-constant artifact, not a fact about GJ1c.

Golden re-regenerated: river_cells 143->192, position-identity diff
purely additive (zero removed, one legitimate in-place overwrite at
the spill-collision cell); attractors/basins/mouths/confluences
byte-identical. Suites: hydrology 26/26, full lib 1943, cascade_golden
1/1, window goldens + believability untouched green.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-25 09:04:54 +02:00
jpmschweitzerandClaude Fable 5 58cb1fec71 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>
2026-07-25 08:40:07 +02:00
jpmschweitzerandClaude Fable 5 8af28f317b fix(simulation): PR #201 review round — wire extent clamp + coalescing tests
Hoshe finding 1: StepCanvasRequest.extent is no longer wire-trusted —
clamp_step_canvas_extent enforces the D-255(b) canvas budget at the
request boundary (per-axis cap 3840 defeating u32::MAX before any
multiplication, then an aspect-preserving total-cell ceiling at the
measured 3840x2160 = 8,294,400-cell workshop budget), mirroring the
legacy carrier's clamp_window_n_v2 discipline; the Global rung ignores
the wire extent entirely. StepCanvasResponse gains the extent echo
field so a client can detect the clamp (the DistrictWindowLayer.n
precedent — a pre-existing gap closed in passing, recorded on the
ticket for T-1182). Seven new tests including an end-to-end u32::MAX
request proving actual allocation respects the cap.

Hoshe finding 2: submit_step_canvas coalescing now has the same two
regression tests its submit_window sibling always had (same-key
collapses to one pending item, different-key does not), exercising
step_canvas_supersede_key.

Targeted suites green: 1928 lib, acceptance gate 5/5, bridge_tcp 22/22,
window_derivation_golden 6/6 byte-green.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-25 03:34:09 +02:00
jpmschweitzerandClaude Fable 5 a64701645b style(simulation): clippy nits on the step-canvas batch (gate bounce)
Two needless mutable borrows in the serve system, one spurious
markdown list marker from a doc-comment line wrap (a leading '- '
turned the whole T-1186 convention note into a lazy continuation), and
a named row/col pair replacing the identity-op grid index in the
settlement-id tie test.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-25 03:19:25 +02:00
jpmschweitzerandClaude Fable 5 ab52897d66 style(simulation): cargo fmt on the step-canvas batch
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-25 03:15:58 +02:00
jpmschweitzerandClaude Fable 5 c6f0bd6da2 fix(simulation): thread body_params through DeriveStepCanvas terrain derive
The T-1184 merge seam: TerrainAnalysisCache::get_or_derive gained a
body_params parameter (real moisture ceiling for the hydrology solve);
the DeriveStepCanvas arm now passes its own body_params so step-canvas
requests get the same hydrology-carrying TerrainAnalysis the legacy
DeriveWindow path does. Acceptance gate + window goldens green
post-merge.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-25 03:14:52 +02:00
jpmschweitzer b7f54a4de0 Merge remote-tracking branch 'origin/main' into t1181-step-canvas 2026-07-25 03:13:18 +02:00
jpmschweitzerandClaude Fable 5 cd2f342421 feat(simulation): step-canvas serving — tagged envelope (D-255, T-1181)
The D-225-discharging wire migration per D-255(c): a new
server/src/atlas/step_canvas.rs subsystem (six-rung StepCanvasRung
ladder — Global variable-extent rung 0 through Chunk 64m — the
StepCanvasRequest/StepCanvasResponse tagged envelope extending the
proven ShapeProbe discriminated-shape pattern, PNG-per-field dense +
MessagePack-native sparse encoding per the T-1179 measured table, and
both server cache tiers: the structurally keep-always GlobalTierCache
and the dual-axis StepCanvasCache with storage TTLs per rung and
SIM_STATE_TTL clock-bucket staleness per the D-227 amendment (1)
formula). Wired through bridge/{mod,tcp,local}.rs (sixth demux shape,
send_step_canvas_response mirroring the five existing senders),
gen_queue.rs (DeriveStepCanvas work item with per-connection-per-rung
coalescing, reusing the shared TerrainAnalysisCache), and plugin.rs
(serve/complete systems, lazy D-206 rung-0 population).

Acceptance gate (mandatory per D-227 amendment (3)):
tests/step_canvas_acceptance_gate.rs — cache-hit == cache-miss
byte-identical for every rung, lossless encode round-trips, cache
round-trips vs fresh derive, distinct-center sanity. 5/5 pass.

Station-spacing cap ADOPTED: course stations floored to District
spacing (2,048 m) at finer rungs — the S2-measured +38-87% chunk/block
course cost had zero display benefit at the same station density
(COURSE_STATION_SPACING_FLOOR_M).

Documented honest gaps, not shortcuts: settlement_id is a proximity
approximation (no footprint polygons exist yet); glaciation/flooded_q
sim-state planes are wire-shape-ready D-253 stubs; rung-0 uses signed
equator-anchored rows (the canonical D-256 core convention — T-1186's
wrong-latitude behavior applies unchanged and unfixed here, by
instruction).

Legacy district_window carrier byte-unchanged: window_derivation_golden
6/6 byte-identical, all district_window suites pass unmodified. Full
suite at implementation time: 2127 passed across 45 binaries.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-25 03:13:08 +02:00
jpmschweitzerandClaude Fable 5 b222cec9be style(simulation): cargo fmt on the review-round test (gate bounce)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-25 02:43:05 +02:00
jpmschweitzerandClaude Fable 5 4ef79b6b45 fix(simulation): PR #200 review round — cache sizing truth + endorheic assertion
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>
2026-07-25 02:41:55 +02:00
jpmschweitzerandClaude Fable 5 24fad7090f feat(simulation): lakes from settled hydrology (D-227, T-1184)
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>
2026-07-25 02:26:22 +02:00
jpmschweitzerandClaude Fable 5 236725eb3d fix(simulation): pre-build the true-keyed region cache (PR #199 review)
Hoshe finding 1: derive_all_districts passed a permanently-empty
region_cache, so every survey cell paid four on-the-fly baseline
derivations — and derive_district_profile's docstring (build the cache
before calling in a loop) was contradicted by its sole production
caller. The cache is now pre-built on the TRUE region keys the shared
core looks up (survey-cell centre metres -> containing district ->
region ±1 ring, BTreeSet-deduped), restoring the per-body build-once
cost model. Cache-hit == cache-miss byte-identity holds by D-227 purity
(build_region_profile and the miss branch share the same expressions) —
verified by the believability harness passing against the UNCHANGED
golden. Finding 2: the cascade.rs call-site comment and the stale
module header now state the pre-build truthfully.

Found in passing, filed as T-1186 (pre-existing, out of scope here):
region_centre_latitude_deg is pole-anchored while the derive core keys
equator-anchored signed regions — northern-hemisphere baselines clamp
to +90.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-25 01:31:06 +02:00
jpmschweitzerandClaude Fable 5 9068fcbc0b style(simulation): cargo fmt on the T-1174 batch (gate bounce)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-25 01:16:43 +02:00
jpmschweitzerandClaude Fable 5 933e1f4ee4 fix(simulation): one absolute-metre derive core (D-256, T-1174)
derive_district_profile is now a thin wrapper over the shared
derive_at_metres_with_riparian core at survey-cell-centre world metres
— one derive core, two position sets. The batch pseudo-grid and the
true D-243 district grid were two coordinate systems sharing one bare
(i32,i32) type; the new SurveyCellPos newtype re-keys every batch
product (BodyWorldState.districts, Layer1Output.survey_basin_dirs) so
the compiler rejects cross-namespace passing.

Fixes two latent same-position divergences the T-1174 investigation
surfaced: three inconsistent latitude conventions collapse into the
core's single inverse mapping, and the region-climate baseline now
floor-divides true world metres instead of collapsing the whole body
onto region (0,0)'s baseline — batch climate becomes latitude/region
graded (D-245 direction: every changed believability metric increased).

Binding preservations per D-256(c): basin_direction rides a post-call
override with the true L1 D8 survey-cell aggregate (layer1's map
re-keyed to SurveyCellPos, identity lookup — a floor-divide lookup
against the pseudo-keyed map would have silently defaulted every cell
North); the riparian verdict comes from near_perennial_water_at, never
the empty-slice default (which would have flipped riverside
vegetation_class).

Quarter-skeleton morphology_zone now resolves at the settlement's
exact world position via derive_at_metres at work-item execution
(where TerrainAnalysisCache lives), replacing the survey-cell-centre
map lookup (D-256(d)); settlement_district_pos fixed to true-district
floor-division in passing (same doc/impl mismatch class). Second
pixel-vs-metre conflation fixed in aliveness_probe's anchor-walk math.

Window path byte-unchanged (window_derivation_golden 6/6 byte-
identical); derivation_harness golden untouched; believability golden
regenerated. Full lib + integration suites green.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-25 00:40:13 +02:00
jpmschweitzerandClaude Fable 5 f44f9a2067 style(simulation): cargo fmt on the workshop benches (gate bounce; clippy and tests were green)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-24 10:59:34 +02:00
jpmschweitzerandClaude Fable 5 b613443d51 test(simulation): post-adversarial workshop benches — population survey, chunk rung, S2 density, global tier
hydrology_equilibrium_bench: bench_population_survey_all_committed_bodies
(all 267 real heightmaps solved independently — zero carved cells population-
wide, ~0.86s total, byte-exact determinism; closes Troblum B1) +
bench_per_basin_size_distribution_real_population (22,270 basins: dense wins
100% for lake carriers). bmv_gridunit_bench: chunk-64m per-cell + deep-step
canvas benches (1,838 ns/cell, ~1.7s full 4K; Option D's missing row) + S2
courses-density benches (+38-87% at chunk/block, mechanism traced to station
spacing scaling with rung cutoff). bmv_global_tier_bench (new): real per-body
radii from systems.db via BodyParamsReader — global tier ~8.85MB PNG across
the population (supersedes the ~174MB mis-priced figure), rung-0 derive
~16-21ms/body measured. All #[ignore]d release tests, stability re-run.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-24 10:57:27 +02:00
jpmschweitzerandClaude Fable 5 3f6b3ec928 fix(simulation): PR #198 review round — spillway split, courses disclosure, appendix fidelity
Tyre C2: DownstreamTarget::OpenSpillway added — success (open low ground,
complete carved path) split from EdgeUnreachable (strict search exhaustion);
both doc comments exact; test updated. Tyre C3: determinism docstring
corrected (no BTreeMap; the endorheic f64 gate stated as deterministic-by-
derivation). Hoshe H1: vacuous cliff_edge test replaced by
single_basin_bowl_never_carves_a_gorge asserting the known-empty outcome.
Hoshe H2/H3: courses-force-empty disclosure at rect_window_replica and in
the results doc; courses.len() print added to the square production-fn
bench — measured 3/6/10 courses in window (NOT courses-empty, verified
twice); 'faithful stand-in' claim retracted for a precise scope statement;
GJ1c 18-course run identified as the sole production-density rate. Tyre C1:
appendix (4) headline rephrased — the tagged-envelope migration cannot be
dodged by payload optimization (byte math), field-count-rule trigger is a
workshop synthesis call; appendix (2) scope split per-shape.

Hydrology unit suite 15/15; atlas lib suite 679 green; benches compile.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-23 19:59:58 +02:00
jpmschweitzerandClaude Fable 5 976d4016e9 style(simulation): fmt + clippy fixes for the measurement batch (gate bounce)
cargo fmt across the four new files; needless_range_loop x2 (enumerate /
iter_mut) and identity_op in hydrology_equilibrium.rs. cargo test was green
on the bounced push — lint-only fixes.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-23 19:25:08 +02:00
jpmschweitzerandClaude Fable 5 53a4c65d62 test(simulation): gridunit derive + wire encoding benches (T-1178, T-1154, T-1179)
bmv_gridunit_bench: production build_district_window_layer par_iter path at
330K/2.07M/8.3M cells (throughput holds, ~190-220 ns/cell parallel), block
(128m) and tile (1m/4m) spacing costs, the 83K-cell deepest-step viewport
shape, and the verified zero-savings octave-cutoff finding below District
spacing. wire_encoding_bench: real GJ338Bd derived canvases through
derive_at_metres, five encodings (raw rmp / bit-packed / RLE / PNG-per-field
/ PNG-of-packed) with measured bytes + encode/decode round-trips; corrected
raw density 6.00 B/cell. All #[ignore]d release tests.

Workshop gate measurements (2)(3)(4) for body-map-viewer.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-23 19:22:47 +02:00
jpmschweitzerandClaude Fable 5 05f9630cb4 feat(simulation): equilibrium hydrology solver prototype + bench (T-1177)
Priority-flood fill with basin grouping, topographic-saddle spill points,
moisture-governed endorheic classification (reuses the reserved
RIVER_DOWNSTREAM_TERMINAL sentinel), and Dijkstra overflow/carving. Pure
function of (elevation, sea_level, climate) — deterministic per D-010, no
stateful simulation. 15 unit tests incl. determinism proofs and direct
carving-mechanism verification; #[ignore]d release benches at 512x256 /
768x432 / 3840x2160 plus the 273-bodies-parallel production shape.

Workshop gate measurement (1) for body-map-viewer: settled hydrology is
VIABLE per body-open (~24 ms at 512x256; ~0.7-0.8 s all 273 bodies).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-23 19:22:28 +02:00
jpmschweitzerandClaude Fable 5 1c21863b72 style(simulation): cargo fmt — review-round test code wraps
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-23 16:04:36 +02:00
jpmschweitzerandClaude Fable 5 c804f2c239 test(simulation): walk/paint agreement invariant pinned on the live Quarter mouth window (not-a-bug determination)
The apparent course-over-drawn-water contradiction resolved to two
reconciliation errors, neither in production: (1) the probe's first
reconstruction bypassed the request layer's wire clamp (Quarter n=32
serves as n=16 — build_district_window_layer trusts n verbatim by
doc); (2) the lead's capture read overestimated — the window frames
only the estuarine tail of a 213-station course (178 land stations
out of frame upstream; the visible water run is genuine Lake/
OpenOcean paint, RGB-verified against MORPHOLOGY_RGB_OPAQUE x
elevation-lightness) and the terminus sits ~240m from the painted
land->water crossing, not tens of km. Walk and paint agree at every
instrumented position (zero flip-flops across the monotonic 178-land/
35-water station sequence). New permanent test reproduces the exact
live window (real GJ380c + systems.db params, district (13195,-2383),
Quarter, clamped n=16; asserts 44 pts + Mouth as identity) and pins
the terminus-lands-in-painted-water invariant mechanism-agnostically;
revert-verified with an injected 500km positional slip. Probe
deleted. cargo test --lib 1878/1878.

Tickets: T-1170

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-23 15:38:08 +02:00
jpmschweitzerandClaude Fable 5 270dba0147 test(simulation): upstream-cut Mouth-terminus regression pin (PR #197 acceptance follow-through)
The live acceptance question (Mouth flag apparently not surviving
crop) resolved to hypothesis (b): the terminus genuinely lay outside
both test windows — the Lendel mouth chord is ~108.5km, not the ~38km
estimated, so a District n=32 window centered on the cell OR the
midpoint misses the bisected waterline; a seaward-cell-centered
window provably ships Mouth. Hypothesis (a) — upstream-only crops
collapsing the flag — was FALSIFIED directly with a constructed
window (upstream anchor cut, true terminus in range -> Mouth ships;
crop reads only last_in). This test converts that probe into a
permanent pin with construction-sanity asserts, closing the blind
spot where the existing GJ1c acceptance test's bbox-derived window
always contains the whole course. Revert-verified: reintroducing a
first_in==0 requirement fails this test by name while the whole-
course test blindly passes — exactly the gap. Probe file deleted.
cargo test --lib 1877/1877.

Tickets: T-1170

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-23 15:22:27 +02:00
jpmschweitzerandClaude Fable 5 d256233faf fix(simulation): PR #197 review round — real seaward chord for Mouth edges (Hoshe #1/#2, Tyre 1/2)
The batch's real bug: extract_river_network computed the seaward
neighbor (nr,nc) to decide the MOUTH sentinel then discarded it, and
build_edges placeholder-pointed mouth edges at themselves — zero
chord, invent_course's degenerate 1-point return, resolve_mouth_
terminus dead code on real data, ALL real mouths resolving None, and
(because Ruling 3g retired the D/Q clip on the promise of real
termini) mouths vanishing at District/Quarter. The second instance of
the threw-away-the-answer anti-pattern Ruling 2b fixed for interior
pointers. Fix: river_seaward: Vec<(u16,u16)> on RiverNetwork
(additive, serde-default, parallel array; meaningful only at MOUTH
entries), captured in the same extraction pass; build_edges gives
Mouth edges the real one-D8-step chord. Permanent acceptance:
all_real_gj1c_mouths_resolve_to_mouth_terminus_not_none — 3/3, revert-
verified failing at the golden's first mouth (38,47). Mouth golden
coverage added (river_course_golden gains district_mouth/quarter_mouth
samples + non-degeneracy test; the previously Interior-only filter
gap closed). Tyre 1: the land-probe's dead dx/len*len arithmetic
replaced — station_spacing_m threaded through the crop path, probe
steps one real cell spacing, comment reconciled. Tyre 2: boxing
comment reattributed to variant-size balancing (Layer1Output retention
lives on TerrainAnalysisCache, not BodyWorldState). Hoshe #4:
cascade_golden's doc now states the attractor cascade accurately
(count-parity, not byte-identity — water_dist seeds from mouths).
Full cargo test green; goldens re-pinned deliberately; bench +3.0%.

Tickets: T-1170

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-23 15:02:16 +02:00
jpmschweitzerandClaude Fable 5 b9afa19d65 docs(meta): PR #197 review captures — stroke-floor width-inertness + unreachable-pole-branch notes; bench reflow
Tyre's two governance sentences on the D-226 course note: (a) the
Godot rasterizer floor makes per-class course WIDTH differentiation
inert at every shipping fit zoom — classes distinguish by opacity
alone until T-1175's per-vertex tapering; the 'trunk widest' promise
is design intent, not current pixels. (b) The pole-row edge-drain
branch is structurally unreachable; the real mechanism is interior
k<0 (revert-verification discovery). Plus the dangling cargo-fmt
reflow in the course-cost bench from the gate-bounce round.

Tickets: T-1170

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-23 14:46:27 +02:00
jpmschweitzerandClaude Fable 5 958de5420e style(simulation): gate bounce — box GenCompletion::BodyAnalyzed state; clippy/fmt sweeps
BodyWorldState grew past clippy's large-enum-variant threshold when it
began retaining Layer1Output (T-1170 Ruling 4b) — boxed, with the two
insert sites deref'd; manual_contains x2 (drainage tests),
cloned_ref_to_slice_refs x3 (river_course tests), fmt wraps.
gen_queue 18/18; clippy -D warnings clean; fmt --check clean.

Tickets: T-1170

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-23 14:14:23 +02:00
jpmschweitzerandClaude Fable 5 4320df9b60 feat(simulation): T-1170 A2/A3 + T-1168 A5 — course inventor, coast termination, riparian signal
A2 (river_course.rs): Stage A rung-independent valley-seeking control
path (chord/8 stations, k=5 bilinear-scored candidates + continuity
penalty); Stage B rung-indexed perpendicular warp on GLOBAL arc-length
(window-independence, Ruling 1e), band chord/2 down to min_wavelength_m
hard-truncate, sine taper to zero at anchors, amplitude min(8% chord,
half-cell) slope/class-scaled. SeedDomain::RiverCourse=17, distinct
salt. Wire: RiverCourse{edge_id,class,points,terminus} on
DistrictWindowLayer.courses (serde-default); bbox-culled, window-
cropped +1 station. TerrainAnalysisCache retains Layer1Output (the
gen_queue:626 discard, Ruling 4b). A3: mouth termination walks
stations sampling the window's OWN rung-consistent morphology verdict,
6-iteration bisect; land-at-anchor probes one segment then None;
EdgeDrain never probes. A5: near_perennial_water point-to-segment
predicate (D-239 §8 governed bands 1-3m class-scaled) threaded through
both batch and window paths; Region always false; never touches
moisture_q. Discipline closed: dormant zoom-ladder bench run + numbers
recorded in the design doc (District 3.009/1.785, Quarter 1.823
us/cell, Region window 0.617ms); course-cost bench CAUGHT a real
+12-36% per-cell riparian scan regression -> precomputed bbox O(1)
reject (60ns->2.2ns/call), final delta +3.4-6.9% at budget; three
determinism tests (overlapping-window byte-identity, cross-rung
amplitude bound, warp-stream cross-correlation r<0.3); goldens: window
sweep gained a verified course-bearing position (pure append), new
river_course golden at both rungs, believability verified unchanged.
Revert-verification discovered the pole-row branch is structurally
unreachable (flow_direction bounds-check) — the real edge-drain path
is k<0 flat-plateau; test fixture rewritten to exercise reality.
scale.rs stale comment fixed. Full cargo test green.

Tickets: T-1170, T-1168

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-23 13:36:16 +02:00
jpmschweitzerandClaude Fable 5 0fea69feb2 feat(simulation): T-1170 A1 — river_downstream pointers; pole-edge drains are not mouths
RiverNetwork gains river_downstream: Vec<u8> (serde-default, parallel
to river_cells): values 0-7 index drainage::D8 (row,col deltas, N/S/E/
W/NE/NW/SE/SW order); sentinels MOUTH=8, EDGE_DRAIN=9, TERMINAL=10
(reserved — the future endorheic-basin hook, Ruling 2c/7b). Captured
in extract_river_network's existing pass (fdir already in scope, one
map, no new grid pass). Pole-edge D8 exits reclassify as EDGE_DRAIN
and leave the mouths list (Ruling 3f); flat-peak interior no-outflow
cells get EDGE_DRAIN too. cascade_golden deliberately re-pinned: GJ1c
mouths 19->3 — sixteen were pole-edge artifacts, exactly Jeroen's
'circles with no sea in sight'; river_cells/attractors counts
unchanged (pure reclassification + additive field). 21/21 drainage
tests incl. mouth-sentinel/mouths-list bijection on the real fixture
and a synthetic pole-draining-grid case.

Tickets: T-1170

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-23 12:39:47 +02:00
jpmschweitzerandClaude Fable 5 5a382c2e56 style(simulation): cargo fmt — assert message wrap in drainage tests
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-23 08:59:48 +02:00
jpmschweitzerandClaude Fable 5 ff98a10d42 feat(simulation): T-1156 — quantized river_class on RiverNetwork (trunk/tributary/stream)
The one additive server change of wave 1 per Tyre's carrier ruling:
river_class: Vec<u8> parallel to river_cells, serde-default-safe, no
new wire field. Log-scaled binning between RIVER_THRESHOLD and the
RIVER-RESTRICTED max accumulation (max over cells passing the is_river
elevation filter — NOT the grid-wide max, which peaks past the
coastline on wet large-ocean bodies and would starve the trunk class
exactly where Araminta's District-shows-trunk-only table needs it;
caught in lead review of round 1, fixed round 2). Log not linear
because accumulation grows combinatorially downstream. By construction
every body with rivers has trunk cells — pinned by a non-synthetic
regression on the committed GJ1c heightmap at the golden's exact
downsample. cascade_layer1.json regenerated: every pre-existing field
byte-identical (python-verified), only the new river_class arrays
added — GJ1c distribution stream 72 / tributary 18 / trunk 3.
drainage 16/16 (+10), layer1 3/3, layer_proxy 50/50, build --tests
clean; revert-verified (non-monotonic binning fails the monotonicity
test by name).

Tickets: T-1156

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-23 08:10:00 +02:00