feat(simulation): D-232 three-phase trait draw + deviation/swerve system (T-994, T-1003)
T-994 — three-phase draw replacing the flat splitmix64 flavor pick: - Phase 1 body K-draw (trait_draw.rs): hard gates -> soft weights (two-part geographic_sector join, PR #148) -> SeedChain::for_body-seeded weighted draw of K (5/3/1/0 by ComplexityTier), pins count toward K, coverage-aware over a new body-level district-type-mix aggregate threaded into CityGenerationContext at L3->L4 dispatch. - Phase 2 district-dominant pick keyed by the D-243 2048m District cell — settlements sharing a cell independently derive the identical template. Resolved at dispatch, never in FillChunk (T-987 stays pure). - trait_catalog_reader.rs: systems.db reader for trait_templates + atlas_body_trait_bias (D-225 resource pattern), registered in main.rs with graceful degradation. - BlockSkeleton carries district_type; assign_block_tags is a pure lookup. T-1003 — deviation/swerve system (trait_swerve.rs): - ArchitectureFlavorRef is now InVocabulary(u8) | Swerve(tag). - Rare per-building wildcard: foreign-import pool (other corridors + cross_corridor) driven by Epicenter/Passage tier, mixed faction, road-graph degree; heritage-callback pool (own-corridor heritage) driven by isolation, remote tier, founding_age_years. Integer bps, base 100, cap 300 per driver — placeholder constants pending calibration. - Sparsity escape hatch = same mechanism, necessity-triggered at the phase-2 pick (deterministic max-weight over the hard-gate-eligible pool). - New SeedDomains: TraitVocabulary(13) / TraitDistrict(14) / TraitSwerve(15). Governance: D-232 amended (district pinned to the D-243 2048m tier — the D-222/D-243 redefinition was never captured; swerve driver mappings + placeholder rates recorded), D-229 flavor_ref field updated to the enum shape, D-235 amended (T-995 vocabulary ratification note; rides here due to single-file entanglement). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -198,7 +198,13 @@ pub enum SettingType {
|
||||
}
|
||||
|
||||
/// Classification of a district (high-level function).
|
||||
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, Default)]
|
||||
///
|
||||
/// `Ord`/`PartialOrd` (T-994): lets callers dedup a body-wide coverage set into a
|
||||
/// `BTreeSet`/`BTreeMap` key (D-010 determinism) — the D-232 trait-template draw's
|
||||
/// `zone_affinity` lookup and the body-level district-type-mix coverage aggregate.
|
||||
/// Declaration order is not a stability-pinned wire format (unlike `MorphologyZone`
|
||||
/// or `SeedDomain`), so this is a safe additive derive.
|
||||
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Default)]
|
||||
pub enum DistrictType {
|
||||
LogisticsHub,
|
||||
Residential,
|
||||
@@ -817,15 +823,31 @@ impl TileRect {
|
||||
}
|
||||
}
|
||||
|
||||
/// Architecture flavor index into the body's trait-template draw (D-229, D-232).
|
||||
/// Architecture flavor reference into the body's trait-template draw (D-229, D-232).
|
||||
///
|
||||
/// Records which template the generator selected at skeleton time for Phase-6 to
|
||||
/// read cold. The selection mechanism is D-232's weighted `allow`/`block` filter;
|
||||
/// the index is frozen-amber once written.
|
||||
/// read cold. The selection mechanism is D-232's three-phase draw (T-994): a body
|
||||
/// vocabulary K-draw, then a per-district dominant-template pick by `zone_affinity`,
|
||||
/// then within-template seed picks (not represented here — that's the D-235 visual
|
||||
/// bundle resolution). The reference is frozen-amber once written.
|
||||
///
|
||||
/// Shaped as an enum (rather than a bare index) so the closed-vocabulary case and
|
||||
/// the future out-of-vocabulary swerve (T-1003, D-232's deviation system) share one
|
||||
/// wire type without a breaking change when the swerve lands — `T-994` introduces
|
||||
/// the shape only; swerve *logic* (foreign-import / heritage-callback draws) is not
|
||||
/// implemented here.
|
||||
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)]
|
||||
pub struct ArchitectureFlavorRef {
|
||||
/// Index into `CityGenerationContext::trait_selection` (0-based).
|
||||
pub flavor_index: u8,
|
||||
pub enum ArchitectureFlavorRef {
|
||||
/// Index into `CityGenerationContext::trait_selection` (0-based) — the body's
|
||||
/// closed K-template vocabulary (D-232 phase 1).
|
||||
InVocabulary(u8),
|
||||
/// A template tag drawn from *outside* the body's closed vocabulary (T-1003,
|
||||
/// D-232 deviation system): the rare per-building foreign-import /
|
||||
/// heritage-callback wildcard (`trait_swerve::roll_building_swerve`), or the
|
||||
/// sparsity escape hatch at district-dominant time
|
||||
/// (`trait_swerve::necessity_swerve`). The passive past-vogue holdover is NOT
|
||||
/// a swerve — it rides the D-217 wear/era condition layer (`era_cause`).
|
||||
Swerve(String),
|
||||
}
|
||||
|
||||
/// A single building footprint tag — the frozen step-3 output placed on every
|
||||
@@ -1116,11 +1138,57 @@ pub struct CityGenerationContext {
|
||||
/// Body vocabulary draw result — K trait-template tags selected at skeleton
|
||||
/// time (D-232). K is locked to `complexity_tier`: Full=5, Moderate=3,
|
||||
/// Minimal=1, Empty=0. NOT named `flavor_profile` (that was the round-2 name).
|
||||
/// Populated by the T-994 phase-1 K-draw; empty when the trait catalog reader
|
||||
/// is unavailable or `complexity_tier == Empty` (K=0).
|
||||
pub trait_selection: Vec<String>,
|
||||
/// Dominant `BulkClass` for this settlement's primary commodity (D-233).
|
||||
pub dominant_bulk_class: BulkClass,
|
||||
/// Spatial concentration of dominant production (D-233).
|
||||
pub dominant_production_ubiquity: ProductionUbiquity,
|
||||
|
||||
// ── T-994 additions (D-232 three-phase draw) ───────────────────────────
|
||||
/// This system's corridor (`star_systems.geographic_sector` —
|
||||
/// core/north_reach/south_reach/west_reach/east_reach/deep_frontier; `None`
|
||||
/// if unset). A SOFT weight on the phase-1 body-vocabulary draw only — composes
|
||||
/// with a template's own `geographic_sector` pool-narrowing column AND its
|
||||
/// `weight_mods.geographic_sector` map (PR #148 review note: a two-part join,
|
||||
/// never a hard gate — D-232 "corridors are tendencies, not borders").
|
||||
pub geographic_sector: Option<String>,
|
||||
/// Body-level district-type coverage: every `DistrictType` present anywhere
|
||||
/// among this body's settlements, deduped (T-994). Threaded from the L3→L4
|
||||
/// dispatch aggregation so the phase-1 K-draw is coverage-aware up front
|
||||
/// (≥1 eligible template per district type actually present on the body).
|
||||
pub body_district_type_mix: Vec<DistrictType>,
|
||||
/// The D-243 2 048 m District cell (`atlas::scale::DistrictPos`) this
|
||||
/// settlement's quarter falls in (T-994). Two settlements sharing a
|
||||
/// `settlement_district_pos` independently derive the identical phase-2
|
||||
/// dominant template for a given `DistrictType` — same body seed + same key,
|
||||
/// so a coherent 2 048 m area reads as one style with no cross-quarter
|
||||
/// coordination required.
|
||||
pub settlement_district_pos: (i32, i32),
|
||||
/// Phase-2 dominant-template pick (D-232), pre-resolved at L3→L4 dispatch time
|
||||
/// (T-994) — **not** at `FillChunk` (T-987 keeps fill pure/cache-free) and not
|
||||
/// even inside the `GenerateSkeleton` Rayon task itself, since the inputs
|
||||
/// (`trait_selection` + the catalog's `zone_affinity`) are already known at
|
||||
/// dispatch. One entry per `DistrictType` (all 9, so `assign_block_tags` is a
|
||||
/// cheap infallible lookup). Usually `InVocabulary` (an index into
|
||||
/// `trait_selection`); `Swerve` when the sparsity escape hatch fired (T-1003).
|
||||
/// `BTreeMap` for D-010 determinism.
|
||||
pub district_dominant_by_type: BTreeMap<DistrictType, ArchitectureFlavorRef>,
|
||||
|
||||
// ── T-1003 additions (D-232 deviation/swerve system) ────────────────────
|
||||
/// Per-building wildcard chances (bps of 10 000): `(foreign_bps,
|
||||
/// heritage_bps)`, resolved once per settlement at dispatch time from the
|
||||
/// driver inputs (`trait_swerve::compute_swerve_rates`). Both zero when no
|
||||
/// catalog reader is wired.
|
||||
pub swerve_rates_bps: (u32, u32),
|
||||
/// Foreign-import swerve candidates — hard-gate-eligible templates outside
|
||||
/// the body vocabulary, from another corridor's grammar or the shared
|
||||
/// `cross_corridor` pool: `(tag, weight_bps)` (`trait_swerve` module).
|
||||
pub swerve_foreign_pool: Vec<(String, u32)>,
|
||||
/// Heritage-callback swerve candidates — the body's own corridor heritage
|
||||
/// sub-pool: `(tag, weight_bps)`.
|
||||
pub swerve_heritage_pool: Vec<(String, u32)>,
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
@@ -1146,6 +1214,12 @@ pub struct BlockSkeleton {
|
||||
/// Grid position (0–3, 0–3).
|
||||
pub position: (u8, u8),
|
||||
pub zoning: ZoningType,
|
||||
/// The D-194 district-mix `DistrictType` this block was assigned (T-994).
|
||||
/// `zoning` is the *function* derived from it (`zoning_for_district`); this
|
||||
/// field keeps the source classification around because the D-232 phase-2
|
||||
/// dominant-template pick keys `zone_affinity` by `DistrictType`, not
|
||||
/// `ZoningType` — dropping it here would make the pick unrecoverable.
|
||||
pub district_type: DistrictType,
|
||||
/// Which multi-block reservation this block belongs to (if any).
|
||||
pub reservation: Option<ReservationId>,
|
||||
pub chunk_layout: ChunkLayout,
|
||||
|
||||
Reference in New Issue
Block a user