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
+7 -5
View File
@@ -24,11 +24,13 @@ use crate::seed::splitmix64;
/// coarsest (~33 km) the heightmap itself carries the shape.
const OCTAVE_WAVELENGTHS_M: [f64; 4] = [32_768.0, 16_384.0, 8_192.0, 4_096.0];
/// Voxel-tier octave wavelengths in metres — the ≈0.252 km band that the
/// district-tier [`terrain_detail`] (440 km) is too coarse to carry and the
/// per-voxel scatter (<64 m) is too fine to reach. This is the [`voxel_relief`]
/// band: the rolling/ridged hills a *walking character* navigates by (T-1081).
const VOXEL_OCTAVE_WAVELENGTHS_M: [f64; 4] = [2_048.0, 1_024.0, 512.0, 256.0];
/// Voxel-tier octave wavelengths in metres — the ≈0.131 km **sub-district** band
/// (all finer than the 2 km district planning unit) that the district-tier
/// [`terrain_detail`] (440 km) is too coarse to carry and the per-voxel scatter
/// (<64 m) is too fine to reach. This is the [`voxel_relief`] band: the rolling/ridged
/// hills a *walking character* navigates by (T-1081). The coarsest octave stays below
/// the district size so the relief never competes with `elev_q`'s district-scale role.
const VOXEL_OCTAVE_WAVELENGTHS_M: [f64; 4] = [1_024.0, 512.0, 256.0, 128.0];
/// Deterministic lattice value in `[-1, 1)` for an integer noise cell.
#[inline]
+8 -2
View File
@@ -334,13 +334,19 @@ fn zone_to_family(zone: &MorphologyZone) -> MorphologyFamily {
///
/// A fully derived `VoxelColumn` with all D-228 axes populated.
/// T-1081: the metre span of the voxel-tier mid-scale relief field — the amplitude
/// ceiling for the ≈0.252 km rolling/ridged hills added to the family base
/// ceiling for the ≈0.131 km rolling/ridged hills added to the family base
/// elevation. Actual relief at a voxel is `voxel_relief(...) * SPAN`, which the
/// envelope (district ruggedness) scales down on gentle terrain, so this is the
/// steep-terrain ceiling, not a uniform amplitude. Provisional — tuned against the
/// believability probe (T-1079) like the moisture gradient; per-body *absolute*
/// elevation span is a later refinement (the T-1080 climate-fields lineage).
const VOXEL_RELIEF_SPAN_M: i32 = 300;
///
/// Kept modest so relief stays mostly *below* the family base elevation: the base is
/// the compressed `elev_q/N` scale (max ~50 m) and `elevation_m` clamps at 0 (sea
/// level), so an oversized span clamps away on low ground — drowning the relief and
/// biasing it positive. A larger span belongs with the deferred per-body absolute
/// elevation model that would give the base real headroom.
const VOXEL_RELIEF_SPAN_M: i32 = 100;
pub fn derive_voxel_column(
world_seed: u64,