From e141a595b1b2b8a0a63086088c498ee488b972f8 Mon Sep 17 00:00:00 2001 From: Jeroen Schweitzer Date: Sat, 25 Jul 2026 18:59:13 +0200 Subject: [PATCH] feat(simulation): believability gate learns basin-direction variety (T-964, D-245) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 --- server/src/atlas/believability.rs | 151 +++++++++++++++++++++++-- server/tests/golden/believability.json | 8 +- 2 files changed, 147 insertions(+), 12 deletions(-) diff --git a/server/src/atlas/believability.rs b/server/src/atlas/believability.rs index f29e61bd2..66f3e5f00 100644 --- a/server/src/atlas/believability.rs +++ b/server/src/atlas/believability.rs @@ -129,6 +129,24 @@ pub struct ContrastMetrics { /// (min vs mean/median), the final K, and same-class-only pooling are Q-123's to /// calibrate against the enforcer's baselines. pub micro_habitat_distinct: usize, + /// Count of districts with `ocean_fraction_q < 100` (not fully submerged) across + /// **all** districts (T-964, D-256/T-1174 addendum) — the guard signal for + /// [`basin_directions_distinct`](Self::basin_directions_distinct): an all-ocean or + /// otherwise basin-less body legitimately has no land to carry a D8 direction, so + /// the criterion below must not fire there. Cheap (no voxel derivation, reuses the + /// same `districts` iteration the scalar contrast fields already run over). + pub land_districts: usize, + /// Distinct [`crate::atlas::scale::BasinDirection`] values across **all** districts + /// (T-964, D-256/T-1174 addendum). Closes the gap the D-256/T-1174 investigation + /// found: an all-North `basin_direction` collapse (every survey cell defaulting, + /// D-256(b)'s `aggregate_survey_basin_dirs` "no valid votes → North" fallback firing + /// everywhere) produced a BYTE-IDENTICAL report under every OTHER field here — + /// `basin_direction` feeds no scalar/categorical contrast field and only reaches the + /// voxel-derived fields indirectly (`chunk_context`'s cross/along channel axis, T-964 + /// evidence), too diluted at the ~3% production voxel-sample ratio to move them. This + /// field reads the SAME field the regression hits, directly, over every district — + /// not a proxy. + pub basin_directions_distinct: usize, } /// Coherence checks — does the world render as a *caused* place? Pass/fail counts @@ -215,6 +233,15 @@ pub fn analyze( terrain_materials: 0, // filled from the voxel sample below voxel_relief_m: 0, // filled from the relief transect below micro_habitat_distinct: 0, // filled from the per-district triple sets below + land_districts: districts + .values() + .filter(|d| d.ocean_fraction_q < 100) + .count(), + basin_directions_distinct: distinct( + districts + .values() + .map(|d| format!("{:?}", d.basin_direction)), + ), }; // ── Voxel-derived metrics over a deterministic seeded spread of districts ── @@ -411,6 +438,24 @@ pub fn evaluate_criteria(r: &BelievabilityReport) -> Vec { pass: c.morphology_zones >= 2, detail: format!("{} distinct zones", c.morphology_zones), }, + Criterion { + name: "basin direction variety", + // T-964, D-256/T-1174 addendum: catches an all-North basin_direction + // collapse (D-256(b)'s "no valid votes → North" fallback firing on every + // district) that every other field here is blind to. GUARDED on + // `land_districts`: a body with no land (all-ocean/basin-less) has no + // cells that can cast a D8 vote at all (`aggregate_survey_basin_dirs` + // excludes ocean-masked cells from voting by construction), so every + // district legitimately defaults to North — `land_districts == 0` means + // "nothing to vary" and passes vacuously (the same idiom "intra-class + // variety" above uses for a barren/ocean world), never a false fail on a + // legitimate waterworld. + pass: c.land_districts == 0 || c.basin_directions_distinct >= 2, + detail: format!( + "{} distinct basin directions across {} land district(s)", + c.basin_directions_distinct, c.land_districts + ), + }, Criterion { name: "terrain-material variety", pass: c.terrain_materials >= 2, @@ -815,33 +860,119 @@ mod tests { VegetationClass::Forest, VegetationClass::RiparianThicket, ]; + let dirs = [ + BasinDirection::North, + BasinDirection::East, + BasinDirection::South, + BasinDirection::West, + ]; let mut districts: BTreeMap = BTreeMap::new(); for x in 0..8 { for y in 0..8 { let i = (x * 8 + y) as usize; - districts.insert( - SurveyCellPos(x, y), - district( - zones[i % zones.len()], - (i as i32 * 7) % 100, // varied elevation - (i as i32 * 3) % 60, // varied slope - (i as i32 * 11) % 100, // varied moisture - (i as i32 * 13) % 40, - vegs[i % vegs.len()], - ), + let mut d = district( + zones[i % zones.len()], + (i as i32 * 7) % 100, // varied elevation + (i as i32 * 3) % 60, // varied slope + (i as i32 * 11) % 100, // varied moisture + (i as i32 * 13) % 40, + vegs[i % vegs.len()], ); + d.basin_direction = dirs[i % dirs.len()]; // varied basin direction (T-964) + districts.insert(SurveyCellPos(x, y), d); } } let report = analyze(42, "varied", &districts, 64, 64, None); assert!(report.contrast.moisture_q.distinct >= 3); assert!(report.contrast.morphology_zones >= 2); assert!(report.contrast.elev_q.spread() >= 10); + assert!(report.contrast.basin_directions_distinct >= 2); let crit = evaluate_criteria(&report); let passed = |name: &str| crit.iter().find(|c| c.name == name).is_some_and(|c| c.pass); assert!(passed("moisture gradient")); assert!(passed("morphology variety")); assert!(passed("elevation relief")); + assert!(passed("basin direction variety")); + } + + /// T-964, D-256/T-1174 addendum: the "basin direction variety" criterion catches + /// an all-North collapse on a body that HAS land (real basins to vary), but must + /// pass VACUOUSLY on a genuine waterworld (no land districts at all) — the D-256(b) + /// survey aggregator excludes ocean-masked cells from voting by construction, so + /// an all-ocean body legitimately defaults every district to North. + #[test] + fn basin_direction_variety_guards_on_land_presence() { + // All-ocean body: ocean_fraction_q = 100 everywhere, every district defaults + // to BasinDirection::South here only because `district()`'s fixed default + // happens to be South — the guard must pass regardless of the value, since + // there is no land to cast a real D8 vote. + let mut all_ocean: BTreeMap = BTreeMap::new(); + for x in 0..4 { + for y in 0..4 { + all_ocean.insert( + SurveyCellPos(x, y), + district( + MorphologyZone::AlluvialPlain, + 10, + 0, + 50, + 100, // fully submerged — no land + VegetationClass::Barren, + ), + ); + } + } + let report = analyze(42, "all_ocean", &all_ocean, 64, 64, None); + assert_eq!( + report.contrast.land_districts, 0, + "fixture sanity: an all-ocean body must report zero land districts" + ); + let crit = evaluate_criteria(&report); + let passed = |name: &str| crit.iter().find(|c| c.name == name).is_some_and(|c| c.pass); + assert!( + passed("basin direction variety"), + "an all-ocean body must pass the basin-direction criterion vacuously, \ + not false-fail for having only one (defaulted) direction" + ); + + // A body WITH land but a genuine all-North collapse (the actual regression + // this criterion exists to catch) must FAIL. + let mut land_all_north: BTreeMap = BTreeMap::new(); + for x in 0..4 { + for y in 0..4 { + let mut d = district( + MorphologyZone::AlluvialPlain, + (x * 20) as i32, + 0, + 50, + 0, // dry land + VegetationClass::Scrub, + ); + d.basin_direction = BasinDirection::North; // every cell defaults + land_all_north.insert(SurveyCellPos(x, y), d); + } + } + let report2 = analyze(42, "land_all_north", &land_all_north, 64, 64, None); + assert!( + report2.contrast.land_districts > 0, + "fixture sanity: this body must have land districts" + ); + assert_eq!( + report2.contrast.basin_directions_distinct, 1, + "fixture sanity: every district must collapse to the same direction" + ); + let crit2 = evaluate_criteria(&report2); + let failed2 = |name: &str| { + crit2 + .iter() + .find(|c| c.name == name) + .is_some_and(|c| !c.pass) + }; + assert!( + failed2("basin direction variety"), + "a land-bearing body with a genuine all-North collapse must FAIL this criterion" + ); } #[test] diff --git a/server/tests/golden/believability.json b/server/tests/golden/believability.json index 571779224..27bad42a2 100644 --- a/server/tests/golden/believability.json +++ b/server/tests/golden/believability.json @@ -29,7 +29,9 @@ "vegetation_classes": 4, "terrain_materials": 3, "voxel_relief_m": 28, - "micro_habitat_distinct": 3 + "micro_habitat_distinct": 3, + "land_districts": 698, + "basin_directions_distinct": 2 }, "coherence": { "water_districts": 46, @@ -70,7 +72,9 @@ "vegetation_classes": 3, "terrain_materials": 2, "voxel_relief_m": 22, - "micro_habitat_distinct": 0 + "micro_habitat_distinct": 0, + "land_districts": 1602, + "basin_directions_distinct": 2 }, "coherence": { "water_districts": 19,