moisture_q was a single body constant (derive_moisture_q took only &BodyParams →
80 for every one of 2048 ocean-world districts), so vegetation/terrain/ecotones
were uniform — "nothing to fuzz" (the T-1080 believability bug).
- district_profile.rs: derive_moisture_q is now a body ceiling (hydrosphere+atmosphere)
× per-district gradient — latitude (equator wet → pole dry), elevation (orographic/
rain-shadow), continentality (100 − ocean_fraction_q). Integer/D-010, no new plumbing
(elev_q/ocean_fraction_q/latitude_deg already reach build_district_profile). Mirrors
D-240's temperature model. Coefficients in ClimateConstants + climate_constants.toml
[moisture_gradient] (provisional; Q-123 calibrates). Tuned so a wet body stays mostly
green with drier patches and a frozen body clamps mostly barren. + gradient unit test.
- region_profile.rs: region-tier moisture gets the region-latitude gradient (elevation/
continentality are district-scale).
- Propagates to precipitation_class / vegetation_class / morphology_zone (all read
moisture_q). D-239 §2 amended. Believability golden regenerated.
Probe (Arbour @ yolo): moisture_q distinct 1 → 49 (spread 0 → 48); 5/7 → 6/7 criteria.
Edict (frozen): moisture 0..20 ×21 — gradient within its low ceiling. Remaining fail
(vegetation-present) is the metric dividing by all-sampled incl. water on a 2/3-ocean
world — a Q-123 calibration concern, not a climate defect.
clippy --all-targets -D warnings clean; 1580 lib tests + harnesses pass.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Addresses PR #167 review (Tyre T1, T3).
T1 — the region climate tier was built but no live path consulted it: both
derive_district_profile (cascade) and derive_district (on-demand) passed
region_baseline_c: None, so the D-243 §4 edge-fuzz blend was dead in production
and district temperature was still derived from scratch. Now both paths compute
region_baseline_at_district(...) and pass it through build_district_profile so
the two-phase modulation (D-243 §3) actually runs. The cascade path
(derive_all_districts) builds a BTreeMap<RegionPos, RegionProfile> covering all
district positions + their +/-1 neighbours once per body and looks up from it;
the on-demand path derives the four surrounding region baselines on the fly.
No production path passes None except genuinely airless bodies (no planet_class).
T3 — renamed BodyParams.district_latitude_deg -> latitude_deg (it is the region
centre latitude in the region fns, a call-site trap under the old name);
dual-scale doc; propagated to body_params_reader.rs and all literal sites.
Golden fixtures are unaffected (they construct districts directly via make_region,
bypassing build_district_profile) — derivation_harness 37/37 green, no re-pin.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Introduces the region (~205 km) climate tier per D-243 §3/§4, above the
DistrictProfile carrier. New region_profile.rs: RegionProfile/RegionClock,
derive_region_baseline_c (latitude lerp + greenhouse, D-240 class-envelope,
no orbit/star inputs), and region_baseline_at_district — the D-243 §4
edge-fuzz warp-perturbed bilinear blend of surrounding region baselines so
the ~205 km grid is invisible in the output.
Splits district temperature (D-243 §3): derive_district_temperature_c now
modulates the region baseline with elevation lapse only, replacing the
from-scratch per-district derivation. build_district_profile takes an
Option<f32> region baseline; None preserves the legacy single-phase path
(existing call sites unchanged). derive_cover (voxel.rs) consumes the
post-refactor value with no signature change.
Region clock (season/weather) scaffolded; transient tick callbacks deferred
to Q-105 per the two-phase convention. 14 region_profile + 5 district
modulation tests added.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Phase 2 of the D-243 re-scale. The ~1km carrier is renamed and re-scaled to
the 2km district, and every consumer reads scale from the canonical scale.rs
instead of a local literal.
- region_profile.rs -> district_profile.rs; RegionProfile -> DistrictProfile,
RegionPos -> DistrictPos (re-exported from scale::DistrictPos), derive_*_regions
-> derive_*_districts, across all 10 consumers + the derivation harness.
- chunk_context now references scale:: for the carrier cell: district 1024m -> 2048m,
shift 4 -> 5 (CHUNK_DISTRICT_SHIFT). This caught a real latent bug: the seed-district
index used a literal '>> 4' while the anchor used the constant, so same-district
chunks could derive different anchors — now both use scale::CHUNK_DISTRICT_SHIFT.
- derivation_harness scale literals ('>> 4', '* 1024', '0..16') converted to
scale:: constants (the same drift the canonical source eliminates). Believability
tests pass at 2km; the voxel determinism golden re-pinned (anchors moved with the
re-scale — deterministic, intended).
Full suite + clippy --all-targets -D warnings green. The district DERIVATION still
tiles the heightmap at 8 cells (the old coarse path); replacing it with on-demand
heightmap interpolation + detail-scatter is phase 3.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
First phase of the D-243 re-scale. Adds server/src/atlas/scale.rs as the
single source of truth for the metric containment ladder (voxel 1m -> chunk
64m -> block 128m -> quarter 512m -> district 2048m -> region 204.8km), the
fixed integer addressing (ChunkPos -> DistrictPos -> RegionPos), and the
elastic seam regions_per_equator(R). Compile-time const asserts enforce the
nesting so the rungs cannot silently drift again — the structural fix for the
Q-110 failure mode (three files, three different region sizes).
Wires body_radius_km (D-204) through BodyParams + the reader: the single
body-specific input to the elastic seam.
No behavior change — foundation only. The rename/re-scale of the carrier
(RegionProfile -> DistrictProfile) and on-demand district derivation follow.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
derive_moisture_q matched hydrosphere on 'ocean'/'rivers'/'subsurface', but the
real bodies.hydrosphere vocab in systems.db is dominated by 'liquid_water' (175
bodies) — so most surface-water worlds fell to the '_ => 30' default, propagating
wrong precipitation_class / glaciation_grade / vegetation. Same root cause as
D-240 (code keyed on a vocab the data doesn't use).
Align the match to the canonical vocab, grouped by available surface moisture
(mirrors the [hydrosphere_maritime] table from T-1033): surface liquid
(liquid_water/ocean/ocean-coastal/extensive) -> 80; rivers/rivers-lakes/moderate
-> 55; ice -> 20; subsurface_liquid -> 15; subsurface/subsurface_ice -> 10;
minimal/trace -> 5; none -> 0. Add a liquid_water regression test and broaden the
clamp sweep to the full vocabulary.
Closes T-1034 — last open ticket under epic T-974 (Atlas-to-tile derivation),
which is now complete.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Re-review of the maritime moderation addition (Hoshe REQUEST_CHANGES, Tyre APPROVE):
- every_planet_class_derives_within_its_band now sweeps hydrosphere
(none/ocean/liquid_water/rivers/ice) as well, so the maritime-compressed
gradient path is covered by the band invariant — not just the None/1.0 case.
(Hoshe #1, Tyre #1)
- Update the BodyParams.hydrosphere doc comment to the real systems.db vocabulary
(liquid_water/ocean-coastal/extensive/etc.) the maritime table keys on. (Hoshe #2)
cargo test passes (the band sweep now ~59k in-band assertions), clippy -D warnings
clean, fmt clean.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add the D-240 hydrosphere modulator: water-rich worlds compress the equator->pole
temperature gradient toward the band midpoint (milder at both ends); dry worlds
swing the full class band.
- [hydrosphere_maritime] table in climate_constants.toml + ClimateConstants
field/method (maritime_factor). Keyed on the ACTUAL bodies.hydrosphere vocab
(liquid_water/ocean/extensive=0.6, rivers/moderate=0.8, ice=0.85, subsurface*
=0.9-0.95; minimal/trace/none/NULL -> 1.0).
- derive_temperature_c step 2 now lerps across a maritime-compressed sub-band
(mid +/- band_half*factor) instead of the full band. Clamp still guarantees the
class-band invariant.
- New maritime_hydrosphere_compresses_the_gradient test (ocean delta < dry delta).
Verified on real worlds: liquid_water/ocean temperate worlds now delta ~24 (milder)
vs dry ~40, all in-band. cargo test passes, clippy -D warnings clean, fmt clean.
Note: discovered derive_moisture_q has the SAME vocab mismatch (expects 'ocean',
DB uses 'liquid_water' for 175 bodies -> falls to default moisture). Pre-existing,
out of scope here — filing a follow-up.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Band-invariant test now sweeps high altitude (6 km) as well as sea level, so
the lapse term + cold-end clamp are exercised jointly, not lat alone. (Hoshe #1, Tyre #3)
- Clarify the temp() helper comment: seed 0 is deterministic but still applies a
constant non-zero nudge. (Hoshe #2)
- (Hoshe #3: confirmed tectonic_activity is genuinely absent from systems-schema.sql;
the reader's 'not in schema' comment is accurate — no change.)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Replace the sun-driven Stefan-Boltzmann temperature with the D-240 class-envelope
model. Temperature derives only from authored fields — no orbit/star physics.
- [planet_class_temperature] envelope table in climate_constants.toml (approved
bands: frozen [-90,-25] .. hot_arid [20,58] .. volcanic [30,90]); cold_/hot_/
warm_ prefix parsing; temperate fallback for unknowns.
- derive_temperature_c(params, constants, body_seed): band = envelope(planet_class);
latitude lerps across it (equator=warm, pole=cold); atmosphere greenhouse +
elevation lapse modulate within; small seed nudge for per-body variety; CLAMP to
band — a body can never escape its class. Airless -> None.
- Delete the dead astrophysics: derive_distance_au, ClimateConstants::luminosity(),
the [star_luminosity] table. Strip orbital_period_days/spectral_class/star_type/
axial_tilt_deg from BodyParams + BodyParamsReader (read 3 cols from bodies, no
star_systems join). DB columns left in place (no regen).
- New every_planet_class_derives_within_its_band test (13 classes x 5 atmo x 19 lat
x 4 seeds, all in band) — the D-240 consistency guard.
Verified on 25 diverse real bodies: the worlds that derived to +356C now sit inside
their class bands (temperate capped at 28C). cargo test passes, clippy -D warnings
clean, fmt clean.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Hoshe REQUEST_CHANGES + Tyre APPROVE:
- Riparian vegetation logic was doubly-wrong: it granted the micro-oasis only
in the impossible cold case (temp < -50, no liquid water) and DENIED it in the
intended hyper-arid case. Split: extreme cold -> Barren always; hyper-arid ->
RiparianScrub iff near perennial water. (Hoshe #2)
- morphology_zone_has_exactly_17_variants was misleading (asserted >=16). Rename
to morphology_zone_region_scale_emits_16_of_17, tighten to ==16, and document
that BraidedPlain is the lone region-unreachable zone (needs lithology, deferred
to ChunkContext) and that Lake IS reachable. Tyre's 'Lake also deferred' was a
false positive (ocean 60-79 -> Lake). (Hoshe #1, Tyre #1)
- derive_morphology_zone docstring now lists the real multi-path emission sites
for TidalFlat/Wetland, ValleyFloor/RiverBank as their own gates, and BraidedPlain's
deferral — the §6 parent-family names are descriptive, not exhaustive. (Hoshe #3, Tyre #2/#3/#4)
- D-239 record: added a T-1025/T-1027 implementation note (enum freeze location,
16/17 region reachability + BraidedPlain deferral, §7 gate-ordering interpretation).
No vocabulary change. cargo test passes, clippy -D warnings clean, fmt clean.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Re-review (Hoshe + Tyre, both APPROVE) caught one stale comment: after the
per-region elevation fix, derive_region_profile owns elevation_km (from elev_q),
not the caller. Update the comment so maintainers don't read it as caller-supplied.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Hoshe + Tyre review (CHANGES REQUESTED):
- domain_warp golden tests were hollow (discarded values, only asserted
dx!=dy). Consolidate into one real golden_vector test with pinned f64
literals as the regression anchor. (Hoshe #1, Tyre #2)
- Per-region temperature used body-level elevation_km for every region, so
alpine and sea-level regions on a body got identical lapse — defeats the
D-239 §2 per-district temperature. Derive elevation_km per region from the
region's own elev_q (× MAX_REGION_ELEVATION_KM). (Tyre #1)
- Region seed was derived under SeedDomain::DomainWarp (collision risk with
the tile warp) and discarded unused. Remove it + the orphaned region_pos_id
and SeedDomain import; keep a reserved _seed param for T-1027/T-1028. (Hoshe #2)
- Fix inverted tilt_factor comment. (Hoshe #3)
- ClimateConstants doc referenced a load() that doesn't exist; correct it —
embedded default() is authoritative today, climate_constants.toml is the
canonical mirror, runtime load lands with T-1032. (Hoshe + Tyre)
- cascade.rs: drainage re-run was mislabeled 'cheap'/'no drainage needed';
document the real cost + PERF/TODO(T-1028/T-1032) against the D-239 §10
budget. (Tyre #3)
cargo test 1497 pass, clippy -D warnings clean, fmt clean.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
First foundation slice of the Atlas-to-tile derivation model (epic T-974),
building the carrier layer ahead of its T-1027+ consumers.
T-1026 — Anti-squaring domain warp (D-239 §4): stateless pure
fn(seed,body_id,pos)->(f64,f64), ±8m, f64 to the final voxel then as-i32
truncation for IEEE-754 cross-target determinism. New domain_warp.rs,
SeedDomain::DomainWarp; golden-vector + cross-thread tests. Position math
only — D-010 integer discipline preserved downstream. Marked dead_code
until the T-1028 VoxelColumn pipeline consumes it.
T-1023 — RegionProfile carrier (D-239 §1,§10): new RegionProfile +
TectonicClass/GlaciationGrade/PrecipitationClass enums + BodyParams; derived
per-region river_threshold replacing the global 200 for tile consumers.
regions: BTreeMap on BodyWorldState, populated via the cascade's new
RegionProfile layer (runs when body_params is Some, else falls back to
Settlement). D-010 integer discipline, BTree ordering.
T-1024 — District climate primitives (D-239 §2): nullable temperature_c +
moisture on RegionProfile, mean-annual scalar (no clock dep; dynamic branch
deferred to Q-105). Hybrid inputs — new bodies.axial_tilt_deg column imported
from planet-gen body-defs (populate_axial_tilt_deg, 2611 bodies), luminosity
and orbital distance derived at runtime; greenhouse + diurnal-swing tables in
source-canonical climate_constants.toml. D-239 implementation note added.
cargo test: 1498 passed, 0 failed. clippy clean (pre-existing
large_enum_variant only). make check-systems-db: stamp fresh.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>