test(simulation): align T-1031 harness with D-240 class-envelope temps
Adapt the believability/budget verification harness to the T-1033 BodyParams strip: validation-body fixtures (Kallast/Glødberg/Marevna) no longer set the removed orbit/star fields (orbital_period_days, axial_tilt_deg, spectral_class, star_type). Temperature is now derived from the planet_class envelope (D-240), so the Marevna validation note/assertion is rewritten — oceanic band [-12,28]°C + maritime 0.6 + standard-atmosphere greenhouse yields ~+26°C at the equator (was a stale ~-56°C orbit-equilibrium note). Add the seed→tile golden fixture (tests/golden/derivation_harness.json) that the determinism regression locks. Also fmt the harness and fix one clippy lint (iter().copied().collect() -> to_vec()) — the file predated the pre-push gate's cargo-test/clippy coverage. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -101,7 +101,15 @@ fn derive_golden(
|
||||
}
|
||||
|
||||
/// The three fixed golden inputs. Varied families and climate states.
|
||||
fn golden_cases() -> Vec<(&'static str, u64, &'static str, RegionProfile, (i32, i32), i32, i32)> {
|
||||
fn golden_cases() -> Vec<(
|
||||
&'static str,
|
||||
u64,
|
||||
&'static str,
|
||||
RegionProfile,
|
||||
(i32, i32),
|
||||
i32,
|
||||
i32,
|
||||
)> {
|
||||
vec![
|
||||
// Case A: AlluvialPlain — temperate forest, active channel.
|
||||
(
|
||||
@@ -112,7 +120,10 @@ fn golden_cases() -> Vec<(&'static str, u64, &'static str, RegionProfile, (i32,
|
||||
MorphologyZone::AlluvialPlain,
|
||||
TectonicClass::Active,
|
||||
GlaciationGrade::None,
|
||||
6, 22, 18, 68,
|
||||
6,
|
||||
22,
|
||||
18,
|
||||
68,
|
||||
Some(12.0),
|
||||
VegetationClass::Forest,
|
||||
),
|
||||
@@ -129,7 +140,10 @@ fn golden_cases() -> Vec<(&'static str, u64, &'static str, RegionProfile, (i32,
|
||||
MorphologyZone::Volcanic,
|
||||
TectonicClass::Volcanic,
|
||||
GlaciationGrade::None,
|
||||
12, 38, 0, 22,
|
||||
12,
|
||||
38,
|
||||
0,
|
||||
22,
|
||||
Some(45.0),
|
||||
VegetationClass::Barren,
|
||||
),
|
||||
@@ -146,7 +160,10 @@ fn golden_cases() -> Vec<(&'static str, u64, &'static str, RegionProfile, (i32,
|
||||
MorphologyZone::Fjord,
|
||||
TectonicClass::Active,
|
||||
GlaciationGrade::Moderate,
|
||||
55, 60, 28, 55,
|
||||
55,
|
||||
60,
|
||||
28,
|
||||
55,
|
||||
Some(-8.0),
|
||||
VegetationClass::Barren,
|
||||
),
|
||||
@@ -167,11 +184,15 @@ fn golden_seed_determinism_regression() {
|
||||
// compare against the golden. This is the core D-010 determinism contract.
|
||||
let run1: Vec<GoldenEntry> = golden_cases()
|
||||
.into_iter()
|
||||
.map(|(lbl, seed, body, region, cp, tx, ty)| derive_golden(lbl, seed, body, ®ion, cp, tx, ty))
|
||||
.map(|(lbl, seed, body, region, cp, tx, ty)| {
|
||||
derive_golden(lbl, seed, body, ®ion, cp, tx, ty)
|
||||
})
|
||||
.collect();
|
||||
let run2: Vec<GoldenEntry> = golden_cases()
|
||||
.into_iter()
|
||||
.map(|(lbl, seed, body, region, cp, tx, ty)| derive_golden(lbl, seed, body, ®ion, cp, tx, ty))
|
||||
.map(|(lbl, seed, body, region, cp, tx, ty)| {
|
||||
derive_golden(lbl, seed, body, ®ion, cp, tx, ty)
|
||||
})
|
||||
.collect();
|
||||
|
||||
assert_eq!(
|
||||
@@ -246,8 +267,7 @@ fn assert_drainage_monotonicity(
|
||||
let base_y = chunk_pos.1 * 64;
|
||||
for dy in 0..64i32 {
|
||||
for dx in 0..64i32 {
|
||||
let col =
|
||||
derive_voxel_column(seed, body_id, region, &chunk, base_x + dx, base_y + dy);
|
||||
let col = derive_voxel_column(seed, body_id, region, &chunk, base_x + dx, base_y + dy);
|
||||
match col.water {
|
||||
Water::Dry => {
|
||||
max_dry_elev = max_dry_elev.max(col.elevation_m);
|
||||
@@ -284,7 +304,10 @@ fn law_drainage_monotonicity_alluvial_sweep() {
|
||||
MorphologyZone::AlluvialPlain,
|
||||
TectonicClass::Stable,
|
||||
GlaciationGrade::None,
|
||||
5, 20, 18, 60,
|
||||
5,
|
||||
20,
|
||||
18,
|
||||
60,
|
||||
Some(15.0),
|
||||
VegetationClass::Forest,
|
||||
);
|
||||
@@ -299,7 +322,10 @@ fn law_drainage_monotonicity_meander_sweep() {
|
||||
MorphologyZone::MeanderReach,
|
||||
TectonicClass::Stable,
|
||||
GlaciationGrade::None,
|
||||
8, 18, 20, 65,
|
||||
8,
|
||||
18,
|
||||
20,
|
||||
65,
|
||||
Some(14.0),
|
||||
VegetationClass::Forest,
|
||||
);
|
||||
@@ -316,7 +342,10 @@ fn law_drainage_monotonicity_fjord_floor_at_sea_level() {
|
||||
MorphologyZone::Fjord,
|
||||
TectonicClass::Active,
|
||||
GlaciationGrade::Moderate,
|
||||
55, 60, 28, 55,
|
||||
55,
|
||||
60,
|
||||
28,
|
||||
55,
|
||||
Some(-8.0),
|
||||
VegetationClass::Barren,
|
||||
);
|
||||
@@ -356,7 +385,10 @@ fn law_drainage_monotonicity_braided_delta() {
|
||||
MorphologyZone::Delta,
|
||||
TectonicClass::Active,
|
||||
GlaciationGrade::None,
|
||||
3, 8, 25, 50,
|
||||
3,
|
||||
8,
|
||||
25,
|
||||
50,
|
||||
Some(18.0),
|
||||
VegetationClass::Scrub,
|
||||
);
|
||||
@@ -385,10 +417,10 @@ fn assert_all_terrain_is(
|
||||
let base_y = chunk_pos.1 * 64;
|
||||
for dy in (0..64i32).step_by(8) {
|
||||
for dx in (0..64i32).step_by(8) {
|
||||
let col =
|
||||
derive_voxel_column(seed, body_id, region, &chunk, base_x + dx, base_y + dy);
|
||||
let col = derive_voxel_column(seed, body_id, region, &chunk, base_x + dx, base_y + dy);
|
||||
assert_eq!(
|
||||
col.terrain, expected,
|
||||
col.terrain,
|
||||
expected,
|
||||
"§8 lithology VIOLATED for '{label}': voxel ({},{}) returned {:?}, expected {:?}",
|
||||
base_x + dx,
|
||||
base_y + dy,
|
||||
@@ -406,11 +438,21 @@ fn law_lithology_lava_emits_lava() {
|
||||
MorphologyZone::Volcanic,
|
||||
TectonicClass::Volcanic,
|
||||
GlaciationGrade::None,
|
||||
15, 35, 0, 20,
|
||||
15,
|
||||
35,
|
||||
0,
|
||||
20,
|
||||
Some(40.0),
|
||||
VegetationClass::Barren,
|
||||
);
|
||||
assert_all_terrain_is(42, "GJ581c", ®ion, (3, 3), TerrainMaterial::Lava, "LavaField");
|
||||
assert_all_terrain_is(
|
||||
42,
|
||||
"GJ581c",
|
||||
®ion,
|
||||
(3, 3),
|
||||
TerrainMaterial::Lava,
|
||||
"LavaField",
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -419,11 +461,21 @@ fn law_lithology_fjord_emits_rock() {
|
||||
MorphologyZone::Fjord,
|
||||
TectonicClass::Active,
|
||||
GlaciationGrade::Moderate,
|
||||
55, 60, 28, 55,
|
||||
55,
|
||||
60,
|
||||
28,
|
||||
55,
|
||||
Some(-8.0),
|
||||
VegetationClass::Barren,
|
||||
);
|
||||
assert_all_terrain_is(42, "fjord_body", ®ion, (0, 0), TerrainMaterial::Rock, "FjordWall");
|
||||
assert_all_terrain_is(
|
||||
42,
|
||||
"fjord_body",
|
||||
®ion,
|
||||
(0, 0),
|
||||
TerrainMaterial::Rock,
|
||||
"FjordWall",
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -432,11 +484,21 @@ fn law_lithology_cliff_coast_emits_rock() {
|
||||
MorphologyZone::CliffCoast,
|
||||
TectonicClass::Active,
|
||||
GlaciationGrade::None,
|
||||
60, 40, 20, 30,
|
||||
60,
|
||||
40,
|
||||
20,
|
||||
30,
|
||||
Some(10.0),
|
||||
VegetationClass::Scrub,
|
||||
);
|
||||
assert_all_terrain_is(42, "cliff_body", ®ion, (0, 0), TerrainMaterial::Rock, "CliffCoast");
|
||||
assert_all_terrain_is(
|
||||
42,
|
||||
"cliff_body",
|
||||
®ion,
|
||||
(0, 0),
|
||||
TerrainMaterial::Rock,
|
||||
"CliffCoast",
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -446,12 +508,20 @@ fn law_lithology_incised_gorge_emits_rock() {
|
||||
MorphologyZone::MountainPass,
|
||||
TectonicClass::Active,
|
||||
GlaciationGrade::None,
|
||||
50, 65, 5, 40,
|
||||
50,
|
||||
65,
|
||||
5,
|
||||
40,
|
||||
Some(5.0),
|
||||
VegetationClass::Scrub,
|
||||
);
|
||||
assert_all_terrain_is(
|
||||
42, "gorge_body", ®ion, (0, 0), TerrainMaterial::Rock, "IncisedGorge",
|
||||
42,
|
||||
"gorge_body",
|
||||
®ion,
|
||||
(0, 0),
|
||||
TerrainMaterial::Rock,
|
||||
"IncisedGorge",
|
||||
);
|
||||
}
|
||||
|
||||
@@ -462,11 +532,21 @@ fn law_lithology_dune_strand_emits_sand() {
|
||||
MorphologyZone::DuneStrand,
|
||||
TectonicClass::Stable,
|
||||
GlaciationGrade::None,
|
||||
12, 15, 20, 25,
|
||||
12,
|
||||
15,
|
||||
20,
|
||||
25,
|
||||
Some(22.0),
|
||||
VegetationClass::Barren,
|
||||
);
|
||||
assert_all_terrain_is(42, "dune_body", ®ion, (0, 0), TerrainMaterial::Sand, "DuneStrand");
|
||||
assert_all_terrain_is(
|
||||
42,
|
||||
"dune_body",
|
||||
®ion,
|
||||
(0, 0),
|
||||
TerrainMaterial::Sand,
|
||||
"DuneStrand",
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -476,12 +556,20 @@ fn law_lithology_braided_delta_emits_gravel() {
|
||||
MorphologyZone::Delta,
|
||||
TectonicClass::Active,
|
||||
GlaciationGrade::None,
|
||||
3, 8, 25, 50,
|
||||
3,
|
||||
8,
|
||||
25,
|
||||
50,
|
||||
Some(18.0),
|
||||
VegetationClass::Scrub,
|
||||
);
|
||||
assert_all_terrain_is(
|
||||
42, "delta_body", ®ion, (0, 0), TerrainMaterial::Gravel, "BraidedDelta",
|
||||
42,
|
||||
"delta_body",
|
||||
®ion,
|
||||
(0, 0),
|
||||
TerrainMaterial::Gravel,
|
||||
"BraidedDelta",
|
||||
);
|
||||
}
|
||||
|
||||
@@ -492,12 +580,20 @@ fn law_lithology_alluvial_plain_emits_soil() {
|
||||
MorphologyZone::AlluvialPlain,
|
||||
TectonicClass::Stable,
|
||||
GlaciationGrade::None,
|
||||
10, 25, 12, 45,
|
||||
10,
|
||||
25,
|
||||
12,
|
||||
45,
|
||||
Some(16.0),
|
||||
VegetationClass::Forest,
|
||||
);
|
||||
assert_all_terrain_is(
|
||||
42, "alluvial_body", ®ion, (0, 0), TerrainMaterial::Soil, "AlluvialPlain",
|
||||
42,
|
||||
"alluvial_body",
|
||||
®ion,
|
||||
(0, 0),
|
||||
TerrainMaterial::Soil,
|
||||
"AlluvialPlain",
|
||||
);
|
||||
}
|
||||
|
||||
@@ -508,12 +604,20 @@ fn law_lithology_meander_reach_emits_soil() {
|
||||
MorphologyZone::MeanderReach,
|
||||
TectonicClass::Stable,
|
||||
GlaciationGrade::None,
|
||||
8, 18, 20, 55,
|
||||
8,
|
||||
18,
|
||||
20,
|
||||
55,
|
||||
Some(14.0),
|
||||
VegetationClass::Forest,
|
||||
);
|
||||
assert_all_terrain_is(
|
||||
42, "meander_body", ®ion, (0, 0), TerrainMaterial::Soil, "MeanderReach",
|
||||
42,
|
||||
"meander_body",
|
||||
®ion,
|
||||
(0, 0),
|
||||
TerrainMaterial::Soil,
|
||||
"MeanderReach",
|
||||
);
|
||||
}
|
||||
|
||||
@@ -578,7 +682,7 @@ fn law_glaciation_grade_2_enables_fjord_with_correct_params() {
|
||||
GlaciationGrade::Moderate, // grade 2 — gate opens
|
||||
55, // steep enough
|
||||
60,
|
||||
25, // coastal
|
||||
25, // coastal
|
||||
55,
|
||||
);
|
||||
assert_eq!(
|
||||
@@ -674,9 +778,7 @@ fn law_climate_vegetation_full_grid_no_skip() {
|
||||
Some(-55.0),
|
||||
None,
|
||||
]
|
||||
.iter()
|
||||
.copied()
|
||||
.collect();
|
||||
.to_vec();
|
||||
|
||||
for moisture_q in (0i32..=100).step_by(10) {
|
||||
for elev_q in (0i32..=100).step_by(10) {
|
||||
@@ -784,35 +886,115 @@ fn budget_families() -> Vec<(&'static str, RegionProfile)> {
|
||||
vec![
|
||||
(
|
||||
"AlluvialPlain",
|
||||
make_region(MorphologyZone::AlluvialPlain, TectonicClass::Stable, GlaciationGrade::None, 5, 20, 18, 60, Some(15.0), VegetationClass::Forest),
|
||||
make_region(
|
||||
MorphologyZone::AlluvialPlain,
|
||||
TectonicClass::Stable,
|
||||
GlaciationGrade::None,
|
||||
5,
|
||||
20,
|
||||
18,
|
||||
60,
|
||||
Some(15.0),
|
||||
VegetationClass::Forest,
|
||||
),
|
||||
),
|
||||
(
|
||||
"LavaField",
|
||||
make_region(MorphologyZone::Volcanic, TectonicClass::Volcanic, GlaciationGrade::None, 12, 35, 0, 20, Some(40.0), VegetationClass::Barren),
|
||||
make_region(
|
||||
MorphologyZone::Volcanic,
|
||||
TectonicClass::Volcanic,
|
||||
GlaciationGrade::None,
|
||||
12,
|
||||
35,
|
||||
0,
|
||||
20,
|
||||
Some(40.0),
|
||||
VegetationClass::Barren,
|
||||
),
|
||||
),
|
||||
(
|
||||
"FjordWall",
|
||||
make_region(MorphologyZone::Fjord, TectonicClass::Active, GlaciationGrade::Moderate, 55, 60, 28, 55, Some(-8.0), VegetationClass::Barren),
|
||||
make_region(
|
||||
MorphologyZone::Fjord,
|
||||
TectonicClass::Active,
|
||||
GlaciationGrade::Moderate,
|
||||
55,
|
||||
60,
|
||||
28,
|
||||
55,
|
||||
Some(-8.0),
|
||||
VegetationClass::Barren,
|
||||
),
|
||||
),
|
||||
(
|
||||
"CliffCoast",
|
||||
make_region(MorphologyZone::CliffCoast, TectonicClass::Active, GlaciationGrade::None, 60, 40, 20, 30, Some(10.0), VegetationClass::Scrub),
|
||||
make_region(
|
||||
MorphologyZone::CliffCoast,
|
||||
TectonicClass::Active,
|
||||
GlaciationGrade::None,
|
||||
60,
|
||||
40,
|
||||
20,
|
||||
30,
|
||||
Some(10.0),
|
||||
VegetationClass::Scrub,
|
||||
),
|
||||
),
|
||||
(
|
||||
"BraidedDelta",
|
||||
make_region(MorphologyZone::Delta, TectonicClass::Active, GlaciationGrade::None, 3, 8, 25, 50, Some(18.0), VegetationClass::Scrub),
|
||||
make_region(
|
||||
MorphologyZone::Delta,
|
||||
TectonicClass::Active,
|
||||
GlaciationGrade::None,
|
||||
3,
|
||||
8,
|
||||
25,
|
||||
50,
|
||||
Some(18.0),
|
||||
VegetationClass::Scrub,
|
||||
),
|
||||
),
|
||||
(
|
||||
"DuneStrand",
|
||||
make_region(MorphologyZone::DuneStrand, TectonicClass::Stable, GlaciationGrade::None, 12, 15, 20, 25, Some(22.0), VegetationClass::Barren),
|
||||
make_region(
|
||||
MorphologyZone::DuneStrand,
|
||||
TectonicClass::Stable,
|
||||
GlaciationGrade::None,
|
||||
12,
|
||||
15,
|
||||
20,
|
||||
25,
|
||||
Some(22.0),
|
||||
VegetationClass::Barren,
|
||||
),
|
||||
),
|
||||
(
|
||||
"IncisedGorge",
|
||||
make_region(MorphologyZone::MountainPass, TectonicClass::Active, GlaciationGrade::None, 50, 65, 5, 40, Some(5.0), VegetationClass::Scrub),
|
||||
make_region(
|
||||
MorphologyZone::MountainPass,
|
||||
TectonicClass::Active,
|
||||
GlaciationGrade::None,
|
||||
50,
|
||||
65,
|
||||
5,
|
||||
40,
|
||||
Some(5.0),
|
||||
VegetationClass::Scrub,
|
||||
),
|
||||
),
|
||||
(
|
||||
"MeanderReach",
|
||||
make_region(MorphologyZone::MeanderReach, TectonicClass::Stable, GlaciationGrade::None, 8, 18, 20, 55, Some(14.0), VegetationClass::Forest),
|
||||
make_region(
|
||||
MorphologyZone::MeanderReach,
|
||||
TectonicClass::Stable,
|
||||
GlaciationGrade::None,
|
||||
8,
|
||||
18,
|
||||
20,
|
||||
55,
|
||||
Some(14.0),
|
||||
VegetationClass::Forest,
|
||||
),
|
||||
),
|
||||
]
|
||||
}
|
||||
@@ -826,7 +1008,10 @@ fn budget_per_family_chunk_derivation() {
|
||||
// Warm up with the fallback family first (also establishes baseline).
|
||||
let (_, _) = derive_chunk_timed(seed, body_id, &budget_families()[0].1, (0, 0));
|
||||
let (_, baseline_us) = derive_chunk_timed(seed, body_id, &budget_families()[0].1, (0, 0));
|
||||
eprintln!("[budget] AlluvialPlain baseline: {} µs / 4096 voxels", baseline_us);
|
||||
eprintln!(
|
||||
"[budget] AlluvialPlain baseline: {} µs / 4096 voxels",
|
||||
baseline_us
|
||||
);
|
||||
|
||||
let mut results: Vec<(&str, u128)> = vec![];
|
||||
|
||||
@@ -888,7 +1073,10 @@ fn budget_voxel_cache_lru_overhead() {
|
||||
MorphologyZone::AlluvialPlain,
|
||||
TectonicClass::Stable,
|
||||
GlaciationGrade::None,
|
||||
5, 20, 18, 60,
|
||||
5,
|
||||
20,
|
||||
18,
|
||||
60,
|
||||
Some(15.0),
|
||||
VegetationClass::Forest,
|
||||
);
|
||||
@@ -905,8 +1093,7 @@ fn budget_voxel_cache_lru_overhead() {
|
||||
let t0 = Instant::now();
|
||||
for dy in 0..64i32 {
|
||||
for dx in 0..64i32 {
|
||||
let _ =
|
||||
cache.get_or_derive(seed, body_id, ®ion, &chunk, base_x + dx, base_y + dy);
|
||||
let _ = cache.get_or_derive(seed, body_id, ®ion, &chunk, base_x + dx, base_y + dy);
|
||||
}
|
||||
}
|
||||
let cache_us = t0.elapsed().as_micros();
|
||||
@@ -947,17 +1134,12 @@ fn budget_voxel_cache_lru_overhead() {
|
||||
|
||||
/// Kallast (GJ144d) params — wiki: star-systems/GJ-144/bodies/GJ144d/index.md
|
||||
fn kallast_body_params() -> BodyParams {
|
||||
// planet_class: temperate | atmosphere: standard | hydrosphere: ocean
|
||||
// orbit.period_days: 280.0 | orbit.axial_tilt_deg: 30.2 | tectonics: active
|
||||
// star.type: K (luminosity_solar: 0.4)
|
||||
// planet_class: temperate | atmosphere: standard | hydrosphere: ocean | tectonics: active
|
||||
// (orbit/star data is non-canonical per D-240 and no longer feeds temperature)
|
||||
BodyParams {
|
||||
hydrosphere: Some("ocean".into()),
|
||||
atmosphere: Some("standard".into()),
|
||||
planet_class: Some("temperate".into()),
|
||||
orbital_period_days: Some(280.0),
|
||||
axial_tilt_deg: Some(30.2),
|
||||
spectral_class: Some("K".into()),
|
||||
star_type: None,
|
||||
tectonic_activity: Some("active".into()),
|
||||
region_latitude_deg: 0.0,
|
||||
elevation_km: 0.0,
|
||||
@@ -966,17 +1148,12 @@ fn kallast_body_params() -> BodyParams {
|
||||
|
||||
/// Glødberg (GJ581c) params — wiki: star-systems/GJ-581/bodies/GJ581c/index.md
|
||||
fn gloedberg_body_params() -> BodyParams {
|
||||
// planet_class: volcanic | atmosphere: standard | hydrosphere: subsurface_liquid
|
||||
// orbit.period_days: 12.0 | orbit.axial_tilt_deg: 0.6 | tectonics: extreme
|
||||
// star.type: M (luminosity_solar: 0.04)
|
||||
// planet_class: volcanic | atmosphere: standard | hydrosphere: subsurface_liquid | tectonics: extreme
|
||||
// (orbit/star data is non-canonical per D-240 and no longer feeds temperature)
|
||||
BodyParams {
|
||||
hydrosphere: Some("subsurface".into()),
|
||||
atmosphere: Some("standard".into()),
|
||||
planet_class: Some("volcanic".into()),
|
||||
orbital_period_days: Some(12.0),
|
||||
axial_tilt_deg: Some(0.6),
|
||||
spectral_class: Some("M".into()),
|
||||
star_type: None,
|
||||
tectonic_activity: Some("volcanic".into()),
|
||||
region_latitude_deg: 0.0,
|
||||
elevation_km: 0.5,
|
||||
@@ -986,17 +1163,12 @@ fn gloedberg_body_params() -> BodyParams {
|
||||
/// Marevna (GJ447c) params — wiki: star-systems/GJ-447/bodies/GJ447c/index.md
|
||||
/// GJ-447 is the real-world identifier for Ross 128.
|
||||
fn marevna_body_params() -> BodyParams {
|
||||
// planet_class: oceanic | atmosphere: standard | hydrosphere: ocean
|
||||
// orbit.period_days: 170.0 | orbit.axial_tilt_deg: 7.0 | tectonics: active
|
||||
// star.type: M (luminosity_solar: 0.04)
|
||||
// planet_class: oceanic | atmosphere: standard | hydrosphere: ocean | tectonics: active
|
||||
// (orbit/star data is non-canonical per D-240 and no longer feeds temperature)
|
||||
BodyParams {
|
||||
hydrosphere: Some("ocean".into()),
|
||||
atmosphere: Some("standard".into()),
|
||||
planet_class: Some("oceanic".into()),
|
||||
orbital_period_days: Some(170.0),
|
||||
axial_tilt_deg: Some(7.0),
|
||||
spectral_class: Some("M".into()),
|
||||
star_type: None,
|
||||
tectonic_activity: Some("active".into()),
|
||||
region_latitude_deg: 0.0,
|
||||
elevation_km: 0.0,
|
||||
@@ -1071,8 +1243,10 @@ fn validation_kallast_alluvial_plain() {
|
||||
|
||||
eprintln!(
|
||||
"[validation] Kallast: zone={:?} temp={:?}°C glaciation={:?} tectonic={:?} — PASS",
|
||||
profile.morphology_zone, profile.temperature_c,
|
||||
profile.glaciation_grade, profile.tectonic_class
|
||||
profile.morphology_zone,
|
||||
profile.temperature_c,
|
||||
profile.glaciation_grade,
|
||||
profile.tectonic_class
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1082,7 +1256,9 @@ fn validation_gloedberg_volcanic_immature_drainage() {
|
||||
// No body named "Cygni B" exists in the current wiki. GJ581c (Glødberg) is
|
||||
// the closest volcanic match. NOTE: update this test if a "Cygni B" body is
|
||||
// added to the wiki in the future.
|
||||
eprintln!("[validation] Glødberg (GJ581c): volcanic proxy — checking LavaField + immature drainage");
|
||||
eprintln!(
|
||||
"[validation] Glødberg (GJ581c): volcanic proxy — checking LavaField + immature drainage"
|
||||
);
|
||||
|
||||
let profile = derive_profile_for_body(&gloedberg_body_params());
|
||||
|
||||
@@ -1131,7 +1307,9 @@ fn validation_gloedberg_volcanic_immature_drainage() {
|
||||
#[test]
|
||||
fn validation_marevna_ocean_island() {
|
||||
// D-239 §1: "Ross 128 = ocean island." GJ-447 is Ross 128; GJ447c = Marevna.
|
||||
eprintln!("[validation] Marevna (GJ447c / Ross 128): ocean island — checking coastal/ocean zone");
|
||||
eprintln!(
|
||||
"[validation] Marevna (GJ447c / Ross 128): ocean island — checking coastal/ocean zone"
|
||||
);
|
||||
|
||||
let profile = derive_profile_for_body(&marevna_body_params());
|
||||
|
||||
@@ -1169,24 +1347,22 @@ fn validation_marevna_ocean_island() {
|
||||
If wrong, fix body params — not the derivation (D-239 §1).",
|
||||
profile.morphology_zone
|
||||
);
|
||||
// Temperature is deterministically derived: log it for audit.
|
||||
// NOTE: At period_days=170 + M-star luminosity=0.04, the equilibrium derivation
|
||||
// yields approximately -56°C — colder than expected for a "habitable" world.
|
||||
// Per D-239 §1: if the body reads wrong, fix the body params (e.g. period_days),
|
||||
// not the derivation. This assertion is intentionally loose — we verify the
|
||||
// derivation pipeline ran without panic and produced a consistent result.
|
||||
// A future wiki update to GJ447c orbital params will bring it into the
|
||||
// habitable range without touching this harness.
|
||||
// Temperature is deterministically derived from the planet_class envelope (D-240),
|
||||
// not orbit/star data: oceanic band [-12, 28]°C, maritime factor 0.6 for an "ocean"
|
||||
// hydrosphere. At the equator (latitude 0) the latitude lerp sits at the warm sub-band
|
||||
// edge (~+20°C) and the standard-atmosphere greenhouse fraction lifts it to ~+26°C —
|
||||
// a habitable result, as expected for an oceanic world. The assertion stays loose: we
|
||||
// verify the pipeline ran without panic and produced a physically plausible value.
|
||||
if let Some(t) = profile.temperature_c {
|
||||
assert!(
|
||||
t > -250.0 && t < 200.0,
|
||||
"Marevna: temperature {t}°C is outside the physical range [-250, 200]"
|
||||
t > -90.0 && t < 90.0,
|
||||
"Marevna: temperature {t}°C is outside the oceanic-class plausible range [-90, 90]"
|
||||
);
|
||||
}
|
||||
|
||||
eprintln!(
|
||||
"[validation] Marevna: zone={:?} temp={:?}°C moisture_q={} — PASS \
|
||||
(NOTE: temp ~-56°C at period_days=170 M-star; wiki params may need tuning per D-239 §1)",
|
||||
(oceanic class-envelope temp at equator per D-240)",
|
||||
profile.morphology_zone, profile.temperature_c, profile.moisture_q
|
||||
);
|
||||
}
|
||||
@@ -1259,6 +1435,11 @@ fn make_region(
|
||||
|
||||
/// Build a minimal flat `TerrainAnalysis` for use in body-level derive calls.
|
||||
/// Same geometry as the region_profile.rs unit tests (64×32 grid, sea_level=0.3).
|
||||
///
|
||||
/// Retained as the gentle-slope counterpart to `make_dry_terrain_analysis` (which
|
||||
/// the validation bodies currently use); kept for future morphology-gate tests that
|
||||
/// need a sloped, partially-oceanic grid rather than the flat all-dry one.
|
||||
#[allow(dead_code)]
|
||||
fn make_test_terrain_analysis() -> TerrainAnalysis {
|
||||
let (w, h) = (64u32, 32u32);
|
||||
let n = (w * h) as usize;
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
[
|
||||
{
|
||||
"label": "alluvial_forest_active_channel",
|
||||
"seed": 16045690984503098046,
|
||||
"body_id": "GJ144d",
|
||||
"tile_x": 640,
|
||||
"tile_y": 1280,
|
||||
"terrain": 0,
|
||||
"vegetation": 1,
|
||||
"water": 0,
|
||||
"elevation_m": 11,
|
||||
"cover": 0
|
||||
},
|
||||
{
|
||||
"label": "lava_field_barren",
|
||||
"seed": 1311768467294899695,
|
||||
"body_id": "GJ581c",
|
||||
"tile_x": 320,
|
||||
"tile_y": 448,
|
||||
"terrain": 5,
|
||||
"vegetation": 0,
|
||||
"water": 0,
|
||||
"elevation_m": 21,
|
||||
"cover": 0
|
||||
},
|
||||
{
|
||||
"label": "fjord_wall_glaciated",
|
||||
"seed": 18369614217980264670,
|
||||
"body_id": "GJ447c",
|
||||
"tile_x": 928,
|
||||
"tile_y": 544,
|
||||
"terrain": 3,
|
||||
"vegetation": 0,
|
||||
"water": 2,
|
||||
"elevation_m": 1,
|
||||
"cover": 1
|
||||
}
|
||||
]
|
||||
Reference in New Issue
Block a user