fix(simulation): make voxel relief sub-district + fix integration-test fallout (T-1081)

The push gate's integration tests (not in cargo test --lib) caught two regressions
from the relief change:

- derivation_harness::cross_district_elevation_blend_reduces_seam_step — the relief's
  large per-position term (span 300 → ±200 m, far above the compressed elev_q/2 base)
  swamped the T-1042 seam measurement and clamped heavily at sea level. Fixes:
  (1) shift the voxel-relief octave band to 0.13–1 km (all sub-district, dropping the
  2 km octave that competed with elev_q's district role); (2) reduce VOXEL_RELIEF_SPAN_M
  300 → 100 so relief stays mostly below the base (fewer sea-level clamp artifacts,
  proportional hills); (3) rewrite the seam test's avg_elev to average over an 8 km
  multi-wavelength y-transect so the zero-mean relief cancels, isolating the base seam.
- derivation_harness::golden_seed_determinism_regression — legitimate golden refresh
  (determinism still holds; elevation values changed intentionally).

Believability relief now ≈22 m mean (was 5 m flat; 59 m at the over-aggressive span 300)
— navigable hills without clamp artifacts, 7/8 criteria. Both goldens regenerated; full
cargo test (38 binaries) + clippy --all-targets -D warnings green. D-239 amendment +
Q-123 item 4 updated to the final span/octave/numbers.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-28 21:43:39 +02:00
co-authored by Claude Opus 4.8
parent dc1d905ce0
commit 677de42bd2
7 changed files with 53 additions and 43 deletions
+33 -31
View File
@@ -1191,40 +1191,42 @@ fn cross_district_elevation_blend_reduces_seam_step() {
"T-1042: boundary blend weight must be 128 (50-50)"
);
// Derive ChunkContext for last-A with the secondary district B at 50-50 blend.
let ctx_last_a = derive_chunk_context(
seed,
body,
&district_a,
last_a_chunk,
Some((&district_b, blend_w)),
);
// First-B: no blend (interior to B).
let ctx_first_b = derive_chunk_context(seed, body, &district_b, first_b_chunk, None);
// Interior chunks: no blend.
// Interior-A context retained for the determinism sub-check (Criterion 3).
let ctx_interior_a = derive_chunk_context(seed, body, &district_a, interior_a_chunk, None);
let ctx_interior_b = derive_chunk_context(seed, body, &district_b, interior_b_chunk, None);
// Average elevation across a full 64-voxel row through each chunk.
// We scan y=0 (along the x cross-axis for this AlluvialPlain basin).
let avg_elev = |chunk_pos: ChunkPos,
ctx: &settled_reach_server::atlas::chunk_context::ChunkContext,
dist: &DistrictProfile|
-> i64 {
let base_x = chunk_pos.0 * scale::CHUNK_M;
let base_y = chunk_pos.1 * scale::CHUNK_M;
let mut sum = 0i64;
for dx in 0..scale::VOXELS_PER_CHUNK {
let col = derive_voxel_column(seed, body, dist, ctx, base_x + dx, base_y);
sum += col.elevation_m as i64;
}
sum / scale::VOXELS_PER_CHUNK as i64
};
// Average elevation over a tall multi-wavelength y-transect at a given x-column,
// deriving a ChunkContext per y-chunk. T-1081 adds a zero-mean voxel-relief term to
// elevation_m; averaged over ≥4× the coarsest relief wavelength (1024 m) it cancels,
// leaving the elev_q-derived base — the quantity T-1042's blend actually smooths. A
// single 64 m row would carry a per-chunk relief offset that swamps the seam signal.
let avg_elev =
|x_chunk: i32, blend: Option<(&DistrictProfile, u8)>, dist: &DistrictProfile| -> i64 {
const Y_CHUNKS: i32 = 128; // 8192 m ≈ 8× the 1024 m coarsest relief octave
let base_x = x_chunk * scale::CHUNK_M;
let mut sum = 0i64;
let mut n = 0i64;
for yc in 0..Y_CHUNKS {
let cp: ChunkPos = (x_chunk, yc);
let ctx = derive_chunk_context(seed, body, dist, cp, blend);
let base_y = yc * scale::CHUNK_M;
for dx in (0..scale::VOXELS_PER_CHUNK).step_by(8) {
for dy in (0..scale::VOXELS_PER_CHUNK).step_by(8) {
let col =
derive_voxel_column(seed, body, dist, &ctx, base_x + dx, base_y + dy);
sum += col.elevation_m as i64;
n += 1;
}
}
}
sum / n
};
let elev_last_a = avg_elev(last_a_chunk, &ctx_last_a, &district_a);
let elev_first_b = avg_elev(first_b_chunk, &ctx_first_b, &district_b);
let elev_interior_a = avg_elev(interior_a_chunk, &ctx_interior_a, &district_a);
let elev_interior_b = avg_elev(interior_b_chunk, &ctx_interior_b, &district_b);
// Force the 50-50 blend with B across the whole last-A column (x=31); the interiors
// and first-B column are unblended (per the boundary detection asserted above).
let elev_last_a = avg_elev(last_a_chunk.0, Some((&district_b, blend_w)), &district_a);
let elev_first_b = avg_elev(first_b_chunk.0, None, &district_b);
let elev_interior_a = avg_elev(interior_a_chunk.0, None, &district_a);
let elev_interior_b = avg_elev(interior_b_chunk.0, None, &district_b);
// Seam step = elevation gap between the blended last-A chunk and the clean first-B chunk.
let seam_step = (elev_last_a - elev_first_b).unsigned_abs() as i64;
+2 -2
View File
@@ -28,7 +28,7 @@
"morphology_zones": 9,
"vegetation_classes": 3,
"terrain_materials": 4,
"voxel_relief_m": 49
"voxel_relief_m": 20
},
"coherence": {
"water_districts": 49,
@@ -68,7 +68,7 @@
"morphology_zones": 9,
"vegetation_classes": 1,
"terrain_materials": 4,
"voxel_relief_m": 45
"voxel_relief_m": 19
},
"coherence": {
"water_districts": 25,
+1 -1
View File
@@ -20,7 +20,7 @@
"terrain": 5,
"vegetation": 0,
"water": 0,
"elevation_m": 21,
"elevation_m": 36,
"cover": 0
},
{