feat(simulation): T-1152 server half — WindowGranularity enum, derive_orbital_at_metres, Region rung on the same carrier

R1 measured first: a capped Region tile through the real production path
(build_district_window_layer + T-1151 par_iter) at the 64x64 wire cap
costs 0.40-0.48ms — faster than the shipped district n=64 window, so
Jeroen's progressive capped-density tiling ruling is comfortably
interactive on-demand. Raw orbital derive ~0.9µs/cell (~2.3x faster than
full derive; region_baseline dominates, not invent_primitives).

R5 redesign: WindowGranularity enum (Quarter/District/Region), serde
named-variant per the RoadNodeKind precedent, spacing from D-243 scale::
constants — the single source of truth. Additive serde-default
window_granularity_v2 request field (None = legacy u32 path; v2 wins when
Some); DistrictWindowLayer.granularity_v2 always echoed. Legacy u32 echo
for Region uses reserved WINDOW_GRANULARITY_REGION_KEY = u32::MAX (never
a legal input) so the old slot cannot lie about aliasing. Cache and
coalescing keys carry the enum itself (Ord by declaration order, D-010).

n stays district-extent at every rung; Region's cell grid is a DIVISION
(round(n/100), min 1) with its own per-axis ceiling
DISTRICT_WINDOW_MAX_N_REGION=6400 and a bounded halving-loop clamp (no
closed form under the rounding division — the client mirror must
replicate the loop).

derive_orbital_at_metres: bilinear envelope reads + region_baseline
temperature, NO invent_primitives (proven by test — slope_q pinned 0),
routed through the shared build_district_profile classification tail so
the existing colorizer family renders orbital cells unchanged. R2
stepped-categorical behavior documented at the function, not implied.

Region aliasing + clamp/echo tests mirror the T-1150 discipline. 1813
lib tests green; clippy clean; fixture regenerated (254->278 bytes, new
echoed field).
This commit is contained in:
2026-07-22 10:35:37 +02:00
parent 2a4597e108
commit d356b09926
9 changed files with 1155 additions and 133 deletions
+269
View File
@@ -1569,6 +1569,128 @@ pub fn derive_at_metres(
)
}
/// The orbital-rung derivation (T-1152, zoom ladder design doc §2/§4): the
/// coarse-granularity twin of [`derive_at_metres`] that skips [`invent_primitives`]
/// entirely — **no coastline warp, no detail-scatter octave sum, no classification
/// noise call of any kind**. Per the design doc's orbital row: "`region_baseline_at_district`
/// only — bilinear blend of 4 region baselines, no `invent_primitives`, 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 terrain has nothing left to
/// contribute at this spacing; calling it would burn cycles synthesizing detail
/// no orbital pixel can resolve. What DOES vary at orbital spacing is the
/// **envelope** the heightmap itself carries (the `TerrainAnalysis` continental
/// shape) and the **region climate baseline** — this function samples exactly
/// those two, nothing else.
///
/// **Cost model (design doc R1 — measure first):** one `bilinear` (elevation),
/// one `bilinear_bool` (ocean mask), one `region_baseline_at_district` call (its
/// own cost is 4×`derive_region_baseline_c` on a cache miss, O(1) on a cache hit)
/// — no octave sum, no coast-warp trig, no character/envelope computation. See
/// `server/tests/zoom_ladder_bench.rs`'s `bench_derive_orbital_at_metres` for the
/// measured per-cell figure this claim rests on.
///
/// Produces the SAME six-field tail every other rung produces (`morphology_zone`,
/// `elev_q`, `temperature_c`, `moisture_q`, `vegetation_class`, `glaciation_grade`)
/// by routing the bilinear-only primitives through the same
/// [`build_district_profile`] classification tail every other rung uses — one
/// classification pipeline, never a second orbital-only decision tree (D-227:
/// classification thresholds don't get a coarse-rung variant any more than the
/// quarter rung got its own "quarter mode" thresholds, design doc §6).
///
/// **R2 (stepped fields):** `moisture_q`/`temperature_c`/`morphology_zone`/etc.
/// are exactly as stepped here as at every other rung — `region_baseline_at_district`
/// floor-divides to the containing `DistrictPos` regardless of caller spacing (see
/// [`derive_at_metres`]'s own doc on this), so this function does not make
/// temperature MORE continuous at orbital scale; it inherits the same
/// district-tier step the design doc documents as permanent, by construction.
///
/// **`slope_q` is fixed at 0`** — the bilinear-only envelope carries no
/// per-cell slope signal at orbital spacing (`ta.slope_deg` is a district-scale
/// proxy; sampling it here would imply a precision the coarse envelope doesn't
/// have). `slope_q` only affects morphology gates 36 (FjordWall/CliffCoast/
/// BraidedDelta/DuneStrand) and the invented-primitives `carve` term this
/// function never runs — passing 0 means those gates fall through to their
/// low-slope alternatives, which is the correct behavior for a coastline sampled
/// at coarser-than-detail-scatter resolution (no invented ruggedness to report).
pub fn derive_orbital_at_metres(
seed: SeedChain,
body_id: &str,
body_params: &BodyParams,
ta: &TerrainAnalysis,
wx: f64,
wy: f64,
climate: &ClimateConstants,
) -> DistrictProfile {
// Same world-metres -> fractional heightmap pixel + latitude mapping
// derive_at_metres uses — the envelope is the SAME TerrainAnalysis grid at
// every rung, only the sampling density differs.
let (px, py, _world_x_m, _world_y_m, lat_deg) = match body_params.body_radius_km {
Some(r_km) if r_km > 0.0 => {
let circumference_m = std::f64::consts::TAU * r_km * 1000.0;
let meridian_m = std::f64::consts::PI * r_km * 1000.0;
let px = (wx / circumference_m).rem_euclid(1.0) * ta.w as f64;
let lat_frac = (wy / meridian_m).clamp(-0.5, 0.5);
let py = (0.5 + lat_frac) * ta.h.saturating_sub(1) as f64;
(px, py, wx, wy, -lat_frac * 180.0)
}
_ => {
let dm = scale::DISTRICT_M as f64;
let px = (wx / dm).clamp(0.0, ta.w.saturating_sub(1) as f64);
let py = (wy / dm).clamp(0.0, ta.h.saturating_sub(1) as f64);
let lat_deg = if ta.h > 1 {
90.0 - (py / (ta.h - 1) as f64) * 180.0
} else {
0.0
};
(px, py, px * dm, py * dm, lat_deg)
}
};
let params = BodyParams {
latitude_deg: lat_deg,
..body_params.clone()
};
// The envelope only — no coast-warp, no detail-scatter. This is exactly
// `invent_primitives`' step-1 "driver tier" raw bilinear reads, promoted to
// be the FINAL primitives instead of a one-step-stale input to invention.
let elev_q =
((bilinear(&ta.elev_pct, ta.w, ta.h, px, py) as f64 * 100.0).round() as i32).clamp(0, 100);
let ocean_fraction_q = ((bilinear_bool(&ta.ocean_mask, ta.w, ta.h, px, py) 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;
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(),
body_id,
district_pos,
&params,
climate,
seed,
None, // no pre-built cache; derive on-the-fly, same posture as derive_at_metres
);
build_district_profile(
seed,
&params,
climate,
slope_q,
elev_q,
ocean_fraction_q,
region_baseline_c,
BasinDirection::default(),
)
}
/// Bilinear interpolation of a row-major `f32` field at fractional `(px, py)`.
/// Columns wrap (equirectangular); rows clamp at the poles.
fn bilinear(field: &[f32], w: usize, h: usize, px: f64, py: f64) -> f32 {
@@ -2066,6 +2188,153 @@ mod tests {
);
}
// -------------------------------------------------------------------
// derive_orbital_at_metres (T-1152, design doc §2/§4 orbital row)
// -------------------------------------------------------------------
/// Determinism (D-010/D-227): two independent orbital derives at the same
/// position produce a bit-identical `DistrictProfile`, mirroring
/// `derive_district_is_deterministic`'s pattern for the finer rungs.
#[test]
fn derive_orbital_at_metres_is_deterministic() {
let hm = test_hm();
let ta = test_ta(&hm);
let climate = ClimateConstants::default();
let p = earth_params();
let dm = scale::REGION_M as f64;
let a = derive_orbital_at_metres(
test_seed(),
"test_body",
&p,
&ta,
3.0 * dm,
2.0 * dm,
&climate,
);
let b = derive_orbital_at_metres(
test_seed(),
"test_body",
&p,
&ta,
3.0 * dm,
2.0 * dm,
&climate,
);
assert_district_profiles_eq(&a, &b);
}
/// The orbital path must NOT run `invent_primitives` — the design doc's
/// central constraint (§2: "no invent_primitives at orbital wavelengths").
/// Direct proof: `slope_q` is always exactly 0 (invention is the only
/// source of nonzero slope_q at this call depth — see
/// `derive_orbital_at_metres`'s doc on why slope_q is fixed), sampled
/// across enough distinct positions that a nonzero value appearing even
/// once would falsify the claim.
#[test]
fn derive_orbital_at_metres_never_invents_slope() {
let hm = test_hm();
let ta = test_ta(&hm);
let climate = ClimateConstants::default();
let p = earth_params();
let dm = scale::REGION_M as f64;
for i in 0..25 {
let wx = (i * 7) as f64 * dm * 0.37;
let wy = (i * 11) as f64 * dm * 0.29;
let prof =
derive_orbital_at_metres(test_seed(), "test_body", &p, &ta, wx, wy, &climate);
assert_eq!(
prof.slope_q, 0,
"orbital derive must never report invented slope (position {i})"
);
}
}
/// The orbital derive's `elev_q`/`temperature_c` must come from the SAME
/// envelope + region-baseline sources `derive_at_metres` reads — not an
/// independent/divergent computation. At a position where the invented
/// scatter happens to contribute exactly zero (impossible to guarantee by
/// construction, so this test instead checks the WEAKER, always-true
/// property: both paths' `elev_q` derive from the same underlying
/// bilinear envelope, so they must be close — within the invented
/// scatter's own bounded contribution range, not arbitrarily different).
/// This guards against the orbital path silently reading a different
/// terrain field entirely (a copy-paste bug this refactor is exactly the
/// kind of change that could introduce).
#[test]
fn derive_orbital_at_metres_elevation_tracks_the_same_envelope() {
let hm = test_hm();
let ta = test_ta(&hm);
let climate = ClimateConstants::default();
let p = earth_params();
let dm = scale::DISTRICT_M as f64;
// Sample at a DISTRICT-aligned position (within the orbital function's
// legal domain — it accepts any world position, this just makes the
// district-mode comparison call meaningful) so both paths read the
// exact same fractional heightmap pixel.
let wx = 40.0 * dm;
let wy = 20.0 * dm;
let orbital = derive_orbital_at_metres(test_seed(), "test_body", &p, &ta, wx, wy, &climate);
let full = derive_at_metres(test_seed(), "test_body", &p, &ta, wx, wy, &climate, 0.0);
// The invented scatter is a bounded perturbation on top of the raw
// envelope (detail_scatter's amplitude is capped well under 100 elev_q
// points) — the two must be in the same ballpark, not exactly equal
// (that would defeat the point of invention existing at all at the
// finer rung) and not wildly different (that would mean the orbital
// path is reading a different field).
let elev_diff = (orbital.elev_q - full.elev_q).abs();
assert!(
elev_diff <= 50,
"orbital elev_q ({}) and full-derive elev_q ({}) must come from the \
same envelope, not diverge arbitrarily",
orbital.elev_q,
full.elev_q
);
}
/// Orbital-scale windows must still fill all six dense wire arrays the
/// client's colorizer family reads (T-1152: "the orbital cells must fill
/// the same six dense arrays the DistrictWindowLayer carries") — this is
/// checked at the `DistrictProfile` level (the pre-packing source of
/// those six fields): every field the packer reads
/// (`morphology_zone`/`elev_q`/`temperature_c`/`moisture_q`/
/// `vegetation_class`/`glaciation_grade`) must be populated the same way
/// regardless of rung — this test asserts the orbital output is a
/// legitimate `DistrictProfile`, not a partially-filled stand-in.
#[test]
fn derive_orbital_at_metres_populates_all_six_wire_fields() {
let hm = test_hm();
let ta = test_ta(&hm);
let climate = ClimateConstants::default();
let p = earth_params();
let dm = scale::REGION_M as f64;
let prof = derive_orbital_at_metres(
test_seed(),
"test_body",
&p,
&ta,
5.0 * dm,
3.0 * dm,
&climate,
);
assert!((0..=100).contains(&prof.elev_q));
assert!((0..=100).contains(&prof.moisture_q));
// temperature_c is Some for a breathable-atmosphere body (earth_params).
assert!(prof.temperature_c.is_some());
// morphology_zone/vegetation_class/glaciation_grade are enums with no
// "unset" state — successfully constructing the DistrictProfile at
// all (no panic) is the actual assertion; the field reads below just
// confirm they're reachable typed values, matching the discipline
// `derive_district_is_deterministic` and neighbours already use.
let _ = prof.morphology_zone;
let _ = prof.vegetation_class;
let _ = prof.glaciation_grade;
}
#[test]
fn derive_district_profile_is_deterministic() {
let hm = test_hm();
+30 -42
View File
@@ -34,7 +34,9 @@ use crate::atlas::cascade::{run_cascade_from_heightmap, CascadeLayer};
use crate::atlas::district_profile::{BodyParams, ClimateConstants, DistrictPos};
use crate::atlas::features::TerrainAnalysis;
use crate::atlas::heightmap::{load_heightmap_png, GRID_H, GRID_W};
use crate::atlas::layer_proxy::{build_district_window_layer, DistrictWindowLayer};
use crate::atlas::layer_proxy::{
build_district_window_layer, DistrictWindowLayer, WindowGranularity,
};
use crate::atlas::shell::{fill_chunk, FilledChunk};
use crate::atlas::skeleton_gen::{assign_all_block_tags, generate_quarter_skeleton};
use crate::atlas::trait_catalog_reader::ExteriorCatalog;
@@ -208,11 +210,18 @@ pub enum GenWorkItem {
/// before this item is built — never trusted from the wire again here.
center: DistrictPos,
n: u32,
/// Derivation granularity (T-1150) — `WINDOW_GRANULARITY_DISTRICT` (1)
/// or `WINDOW_GRANULARITY_QUARTER` (4). Already resolved via
/// `resolve_window_granularity` by the caller.
granularity: u32,
/// Derivation granularity (T-1150, widened T-1152 to the full
/// [`WindowGranularity`] vocabulary — `District`/`Quarter` (finer)
/// plus `Region` (coarser, T-1152)). Already resolved via
/// `resolve_window_granularity_v2` by the caller — this is a
/// concrete rung, never a raw wire value.
granularity: WindowGranularity,
/// Octave cutoff in whole metres (T-1149/T-1150), `0` = no cutoff.
/// Meaningless for `granularity: Region` (`derive_orbital_at_metres`
/// never calls the octave-scatter path this cuts off) but still
/// carried and echoed uniformly — see `derive_orbital_at_metres`'s
/// doc for why the field is harmless-but-unused there, not
/// special-cased away.
min_wl_m: u32,
},
}
@@ -227,13 +236,17 @@ impl GenWorkItem {
/// Coalescing key for `DeriveWindow` items only — `(connection, body,
/// granularity)` (T-1150, design doc §3 [SOFT] recommendation, extending
/// T-1137's `(connection, body)`). `granularity` is part of the key so an
/// in-flight district-spacing (granularity 1) pan-burst is never
/// superseded by an unrelated quarter-spacing (granularity 4) request for
/// the same connection+body, and vice versa — the two rungs are separate
/// in-flight derives, not competing updates to the same one.
/// T-1137's `(connection, body)`; widened T-1152 to carry the full
/// [`WindowGranularity`] enum rather than the legacy `u32`, so `Region`
/// occupies its own coalescing slot exactly like `District`/`Quarter` do
/// — this is one of the five T-1150 touch points the R5 redesign must
/// carry the new representation through). `granularity` is part of the
/// key so an in-flight district-spacing pan-burst is never superseded by
/// an unrelated quarter- or region-spacing request for the same
/// connection+body, and vice versa — every rung is a separate in-flight
/// derive, not a competing update to the same one.
/// `None` for every other variant (they don't coalesce this way).
pub fn window_supersede_key(&self) -> Option<(ConnectionId, &str, u32)> {
pub fn window_supersede_key(&self) -> Option<(ConnectionId, &str, WindowGranularity)> {
if let GenWorkItem::DeriveWindow {
body_id,
conn_id,
@@ -1150,19 +1163,14 @@ mod tests {
/// coalescing tests can exercise the granularity axis of
/// `window_supersede_key()` without a second near-duplicate helper.
fn derive_window(body_id: &str, conn_id: ConnectionId, center: DistrictPos) -> GenWorkItem {
derive_window_at(
body_id,
conn_id,
center,
crate::atlas::layer_proxy::WINDOW_GRANULARITY_DISTRICT,
)
derive_window_at(body_id, conn_id, center, WindowGranularity::District)
}
fn derive_window_at(
body_id: &str,
conn_id: ConnectionId,
center: DistrictPos,
granularity: u32,
granularity: WindowGranularity,
) -> GenWorkItem {
GenWorkItem::DeriveWindow {
body_id: body_id.to_string(),
@@ -1316,21 +1324,11 @@ mod tests {
let conn = ConnectionId(9);
q.submit_window(
derive_window_at(
"GranBody",
conn,
(0, 0),
crate::atlas::layer_proxy::WINDOW_GRANULARITY_DISTRICT,
),
derive_window_at("GranBody", conn, (0, 0), WindowGranularity::District),
GenPriority::Immediate,
);
q.submit_window(
derive_window_at(
"GranBody",
conn,
(0, 0),
crate::atlas::layer_proxy::WINDOW_GRANULARITY_QUARTER,
),
derive_window_at("GranBody", conn, (0, 0), WindowGranularity::Quarter),
GenPriority::Immediate,
);
assert_eq!(
@@ -1352,21 +1350,11 @@ mod tests {
let conn = ConnectionId(11);
q.submit_window(
derive_window_at(
"SameGranBody",
conn,
(0, 0),
crate::atlas::layer_proxy::WINDOW_GRANULARITY_QUARTER,
),
derive_window_at("SameGranBody", conn, (0, 0), WindowGranularity::Quarter),
GenPriority::Immediate,
);
q.submit_window(
derive_window_at(
"SameGranBody",
conn,
(5, 5),
crate::atlas::layer_proxy::WINDOW_GRANULARITY_QUARTER,
),
derive_window_at("SameGranBody", conn, (5, 5), WindowGranularity::Quarter),
GenPriority::Immediate,
);
assert_eq!(
File diff suppressed because it is too large Load Diff
+2 -1
View File
@@ -418,7 +418,7 @@ fn drain_generation_completions(
body_id,
layer.center,
layer.n,
layer.granularity,
layer.granularity_v2,
layer.min_wl_m,
),
*layer,
@@ -914,6 +914,7 @@ mod tests {
window_center: None,
window_n: 0,
window_granularity: 0,
window_granularity_v2: None,
window_min_wl_m: 0,
},
)]));
+2
View File
@@ -1202,6 +1202,7 @@ mod inbound_tests {
window_center: None,
window_n: 0,
window_granularity: 0,
window_granularity_v2: None,
window_min_wl_m: 0,
};
let frame = rmp_serde::to_vec_named(&req).unwrap();
@@ -1249,6 +1250,7 @@ mod inbound_tests {
window_center: None,
window_n: 0,
window_granularity: 0,
window_granularity_v2: None,
window_min_wl_m: 0,
})
.unwrap();