From 3368891976a438a54db0aa329f36f3625f3a270e Mon Sep 17 00:00:00 2001 From: Jeroen Schweitzer Date: Wed, 22 Jul 2026 23:31:14 +0200 Subject: [PATCH] =?UTF-8?q?fix(simulation):=20PR=20#194=20review=20round?= =?UTF-8?q?=20=E2=80=94=20rung-floor=20dependency=20direction,=20golden=20?= =?UTF-8?q?body=20coverage,=20doc=20honesty?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Tyre's I1 (his ruling: the cutoff's job is Nyquist, a property of the RUNG): MIN_WL_BANDS_M's District band now derives from 2*DISTRICT_M directly, decoupled from OCTAVE_WAVELENGTHS_M[3] — a detail_scatter retune can no longer silently redefine the Atlas rung floor. Direction- agnostic const assert pins the coincidence so drift on either side breaks the build for a deliberate human decision; golden_cutoffs_match_ the_scale_ladder now pins the District coupling too. I2: D-226 paraphrase replaced with cites to the T-1150 wire-contract note + T-1162 refinement resolution (2), plus a self-found stale 2048m claim fixed in the same comments. I4: golden extended with airless/dry (ceiling_q==0 short-circuit) and volcanic-coast (ridged warp) body rows via body_sweep_samples() — fixture regen verified 510 insertions, 0 deletions (existing rows byte-identical, purely appended). Q2 nit: vegetation_invention module doc now states majority-preservation as the coherence guarantee, not per-cell class stability (a boundary cell's flip IS the clearing mechanism). Forward-contract for T-1156: 0x5EED_C0DE promoted to named WINDOW_RELIEF_SALT const. 158 focused tests green; cargo check --tests clean. Tickets: T-1162, T-1161 Co-Authored-By: Claude Fable 5 --- server/src/atlas/coast_invention.rs | 15 +- server/src/atlas/district_profile.rs | 43 +- server/src/atlas/layer_proxy.rs | 51 +- server/src/atlas/vegetation_invention.rs | 45 +- .../golden/window_derivation_golden.json | 510 ++++++++++++++++++ server/tests/window_derivation_golden.rs | 163 +++++- 6 files changed, 751 insertions(+), 76 deletions(-) diff --git a/server/src/atlas/coast_invention.rs b/server/src/atlas/coast_invention.rs index 962903e3e..b83c46d6c 100644 --- a/server/src/atlas/coast_invention.rs +++ b/server/src/atlas/coast_invention.rs @@ -64,13 +64,14 @@ const CHARACTER_FIELD_SALT: u64 = 0x0C0A_57C4_A24C_7E12; /// density, not detail). A Quarter-rung request (`min_wavelength_m` cutoff /// quantized to 1,024 m, see `layer_proxy::MIN_WL_BANDS_M`) admits every /// octave down to this floor; a District-rung request (cutoff quantized to -/// District's OWN real band, 4,096 m — District's Nyquist limit, matching -/// `terrain_detail`'s pre-existing finest octave) truncates the two finest -/// additions (2,048/1,024 m — genuinely below District's floor) while -/// legitimately ADMITTING the other two (8,192/4,096 m — new content that IS -/// coarse enough for District to resolve, not a leak). Either way Quarter -/// still sees strictly more than District at the SAME position (the two -/// finest additions are Quarter-exclusive). The +/// District's OWN real band, `2 × DISTRICT_M = 4,096` m — District's own +/// Nyquist limit, derived independently from the rung's spacing per PR #194 +/// I1, NOT from any invention field's octave array) truncates the two +/// finest additions (2,048/1,024 m — genuinely below District's floor) +/// while legitimately ADMITTING the other two (8,192/4,096 m — new content +/// that IS coarse enough for District to resolve, not a leak). Either way +/// Quarter still sees strictly more than District at the SAME position (the +/// two finest additions are Quarter-exclusive). The /// `enveloped_fbm`-style hard-truncate cutoff discipline is honored via /// [`warp_fbm`]'s own `min_wavelength_m` parameter — `0.0` (no cutoff) is /// byte-identical to every pre-T-1162 caller. diff --git a/server/src/atlas/district_profile.rs b/server/src/atlas/district_profile.rs index d4c422c12..a73f7bcc2 100644 --- a/server/src/atlas/district_profile.rs +++ b/server/src/atlas/district_profile.rs @@ -1058,6 +1058,16 @@ pub fn derive_moisture_q( // T-1125 — invented primitives (shared by both derivation paths) // --------------------------------------------------------------------------- +/// Distinct hash-path salt for the T-1162 sub-district relief stream (part +/// b) — keeps `voxel_relief`'s noise uncorrelated with the district-band +/// `terrain_detail` scatter sampled at the same position. Promoted to a +/// named const (Tyre, PR #194 forward-contract for T-1156) matching +/// `vegetation_invention::VEGETATION_MASSIF_SALT`/`VEGETATION_TEXTURE_SALT`'s +/// named-and-greppable convention, ahead of T-1156 adding a fourth +/// isolated stream (rivers) — a fourth inline hex literal here would have +/// made the pattern harder to audit at a glance. +const WINDOW_RELIEF_SALT: u64 = 0x5EED_C0DE; + /// The invented `(slope_q, elev_q, ocean_fraction_q)` triple (T-1125, D-227). struct InventedPrimitives { slope_q: i32, @@ -1165,22 +1175,25 @@ fn invent_primitives( // envelope/ruggedness inputs as the district-band `scatter` above (one // amplitude ceiling, two wavelength bands composing additively — never a // second independently-tuned amplitude rule) and the SAME - // `min_wavelength_m` cutoff. At District's cutoff (≥2,048 m) every - // VOXEL_OCTAVE_WAVELENGTHS_M entry (all ≤1,024 m) is truncated, so - // `relief` is always exactly 0.0 there — District's output is unchanged - // byte-for-byte. At Quarter's cutoff (1,024 m) only the two coarsest - // voxel-band entries (1,024, 512) survive; the two finest (256, 128) stay - // truncated even at Quarter (below Quarter's own 512 m spacing's Nyquist - // floor of 1,024 m) — this is correct and expected (D-226(d) note): a - // contributing wavelength is never capped BY the request-granularity - // floor ruling itself (the coast warp already crosses scales the other - // way), it is simply that only 2 of the 4 voxel octaves are coarse enough - // to matter at Quarter's own sample density; the other two are reserved - // for a future finer-than-Quarter rung. Distinct seed salt (`^ 0x5EED_C0DE`) - // keeps this stream uncorrelated with `scatter`'s stream at the same - // position (same isolation discipline as `coast_invention`'s warp salt). + // `min_wavelength_m` cutoff. At District's real Nyquist floor (4,096 m, + // `layer_proxy::MIN_WL_BANDS_M`) every VOXEL_OCTAVE_WAVELENGTHS_M entry + // (all ≤1,024 m) is truncated, so `relief` is always exactly 0.0 there — + // District's output is unchanged byte-for-byte. At Quarter's cutoff + // (1,024 m) only the two coarsest voxel-band entries (1,024, 512) + // survive; the two finest (256, 128) stay truncated even at Quarter + // (below Quarter's own 512 m spacing's Nyquist floor of 1,024 m) — this + // is correct and expected per the D-226 T-1150 wire-contract note and + // T-1162 refinement resolution (2): a contributing wavelength is never + // capped by the rung's sample-density floor alone (the coast warp + // already crosses scales the other way), it is simply that only 2 of + // the 4 voxel octaves are coarse enough to matter at Quarter's own + // sample density; the other two are reserved for a future + // finer-than-Quarter rung. Distinct seed salt + // ([`WINDOW_RELIEF_SALT`]) keeps this stream uncorrelated with + // `scatter`'s stream at the same position (same isolation discipline as + // `coast_invention`'s warp salt). let relief = crate::atlas::detail_scatter::voxel_relief( - seed.seed() ^ 0x5EED_C0DE, + seed.seed() ^ WINDOW_RELIEF_SALT, world_x_m, world_y_m, env_amp, diff --git a/server/src/atlas/layer_proxy.rs b/server/src/atlas/layer_proxy.rs index 78c979e82..5500e6013 100644 --- a/server/src/atlas/layer_proxy.rs +++ b/server/src/atlas/layer_proxy.rs @@ -405,17 +405,27 @@ fn clamp_window_n_v2(raw_n: u32, granularity: WindowGranularity) -> u32 { } /// Quantized `window_min_wl_m` bands (T-1150, zoom ladder design doc §5; -/// retuned T-1162 part (c)): `0` (no cutoff) plus every entry of -/// [`crate::atlas::detail_scatter::OCTAVE_WAVELENGTHS_M`] (32,768/16,384/ -/// 8,192/4,096 m — District's own Nyquist floor, `2 × DISTRICT_M`), plus a -/// FIFTH band at `1,024` m — Quarter's own Nyquist floor (`2 × QUARTER_M = -/// 1,024`, matching a rung's content wavelength to what its `512` m sample -/// spacing can actually resolve — nothing finer than the rung can express, -/// nothing coarser than it deserves). `1,024` m is also the finest entry of -/// the extended [`crate::atlas::coast_invention::WARP_OCTAVE_WAVELENGTHS_M`] -/// band (T-1162 part a) and the coarsest entry of -/// [`crate::atlas::detail_scatter::VOXEL_OCTAVE_WAVELENGTHS_M`] the sub-district -/// relief wiring (T-1162 part b) admits at Quarter — one band serves both. +/// retuned T-1162 part (c); band 4 re-derived per Tyre's PR #194 review I1). +/// `0` (no cutoff) plus the two coarse legacy bands +/// [`crate::atlas::detail_scatter::OCTAVE_WAVELENGTHS_M`]`[0..2]` (32,768/ +/// 16,384/8,192 m — carried over unchanged, no rung claims these as its own +/// Nyquist floor), plus **District's own Nyquist floor** computed directly +/// from the rung's spacing (`2 × DISTRICT_M = 4,096` m), plus **Quarter's own +/// Nyquist floor** (`2 × QUARTER_M = 1,024` m). +/// +/// **Dependency direction (Tyre, PR #194 I1):** the cutoff's semantic job is +/// Nyquist truncation — a property of the RUNG (its sample spacing), never of +/// any one invention field's octave choices. Band 4 is therefore derived from +/// `scale::DISTRICT_M` directly, NOT from +/// `detail_scatter::OCTAVE_WAVELENGTHS_M[3]` (the old T-1162 wiring) — that +/// coupling ran backwards: a future `detail_scatter` retune could silently +/// redefine the Atlas rung floor, and the coast warp already extends its OWN +/// octaves below `OCTAVE_WAVELENGTHS_M`'s range (T-1162 part a), proving no +/// single invention field's array is entitled to dictate the floor. The two +/// values happen to coincide today (4,096 = `2 × DISTRICT_M` = also +/// `OCTAVE_WAVELENGTHS_M[3]`) — the `const _: () = assert!(...)` immediately +/// below pins that coincidence so a future drift on EITHER side breaks the +/// build loudly instead of silently decoupling the two meanings. /// /// **Pre-T-1162 bands unchanged in VALUE** (32,768/16,384/8,192/4,096 stay /// exactly where they were) — but **NOT unchanged in behavior at 8,192/4,096 @@ -442,10 +452,25 @@ const MIN_WL_BANDS_M: [f64; 6] = [ crate::atlas::detail_scatter::OCTAVE_WAVELENGTHS_M[0], crate::atlas::detail_scatter::OCTAVE_WAVELENGTHS_M[1], crate::atlas::detail_scatter::OCTAVE_WAVELENGTHS_M[2], - crate::atlas::detail_scatter::OCTAVE_WAVELENGTHS_M[3], - 1_024.0, + 2.0 * DISTRICT_M as f64, + 2.0 * crate::atlas::scale::QUARTER_M as f64, ]; +/// Direction-agnostic guard (Tyre, PR #194 I1): `MIN_WL_BANDS_M`'s District +/// band is now derived from `2 × DISTRICT_M`, deliberately decoupled from +/// `detail_scatter::OCTAVE_WAVELENGTHS_M[3]` (see the doc above). The two +/// values are expected to keep coinciding — `terrain_detail`'s finest octave +/// IS meant to sit at District's Nyquist floor — but nothing in the type +/// system enforces that anymore now that the dependency runs one direction +/// only. This assert exists so that if either side ever drifts (a +/// `detail_scatter` octave retune, or a `DISTRICT_M` scale-ladder change). +/// the build breaks loudly and a human decides deliberately whether the +/// coincidence should be restored or the two meanings were meant to diverge +/// — never a silent redefinition of the Atlas rung floor. +const _: () = assert!( + crate::atlas::detail_scatter::OCTAVE_WAVELENGTHS_M[3] as i64 == 2 * DISTRICT_M as i64 +); + /// Snap a wire-supplied `window_min_wl_m` to the nearest fixed band in /// [`MIN_WL_BANDS_M`] (T-1150, design doc §5's gap-fix): "as specified, /// `window_min_wl_m` is viewport-continuous while the cache key/echo tuple is diff --git a/server/src/atlas/vegetation_invention.rs b/server/src/atlas/vegetation_invention.rs index b027bae3f..cf1a06235 100644 --- a/server/src/atlas/vegetation_invention.rs +++ b/server/src/atlas/vegetation_invention.rs @@ -49,22 +49,35 @@ //! //! ## Cross-rung coherence (the ticket's hard requirement) //! -//! A forest at Region scale MUST still read as forest-majority when sampled -//! at Quarter — the finer rungs REFINE the boundary and punch clearings, they -//! never contradict the coarse verdict wholesale. This is achieved the SAME -//! way `coast_invention`'s warp achieves cross-rung coherence: a SINGLE fBm -//! sum whose octave terms span coarse-to-fine wavelengths, sampled at -//! whatever position/cutoff a rung asks for — not two independently-seeded -//! fields for "coarse" and "fine" that could disagree. The coarse octaves -//! (massif-scale, ≈100–400 km, always present regardless of cutoff — same -//! posture as `coast_invention::character_field`, which is NEVER -//! cutoff-gated) set the DC bias (which side of "possible forest" a broad -//! area sits on); the fine octaves (district/quarter-scale, cutoff-gated -//! exactly like `terrain_detail`/`voxel_relief`) add zero-mean texture on top -//! that punches clearings and copses WITHOUT being able to flip the coarse -//! bias's sign at typical amplitudes (the fine-octave contribution is capped -//! well inside the coarse term's own swing — see [`moisture_perturb_q`]'s -//! amplitude split). +//! A forest at Region scale MUST still read as forest-**majority** when +//! sampled at Quarter — the finer rungs REFINE the boundary and punch +//! clearings, they never contradict the coarse verdict wholesale. **This is +//! a majority-preservation guarantee, not a per-cell class-stability +//! guarantee** — punching an individual clearing or copse INTO a forest +//! massif is the fine tier doing its job, not a violation of coherence; the +//! two are compatible because the guarantee is about the aggregate reading +//! over a patch, not about any single cell's class surviving refinement +//! unchanged. This is achieved the SAME way `coast_invention`'s warp +//! achieves cross-rung coherence: a SINGLE fBm sum whose octave terms span +//! coarse-to-fine wavelengths, sampled at whatever position/cutoff a rung +//! asks for — not two independently-seeded fields for "coarse" and "fine" +//! that could disagree. The coarse octaves (massif-scale, ≈100–400 km, +//! always present regardless of cutoff — same posture as +//! `coast_invention::character_field`, which is NEVER cutoff-gated) set the +//! DC bias (which side of "possible forest" a broad area sits on) at 70% of +//! the blend weight; the fine octaves (district/quarter-scale, cutoff-gated +//! exactly like `terrain_detail`/`voxel_relief`) contribute the remaining +//! 30% as zero-mean texture. That weighting means the fine tier alone can +//! never flip the BLENDED FIELD's sign — but the blended field is only an +//! intermediate `[-1, 1]` value; after it is scaled by the body's +//! `ceiling_q` and added to `base_moisture_q`, the RESULT crosses +//! `derive_vegetation`'s class thresholds exactly as elevation/temperature +//! do elsewhere in this cascade. A boundary cell sitting close enough to a +//! threshold WILL legitimately flip class under the fine tier's +//! contribution — that flip IS the clearing/copse the ticket asks for. What +//! the weighting guarantees is that flips stay localized (isolated cells +//! near a boundary), so the MAJORITY class over any sampled patch tracks the +//! coarse massif tier, never the fine tier alone. //! //! ## Wavelength discipline (per rung, identical to parts 1–2 of T-1162) //! diff --git a/server/tests/golden/window_derivation_golden.json b/server/tests/golden/window_derivation_golden.json index be79ce965..1e6afbf70 100644 --- a/server/tests/golden/window_derivation_golden.json +++ b/server/tests/golden/window_derivation_golden.json @@ -253,5 +253,515 @@ "temperature_dc": -64, "moisture_q": 43, "vegetation": 1 + }, + { + "label": "airless_dry/coastal_a", + "rung": "district", + "wx_m": 2000000, + "wy_m": 1500000, + "min_wl_m": 4096, + "morphology": 8, + "tectonic": 0, + "glaciation": 0, + "precipitation": 0, + "slope_q": 2, + "elev_q": 44, + "ocean_fraction_q": 0, + "temperature_dc": -2147483648, + "moisture_q": 0, + "vegetation": 0 + }, + { + "label": "airless_dry/coastal_a", + "rung": "quarter", + "wx_m": 2000000, + "wy_m": 1500000, + "min_wl_m": 1024, + "morphology": 8, + "tectonic": 0, + "glaciation": 0, + "precipitation": 0, + "slope_q": 2, + "elev_q": 48, + "ocean_fraction_q": 0, + "temperature_dc": -2147483648, + "moisture_q": 0, + "vegetation": 0 + }, + { + "label": "airless_dry/coastal_a", + "rung": "region", + "wx_m": 2000000, + "wy_m": 1500000, + "min_wl_m": 0, + "morphology": 8, + "tectonic": 0, + "glaciation": 0, + "precipitation": 0, + "slope_q": 0, + "elev_q": 41, + "ocean_fraction_q": 0, + "temperature_dc": -2147483648, + "moisture_q": 0, + "vegetation": 0 + }, + { + "label": "airless_dry/coastal_b", + "rung": "district", + "wx_m": 2050000, + "wy_m": 1500000, + "min_wl_m": 4096, + "morphology": 8, + "tectonic": 0, + "glaciation": 0, + "precipitation": 0, + "slope_q": 1, + "elev_q": 42, + "ocean_fraction_q": 0, + "temperature_dc": -2147483648, + "moisture_q": 0, + "vegetation": 0 + }, + { + "label": "airless_dry/coastal_b", + "rung": "quarter", + "wx_m": 2050000, + "wy_m": 1500000, + "min_wl_m": 1024, + "morphology": 8, + "tectonic": 0, + "glaciation": 0, + "precipitation": 0, + "slope_q": 2, + "elev_q": 39, + "ocean_fraction_q": 0, + "temperature_dc": -2147483648, + "moisture_q": 0, + "vegetation": 0 + }, + { + "label": "airless_dry/coastal_b", + "rung": "region", + "wx_m": 2050000, + "wy_m": 1500000, + "min_wl_m": 0, + "morphology": 8, + "tectonic": 0, + "glaciation": 0, + "precipitation": 0, + "slope_q": 0, + "elev_q": 41, + "ocean_fraction_q": 0, + "temperature_dc": -2147483648, + "moisture_q": 0, + "vegetation": 0 + }, + { + "label": "airless_dry/coastal_c", + "rung": "district", + "wx_m": 2100000, + "wy_m": 1560000, + "min_wl_m": 4096, + "morphology": 8, + "tectonic": 0, + "glaciation": 0, + "precipitation": 0, + "slope_q": 2, + "elev_q": 44, + "ocean_fraction_q": 0, + "temperature_dc": -2147483648, + "moisture_q": 0, + "vegetation": 0 + }, + { + "label": "airless_dry/coastal_c", + "rung": "quarter", + "wx_m": 2100000, + "wy_m": 1560000, + "min_wl_m": 1024, + "morphology": 8, + "tectonic": 0, + "glaciation": 0, + "precipitation": 0, + "slope_q": 2, + "elev_q": 45, + "ocean_fraction_q": 0, + "temperature_dc": -2147483648, + "moisture_q": 0, + "vegetation": 0 + }, + { + "label": "airless_dry/coastal_c", + "rung": "region", + "wx_m": 2100000, + "wy_m": 1560000, + "min_wl_m": 0, + "morphology": 8, + "tectonic": 0, + "glaciation": 0, + "precipitation": 0, + "slope_q": 0, + "elev_q": 41, + "ocean_fraction_q": 0, + "temperature_dc": -2147483648, + "moisture_q": 0, + "vegetation": 0 + }, + { + "label": "airless_dry/inland", + "rung": "district", + "wx_m": 500000, + "wy_m": 3000000, + "min_wl_m": 4096, + "morphology": 8, + "tectonic": 0, + "glaciation": 0, + "precipitation": 0, + "slope_q": 3, + "elev_q": 44, + "ocean_fraction_q": 0, + "temperature_dc": -2147483648, + "moisture_q": 0, + "vegetation": 0 + }, + { + "label": "airless_dry/inland", + "rung": "quarter", + "wx_m": 500000, + "wy_m": 3000000, + "min_wl_m": 1024, + "morphology": 8, + "tectonic": 0, + "glaciation": 0, + "precipitation": 0, + "slope_q": 4, + "elev_q": 39, + "ocean_fraction_q": 0, + "temperature_dc": -2147483648, + "moisture_q": 0, + "vegetation": 0 + }, + { + "label": "airless_dry/inland", + "rung": "region", + "wx_m": 500000, + "wy_m": 3000000, + "min_wl_m": 0, + "morphology": 8, + "tectonic": 0, + "glaciation": 0, + "precipitation": 0, + "slope_q": 0, + "elev_q": 42, + "ocean_fraction_q": 0, + "temperature_dc": -2147483648, + "moisture_q": 0, + "vegetation": 0 + }, + { + "label": "airless_dry/high_lat", + "rung": "district", + "wx_m": 1200000, + "wy_m": 8500000, + "min_wl_m": 4096, + "morphology": 8, + "tectonic": 0, + "glaciation": 0, + "precipitation": 0, + "slope_q": 2, + "elev_q": 76, + "ocean_fraction_q": 0, + "temperature_dc": -2147483648, + "moisture_q": 0, + "vegetation": 0 + }, + { + "label": "airless_dry/high_lat", + "rung": "quarter", + "wx_m": 1200000, + "wy_m": 8500000, + "min_wl_m": 1024, + "morphology": 8, + "tectonic": 0, + "glaciation": 0, + "precipitation": 0, + "slope_q": 3, + "elev_q": 79, + "ocean_fraction_q": 0, + "temperature_dc": -2147483648, + "moisture_q": 0, + "vegetation": 0 + }, + { + "label": "airless_dry/high_lat", + "rung": "region", + "wx_m": 1200000, + "wy_m": 8500000, + "min_wl_m": 0, + "morphology": 8, + "tectonic": 0, + "glaciation": 0, + "precipitation": 0, + "slope_q": 0, + "elev_q": 77, + "ocean_fraction_q": 0, + "temperature_dc": -2147483648, + "moisture_q": 0, + "vegetation": 0 + }, + { + "label": "volcanic_coast/coastal_a", + "rung": "district", + "wx_m": 2000000, + "wy_m": 1500000, + "min_wl_m": 4096, + "morphology": 15, + "tectonic": 2, + "glaciation": 0, + "precipitation": 3, + "slope_q": 3, + "elev_q": 25, + "ocean_fraction_q": 0, + "temperature_dc": 497, + "moisture_q": 60, + "vegetation": 3 + }, + { + "label": "volcanic_coast/coastal_a", + "rung": "quarter", + "wx_m": 2000000, + "wy_m": 1500000, + "min_wl_m": 1024, + "morphology": 15, + "tectonic": 2, + "glaciation": 0, + "precipitation": 3, + "slope_q": 6, + "elev_q": 13, + "ocean_fraction_q": 0, + "temperature_dc": 560, + "moisture_q": 62, + "vegetation": 3 + }, + { + "label": "volcanic_coast/coastal_a", + "rung": "region", + "wx_m": 2000000, + "wy_m": 1500000, + "min_wl_m": 0, + "morphology": 15, + "tectonic": 2, + "glaciation": 0, + "precipitation": 3, + "slope_q": 0, + "elev_q": 28, + "ocean_fraction_q": 0, + "temperature_dc": 482, + "moisture_q": 59, + "vegetation": 3 + }, + { + "label": "volcanic_coast/coastal_b", + "rung": "district", + "wx_m": 2050000, + "wy_m": 1500000, + "min_wl_m": 4096, + "morphology": 15, + "tectonic": 2, + "glaciation": 0, + "precipitation": 3, + "slope_q": 4, + "elev_q": 34, + "ocean_fraction_q": 0, + "temperature_dc": 456, + "moisture_q": 58, + "vegetation": 3 + }, + { + "label": "volcanic_coast/coastal_b", + "rung": "quarter", + "wx_m": 2050000, + "wy_m": 1500000, + "min_wl_m": 1024, + "morphology": 15, + "tectonic": 2, + "glaciation": 0, + "precipitation": 3, + "slope_q": 6, + "elev_q": 24, + "ocean_fraction_q": 0, + "temperature_dc": 508, + "moisture_q": 60, + "vegetation": 3 + }, + { + "label": "volcanic_coast/coastal_b", + "rung": "region", + "wx_m": 2050000, + "wy_m": 1500000, + "min_wl_m": 0, + "morphology": 15, + "tectonic": 2, + "glaciation": 0, + "precipitation": 3, + "slope_q": 0, + "elev_q": 28, + "ocean_fraction_q": 0, + "temperature_dc": 487, + "moisture_q": 59, + "vegetation": 3 + }, + { + "label": "volcanic_coast/coastal_c", + "rung": "district", + "wx_m": 2100000, + "wy_m": 1560000, + "min_wl_m": 4096, + "morphology": 15, + "tectonic": 2, + "glaciation": 0, + "precipitation": 3, + "slope_q": 2, + "elev_q": 28, + "ocean_fraction_q": 0, + "temperature_dc": 486, + "moisture_q": 59, + "vegetation": 3 + }, + { + "label": "volcanic_coast/coastal_c", + "rung": "quarter", + "wx_m": 2100000, + "wy_m": 1560000, + "min_wl_m": 1024, + "morphology": 15, + "tectonic": 2, + "glaciation": 0, + "precipitation": 3, + "slope_q": 4, + "elev_q": 33, + "ocean_fraction_q": 0, + "temperature_dc": 460, + "moisture_q": 59, + "vegetation": 3 + }, + { + "label": "volcanic_coast/coastal_c", + "rung": "region", + "wx_m": 2100000, + "wy_m": 1560000, + "min_wl_m": 0, + "morphology": 15, + "tectonic": 2, + "glaciation": 0, + "precipitation": 3, + "slope_q": 0, + "elev_q": 29, + "ocean_fraction_q": 0, + "temperature_dc": 481, + "moisture_q": 59, + "vegetation": 3 + }, + { + "label": "volcanic_coast/inland", + "rung": "district", + "wx_m": 500000, + "wy_m": 3000000, + "min_wl_m": 4096, + "morphology": 15, + "tectonic": 2, + "glaciation": 0, + "precipitation": 2, + "slope_q": 3, + "elev_q": 24, + "ocean_fraction_q": 0, + "temperature_dc": 565, + "moisture_q": 49, + "vegetation": 3 + }, + { + "label": "volcanic_coast/inland", + "rung": "quarter", + "wx_m": 500000, + "wy_m": 3000000, + "min_wl_m": 1024, + "morphology": 15, + "tectonic": 2, + "glaciation": 0, + "precipitation": 2, + "slope_q": 4, + "elev_q": 21, + "ocean_fraction_q": 0, + "temperature_dc": 581, + "moisture_q": 49, + "vegetation": 3 + }, + { + "label": "volcanic_coast/inland", + "rung": "region", + "wx_m": 500000, + "wy_m": 3000000, + "min_wl_m": 0, + "morphology": 15, + "tectonic": 2, + "glaciation": 0, + "precipitation": 2, + "slope_q": 0, + "elev_q": 23, + "ocean_fraction_q": 0, + "temperature_dc": 571, + "moisture_q": 49, + "vegetation": 3 + }, + { + "label": "volcanic_coast/high_lat", + "rung": "district", + "wx_m": 1200000, + "wy_m": 8500000, + "min_wl_m": 4096, + "morphology": 15, + "tectonic": 2, + "glaciation": 0, + "precipitation": 2, + "slope_q": 3, + "elev_q": 68, + "ocean_fraction_q": 0, + "temperature_dc": 545, + "moisture_q": 29, + "vegetation": 2 + }, + { + "label": "volcanic_coast/high_lat", + "rung": "quarter", + "wx_m": 1200000, + "wy_m": 8500000, + "min_wl_m": 1024, + "morphology": 15, + "tectonic": 2, + "glaciation": 0, + "precipitation": 2, + "slope_q": 4, + "elev_q": 65, + "ocean_fraction_q": 0, + "temperature_dc": 561, + "moisture_q": 30, + "vegetation": 2 + }, + { + "label": "volcanic_coast/high_lat", + "rung": "region", + "wx_m": 1200000, + "wy_m": 8500000, + "min_wl_m": 0, + "morphology": 15, + "tectonic": 2, + "glaciation": 0, + "precipitation": 2, + "slope_q": 0, + "elev_q": 66, + "ocean_fraction_q": 0, + "temperature_dc": 555, + "moisture_q": 30, + "vegetation": 2 } ] diff --git a/server/tests/window_derivation_golden.rs b/server/tests/window_derivation_golden.rs index c66672dde..69d4bb3ec 100644 --- a/server/tests/window_derivation_golden.rs +++ b/server/tests/window_derivation_golden.rs @@ -18,6 +18,16 @@ //! quantization will change this golden's values — regenerate deliberately //! (per the asset-pipeline discipline: source changes, not hand-edits). //! +//! **Body coverage (Tyre, PR #194 review I4):** the sweep runs against THREE +//! bodies, not one — the original temperate/ocean/breathable body (unchanged +//! from the initial T-1162 landing), plus an airless/dry body (exercises +//! `vegetation_invention::VegetationEnvelope`'s `ceiling_q == 0` short +//! circuit at the full derivation-stack level) and a volcanic/high-tectonic +//! coastal body (exercises the ridged-warp/wide-`scatter_floor` branch of +//! `coast_invention`). The two new bodies' rows are APPENDED after the +//! original body's rows (never interleaved), so the original rows stay +//! byte-identical across the I4 regen — see `body_sweep_samples`'s doc. +//! //! Run: `cargo test --test window_derivation_golden` //! Regenerate: `UPDATE_GOLDEN=1 cargo test --test window_derivation_golden` @@ -36,6 +46,14 @@ const GOLDEN_FILE: &str = "tests/golden/window_derivation_golden.json"; /// Compact representation of a `DistrictProfile` sample for golden pinning. /// Integer-discriminant fields only (D-010) — no float equality flakiness. +/// +/// **No `body` field (Tyre, PR #194 I4 constraint):** the two new body rows +/// (I4) distinguish themselves via the `label` field's prefix instead of a +/// new struct field — adding a field here would change the JSON shape of +/// EVERY existing row (not just the new ones), which fails I4's explicit +/// "existing rows must stay byte-identical" requirement. `label` was always +/// a free-form string, so `"golden_body/coastal_a"` vs `"airless_dry/coastal_a"` +/// costs nothing structurally and keeps the diff a pure append. #[derive(Debug, serde::Serialize, serde::Deserialize, PartialEq, Eq, Clone)] struct GoldenSample { label: String, @@ -97,6 +115,43 @@ fn sample_params() -> BodyParams { } } +/// I4 (Tyre, PR #194 review): airless/dry body params — exercises +/// `vegetation_invention::VegetationEnvelope`'s `ceiling_q == 0` short +/// circuit (no water, no atmosphere → zero patchiness swing, per +/// `envelope_airless_or_dry_body_has_zero_ceiling`'s unit-level proof) at +/// the FULL derivation-stack level, which the unit test alone doesn't pin. +/// Also airless (`atmosphere: "none"`) so `temperature_c`/`vegetation_class` +/// take the `None`/`Absent` branches — a body-envelope regression that +/// invented forest on a bone-dry world would show up here as a NEW +/// non-Barren/non-Absent vegetation discriminant in the golden diff. +fn airless_dry_params() -> BodyParams { + BodyParams { + hydrosphere: Some("none".into()), + atmosphere: Some("none".into()), + planet_class: Some("arid".into()), + body_radius_km: Some(3_390.0), // Mars-scale, deliberately distinct from the wet body + ..Default::default() + } +} + +/// I4 (Tyre, PR #194 review): volcanic/high-tectonic coastal body params — +/// exercises `coast_invention`'s ridged-warp + wide-`scatter_floor` branch +/// (`TectonicClass::Volcanic` → `tectonic_energy` near its ceiling in +/// `body_coast_envelope`, driving up `roughness`/`warp_amplitude_px`/ +/// `scatter_floor` per that function's doc) — the coast-crinkle branch most +/// likely to visibly differ from the temperate body's gentler warp, and thus +/// the branch most likely to silently regress without dedicated coverage. +fn volcanic_coast_params() -> BodyParams { + BodyParams { + hydrosphere: Some("ocean".into()), + atmosphere: Some("breathable".into()), + planet_class: Some("volcanic".into()), + tectonic_activity: Some("volcanic".into()), + body_radius_km: Some(6_000.0), + ..Default::default() + } +} + /// Fixed sweep positions (world metres from origin) — a handful of points /// spanning a coastal stretch (per the heightmap's ripple) plus a couple of /// clearly inland/high-latitude points, so the golden exercises coast warp, @@ -165,53 +220,105 @@ const DISTRICT_MIN_WL_M: f64 = 4_096.0; /// new T-1162 entry — Quarter's own Nyquist floor, `2 * QUARTER_M`). const QUARTER_MIN_WL_M: f64 = 1_024.0; -/// Build the full fixed sweep: every position × the three rung cutoffs -/// (District / Quarter use their REAL production `MIN_WL_BANDS_M` values / -/// Region via `derive_orbital_at_metres`, which takes no cutoff parameter — -/// see its own doc on why). -fn golden_samples() -> Vec { - let hm = sample_hm(); - let ta = sample_ta(&hm); - let params = sample_params(); - let climate = ClimateConstants::default(); - let seed = SeedChain::root(0xC0FFEE_u64).derive(SeedDomain::Body, 7); - let body_id = "golden_body"; - +/// Run the fixed sweep (every position × the three rung cutoffs — District / +/// Quarter use their REAL production `MIN_WL_BANDS_M` values / Region via +/// `derive_orbital_at_metres`, which takes no cutoff parameter — see its own +/// doc on why) for ONE body. Extracted (Tyre, PR #194 I4) so multiple bodies +/// can share the same sweep logic; `label_prefix` (empty for the original +/// body, non-empty for the I4 additions) is prepended to each row's `label` +/// so multi-body output stays distinguishable without a new struct field +/// (see [`GoldenSample`]'s doc on why no `body` field was added). +#[allow(clippy::too_many_arguments)] +fn body_sweep_samples( + label_prefix: &str, + seed: SeedChain, + body_id: &str, + params: &BodyParams, + ta: &TerrainAnalysis, + climate: &ClimateConstants, +) -> Vec { let mut out = Vec::new(); for (label, wx, wy) in sweep_positions() { + let label = format!("{label_prefix}{label}"); out.push(derive_golden_sample( - label, + &label, "district", seed, body_id, - ¶ms, - &ta, - &climate, + params, + ta, + climate, wx, wy, DISTRICT_MIN_WL_M, false, )); out.push(derive_golden_sample( - label, + &label, "quarter", seed, body_id, - ¶ms, - &ta, - &climate, + params, + ta, + climate, wx, wy, QUARTER_MIN_WL_M, false, )); out.push(derive_golden_sample( - label, "region", seed, body_id, ¶ms, &ta, &climate, wx, wy, 0.0, true, + &label, "region", seed, body_id, params, ta, climate, wx, wy, 0.0, true, )); } out } +/// Build the full golden sample set: the ORIGINAL temperate/ocean/breathable +/// body's sweep first (byte-identical inputs to the pre-I4 `golden_samples` +/// — same seed, same `body_id`, same unprefixed labels, so its rows are +/// byte-identical in the regenerated fixture), THEN the two I4 body rows +/// appended after (never interleaved) so the diff against the pre-I4 golden +/// is a pure append, not a reshuffle. +fn golden_samples() -> Vec { + let hm = sample_hm(); + let ta = sample_ta(&hm); + let climate = ClimateConstants::default(); + + let mut out = Vec::new(); + + // Original body — UNCHANGED inputs from pre-I4 (T-1162 initial landing). + out.extend(body_sweep_samples( + "", + SeedChain::root(0xC0FFEE_u64).derive(SeedDomain::Body, 7), + "golden_body", + &sample_params(), + &ta, + &climate, + )); + + // I4 addition 1: airless/dry — ceiling_q == 0 vegetation short-circuit. + out.extend(body_sweep_samples( + "airless_dry/", + SeedChain::root(0xC0FFEE_u64).derive(SeedDomain::Body, 8), + "golden_body_airless_dry", + &airless_dry_params(), + &ta, + &climate, + )); + + // I4 addition 2: volcanic/high-tectonic coast — ridged warp, wide scatter_floor. + out.extend(body_sweep_samples( + "volcanic_coast/", + SeedChain::root(0xC0FFEE_u64).derive(SeedDomain::Body, 9), + "golden_body_volcanic_coast", + &volcanic_coast_params(), + &ta, + &climate, + )); + + out +} + #[test] fn window_derivation_golden_regression() { let manifest = PathBuf::from(env!("CARGO_MANIFEST_DIR")); @@ -294,12 +401,18 @@ fn quarter_and_district_rungs_diverge_at_the_same_position() { ); } -/// `scale::DISTRICT_M` / `scale::QUARTER_M` sanity — documents WHY 2,048/1,024 -/// are the cutoffs used above (District's own spacing; Quarter's own Nyquist -/// floor, `2 × QUARTER_M`), so a future scale-ladder change surfaces here. +/// `scale::DISTRICT_M` / `scale::QUARTER_M` sanity — documents WHY +/// `DISTRICT_MIN_WL_M`/`QUARTER_MIN_WL_M` are the cutoffs used above (each +/// rung's own Nyquist floor, `2 × `), so a future +/// scale-ladder change surfaces here. Pins BOTH rungs' coupling (Tyre, PR +/// #194 I1 — District's coupling was previously unpinned; only Quarter's +/// `2 × QUARTER_M` was checked) — this mirrors +/// `layer_proxy::MIN_WL_BANDS_M`'s own direct `2 × DISTRICT_M` / `2 × +/// QUARTER_M` derivation, not `detail_scatter::OCTAVE_WAVELENGTHS_M`. #[test] fn golden_cutoffs_match_the_scale_ladder() { assert_eq!(scale::DISTRICT_M, 2_048); assert_eq!(scale::QUARTER_M, 512); - assert_eq!(2 * scale::QUARTER_M, 1_024); + assert_eq!(2 * scale::DISTRICT_M, DISTRICT_MIN_WL_M as i32); + assert_eq!(2 * scale::QUARTER_M, QUARTER_MIN_WL_M as i32); }