From c804f2c239934c4876c4123033893e3d3940aeb2 Mon Sep 17 00:00:00 2001 From: Jeroen Schweitzer Date: Thu, 23 Jul 2026 15:38:08 +0200 Subject: [PATCH] test(simulation): walk/paint agreement invariant pinned on the live Quarter mouth window (not-a-bug determination) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 --- server/src/atlas/layer_proxy.rs | 136 ++++++++++++++++++++++++++++++++ 1 file changed, 136 insertions(+) diff --git a/server/src/atlas/layer_proxy.rs b/server/src/atlas/layer_proxy.rs index 37bec5662..f0c7a97ae 100644 --- a/server/src/atlas/layer_proxy.rs +++ b/server/src/atlas/layer_proxy.rs @@ -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", + ¶ms, + &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]