Files
settled-reach/server/data/climate_constants.toml
jpmschweitzerandClaude Opus 4.8 f771c9ce4e fix(simulation): address believability-stack review — all findings processed
Stack review (Hoshe + Tyre) of T-1083+T-1082+T-1080. Every finding fixed or disposed:

- believability.rs sample_indices: replace the rejection-sampling loop (could stall
  when n ≈ take) with deterministic partial Fisher-Yates — O(n), guaranteed
  termination, distinct, sorted (Hoshe+Tyre).
- believability.rs drainage proxy: exclude water-body districts (all elev 0, no banks)
  and require both wet + dry voxels — they were passing vacuously and inflating the
  metric (Hoshe).
- believability.rs read_cities: log skipped malformed rows instead of dropping silently
  (Hoshe).
- voxel.rs: add the 3 WaterBody zones to all_families_no_panic_at_extreme_positions +
  fix the "7 families" comment (Hoshe).
- climate_constants.toml: bold warning that [moisture_gradient] is not loaded until
  T-1032 — tune ClimateConstants::default() (Tyre).
- Q-123: record the per-zone "water renders wet" threshold + the land-relative
  vegetation-present denominator as calibration items (Tyre + the open 7th criterion).
- T-1083 ticket: note the sampling-fix attribution (landed in the T-1082 commit).

Believability golden regenerated (sampler + drainage fixes moved the metrics).
clippy --all-targets -D warnings clean; 1580 lib tests + harness pass.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-28 17:41:03 +02:00

104 lines
5.2 KiB
TOML
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Climate constants for district temperature derivation (T-1024, D-239 §2, D-240).
#
# Source-canonical — loaded by the Rust simulation at runtime.
# Changing these constants does NOT require a DB migration (runtime file, not DB).
# To tune: edit here, rerun the server, inspect Atlas temperature maps.
#
# Three tables are required:
# [planet_class_temperature] — per-class [cold_end, warm_end] °C band (D-240).
# [greenhouse_offset_c] — mean-annual base temperature offset by atmosphere class.
# [diurnal_amplitude_c] — day/night swing AMPLITUDE by atmosphere class.
#
# Temperature derivation formula (D-240):
# (cold, warm) = planet_class_temperature[planet_class] # envelope
# t_lat = warm - (warm - cold) * (|latitude_deg| / 90) # latitude lerp
# greenhouse modulates within the band
# elevation lapse pulls toward cold end
# seed nudge ±~3°C
# CLAMP to [cold, warm] — body can never derive outside its class band.
#
# No atmosphere → temperature_c = None (airless body; D-227).
# ---------------------------------------------------------------------------
# Planet class temperature envelopes (D-240).
# Each entry: [cold_end_c, warm_end_c] — the band a body of this class stays in.
# Prefix rules: "cold_*" shifts both ends ~10°C colder; "hot_*" ~10°C warmer;
# "warm_*" ~5°C warmer. Unknown class falls back to "temperate" band.
# ---------------------------------------------------------------------------
[planet_class_temperature]
frozen = [-90.0, -25.0]
ice = [-90.0, -25.0]
boreal = [-35.0, 12.0]
cold_arid = [-40.0, 20.0]
temperate = [-12.0, 28.0]
oceanic = [-12.0, 28.0]
subtropical = [ 2.0, 34.0]
warm_ocean = [ 2.0, 34.0]
tropical = [ 16.0, 40.0]
arid = [ -5.0, 45.0]
hot_arid = [ 20.0, 58.0]
volcanic = [ 30.0, 90.0]
geothermal = [ 30.0, 90.0]
[greenhouse_offset_c]
# Greenhouse warming contribution per atmosphere class — used as a fractional
# nudge toward the warm end of the class band, not an absolute Kelvin offset.
# "none" is not present — airless bodies skip the climate branch entirely (D-227).
# Values represent a 0.01.0 fraction of the band width to add toward warm end.
# thin=0.1 (slightly warmer), breathable/standard=0.25, toxic=0.25, dense=0.55
thin = 0.10
standard = 0.25
toxic = 0.25
breathable = 0.25
dense = 0.55
[diurnal_amplitude_c]
# Day/night swing amplitude (°C). The actual swing is ±amplitude around the
# mean temperature; the morning minimum is T_mean - amplitude, noon maximum is
# T_mean + amplitude. Thick/dense atmosphere = small swing (heat redistribution);
# thin/no atmosphere = large swing.
#
# "none" is excluded — airless bodies have no climate temperature (D-227).
# Values are plausible physics; tune without recompile by editing this file.
thin = 50 # ~50°C day/night swing: large, like Mars
standard = 15 # ~15°C: Earth-like moderate swing
toxic = 20 # intermediate: thick but maybe less redistribution
breathable = 15 # synonym for standard
dense = 3 # ~3°C: Venus-like near-uniform temperature
# ---------------------------------------------------------------------------
[hydrosphere_maritime]
# Maritime moderation (D-240): scales the equator→pole temperature gradient by
# hydrosphere. 1.0 = full gradient (dry world swings the whole class band);
# < 1.0 compresses toward the band midpoint (water-rich worlds are milder at
# both poles and equator). Keys = actual bodies.hydrosphere vocabulary in
# systems.db. "minimal"/"trace"/"none"/absent default to 1.0 in code.
liquid_water = 0.6 # large surface liquid — strongly moderated
ocean = 0.6
"ocean-coastal" = 0.6
extensive = 0.6
rivers = 0.8 # partial surface water — mild moderation
"rivers-lakes" = 0.8
moderate = 0.8
ice = 0.85 # frozen surface — slight moderation
subsurface_liquid = 0.9
subsurface = 0.95 # buried water — minimal surface effect
subsurface_ice = 0.95
# ---------------------------------------------------------------------------
[moisture_gradient]
# !! NOT LOADED AT RUNTIME until T-1032 wires TOML loading. The LIVE source is
# !! ClimateConstants::default() in server/src/atlas/district_profile.rs — editing
# !! these values here alone has NO effect (the file header's "tune: edit here"
# !! does not yet apply to this table). Change BOTH, or change the Rust default.
# Per-district moisture spatial gradient (T-1080, D-239 §2). Integer points
# subtracted from the body's hydrosphere moisture *ceiling* so the field varies
# across the body instead of being a single constant (the bug: moisture_q = 80 for
# every district -> uniform vegetation/terrain). Wet at coast/lowland/tropics, drier
# toward interior/highland/poles. Provisional magnitudes — Q-123 calibrates. Mirrors
# the embedded ClimateConstants::default(); not yet loaded at runtime (TOML wiring is
# T-1032), kept in sync by hand like the other tables.
lat_penalty = 20 # lost equator->pole (x |latitude|/90)
elev_penalty = 15 # lost low->high elevation (x elev_q/100, rain-shadow)
continental_penalty = 20 # lost coast->interior (x (100 - ocean_fraction_q)/100)