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>
This commit is contained in:
@@ -847,16 +847,30 @@ pub fn derive_temperature_c(
|
||||
///
|
||||
/// D-239 §2: moisture is derived from hydrosphere + atmosphere; 0 = arid, 100 = saturated.
|
||||
/// Integer output (D-010).
|
||||
///
|
||||
/// The `hydro` arms use the **actual `bodies.hydrosphere` vocabulary in systems.db**
|
||||
/// — same canonical set the `[hydrosphere_maritime]` table (D-240) keys on — grouped
|
||||
/// by available surface moisture. Keying on a vocab the data doesn't use (e.g. only
|
||||
/// `"ocean"`, which is 19 bodies, while 175 use `"liquid_water"`) silently dropped most
|
||||
/// water worlds to the default (T-1034 — same root cause as D-240).
|
||||
pub fn derive_moisture_q(params: &BodyParams) -> i32 {
|
||||
let hydro = params.hydrosphere.as_deref().unwrap_or("none");
|
||||
let atmo = params.atmosphere.as_deref().unwrap_or("none");
|
||||
|
||||
let base: i32 = match hydro {
|
||||
"none" => 0,
|
||||
"subsurface" => 10,
|
||||
// Large surface liquid — saturated.
|
||||
"liquid_water" | "ocean" | "ocean-coastal" | "extensive" => 80,
|
||||
// Partial surface water (rivers / lakes / seasonal) — moderate.
|
||||
"rivers" | "rivers-lakes" | "moderate" => 55,
|
||||
// Frozen surface water — low available moisture.
|
||||
"ice" => 20,
|
||||
"rivers" => 55,
|
||||
"ocean" => 80,
|
||||
// Buried water — minimal surface effect.
|
||||
"subsurface_liquid" => 15,
|
||||
"subsurface" | "subsurface_ice" => 10,
|
||||
// Effectively dry.
|
||||
"minimal" | "trace" => 5,
|
||||
"none" => 0,
|
||||
// Unknown vocab — conservative mid-low default.
|
||||
_ => 30,
|
||||
};
|
||||
let atmo_boost: i32 = match atmo {
|
||||
@@ -1465,6 +1479,23 @@ mod tests {
|
||||
assert!(q >= 70, "ocean + breathable moisture {q} should be >= 70");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn moisture_q_liquid_water_is_high_not_default() {
|
||||
// T-1034 regression: "liquid_water" is the dominant surface-water vocab in
|
||||
// systems.db (175 bodies). It must map to the high surface-liquid band, not
|
||||
// silently fall to the `_ => 30` default like it did before the fix.
|
||||
let params = BodyParams {
|
||||
hydrosphere: Some("liquid_water".into()),
|
||||
atmosphere: Some("standard".into()),
|
||||
..Default::default()
|
||||
};
|
||||
let q = derive_moisture_q(¶ms);
|
||||
assert!(
|
||||
q >= 70,
|
||||
"liquid_water moisture {q} should be >= 70 (surface-liquid band), not the default 30"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn moisture_q_airless_is_zero() {
|
||||
let params = BodyParams {
|
||||
@@ -1478,8 +1509,25 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn moisture_q_clamped_to_range() {
|
||||
// All combinations must stay in [0, 100].
|
||||
let hydros = ["none", "subsurface", "ice", "rivers", "ocean", "unknown"];
|
||||
// All combinations must stay in [0, 100]. Sweep the full canonical
|
||||
// `bodies.hydrosphere` vocabulary (T-1034) plus an unknown fallback.
|
||||
let hydros = [
|
||||
"liquid_water",
|
||||
"ocean",
|
||||
"ocean-coastal",
|
||||
"extensive",
|
||||
"rivers",
|
||||
"rivers-lakes",
|
||||
"moderate",
|
||||
"ice",
|
||||
"subsurface_liquid",
|
||||
"subsurface",
|
||||
"subsurface_ice",
|
||||
"minimal",
|
||||
"trace",
|
||||
"none",
|
||||
"unknown",
|
||||
];
|
||||
let atmos = [
|
||||
"none",
|
||||
"thin",
|
||||
|
||||
Reference in New Issue
Block a user