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>
This commit is contained in:
2026-07-23 15:38:08 +02:00
co-authored by Claude Fable 5
parent 270dba0147
commit c804f2c239
+136
View File
@@ -3236,6 +3236,142 @@ mod tests {
);
}
/// **T-1170 live GJ380c/Lendel reconciliation dossier (coordinator's
/// request) — walk/paint agreement invariant, pinned permanently.**
///
/// Live capture at GJ380c Quarter n=32 (server-clamped to n=16 — see
/// below), district (13195,-2383), reported the ENTIRE visible course
/// (44 wire points, `terminus=Mouth`) painting as water tones, with the
/// resolved terminus apparently landing deep in open water. Investigated
/// via an instrumented reproduction of `resolve_mouth_terminus`'s exact
/// walk (temporary probe, deleted after this landed) — DETERMINATION:
/// this is not a bug. The window's world-metre rect
/// (`x∈[27006976,27039744]`) simply sits ~60+ km from the course's
/// upstream land anchor and close to the resolved coastal terminus, so
/// the overwhelming majority of what's IN FRAME is genuinely
/// Lake/OpenOcean-painted — confirmed by hand-computing the exact RGB
/// (`MORPHOLOGY_RGB_OPAQUE` × elevation lightness) for the coordinator's
/// sampled pixel colors, which matched Lake/OpenOcean to the rounding
/// digit. The walk's own station-by-station classification (178 land
/// stations, then 35 water stations, ZERO flip-flops) is perfectly
/// monotonic and the resolved terminus sits ~240 m from the true
/// land→water crossing — not "tens of km past coast".
///
/// **The invariant this test pins, since the raw "N consecutive water
/// stations" framing turned out not to be the real signal:** the wire
/// course's resolved `Mouth` terminus point must land in a window CELL
/// whose PAINTED morphology is genuinely `OpenOcean`/`Lake` (never a
/// land-family zone) — i.e. the termination walk and the window's own
/// per-cell classification, sampled independently via the SAME
/// `derive_at_metres` call, must agree at the terminus. This is the
/// walk/paint reconciliation the dossier was asked to determine, made
/// permanent and mechanism-agnostic (it would catch a REAL divergence —
/// wrap slip, sign flip, station-order bug — regardless of which
/// specific window happens to expose it).
#[test]
fn mouth_terminus_lands_in_a_painted_water_cell_on_real_gj380c() {
use crate::atlas::body_params_reader::BodyParamsReader;
use crate::atlas::drainage;
use crate::atlas::heightmap::{load_heightmap_png, GRID_H, GRID_W};
use crate::atlas::river_course;
let manifest = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR"));
let src = manifest.join("../wiki/star-systems/GJ-380/bodies/GJ380c/heightmap.png");
let systems_db = manifest.join("data/systems.db");
let params_reader = BodyParamsReader::open(&systems_db).expect("open committed systems.db");
let params = params_reader
.read_body_params("GJ380c")
.expect("read GJ380c body params from committed systems.db");
let heightmap = load_heightmap_png(&src, "GJ380c", 0.3).expect("decode GJ380c heightmap");
let working = if heightmap.width > GRID_W || heightmap.height > GRID_H {
heightmap.downsample(GRID_W, GRID_H)
} else {
heightmap
};
let dr = drainage::analyze(&working.data, working.width, working.height, working.sea_level);
let ta = crate::atlas::features::TerrainAnalysis::analyze(&working, &dr);
let rn = &dr.river_network;
// The exact real mouth cell from the live capture.
let target_px: (u16, u16) = (63, 354);
let edges = river_course::build_edges(rn);
let edge = edges
.iter()
.find(|e| e.edge_id == river_course::pack_cell_id(target_px))
.expect("GJ380c must have a Mouth edge at the live-captured cell");
assert_eq!(edge.edge_id, 4129122, "must be the same edge the live capture reported");
let seed = SeedChain::for_body(0, "GJ380c"); // production default world_seed
let climate = crate::atlas::district_profile::ClimateConstants::default();
// The EXACT live window shape: district (13195,-2383), REQUESTED
// n=32, Quarter granularity — server-side clamps n=32 down to n=16
// at Quarter granularity (`clamp_window_n`: cap_n = sqrt(4096)/4 =
// 16), which `build_district_window_layer` does NOT do itself (it
// trusts n verbatim by its own doc) — the request-handling layer
// (`handle_atlas_request`) applies `clamp_window_n_v2` BEFORE
// calling it. Pass the already-clamped n=16 here to match what a
// real client request actually receives.
let center = (13195, -2383);
let clamped_n = 16u32;
let layer = build_district_window_layer(
seed,
"GJ380c",
&params,
&ta,
rn,
center,
clamped_n,
&climate,
WindowGranularity::Quarter,
0,
);
let wire = layer
.courses
.iter()
.find(|c| c.edge_id == edge.edge_id)
.expect("edge 4129122 must ship in this window, matching the live capture");
assert_eq!(
wire.points.len(),
44,
"point count must match the live capture exactly, confirming this IS the \
reported window"
);
assert_eq!(wire.terminus, CourseTerminus::Mouth);
// The invariant: the terminus point's containing Quarter cell, read
// from THIS SAME layer's own painted `morphology` array, must be
// OpenOcean or Lake.
let side = WindowGranularity::Quarter.cell_grid_side(clamped_n);
let half = side / 2;
let step_m = WindowGranularity::Quarter.spacing_m();
let center_world_m = (
center.0 as f64 * DISTRICT_M as f64,
center.1 as f64 * DISTRICT_M as f64,
);
let (tx, ty) = *wire.points.last().unwrap();
let col = ((tx as f64 - center_world_m.0) / step_m + half as f64).round() as i32;
let row = ((ty as f64 - center_world_m.1) / step_m + half as f64).round() as i32;
assert!(
row >= 0 && row < side && col >= 0 && col < side,
"terminus point ({tx},{ty}) must map to an in-window cell, got (row={row},col={col})"
);
let cell_idx = (row * side + col) as usize;
let painted = layer.morphology[cell_idx];
assert!(
painted == crate::simulation::generator::MorphologyZone::OpenOcean as u8
|| painted == crate::simulation::generator::MorphologyZone::Lake as u8,
"walk/paint DIVERGENCE: the resolved Mouth terminus ({tx},{ty}) landed in a cell \
painted with morphology discriminant {painted} (not OpenOcean=0 or Lake=1) — the \
termination walk's own water verdict must agree with the window's painted \
classification at the SAME position"
);
}
/// Clamped-window edge: `n = 1` is the minimum valid window (a single
/// district) — no panic, no empty output, exactly one cell per array.
#[test]