test(simulation): address PR #165 review (T-1031)

Hoshe review findings — close silent-pass gaps in the §8 drainage tests:
- assert_drainage_monotonicity now returns whether it actually checked (chunk
  had both wet and dry tiles); the three sweep tests (Alluvial/Meander/Braided
  Delta) assert at least one chunk exercised the law, so a regression that
  zeroes all channels fails loudly instead of passing vacuously.
- The fjord-floor test scans the full 64x64 chunk instead of a single Y=32 row
  and asserts the deep-water trough exists, so the sea-level floor law can no
  longer be skipped by a probe that missed the trough.
- Remove the unreferenced make_test_terrain_analysis helper (was behind
  #[allow(dead_code)] with a 'future use' comment — the maintenance trap the
  review flagged); make_dry_terrain_analysis covers the validation bodies.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-08 22:27:02 +02:00
co-authored by Claude Opus 4.8
parent de5f0f1e58
commit 5cc4ff6c0c
+68 -54
View File
@@ -246,16 +246,22 @@ fn golden_seed_determinism_regression() {
// level; BraidedDelta/CliffCoast/FjordWall floors at sea level."
// Tested by deriving a full 64×64 chunk and checking min(wet_elev) ≤ max(dry_elev).
/// Returns `true` if the monotonicity assertion was actually exercised (the chunk
/// produced both wet and dry tiles). A `false` return means the chunk had no wet
/// tiles, so the law was trivially satisfied without checking anything — callers
/// sweep several chunks and assert at least one returned `true`, so a derivation
/// regression that silently zeroes all channels fails loudly instead of passing.
#[must_use]
fn assert_drainage_monotonicity(
seed: u64,
body_id: &str,
label: &str,
region: &RegionProfile,
chunk_pos: (i32, i32),
) {
) -> bool {
let chunk = derive_chunk_context(seed, body_id, region, chunk_pos);
if !chunk.has_active_channel {
return; // No channel → monotonicity trivially satisfied.
return false; // No channel → monotonicity trivially satisfied.
}
let mut max_dry_elev = i32::MIN;
@@ -295,7 +301,9 @@ fn assert_drainage_monotonicity(
chunk_pos.0,
chunk_pos.1
);
return true;
}
false
}
#[test]
@@ -311,9 +319,15 @@ fn law_drainage_monotonicity_alluvial_sweep() {
Some(15.0),
VegetationClass::Forest,
);
let mut checked = false;
for (cx, cy) in [(0, 0), (1, 0), (0, 1), (4, 4), (8, 3)] {
assert_drainage_monotonicity(42, "GJ144d", "AlluvialPlain", &region, (cx, cy));
checked |= assert_drainage_monotonicity(42, "GJ144d", "AlluvialPlain", &region, (cx, cy));
}
assert!(
checked,
"AlluvialPlain sweep exercised no wet tiles — the monotonicity law was never \
actually checked; a derivation regression could silently pass this test."
);
}
#[test]
@@ -329,9 +343,15 @@ fn law_drainage_monotonicity_meander_sweep() {
Some(14.0),
VegetationClass::Forest,
);
let mut checked = false;
for (cx, cy) in [(0, 0), (2, 1), (5, 5)] {
assert_drainage_monotonicity(99, "GJ447c", "MeanderReach", &region, (cx, cy));
checked |= assert_drainage_monotonicity(99, "GJ447c", "MeanderReach", &region, (cx, cy));
}
assert!(
checked,
"MeanderReach sweep exercised no wet tiles — the monotonicity law was never \
actually checked; a derivation regression could silently pass this test."
);
}
#[test]
@@ -353,30 +373,45 @@ fn law_drainage_monotonicity_fjord_floor_at_sea_level() {
let mut deep_elevs: Vec<i32> = vec![];
let mut dry_elevs: Vec<i32> = vec![];
for dx in 0..64i32 {
let col = derive_voxel_column(42, "fjord_body", &region, &chunk, dx, 32);
match col.water {
Water::Deep => deep_elevs.push(col.elevation_m),
Water::Dry => dry_elevs.push(col.elevation_m),
_ => {}
// Scan the full 64×64 chunk, not a single row — the deep-water trough axis is
// not guaranteed to intersect any fixed Y, so a single-row probe could miss it
// entirely and silently pass without ever checking the sea-level claim.
for dy in 0..64i32 {
for dx in 0..64i32 {
let col = derive_voxel_column(42, "fjord_body", &region, &chunk, dx, dy);
match col.water {
Water::Deep => deep_elevs.push(col.elevation_m),
Water::Dry => dry_elevs.push(col.elevation_m),
_ => {}
}
}
}
if !deep_elevs.is_empty() && !dry_elevs.is_empty() {
let max_deep = *deep_elevs.iter().max().unwrap();
let min_dry = *dry_elevs.iter().min().unwrap();
// Fjord floor (deep water) must be below wall elevation.
assert!(
max_deep <= min_dry,
"§8 FjordWall drainage: deep-water max elev {max_deep} m must be \
≤ dry wall min elev {min_dry} m"
);
// Fjord floor must be near sea level (D-239 §8).
assert!(
max_deep <= 5,
"§8 FjordWall: deep-water floor elev {max_deep} m must be near sea level (≤5 m)"
);
}
// A glaciated fjord chunk MUST carve a deep-water trough — if it doesn't, the
// derivation regressed and the sea-level law below would never run. Fail loudly.
assert!(
!deep_elevs.is_empty(),
"§8 FjordWall: no deep-water tiles found in the fjord chunk — the trough \
derivation regressed; the sea-level floor law was never exercised."
);
assert!(
!dry_elevs.is_empty(),
"§8 FjordWall: no dry wall tiles found in the fjord chunk."
);
let max_deep = *deep_elevs.iter().max().unwrap();
let min_dry = *dry_elevs.iter().min().unwrap();
// Fjord floor (deep water) must be below wall elevation.
assert!(
max_deep <= min_dry,
"§8 FjordWall drainage: deep-water max elev {max_deep} m must be \
≤ dry wall min elev {min_dry} m"
);
// Fjord floor must be near sea level (D-239 §8).
assert!(
max_deep <= 5,
"§8 FjordWall: deep-water floor elev {max_deep} m must be near sea level (≤5 m)"
);
}
#[test]
@@ -392,9 +427,16 @@ fn law_drainage_monotonicity_braided_delta() {
Some(18.0),
VegetationClass::Scrub,
);
let mut checked = false;
for (cx, cy) in [(0, 0), (1, 1)] {
assert_drainage_monotonicity(17, "delta_body", "BraidedDelta", &region, (cx, cy));
checked |=
assert_drainage_monotonicity(17, "delta_body", "BraidedDelta", &region, (cx, cy));
}
assert!(
checked,
"BraidedDelta sweep exercised no wet tiles — the monotonicity law was never \
actually checked; a derivation regression could silently pass this test."
);
}
// ── §8 Law 2: Lithology → Landform ──────────────────────────────────────────
@@ -1433,34 +1475,6 @@ fn make_region(
}
}
/// Build a minimal flat `TerrainAnalysis` for use in body-level derive calls.
/// Same geometry as the region_profile.rs unit tests (64×32 grid, sea_level=0.3).
///
/// Retained as the gentle-slope counterpart to `make_dry_terrain_analysis` (which
/// the validation bodies currently use); kept for future morphology-gate tests that
/// need a sloped, partially-oceanic grid rather than the flat all-dry one.
#[allow(dead_code)]
fn make_test_terrain_analysis() -> TerrainAnalysis {
let (w, h) = (64u32, 32u32);
let n = (w * h) as usize;
let data: Vec<f32> = (0..n)
.map(|i| {
let r = (i / w as usize) as f32 / h as f32;
let c = (i % w as usize) as f32 / w as f32;
(r * 0.6 + c * 0.4).min(1.0)
})
.collect();
let hm = BodyHeightmap {
body_id: "test".into(),
width: w,
height: h,
data,
sea_level: 0.3,
};
let dr = drainage::analyze(&hm.data, hm.width, hm.height, hm.sea_level);
TerrainAnalysis::analyze(&hm, &dr)
}
/// Build a flat all-dry `TerrainAnalysis` for validation body derivation.
///
/// All cells have elevation = 0.5 with sea_level = 0.3 → ocean_fraction_q = 0 at