fix(simulation): one shared invent_coastal_position — PR #208 review round (T-1160)

Hoshe found the concrete residual: the hand-copied driver block called
derive_temperature_c unconditionally where invent_primitives prefers the
lapse-adjusted region baseline on non-airless bodies — driver_temp feeds
glaciation/moisture into the warp magnitude, so orbital displacement
could still differ from District at the same position (the ticket's
defect class, one step upstream); the copy structurally couldn't branch
right because region_baseline_at_district was computed after it. Tyre
demanded the structural cure: steps 1-3 now live in ONE shared helper
(invent_coastal_position -> warped position + CoastCharacter);
invent_primitives composes helper + detail-scatter; the orbital path
hoists the baseline and makes a single helper call. The audit test's own
'District-style' side turned out to be a THIRD copy carrying the same
bug — rewired to the real helper (raw pre-fix side untouched as the
historical baseline; refreshed: 5.01% disagreement, mean 5,957.9 m,
748.9 ns/cell). Golden verified byte-identical under forced regen, with
the reason traced: the wire temperature never flowed through the buggy
internal branch, and the fixture's probe positions cross no discrete
boundary — the 267-body audit is the instrument that sees the drift.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-25 17:22:16 +02:00
co-authored by Claude Fable 5
parent 71f70f035e
commit 077d787c4a
+231 -143
View File
@@ -1148,10 +1148,14 @@ struct InventedPrimitives {
ocean_fraction_q: i32,
}
/// Compose the invented district primitives at one position — the shared front
/// half of BOTH derivation paths ([`derive_district`] on-demand and
/// [`derive_district_profile`] batch), so the D-227 invention can never diverge
/// between them again (the pre-T-1125 failure: the batch path was scatter-free).
/// Compose steps 1-3 of the invented-coastline pipeline — the driver-tier
/// climate estimate, the body/position coast character, and the warped
/// sampling position those two produce. **The single shared implementation**
/// (T-1160 PR #208 review, hoshe + tyre): every caller that needs the
/// invented coastline's WARPED POSITION (never a second hand-synced copy of
/// this branch) goes through here — [`invent_primitives`] (steps 1-3, then
/// composes step 4 on top) and [`derive_orbital_at_metres`] (steps 1-3 only,
/// no step 4).
///
/// Steps:
/// 1. **Driver tier (one-step-stale, T-1125 circularity ruling):** the raw
@@ -1160,23 +1164,43 @@ struct InventedPrimitives {
/// these stale drivers; it never reads the warped values it produces. The
/// raw inputs are the coarse ~40160 km/pixel envelope anyway, so one step
/// of staleness is far below the signal's own resolution.
///
/// **Region-baseline branch (T-1160 PR #208 fix):** `driver_temp` prefers
/// the lapse-adjusted [`derive_district_temperature_c`] whenever
/// `region_baseline_c` is `Some` — the SAME branch [`derive_district_profile`]'s
/// batch path and [`derive_at_metres`]'s on-demand path have always used —
/// falling back to the body-level [`derive_temperature_c`] only for airless
/// bodies (`region_baseline_c: None`, no region climate to lapse-adjust).
/// Before this fix, a hand-copied version of this block inside
/// `derive_orbital_at_metres` called `derive_temperature_c`
/// UNCONDITIONALLY — wrong on every non-airless body (the entire coastline
/// population), silently producing a different `driver_temp` →
/// `driver_moisture` → `driver_glaciation` (a discrete band) →
/// `coast_character_at` → warp displacement than District/Quarter at the
/// identical position, reintroducing the exact T-1160 defect class one
/// step upstream of the fix that closed it for the sampling position
/// itself.
/// 2. **Character:** tier-1 body envelope ([`coast_invention::body_coast_envelope`];
/// `derive_tectonic_class` hoisted here — it needs only `BodyParams`) +
/// tier-2 position character ([`coast_invention::coast_character_at`]).
/// 3. **Invented coastline:** every envelope field (elevation, slope, ocean
/// mask) is sampled at the SAME warped position, so terrain moves coherently
/// — a warped-in bay carries its sea-level elevation with it.
/// 4. **Slope-independent scatter:** the character's `scatter_floor` breaks the
/// old amplitude-slaved-to-coarse-slope collapse (invention ≈ 0 exactly on
/// low-relief coasts); `ridge` carries fjord/tectonic sharpness.
/// 3. **Invented coastline:** the warped `(spx, spy)` position — every
/// envelope field (elevation, slope, ocean mask) a caller samples at this
/// position moves coherently — a warped-in bay carries its sea-level
/// elevation with it.
///
/// `body_params` must already carry the district's `latitude_deg`.
///
/// `min_wavelength_m` (T-1149, zoom ladder §2): threaded straight to the
/// `terrain_detail` scatter call — octaves finer than this are truncated.
/// `0.0` = no cutoff = today's behavior.
/// coast-warp call — octaves finer than this are truncated. `0.0` = no
/// cutoff = today's behavior.
///
/// Returns `(spx, spy, ch)`: the warped position, plus the resolved
/// [`coast_invention::CoastCharacter`] — [`invent_primitives`]' step 4
/// (slope-independent scatter) reads `ch.scatter_floor`/`ch.ridge`, so the
/// character has to come back out rather than be recomputed a second time.
/// [`derive_orbital_at_metres`] (steps 1-3 only) uses just the position.
#[allow(clippy::too_many_arguments)]
fn invent_primitives(
fn invent_coastal_position(
seed: SeedChain,
body_params: &BodyParams,
climate: &ClimateConstants,
@@ -1187,7 +1211,7 @@ fn invent_primitives(
world_y_m: f64,
region_baseline_c: Option<f32>,
min_wavelength_m: f64,
) -> InventedPrimitives {
) -> (f64, f64, coast_invention::CoastCharacter) {
// ── 1. Driver tier: UNWARPED raw-bilinear climate (one-step-stale). ─────
let raw_elev_q =
((bilinear(&ta.elev_pct, ta.w, ta.h, px, py) as f64 * 100.0).round() as i32).clamp(0, 100);
@@ -1220,11 +1244,58 @@ fn invent_primitives(
// ── 3. Invented coastline: warp the whole envelope sampling. ────────────
// T-1162: the coast warp gets the SAME min_wavelength_m cutoff as the
// terrain-detail scatter below — one rung, one cutoff, applied to both
// continuous fields that compose the invented coastline.
// terrain-detail scatter (invent_primitives' step 4) — one rung, one
// cutoff, applied to both continuous fields that compose the invented
// coastline.
let (wdx, wdy) =
coast_invention::coast_warp_px(seed.seed(), world_x_m, world_y_m, &ch, min_wavelength_m);
let (spx, spy) = (px + wdx, py + wdy);
(px + wdx, py + wdy, ch)
}
/// Compose the invented district primitives at one position — the shared front
/// half of BOTH derivation paths ([`derive_district`] on-demand and
/// [`derive_district_profile`] batch), so the D-227 invention can never diverge
/// between them again (the pre-T-1125 failure: the batch path was scatter-free).
///
/// Steps 1-3 (driver tier, character, invented warped position) are
/// [`invent_coastal_position`] — this function calls it, samples the
/// envelope at the returned position, then composes step 4 (slope-independent
/// scatter) on top:
/// 4. **Slope-independent scatter:** the character's `scatter_floor` breaks the
/// old amplitude-slaved-to-coarse-slope collapse (invention ≈ 0 exactly on
/// low-relief coasts); `ridge` carries fjord/tectonic sharpness.
///
/// `body_params` must already carry the district's `latitude_deg`.
///
/// `min_wavelength_m` (T-1149, zoom ladder §2): threaded straight to the
/// `terrain_detail` scatter call — octaves finer than this are truncated.
/// `0.0` = no cutoff = today's behavior.
#[allow(clippy::too_many_arguments)]
fn invent_primitives(
seed: SeedChain,
body_params: &BodyParams,
climate: &ClimateConstants,
ta: &TerrainAnalysis,
px: f64,
py: f64,
world_x_m: f64,
world_y_m: f64,
region_baseline_c: Option<f32>,
min_wavelength_m: f64,
) -> InventedPrimitives {
// ── Steps 1-3: driver tier, character, invented warped position. ────────
let (spx, spy, ch) = invent_coastal_position(
seed,
body_params,
climate,
ta,
px,
py,
world_x_m,
world_y_m,
region_baseline_c,
min_wavelength_m,
);
let elev_pct = bilinear(&ta.elev_pct, ta.w, ta.h, spx, spy) as f64;
let slope_deg = bilinear(&ta.slope_deg, ta.w, ta.h, spx, spy) as f64;
let ocean_frac = bilinear_bool(&ta.ocean_mask, ta.w, ta.h, spx, spy) as f64;
@@ -1931,12 +2002,16 @@ fn derive_at_metres_with_riparian(
/// coarse-granularity twin of [`derive_at_metres`] that skips MOST of
/// [`invent_primitives`] — **no detail-scatter octave sum, no classification
/// noise call of any kind** — but DOES apply the coast-warp position shift
/// (T-1160). Per the design doc's orbital row: "`region_baseline_at_district`
/// only — bilinear blend of 4 region baselines, no [detail-scatter]
/// invention, no classification [driver]." Orbital sample spacing (≥205 km,
/// D-243's region rung and coarser) sits below `detail_scatter`'s own octave
/// floor (`OCTAVE_WAVELENGTHS_M`'s coarsest entry is 32,768 m ≈ 32.8 km — an
/// order of magnitude finer than a region), so the invented RELIEF texture has
/// (T-1160) via [`invent_coastal_position`], the SAME shared steps 1-3
/// helper [`invent_primitives`] composes on top of (never a hand-copied
/// replica of that logic — see the helper's own doc for why that class of
/// bug is now structurally closed, not just fixed once). Per the design
/// doc's orbital row: "`region_baseline_at_district` only — bilinear blend
/// of 4 region baselines, no [detail-scatter] invention, no classification
/// [driver]." Orbital sample spacing (≥205 km, D-243's region rung and
/// coarser) sits below `detail_scatter`'s own octave floor
/// (`OCTAVE_WAVELENGTHS_M`'s coarsest entry is 32,768 m ≈ 32.8 km — an order
/// of magnitude finer than a region), so the invented RELIEF texture has
/// nothing left to contribute at this spacing; running it would burn cycles
/// synthesizing detail no orbital pixel can resolve. The coastline WARP is
/// different: `WARP_OCTAVE_WAVELENGTHS_M`'s coarsest entries run up to 262,144 m
@@ -1951,20 +2026,30 @@ fn derive_at_metres_with_riparian(
/// position**, plus the **region climate baseline** — this function samples
/// exactly those, nothing else.
///
/// **Ordering (T-1160 PR #208 fix):** `region_baseline_at_district` is
/// called BEFORE [`invent_coastal_position`], not after — the helper's
/// driver-tier branch (step 1) needs the resolved baseline to pick the SAME
/// region-baseline-preferring formula `invent_primitives`/`derive_at_metres`
/// use. A structurally-forced-wrong hand-copy of the driver tier (computed
/// before the baseline existed in scope) is exactly the bug PR #208 review
/// caught: it could not branch correctly no matter how carefully it was
/// hand-synced, because the value it needed to branch on didn't exist yet.
///
/// **Cost model (T-1160 audit, measured on 267 real bodies, release build):**
/// the added driver-tier climate + `coast_character_at` + `coast_warp_px` work
/// costs ~784 ns/cell (`coast_warp_px` alone: ~528 ns/cell) — roughly half of
/// what `invent_primitives`' FULL pipeline costs on top of this function's own
/// ~903 ns/cell baseline (`bench_derive_orbital_at_metres_region_spacing`:
/// orbital 902.6 ns/cell vs. full `derive_at_metres` 1940.6 ns/cell at the same
/// spacing — a 2.15x gap, of which detail-scatter/classification-noise is the
/// remainder this function still skips). At the D-255(a) fixed-rung ceiling
/// (3,840×2,160 = 8.3M cells) the added cost is ~6.5 s single-threaded / low
/// hundreds of ms on the row-chunked parallel serving path (T-1151); at a
/// realistic Global-rung Earth-sized-body canvas (195×97 ≈ 18.9K cells) it is
/// ~15 ms. Accepted: coastline correctness at the orbital/Region seam is worth
/// a sub-millisecond-to-low-second cost that scales with (and is bounded by)
/// the same canvas-size ceiling every other rung's cost already respects.
/// (now inside [`invent_coastal_position`]) costs ~784 ns/cell (`coast_warp_px`
/// alone: ~528 ns/cell) — roughly half of what `invent_primitives`' FULL
/// pipeline costs on top of this function's own ~903 ns/cell baseline
/// (`bench_derive_orbital_at_metres_region_spacing`: orbital 902.6 ns/cell vs.
/// full `derive_at_metres` 1940.6 ns/cell at the same spacing — a 2.15x gap, of
/// which detail-scatter/classification-noise is the remainder this function
/// still skips). At the D-255(a) fixed-rung ceiling (3,840×2,160 = 8.3M cells)
/// the added cost is ~6.5 s single-threaded / low hundreds of ms on the
/// row-chunked parallel serving path (T-1151); at a realistic Global-rung
/// Earth-sized-body canvas (195×97 ≈ 18.9K cells) it is ~15 ms. Accepted:
/// coastline correctness at the orbital/Region seam is worth a
/// sub-millisecond-to-low-second cost that scales with (and is bounded by) the
/// same canvas-size ceiling every other rung's cost already respects.
///
/// Produces the SAME six-field tail every other rung produces (`morphology_zone`,
/// `elev_q`, `temperature_c`, `moisture_q`, `vegetation_class`, `glaciation_grade`)
@@ -2028,61 +2113,14 @@ pub fn derive_orbital_at_metres(
..body_params.clone()
};
// T-1160: coast-warp the sampling POSITION (steps 1-3 of
// `invent_primitives`), but skip step 4 (slope-independent detail-scatter)
// — the envelope carries no per-cell slope signal at orbital spacing (see
// the function doc's note on `slope_q`, unchanged). Before this fix, this
// function sampled `ta.elev_pct`/`ta.ocean_mask` RAW while District/Quarter
// sampled the SAME arrays at the coast-warped position — a structurally
// different coastline at the orbital-to-district seam (audit: 5.0%
// land/ocean classification disagreement at coastal-band cells across 267
// real bodies, mean displacement ~6.0 km / max ~18.9 km at region
// spacing). Applying the warp here makes the orbital rung sample the SAME
// invented coastline every finer rung already draws — coarser density,
// same line, not a different line (T-1160).
//
// Driver tier: raw-bilinear reads feed the coast character exactly as
// `invent_primitives` step 1 does (one-step-stale climate driving the
// coast personality, never circular on its own warped output).
let raw_elev_q =
((bilinear(&ta.elev_pct, ta.w, ta.h, px, py) as f64 * 100.0).round() as i32).clamp(0, 100);
let raw_ocean_q = ((bilinear_bool(&ta.ocean_mask, ta.w, ta.h, px, py) as f64 * 100.0).round()
as i32)
.clamp(0, 100);
let driver_params = BodyParams {
elevation_km: (raw_elev_q as f64 / 100.0) * MAX_REGION_ELEVATION_KM,
..params.clone()
};
let driver_temp = derive_temperature_c(&driver_params, climate, seed.seed());
let driver_moisture = derive_moisture_q(&driver_params, raw_elev_q, raw_ocean_q, climate);
let driver_glaciation = derive_glaciation_grade_from_climate(driver_temp, driver_moisture);
// Character + invented coastline (steps 2-3): same body-personality
// envelope + position character + warp displacement District/Quarter use,
// applied to the SAME `(px, py)` this function already resolved.
let tectonic = derive_tectonic_class(body_params);
let envelope = coast_invention::body_coast_envelope(body_params, tectonic);
let ch = coast_invention::coast_character_at(
&envelope,
seed.seed(),
world_x_m,
world_y_m,
lat_deg,
driver_glaciation,
driver_moisture,
);
let (wdx, wdy) = coast_invention::coast_warp_px(seed.seed(), world_x_m, world_y_m, &ch, 0.0);
let (spx, spy) = (px + wdx, py + wdy);
let elev_q = ((bilinear(&ta.elev_pct, ta.w, ta.h, spx, spy) as f64 * 100.0).round() as i32)
.clamp(0, 100);
let ocean_fraction_q = ((bilinear_bool(&ta.ocean_mask, ta.w, ta.h, spx, spy) as f64 * 100.0)
.round() as i32)
.clamp(0, 100);
// No invented ruggedness at orbital spacing (see the function doc's note
// on slope_q) — the envelope carries no per-cell slope signal this coarse.
let slope_q = 0;
// T-1160 PR #208 fix: `region_baseline_at_district` is hoisted ABOVE the
// coastal-position work below — the shared helper's driver tier (step 1)
// needs it to pick the SAME region-baseline-preferring branch
// `invent_primitives`/`derive_at_metres` use. The pre-fix structure
// computed this AFTER a hand-copied driver-tier block, which is exactly
// why that copy could not branch correctly and silently called the
// airless-only `derive_temperature_c` unconditionally (see
// `invent_coastal_position`'s doc for the full defect story).
let district_pos: DistrictPos = (
(wx / scale::DISTRICT_M as f64).floor() as i32,
(wy / scale::DISTRICT_M as f64).floor() as i32,
@@ -2097,6 +2135,41 @@ pub fn derive_orbital_at_metres(
None, // no pre-built cache; derive on-the-fly, same posture as derive_at_metres
);
// T-1160: coast-warp the sampling POSITION via the SAME shared helper
// (`invent_coastal_position`, steps 1-3 of `invent_primitives`) District/
// Quarter use — step 4 (slope-independent detail-scatter) is skipped
// (the envelope carries no per-cell slope signal at orbital spacing, see
// the function doc's note on `slope_q`). Before T-1160, this function
// sampled `ta.elev_pct`/`ta.ocean_mask` RAW while District/Quarter
// sampled the SAME arrays at the coast-warped position — a structurally
// different coastline at the orbital-to-district seam (audit: 5.0%
// land/ocean classification disagreement at coastal-band cells across 267
// real bodies, mean displacement ~6.0 km / max ~18.9 km at region
// spacing). Routing through the ONE shared helper (rather than a
// hand-copied replica) makes the region-baseline branch structurally
// impossible to diverge again.
let (spx, spy, _ch) = invent_coastal_position(
seed,
&params,
climate,
ta,
px,
py,
world_x_m,
world_y_m,
region_baseline_c,
0.0,
);
let elev_q = ((bilinear(&ta.elev_pct, ta.w, ta.h, spx, spy) as f64 * 100.0).round() as i32)
.clamp(0, 100);
let ocean_fraction_q = ((bilinear_bool(&ta.ocean_mask, ta.w, ta.h, spx, spy) as f64 * 100.0)
.round() as i32)
.clamp(0, 100);
// No invented ruggedness at orbital spacing (see the function doc's note
// on slope_q) — the envelope carries no per-cell slope signal this coarse.
let slope_q = 0;
// T-1184: same continuous filled-surface comparison every rung samples,
// at the orbital rung's own (px, py) — lake edges refine at Region
// spacing exactly as they do at every finer rung (D-227 amendment (4)).
@@ -3572,19 +3645,34 @@ mod tests {
/// orbital-vs-district coastline positional divergence that existed
/// BEFORE this ticket: `derive_orbital_at_metres` used to sample
/// `ta.ocean_mask` raw (no `coast_warp_px`) while District/Quarter warped
/// the same mask first (`invent_primitives` step 3). This test
/// independently reimplements both the pre-fix raw read (a) and the
/// District-style warped read (b) — deliberately NOT calling
/// `derive_orbital_at_metres` itself, so the measurement stays valid as a
/// historical baseline regardless of that function's current
/// implementation — loads every real `heightmap.png` under
/// `wiki/star-systems/`, and for a grid of region-spacing sample points on
/// each body reports how often (a) and (b) disagree on land/ocean
/// classification, the warp displacement converted to real metres, and
/// the per-cell cost of computing (b). These are the numbers T-1160's
/// fix (applying the warp at orbital sampling, see
/// `derive_orbital_at_metres`'s doc) is based on. `#[ignore]`d — reads
/// ~267 real wiki heightmap files, run explicitly:
/// the same mask first (`invent_primitives` step 3).
///
/// Side (a), the pre-fix raw read, deliberately stays a hand-rolled
/// historical baseline (NOT a call into current production code) — it
/// exists to measure what the BUG used to do, so it must not silently
/// track whatever `derive_orbital_at_metres` does today.
///
/// Side (b), the "District-style warped read," calls the REAL production
/// [`region_baseline_at_district`] + [`invent_coastal_position`] (PR #208
/// review fix) rather than hand-copying their steps a third time — the
/// original version of this test independently reimplemented the
/// driver-tier branch inline (unconditional `derive_temperature_c`,
/// never the region-baseline-preferring `derive_district_temperature_c`),
/// which was itself a THIRD copy of the exact defect class T-1160 exists
/// to close, undetected because this test's own numbers still "looked
/// plausible" without ever exercising the region-baseline branch. Routing
/// through the shared helper means this test's post-fix side can never
/// drift from what `derive_orbital_at_metres`/`invent_primitives`
/// actually do.
///
/// Loads every real `heightmap.png` under `wiki/star-systems/`, and for a
/// grid of region-spacing sample points on each body reports how often
/// (a) and (b) disagree on land/ocean classification, the warp
/// displacement converted to real metres, and the per-cell cost of
/// computing (b). These are the numbers T-1160's fix (applying the warp
/// at orbital sampling, see `derive_orbital_at_metres`'s doc) is based
/// on. `#[ignore]`d — reads ~267 real wiki heightmap files, run
/// explicitly:
/// `cargo test --release -p settled-reach-server derive_orbital_coastline_divergence_audit -- --ignored --nocapture`
#[test]
#[ignore]
@@ -3614,7 +3702,6 @@ mod tests {
let mut displacement_samples = 0u64;
let mut warp_evals = 0u64;
let mut warp_only_nanos = 0u64;
let mut warp_plus_character_nanos = 0u64;
for hm_path in &heightmaps {
@@ -3639,9 +3726,7 @@ mod tests {
};
let circumference_m = std::f64::consts::TAU * 6371.0 * 1000.0;
let meridian_m = std::f64::consts::PI * 6371.0 * 1000.0;
let tectonic = derive_tectonic_class(&body_params);
let envelope = coast_invention::body_coast_envelope(&body_params, tectonic);
let body_id = "audit_body";
// Sample on a region-spacing grid across the whole body — same
// spacing the orbital/Region rung actually renders at.
@@ -3692,43 +3777,54 @@ mod tests {
total_cells += 1;
// (b) District-style warped read at the SAME position —
// mirrors invent_primitives' driver-tier + character +
// warp steps, using the real per-body envelope. Timed
// calls the REAL production region_baseline_at_district +
// invent_coastal_position (PR #208 review fix) rather
// than hand-copying their steps a third time (see this
// test's own doc for why that was the bug). Timed
// separately from the file-I/O/drainage/TerrainAnalysis
// setup above — this is the actual per-cell cost T-1160
// would add at orbital sampling, not body-load overhead.
let cell_start = Instant::now();
let raw_elev_q = ((bilinear(&ta.elev_pct, ta.w, ta.h, px, py) as f64 * 100.0)
.round() as i32)
.clamp(0, 100);
let driver_params = BodyParams {
elevation_km: (raw_elev_q as f64 / 100.0) * MAX_REGION_ELEVATION_KM,
let params = BodyParams {
latitude_deg: lat_deg,
..body_params.clone()
};
let driver_temp = derive_temperature_c(&driver_params, &climate, seed.seed());
let driver_moisture =
derive_moisture_q(&driver_params, raw_elev_q, raw_ocean_q, &climate);
let driver_glaciation =
derive_glaciation_grade_from_climate(driver_temp, driver_moisture);
let ch = coast_invention::coast_character_at(
&envelope,
let district_pos: DistrictPos = (
(wx / scale::DISTRICT_M as f64).floor() as i32,
(wy / scale::DISTRICT_M as f64).floor() as i32,
);
let region_baseline_c = region_profile::region_baseline_at_district(
seed.seed(),
wx,
wy,
lat_deg,
driver_glaciation,
driver_moisture,
body_id,
district_pos,
&params,
&climate,
seed,
None,
);
warp_plus_character_nanos += cell_start.elapsed().as_nanos() as u64;
warp_evals += 1;
let warp_call_start = Instant::now();
let (wdx, wdy) = coast_invention::coast_warp_px(seed.seed(), wx, wy, &ch, 0.0);
warp_only_nanos += warp_call_start.elapsed().as_nanos() as u64;
warp_plus_character_nanos += warp_call_start.elapsed().as_nanos() as u64;
let (spx, spy) = (px + wdx, py + wdy);
let cell_start = Instant::now();
let (spx, spy, _ch) = invent_coastal_position(
seed,
&params,
&climate,
&ta,
px,
py,
wx,
wy,
region_baseline_c,
0.0,
);
// The helper is one atomic call now (steps 1-3 fused, PR
// #208 review fix) — a single timing captures the full
// per-cell added cost; there is no longer a meaningful
// way to isolate "just coast_warp_px" from "driver tier +
// character" as two separate measurements the way the
// pre-fix hand-inlined version allowed.
warp_plus_character_nanos += cell_start.elapsed().as_nanos() as u64;
let (wdx, wdy) = (spx - px, spy - py);
let warped_ocean_q =
((bilinear_bool(&ta.ocean_mask, ta.w, ta.h, spx, spy) as f64 * 100.0)
.round() as i32)
@@ -3765,11 +3861,6 @@ mod tests {
} else {
0.0
};
let ns_per_warp_call = if warp_evals > 0 {
warp_only_nanos as f64 / warp_evals as f64
} else {
0.0
};
let ns_per_full_cell_cost = if warp_evals > 0 {
warp_plus_character_nanos as f64 / warp_evals as f64
} else {
@@ -3783,10 +3874,7 @@ mod tests {
eprintln!("mean warp displacement: {mean_displacement_m:.1} m");
eprintln!("max warp displacement: {max_displacement_m:.1} m");
eprintln!(
"coast_warp_px call cost: {ns_per_warp_call:.1} ns/call ({warp_evals} calls, {warp_only_nanos} ns total)"
);
eprintln!(
"full added cost/cell: {ns_per_full_cell_cost:.1} ns/cell (driver temp/moisture/glaciation + coast_character_at + coast_warp_px)"
"full added cost/cell: {ns_per_full_cell_cost:.1} ns/cell (invent_coastal_position: driver temp/moisture/glaciation + coast_character_at + coast_warp_px, one production call)"
);
// Sanity floor — this audit is meaningless if it silently sampled