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>
This commit is contained in:
2026-06-14 22:53:18 +02:00
co-authored by Claude Opus 4.8
parent 38054d4b12
commit b3b5bfc2e3
12 changed files with 945 additions and 886 deletions
+5 -5
View File
@@ -30,8 +30,8 @@ use crossbeam_channel::{Receiver, Sender};
use crate::atlas::attractor_matching::CityRecord;
use crate::atlas::body_world_state::BodyWorldState;
use crate::atlas::cascade::{run_cascade_from_heightmap, CascadeLayer};
use crate::atlas::district_profile::BodyParams;
use crate::atlas::heightmap::{load_heightmap_png, GRID_H, GRID_W};
use crate::atlas::region_profile::BodyParams;
use crate::atlas::skeleton_gen::{assign_all_block_tags, generate_quarter_skeleton};
use crate::seed::SeedChain;
use crate::simulation::generator::{CityGenerationContext, QuarterWorldState};
@@ -77,8 +77,8 @@ pub enum GenWorkItem {
/// time. Drives Layer-3 TerritorialStatus + spatial character (#956,
/// D-212/214/215). `None` → `FrontierUnclaimed`.
dominant_faction: Option<String>,
/// Body physical parameters for the RegionProfile layer (T-1023, D-239 §1).
/// Pre-resolved at dispatch time. `None` → region layer skipped for this body.
/// Body physical parameters for the DistrictProfile layer (T-1023, D-239 §1).
/// Pre-resolved at dispatch time. `None` → district layer skipped for this body.
/// Boxed: `BodyParams` is large relative to other variants (clippy
/// large_enum_variant) — boxing keeps `GenWorkItem` compact.
body_params: Option<Box<BodyParams>>,
@@ -375,8 +375,8 @@ fn run_work_item(item: &GenWorkItem) -> GenCompletion {
hm
};
// Run the full cascade through RoadGraph (Layer 2, T-1038), the
// terminal layer. It subsumes Settlement, RegionProfile (T-1023),
// and all prior layers. RegionProfile derivation still gates on
// terminal layer. It subsumes Settlement, DistrictProfile (T-1023),
// and all prior layers. DistrictProfile derivation still gates on
// body_params internally (skipped when absent — e.g. a body with no
// params row), but the road graph needs no body params, so it runs
// for every analyzed body.