test(simulation): post-adversarial workshop benches — population survey, chunk rung, S2 density, global tier

hydrology_equilibrium_bench: bench_population_survey_all_committed_bodies
(all 267 real heightmaps solved independently — zero carved cells population-
wide, ~0.86s total, byte-exact determinism; closes Troblum B1) +
bench_per_basin_size_distribution_real_population (22,270 basins: dense wins
100% for lake carriers). bmv_gridunit_bench: chunk-64m per-cell + deep-step
canvas benches (1,838 ns/cell, ~1.7s full 4K; Option D's missing row) + S2
courses-density benches (+38-87% at chunk/block, mechanism traced to station
spacing scaling with rung cutoff). bmv_global_tier_bench (new): real per-body
radii from systems.db via BodyParamsReader — global tier ~8.85MB PNG across
the population (supersedes the ~174MB mis-priced figure), rung-0 derive
~16-21ms/body measured. All #[ignore]d release tests, stability re-run.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-24 10:57:27 +02:00
co-authored by Claude Fable 5
parent 63e299adc6
commit b613443d51
5 changed files with 1252 additions and 0 deletions
+437
View File
@@ -228,6 +228,17 @@ fn determinism_at_330k_cells() {
/// solved across the Rayon pool, at the 512×256 production grid size —
/// directly answering the workshop's red-flag-2-adjacent question of
/// whether per-body-open hydrology is affordable at scale.
///
/// **Scope note (population-survey gap, closed by
/// [`bench_population_survey_all_committed_bodies`] below):** this bench
/// solves ONE real body (GJ1c) 273 times — it proves the *wall-clock*
/// affordability of running 273 independent solves in parallel (the
/// question it was built to answer), but the 273 solves are not 273
/// *distinct* bodies, so it says nothing about how basin/endorheic/carved-
/// cell distributions vary across the real body population. That is a
/// different question, answered by the population survey, not this bench —
/// left as-is (not rewritten) since it still correctly answers the
/// question it was designed for.
#[test]
#[ignore]
fn bench_parallel_273_bodies_at_512x256() {
@@ -258,3 +269,429 @@ fn bench_parallel_273_bodies_at_512x256() {
elapsed.as_secs_f64() * 1000.0 / body_count as f64
);
}
/// **POPULATION SURVEY (post-adversarial, Troblum finding).** Loads and
/// solves EVERY real committed heightmap PNG in the repo (267 distinct
/// bodies as of this bench, `wiki/star-systems/*/bodies/*/heightmap.png`),
/// each downsampled to the real 512×256 production working grid with its
/// own PNG-embedded `sea_level`, run independently in parallel across the
/// Rayon pool — the actual population-scale question
/// [`bench_parallel_273_bodies_at_512x256`] does not answer (that bench
/// solves ONE body 273 times, not 273 distinct bodies; see its doc comment
/// above). This closes the gap: total wall time for the REAL population,
/// and — the load-bearing part for the cliff Phase-4 ruling — the
/// distribution of basins/endorheic-basins/carved-cliff-edge-cells ACROSS
/// the population, not just on GJ1c.
///
/// **Known scope limit, stated explicitly (not hidden):** every body uses
/// the SAME `ClimateInputs { moisture_q: 55 }` (`default_climate()`) — the
/// module's own doc already states real per-body moisture requires wiring
/// in `BodyWorldState.districts`/`regions` climate context, which is out of
/// scope for this survey (same limitation the original T-1177 prototype
/// documented, "No per-basin moisture/climate lookup"). This means the
/// endorheic classification specifically is measured under a uniform
/// climate assumption, not each body's real hydrosphere/atmosphere-derived
/// moisture — a real per-body climate wiring pass could shift the
/// endorheic counts. It does NOT limit the carved-cliff-edge finding below:
/// carving depends on ELEVATION geometry (the narrow two-basin-saddle
/// condition documented in the module), not on `moisture_q` at all — the
/// climate input only gates the endorheic/overflow classification of an
/// already-identified basin, never whether carving occurs.
#[test]
#[ignore]
fn bench_population_survey_all_committed_bodies() {
use rayon::prelude::*;
use settled_reach_server::atlas::hydrology_equilibrium::{BasinOutcome, DownstreamTarget};
let wiki_root = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("../wiki/star-systems");
// Discover every committed heightmap PNG (deterministic ordering: sort
// by path so the survey's own reporting order is stable run-to-run —
// not load-bearing for solve() itself, which is pure per-body, but
// keeps the printed output diffable).
let mut heightmap_paths: Vec<std::path::PathBuf> = Vec::new();
fn walk(dir: &std::path::Path, out: &mut Vec<std::path::PathBuf>) {
let Ok(entries) = std::fs::read_dir(dir) else {
return;
};
for entry in entries.flatten() {
let path = entry.path();
if path.is_dir() {
walk(&path, out);
} else if path.file_name().and_then(|n| n.to_str()) == Some("heightmap.png") {
out.push(path);
}
}
}
walk(&wiki_root, &mut heightmap_paths);
heightmap_paths.sort();
assert!(
heightmap_paths.len() > 200,
"expected the real committed body population (~267 as of this bench), found {} — \
did the wiki_root path resolve correctly? ({wiki_root:?})",
heightmap_paths.len()
);
struct BodySurvey {
body_id: String,
basins: usize,
overflow: usize,
endorheic: usize,
lake_cells: usize,
carved_cells: usize,
cliff_edge_cells: usize,
solve_ms: f64,
}
let t0 = Instant::now();
let surveys: Vec<BodySurvey> = heightmap_paths
.par_iter()
.map(|path| {
// body_id = the directory name one level up from heightmap.png
// (wiki/star-systems/<system>/bodies/<body_id>/heightmap.png).
let body_id = path
.parent()
.and_then(|p| p.file_name())
.and_then(|n| n.to_str())
.unwrap_or("UNKNOWN")
.to_string();
let heightmap = settled_reach_server::atlas::heightmap::load_heightmap_png(
path, &body_id, 0.3,
)
.unwrap_or_else(|e| panic!("decode committed heightmap for {body_id} ({path:?}): {e}"));
let small = heightmap.downsample(512, 256);
let t_solve = Instant::now();
let result = solve(&small.data, 512, 256, small.sea_level, default_climate());
let solve_ms = t_solve.elapsed().as_secs_f64() * 1000.0;
let lake_cells: usize = result.basins.iter().map(|b| b.cells.len()).sum();
let carved_cells: usize = result
.basins
.iter()
.filter(|b| {
matches!(
b.outcome,
BasinOutcome::Overflow {
downstream_target: DownstreamTarget::Sea
| DownstreamTarget::Basin(_)
| DownstreamTarget::OpenSpillway,
..
}
) && result.channel_depth_scaled[b.spill_cell] > 0
})
.count();
let cliff_edge_cells = result.cliff_edge.iter().filter(|&&c| c).count();
let endorheic = result
.basins
.iter()
.filter(|b| matches!(b.outcome, BasinOutcome::Endorheic { .. }))
.count();
let overflow = result
.basins
.iter()
.filter(|b| matches!(b.outcome, BasinOutcome::Overflow { .. }))
.count();
BodySurvey {
body_id,
basins: result.basins.len(),
overflow,
endorheic,
lake_cells,
carved_cells,
cliff_edge_cells,
solve_ms,
}
})
.collect();
let elapsed = t0.elapsed();
let body_count = surveys.len();
let total_basins: usize = surveys.iter().map(|s| s.basins).sum();
let total_overflow: usize = surveys.iter().map(|s| s.overflow).sum();
let total_endorheic: usize = surveys.iter().map(|s| s.endorheic).sum();
let total_lake_cells: usize = surveys.iter().map(|s| s.lake_cells).sum();
let total_carved_cells: usize = surveys.iter().map(|s| s.carved_cells).sum();
let total_cliff_edge_cells: usize = surveys.iter().map(|s| s.cliff_edge_cells).sum();
let bodies_with_any_carving = surveys.iter().filter(|s| s.cliff_edge_cells > 0).count();
let mut by_cliff_edge: Vec<&BodySurvey> = surveys.iter().collect();
by_cliff_edge.sort_by(|a, b| b.cliff_edge_cells.cmp(&a.cliff_edge_cells));
println!(
"\n=== POPULATION SURVEY: {body_count} real committed bodies x 512x256, Rayon par_iter ({} threads available) ===",
std::thread::available_parallelism()
.map(|n| n.get())
.unwrap_or(0)
);
println!(
" {:>9.2} ms total wall time, {:>7.3} ms/body average",
elapsed.as_secs_f64() * 1000.0,
elapsed.as_secs_f64() * 1000.0 / body_count as f64
);
println!(
" basins: {total_basins} total across population ({total_overflow} overflow, {total_endorheic} endorheic)"
);
println!(" lake cells (summed across population): {total_lake_cells}");
println!(
" carved-outlet basins (channel_depth_scaled > 0 at spill cell, summed): {total_carved_cells}"
);
println!(
" cliff_edge=true cells (summed across population): {total_cliff_edge_cells}"
);
println!(
" bodies with ANY cliff_edge cell: {bodies_with_any_carving} / {body_count} ({:.2}%)",
100.0 * bodies_with_any_carving as f64 / body_count as f64
);
println!("\n Top 15 bodies by cliff_edge cell count (the max-carve outliers):");
for s in by_cliff_edge.iter().take(15) {
println!(
" {:>10} cliff_edge_cells={:>4} carved_basins={:>2} basins={:>3} (overflow={:>3}, endorheic={:>2}) lake_cells={:>6} solve={:.2}ms",
s.body_id, s.cliff_edge_cells, s.carved_cells, s.basins, s.overflow, s.endorheic, s.lake_cells, s.solve_ms
);
}
let zero_carve_bodies = surveys.iter().filter(|s| s.cliff_edge_cells == 0).count();
println!(
"\n Bodies with ZERO cliff_edge cells: {zero_carve_bodies} / {body_count} ({:.2}%)",
100.0 * zero_carve_bodies as f64 / body_count as f64
);
// Determinism spot-check on the max-carve outlier (if any carving was
// found at all) — re-solve it once more and confirm byte-identical
// cliff_edge/channel_depth output, so the survey's headline outlier
// isn't itself an artifact of non-determinism.
if let Some(top) = by_cliff_edge.first() {
if top.cliff_edge_cells > 0 {
let path = heightmap_paths
.iter()
.find(|p| {
p.parent()
.and_then(|d| d.file_name())
.and_then(|n| n.to_str())
== Some(top.body_id.as_str())
})
.expect("outlier body path must exist (found via the same walk above)");
let heightmap = settled_reach_server::atlas::heightmap::load_heightmap_png(
path,
&top.body_id,
0.3,
)
.expect("re-decode outlier heightmap for determinism spot-check");
let small = heightmap.downsample(512, 256);
let r1 = solve(&small.data, 512, 256, small.sea_level, default_climate());
let r2 = solve(&small.data, 512, 256, small.sea_level, default_climate());
assert_eq!(
r1.cliff_edge, r2.cliff_edge,
"max-carve outlier {} must be deterministic (cliff_edge)",
top.body_id
);
assert_eq!(
r1.channel_depth_scaled, r2.channel_depth_scaled,
"max-carve outlier {} must be deterministic (channel_depth_scaled)",
top.body_id
);
println!(
"\n Determinism spot-check on max-carve outlier ({}): PASS (byte-identical across two solves)",
top.body_id
);
}
}
}
/// **PER-BASIN SIZE DISTRIBUTION (body-map-viewer workshop, Araminta's
/// endorheic-carrier crossover question, routed via the coordinator).**
/// [`bench_population_survey_all_committed_bodies`] above reports only
/// AGGREGATE lake-cell totals (2,694,012 summed across 22,270 basins) — it
/// does not report individual basin SIZES, which is exactly what a
/// sparse-list-vs-dense-field crossover analysis needs (a sparse per-cell
/// list is cheap for small basins and expensive for large ones; the
/// crossover point depends on the actual size DISTRIBUTION, not the
/// aggregate). This bench solves every real committed body at the real
/// 512×256 production working grid (same population, same grid size as the
/// population survey above) and records every individual basin's cell
/// count, then reports the full distribution: histogram buckets, percentiles,
/// and the largest basins found, so the crossover call is made from a real
/// distribution rather than the single synthetic 8.3M-cell grid's one
/// data point (412,700 cells — T-1177's original measured appendix, a
/// SYNTHETIC ridged-terrain grid at a canvas size no production path
/// actually derives hydrology at synchronously, not a real-population
/// statistic).
#[test]
#[ignore]
fn bench_per_basin_size_distribution_real_population() {
use rayon::prelude::*;
let wiki_root =
std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("../wiki/star-systems");
let mut heightmap_paths: Vec<std::path::PathBuf> = Vec::new();
fn walk(dir: &std::path::Path, out: &mut Vec<std::path::PathBuf>) {
let Ok(entries) = std::fs::read_dir(dir) else {
return;
};
for entry in entries.flatten() {
let path = entry.path();
if path.is_dir() {
walk(&path, out);
} else if path.file_name().and_then(|n| n.to_str()) == Some("heightmap.png") {
out.push(path);
}
}
}
walk(&wiki_root, &mut heightmap_paths);
heightmap_paths.sort();
assert!(
heightmap_paths.len() > 200,
"expected the real committed body population (~267), found {}",
heightmap_paths.len()
);
// (body_id, basin_cell_count, outcome_label) for EVERY basin across the
// whole population — the raw material for the distribution below.
let all_basins: Vec<(String, usize, &'static str)> = heightmap_paths
.par_iter()
.flat_map(|path| {
let body_id = path
.parent()
.and_then(|p| p.file_name())
.and_then(|n| n.to_str())
.unwrap_or("UNKNOWN")
.to_string();
let heightmap = settled_reach_server::atlas::heightmap::load_heightmap_png(
path, &body_id, 0.3,
)
.unwrap_or_else(|e| panic!("decode committed heightmap for {body_id} ({path:?}): {e}"));
let small = heightmap.downsample(512, 256);
let result = solve(&small.data, 512, 256, small.sea_level, default_climate());
result
.basins
.iter()
.map(|b| {
let outcome_label = match b.outcome {
settled_reach_server::atlas::hydrology_equilibrium::BasinOutcome::Overflow {
..
} => "overflow",
settled_reach_server::atlas::hydrology_equilibrium::BasinOutcome::Endorheic {
..
} => "endorheic",
};
(body_id.clone(), b.cells.len(), outcome_label)
})
.collect::<Vec<_>>()
})
.collect();
assert_eq!(
all_basins.len(),
22_270,
"basin count must match the population survey's own total exactly \
(same population, same grid size, same solver — a mismatch here \
means the two benches drifted, not that either is wrong)"
);
let mut sizes: Vec<usize> = all_basins.iter().map(|(_, n, _)| *n).collect();
sizes.sort_unstable();
let total: usize = sizes.iter().sum();
let n = sizes.len();
let percentile = |p: f64| -> usize {
let idx = ((p / 100.0) * (n - 1) as f64).round() as usize;
sizes[idx.min(n - 1)]
};
// Histogram buckets chosen to bracket plausible sparse-vs-dense
// crossover points: a Vec<(u16,u16)> cell entry is 4 raw bytes/cell
// (MessagePack-framed, somewhat less) vs. the dense `water` field's
// PNG-per-field rate of ~1.9 bytes/cell (T-1179) applied ONLY to that
// basin's own bounding extent — the buckets below span from "clearly
// sparse wins" (tiny basins) through "clearly dense wins" (the largest
// basins in this population).
let buckets: [(usize, usize, &str); 7] = [
(0, 10, "1-10 cells"),
(11, 50, "11-50 cells"),
(51, 200, "51-200 cells"),
(201, 1_000, "201-1,000 cells"),
(1_001, 5_000, "1,001-5,000 cells"),
(5_001, 20_000, "5,001-20,000 cells"),
(20_001, usize::MAX, "20,001+ cells"),
];
let mut bucket_counts = [0usize; 7];
let mut bucket_cell_totals = [0usize; 7];
for &size in &sizes {
for (i, (lo, hi, _)) in buckets.iter().enumerate() {
if size >= *lo && size <= *hi {
bucket_counts[i] += 1;
bucket_cell_totals[i] += size;
break;
}
}
}
let mut by_size: Vec<&(String, usize, &str)> = all_basins.iter().collect();
by_size.sort_by(|a, b| b.1.cmp(&a.1));
println!("\n=== PER-BASIN SIZE DISTRIBUTION: {n} basins, real 267-body population, 512x256 working grid ===");
println!(" total lake cells (cross-check vs population survey's 2,694,012): {total}");
println!(" min={}, max={}, mean={:.1}, median(p50)={}",
sizes[0], sizes[n - 1], total as f64 / n as f64, percentile(50.0));
println!(" percentiles: p10={} p25={} p50={} p75={} p90={} p95={} p99={} p99.9={}",
percentile(10.0), percentile(25.0), percentile(50.0), percentile(75.0),
percentile(90.0), percentile(95.0), percentile(99.0), percentile(99.9));
println!("\n Histogram (basin cell-count buckets):");
for (i, (_, _, label)) in buckets.iter().enumerate() {
println!(
" {label:<18}: {:>6} basins ({:>5.2}% of basins), {:>9} cells total ({:>5.2}% of lake cells)",
bucket_counts[i],
100.0 * bucket_counts[i] as f64 / n as f64,
bucket_cell_totals[i],
100.0 * bucket_cell_totals[i] as f64 / total as f64
);
}
println!("\n Top 20 largest basins (real population, real bodies):");
for (body_id, size, outcome) in by_size.iter().take(20) {
println!(" {body_id:>12} cells={size:>7} outcome={outcome}");
}
// Bytes-if-sparse vs bytes-if-dense-per-basin-extent crossover, using
// T-1179's measured PNG-per-field rate (638,382 B / 331,776 cells) as
// the dense-encoding baseline, and 4 raw bytes/cell (u16,u16 pair,
// MessagePack framing not applied — a conservative/pessimistic sparse
// estimate, since MessagePack's compact array framing would cost less,
// per T-1179's own "6.00 not 7 bytes/cell" finding for a different
// field shape) for the sparse Vec<(u16,u16)> carrier.
const PNG_BYTES_PER_CELL: f64 = 638_382.0 / 331_776.0;
const SPARSE_BYTES_PER_CELL: f64 = 4.0;
let mut crossover_basin_count = 0usize;
let mut sparse_wins_cells = 0usize;
let mut dense_wins_cells = 0usize;
for &size in &sizes {
let sparse_cost = size as f64 * SPARSE_BYTES_PER_CELL;
let dense_cost = size as f64 * PNG_BYTES_PER_CELL;
if sparse_cost <= dense_cost {
crossover_basin_count += 1;
sparse_wins_cells += size;
} else {
dense_wins_cells += size;
}
}
println!(
"\n Sparse-vs-dense crossover (sparse={SPARSE_BYTES_PER_CELL} B/cell raw vs dense={:.3} B/cell PNG-per-field):",
PNG_BYTES_PER_CELL
);
println!(
" sparse cheaper for {crossover_basin_count} / {n} basins ({:.2}%), covering {sparse_wins_cells} cells ({:.2}% of lake cells)",
100.0 * crossover_basin_count as f64 / n as f64,
100.0 * sparse_wins_cells as f64 / total as f64
);
println!(
" dense cheaper for {} / {n} basins ({:.2}%), covering {dense_wins_cells} cells ({:.2}% of lake cells)",
n - crossover_basin_count,
100.0 * (n - crossover_basin_count) as f64 / n as f64,
100.0 * dense_wins_cells as f64 / total as f64
);
println!();
}