Commit Graph
17 Commits
Author SHA1 Message Date
jpmschweitzerandClaude Opus 4.8 bb5069aa13 feat(simulation): district moisture spatial gradient (T-1080)
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>
2026-06-28 17:25:18 +02:00
jpmschweitzerandClaude Opus 4.8 d974cf42b0 fix(simulation): wire region baseline into production district temp + rename latitude field (T-1078)
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>
2026-06-15 17:30:33 +02:00
jpmschweitzerandClaude Opus 4.8 030e0907bc feat(simulation): region climate tier — baseline + district modulation + edge fuzz (T-1078)
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>
2026-06-15 14:05:37 +02:00
jpmschweitzerandClaude Opus 4.8 b3b5bfc2e3 refactor(simulation): rename carrier RegionProfile->DistrictProfile + re-scale to the D-243 ladder (T-1077)
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>
2026-06-14 22:53:18 +02:00
jpmschweitzerandClaude Opus 4.8 38054d4b12 feat(simulation): canonical spatial scale ladder + body_radius_km (T-1077)
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>
2026-06-14 22:04:50 +02:00
jpmschweitzerandClaude Opus 4.8 4984d59bf4 fix(simulation): derive_moisture_q canonical hydrosphere vocab (T-1034)
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>
2026-06-08 23:01:43 +02:00
jpmschweitzer b8f8a5fb23 Merge remote-tracking branch 'origin/main' into verification-harness 2026-06-08 19:25:27 +02:00
jpmschweitzerandClaude Opus 4.8 a943147843 test(simulation): believability + budget verification harness (T-1031)
D-239 §1/§8/§9/§10 verification harness (server/tests/derivation_harness.rs):
golden-seed determinism regression, §8 binding-law sweeps (drainage monotonicity,
lithology->landform, glaciation->form no-glacial-U-at-grade-0, climate->vegetation
no-skip + riparian), per-family <5ms/chunk budget assertion, and validation-case
bodies (Kallast=alluvial pass; Velen/Gruenfeld skipped-not-in-wiki). Exposes
derive_morphology_zone as pub for the integration test.

NOTE: golden file not yet generated + fixtures predate the T-1033 BodyParams strip;
fixed in follow-up commits after merging main.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-08 19:25:18 +02:00
jpmschweitzerandClaude Opus 4.8 bafed6ad9a test+docs(simulation): address PR #164 re-review (maritime)
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>
2026-06-08 19:09:39 +02:00
jpmschweitzerandClaude Opus 4.8 b894a721ad feat(simulation): hydrosphere maritime moderation of temperature (T-1033, D-240)
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>
2026-06-08 18:53:26 +02:00
jpmschweitzerandClaude Opus 4.8 54609eab1a test+docs(simulation): address PR #164 review (both APPROVE)
- 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>
2026-06-08 18:36:41 +02:00
jpmschweitzerandClaude Opus 4.8 b6be9f5758 feat(simulation): planet_class temperature envelope, drop orbit/star inputs (T-1033, D-240)
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>
2026-06-08 18:28:24 +02:00
jpmschweitzerandClaude Opus 4.8 868da28192 fix(simulation): address PR #160 review (climate + morphology)
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>
2026-06-08 13:24:13 +02:00
jpmschweitzerandClaude Opus 4.8 961855f276 feat(simulation): climate-derived fields + frozen 17-zone morphology (T-1025, T-1027)
T-1025 (D-239 §2) — climate-derived fields, all from the temperature(+moisture)
primitive:
- precipitation_class + glaciation_grade re-keyed to (temperature_c, moisture_q)
  inputs (were keyed off raw body params); river_threshold signature follows.
- New VegetationClass (Absent/Barren/Scrub/Forest/RiparianScrub/RiparianThicket)
  + derive_vegetation: treeline bands x elevation, structural Forest->Scrub->Barren
  no-skip, riparian 1-3 tile band; airless (temp None) -> Absent.
- 21 tests.

T-1027 (D-239 §5/§6/§7) — morphology classifier:
- FROZEN 17-zone MorphologyZone enum exactly per D-239 §6 (OpenOcean..Wetland,
  repr(u8) pinned). Removed legacy Sea/CoastalLowland/Island/Canyon/Unknown;
  all consumers (skeleton_gen street_topology) remapped to nearest D-239 zone.
- 8-family gated decision tree (LavaField..AlluvialPlain fallback) over integer
  inputs; hard gates: Fjord>=GlaciationGrade2, LavaField=Volcanic tectonic,
  lithology slope/form laws (§8). 4 sub-classification zones (TidalFlat,
  Estuarine, Alpine, Wetland) derived from family + elevation/water.
- Build-time compatibility-matrix invariant tests (§7): MeanderReach<->Volcanic
  and Volcanic<->Fjord forbidden adjacencies structurally prevented by gate order.
- 13 tests incl 17-variant completeness + discriminant pinning.

D-010 integer discipline throughout. cargo test 1534 pass, clippy -D warnings
clean, fmt clean.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-08 13:12:34 +02:00
jpmschweitzerandClaude Opus 4.8 7084a41013 docs(simulation): fix stale elevation comment in derive_all_regions
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>
2026-06-08 11:21:35 +02:00
jpmschweitzerandClaude Opus 4.8 95f26ae3e9 fix(simulation): address PR #158 review (carrier foundation)
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>
2026-06-08 11:10:32 +02:00
jpmschweitzerandClaude Opus 4.8 def70eaf37 feat(simulation): D-239 three-carrier foundation (T-1023/1024/1026)
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>
2026-06-08 09:28:31 +02:00