Merge remote-tracking branch 'origin/climate-morphology-layers'
This commit is contained in:
@@ -1771,6 +1771,7 @@ Technical foundation decisions that constrain implementation: engine, client-ser
|
|||||||
- **Raised by:** tile-derivation-contract workshop (Tyre — refinement chain, warp, determinism; Gestalt — 8 families, game-feel; Troblum — feasibility, warp precision, scale corrections; Miri — believability laws, vocabulary, lore reconciliation), lead-interviewed decisions + an adversarial verification pass, 2026-06-07.
|
- **Raised by:** tile-derivation-contract workshop (Tyre — refinement chain, warp, determinism; Gestalt — 8 families, game-feel; Troblum — feasibility, warp precision, scale corrections; Miri — believability laws, vocabulary, lore reconciliation), lead-interviewed decisions + an adversarial verification pass, 2026-06-07.
|
||||||
- **Dissent:** Tyre's initial cross-family elevation-blend was resolved against (prevent-at-source). Early-integer-truncation of the warp (raised against Gestalt's `ElevationDelta` ranges and by Tyre) was resolved against in favour of f64-to-voxel.
|
- **Dissent:** Tyre's initial cross-family elevation-blend was resolved against (prevent-at-source). Early-integer-truncation of the warp (raised against Gestalt's `ElevationDelta` ranges and by Tyre) was resolved against in favour of f64-to-voxel.
|
||||||
- **Implementation note (T-1024, 2026-06-07):** §1 per-body `RIVER_THRESHOLD` is now a derived field (`derive_river_threshold`) on `RegionProfile`. §2 district temperature is a nullable `f32` on `RegionProfile` sampled from a per-region climate derivation (`derive_temperature_c`); moisture is a separate integer primitive (`derive_moisture_q`, 0–100). Both populate the `RegionProfile` carrier during the L4 cascade run. Climate inputs use a **hybrid strategy**: stellar luminosity and spectral class are sourced from the import pipeline (`bodies.axial_tilt_deg`, `star_systems.spectral_class`); greenhouse offsets and diurnal amplitudes are tunable at runtime via `server/data/climate_constants.toml` (source-canonical TOML, not hardcoded).
|
- **Implementation note (T-1024, 2026-06-07):** §1 per-body `RIVER_THRESHOLD` is now a derived field (`derive_river_threshold`) on `RegionProfile`. §2 district temperature is a nullable `f32` on `RegionProfile` sampled from a per-region climate derivation (`derive_temperature_c`); moisture is a separate integer primitive (`derive_moisture_q`, 0–100). Both populate the `RegionProfile` carrier during the L4 cascade run. Climate inputs use a **hybrid strategy**: stellar luminosity and spectral class are sourced from the import pipeline (`bodies.axial_tilt_deg`, `star_systems.spectral_class`); greenhouse offsets and diurnal amplitudes are tunable at runtime via `server/data/climate_constants.toml` (source-canonical TOML, not hardcoded).
|
||||||
|
- **Implementation note (T-1025/T-1027, 2026-06-08):** §6's frozen 17-zone `MorphologyZone` enum is realised in `server/src/simulation/generator.rs` (`repr(u8)`, discriminant-pinned). The §5 8-family gated classifier + §7 compatibility-matrix invariants live in `derive_morphology_zone` (`region_profile.rs`). **16 of the 17 zones are reachable at RegionProfile scale; `BraidedPlain` is the exception** — distinguishing it from `Delta` needs a lithology signal (§8 Gravel→braided) that `RegionProfile` does not carry, so `BraidedPlain` is **deferred to ChunkContext** sub-classification. The §7 compatibility invariant is enforced as a **classifier-gate-ordering** property (a build-time test that a single region cannot yield a forbidden pair), per §7's "build-time test" language; genuine cross-region sharp seams (cliff↔fjord, lithology faults) remain permitted. §2 climate-derived fields (`precipitation_class`, `glaciation_grade`, `vegetation_class`) all derive from the temperature(+moisture) primitive (T-1025).
|
||||||
- **Cross-reference:** [D-227](#d-227) (derive-don't-store voxel model), [D-228](#d-228) (composite tile axes / cohesion / seasonal state), [D-210](#d-210) (temperature proxy — formalised), [D-203](#d-203) (BodyWorldState cache), [D-206](#d-206) (background analysis pass), [D-208](#d-208) (drainage / D8), [D-010](#d-010) (determinism), [D-234](#d-234) (street/footprint geometry — consumes morphology), [D-142](content.md#d-142) (zone types), [D-217](#d-217) (tile condition), [Q-102](../questions/architecture.md#q-102) (cohesion = the warp), [Q-103](../questions/architecture.md#q-103) (mutator schema — open), [Q-105](../questions/architecture.md#q-105) (seasonal/clock state — temperature/ElevationDelta forward contract)
|
- **Cross-reference:** [D-227](#d-227) (derive-don't-store voxel model), [D-228](#d-228) (composite tile axes / cohesion / seasonal state), [D-210](#d-210) (temperature proxy — formalised), [D-203](#d-203) (BodyWorldState cache), [D-206](#d-206) (background analysis pass), [D-208](#d-208) (drainage / D8), [D-010](#d-010) (determinism), [D-234](#d-234) (street/footprint geometry — consumes morphology), [D-142](content.md#d-142) (zone types), [D-217](#d-217) (tile condition), [Q-102](../questions/architecture.md#q-102) (cohesion = the warp), [Q-103](../questions/architecture.md#q-103) (mutator schema — open), [Q-105](../questions/architecture.md#q-105) (seasonal/clock state — temperature/ElevationDelta forward contract)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|||||||
+1007
-110
File diff suppressed because it is too large
Load Diff
@@ -1046,19 +1046,31 @@ enum Topology {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn street_topology(m: &MorphologyZone) -> Topology {
|
fn street_topology(m: &MorphologyZone) -> Topology {
|
||||||
|
// D-234 morphology-gated trunk topology.
|
||||||
|
// Updated for D-239 §6 frozen 17-zone vocabulary (T-1027).
|
||||||
match m {
|
match m {
|
||||||
MorphologyZone::Fjord | MorphologyZone::Canyon | MorphologyZone::MountainPass => {
|
// Ribbon: linear/constrained terrain — follow the single axis.
|
||||||
Topology::Ribbon
|
MorphologyZone::Fjord
|
||||||
}
|
| MorphologyZone::CliffCoast
|
||||||
|
| MorphologyZone::MountainPass
|
||||||
|
| MorphologyZone::Alpine
|
||||||
|
| MorphologyZone::ValleyFloor => Topology::Ribbon,
|
||||||
|
|
||||||
|
// HubSpoke: water-enclosed or island-like contexts — radiate from a centre.
|
||||||
MorphologyZone::Delta
|
MorphologyZone::Delta
|
||||||
|
| MorphologyZone::Estuarine
|
||||||
| MorphologyZone::OpenOcean
|
| MorphologyZone::OpenOcean
|
||||||
| MorphologyZone::Lake
|
| MorphologyZone::Lake
|
||||||
| MorphologyZone::Sea
|
| MorphologyZone::DuneStrand
|
||||||
| MorphologyZone::Island => Topology::HubSpoke,
|
| MorphologyZone::TidalFlat => Topology::HubSpoke,
|
||||||
|
|
||||||
|
// Mesh: flat/open terrain — any pattern.
|
||||||
MorphologyZone::AlluvialPlain
|
MorphologyZone::AlluvialPlain
|
||||||
| MorphologyZone::MeanderReach
|
| MorphologyZone::MeanderReach
|
||||||
| MorphologyZone::CoastalLowland
|
| MorphologyZone::RiverBank
|
||||||
| MorphologyZone::Unknown => Topology::Mesh,
|
| MorphologyZone::BraidedPlain
|
||||||
|
| MorphologyZone::Wetland
|
||||||
|
| MorphologyZone::Volcanic => Topology::Mesh,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1748,7 +1760,7 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn hub_spoke_shares_a_common_node() {
|
fn hub_spoke_shares_a_common_node() {
|
||||||
let aps = derive_access_points(&[0, 2, 4, 6], &[]);
|
let aps = derive_access_points(&[0, 2, 4, 6], &[]);
|
||||||
let corridors = derive_corridors(&aps, &MorphologyZone::Island);
|
let corridors = derive_corridors(&aps, &MorphologyZone::OpenOcean);
|
||||||
// Every spoke touches the hub.
|
// Every spoke touches the hub.
|
||||||
let hub = central_node(&aps) as u16;
|
let hub = central_node(&aps) as u16;
|
||||||
assert!(corridors.iter().all(|c| c.from == hub || c.to == hub));
|
assert!(corridors.iter().all(|c| c.from == hub || c.to == hub));
|
||||||
@@ -1771,14 +1783,14 @@ mod tests {
|
|||||||
let inland = subdivide_block_footprints(
|
let inland = subdivide_block_footprints(
|
||||||
70,
|
70,
|
||||||
&BulkClass::NonPhysical,
|
&BulkClass::NonPhysical,
|
||||||
&MorphologyZone::CoastalLowland,
|
&MorphologyZone::RiverBank,
|
||||||
None,
|
None,
|
||||||
SeedChain::root(3),
|
SeedChain::root(3),
|
||||||
);
|
);
|
||||||
let quay = subdivide_block_footprints(
|
let quay = subdivide_block_footprints(
|
||||||
70,
|
70,
|
||||||
&BulkClass::NonPhysical,
|
&BulkClass::NonPhysical,
|
||||||
&MorphologyZone::CoastalLowland,
|
&MorphologyZone::RiverBank,
|
||||||
Some(Edge::North),
|
Some(Edge::North),
|
||||||
SeedChain::root(3),
|
SeedChain::root(3),
|
||||||
);
|
);
|
||||||
@@ -1796,14 +1808,14 @@ mod tests {
|
|||||||
let inland = subdivide_block_footprints(
|
let inland = subdivide_block_footprints(
|
||||||
10,
|
10,
|
||||||
&BulkClass::BulkSolid,
|
&BulkClass::BulkSolid,
|
||||||
&MorphologyZone::CoastalLowland,
|
&MorphologyZone::RiverBank,
|
||||||
None,
|
None,
|
||||||
SeedChain::root(11),
|
SeedChain::root(11),
|
||||||
);
|
);
|
||||||
let quay = subdivide_block_footprints(
|
let quay = subdivide_block_footprints(
|
||||||
10,
|
10,
|
||||||
&BulkClass::BulkSolid,
|
&BulkClass::BulkSolid,
|
||||||
&MorphologyZone::CoastalLowland,
|
&MorphologyZone::RiverBank,
|
||||||
Some(Edge::North),
|
Some(Edge::North),
|
||||||
SeedChain::root(11),
|
SeedChain::root(11),
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -946,38 +946,65 @@ pub struct DoorSpec {
|
|||||||
pub interior_descriptor: InteriorDescriptor,
|
pub interior_descriptor: InteriorDescriptor,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Region-level morphology zone (D-228, D-232, D-234).
|
/// Region-level morphology zone — D-239 §6 frozen 17-zone vocabulary (T-1027).
|
||||||
|
///
|
||||||
|
/// **FREEZE POINT**: this enum is the canonical freeze per D-239 §6.
|
||||||
|
/// Adding, renaming, or removing a zone **requires a D-record amendment**
|
||||||
|
/// (reviewer-enforced). Classifier tuning that merely re-classifies a region
|
||||||
|
/// is NOT a vocabulary change and stays free.
|
||||||
|
///
|
||||||
|
/// Zones ≠ families. Four zones — TidalFlat, Estuarine, Alpine, Wetland —
|
||||||
|
/// are derived sub-classifications (family + elevation/water-height), not
|
||||||
|
/// distinct generator families.
|
||||||
///
|
///
|
||||||
/// Shared by all tiles in a region; constrains street geometry (D-234)
|
/// Shared by all tiles in a region; constrains street geometry (D-234)
|
||||||
/// and acts as a soft weight on cultural-template eligibility (D-232).
|
/// and acts as a soft weight on cultural-template eligibility (D-232).
|
||||||
/// Carried on `CityGenerationContext` (D-233 amend to D-199).
|
/// Carried on `CityGenerationContext` (D-233 amend to D-199).
|
||||||
|
///
|
||||||
|
/// Integer-discriminant, D-010 compliant. `repr(u8)` pins values for
|
||||||
|
/// serialisation stability; append-only.
|
||||||
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, Default)]
|
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, Default)]
|
||||||
|
#[repr(u8)]
|
||||||
pub enum MorphologyZone {
|
pub enum MorphologyZone {
|
||||||
/// Steep-sided inlet — ribbon/hub-and-spoke streets only; pier geometry on water edges.
|
/// Deep-water ocean — hub-and-spoke; perimeter access priority.
|
||||||
Fjord,
|
OpenOcean = 0,
|
||||||
|
/// Lake body — hub-and-spoke; perimeter access toward water.
|
||||||
|
Lake = 1,
|
||||||
|
/// Tidal flat (sub-classification): low coastal plain exposed at low tide.
|
||||||
|
/// Derived from CliffCoast/AlluvialPlain family + tidal signal + low elevation.
|
||||||
|
TidalFlat = 2,
|
||||||
|
/// Dune strand — ribbon/hub-and-spoke; wind-aligned lot orientation.
|
||||||
|
DuneStrand = 3,
|
||||||
|
/// Cliff coast — ribbon only; vertical face at water edge.
|
||||||
|
CliffCoast = 4,
|
||||||
|
/// Fjord — ribbon/hub-and-spoke; pier geometry; requires GlaciationGrade ≥ 2.
|
||||||
|
Fjord = 5,
|
||||||
/// River delta / braided channel — hub-and-spoke following channels; bridges as forced nodes.
|
/// River delta / braided channel — hub-and-spoke following channels; bridges as forced nodes.
|
||||||
Delta,
|
Delta = 6,
|
||||||
/// Meandering river reach — any pattern.
|
/// Estuarine (sub-classification): brackish tidal zone at river mouth.
|
||||||
MeanderReach,
|
/// Derived from Delta/AlluvialPlain family + tidal signal + low elevation.
|
||||||
|
Estuarine = 7,
|
||||||
/// Flat alluvial plain — any pattern; primary default for plains settlements.
|
/// Flat alluvial plain — any pattern; primary default for plains settlements.
|
||||||
#[default]
|
#[default]
|
||||||
AlluvialPlain,
|
AlluvialPlain = 8,
|
||||||
/// Open ocean surface (deep-water context) — hub-and-spoke; perimeter access priority.
|
/// River bank — gentle approach; pier geometry on water-facing edges.
|
||||||
OpenOcean,
|
RiverBank = 9,
|
||||||
/// Lake shore — hub-and-spoke; perimeter access toward water.
|
/// Meandering river reach — any pattern.
|
||||||
Lake,
|
MeanderReach = 10,
|
||||||
/// Interior sea body.
|
/// Braided channel plain — hub-and-spoke; gravel/sand substrate.
|
||||||
Sea,
|
BraidedPlain = 11,
|
||||||
|
/// Valley floor — ribbon or mesh; enclosed by flanking slopes.
|
||||||
|
ValleyFloor = 12,
|
||||||
/// Mountain pass terrain — ribbon only; elevation steps as block boundaries.
|
/// Mountain pass terrain — ribbon only; elevation steps as block boundaries.
|
||||||
MountainPass,
|
MountainPass = 13,
|
||||||
/// Coastal lowland — any pattern; pier geometry on water-facing edges.
|
/// Alpine (sub-classification): above treeline high-altitude zone.
|
||||||
CoastalLowland,
|
/// Derived from IncisedGorge/ValleyFloor family + high elevation.
|
||||||
/// Island context — hub-and-spoke; perimeter access priority.
|
Alpine = 14,
|
||||||
Island,
|
/// Volcanic — lava field / shield slope; requires TectonicClass::Volcanic.
|
||||||
/// Canyon floor — ribbon or hub-and-spoke only.
|
Volcanic = 15,
|
||||||
Canyon,
|
/// Wetland (sub-classification): low-gradient, saturated or seasonally flooded.
|
||||||
/// Unknown / unclassified — fallback to AlluvialPlain behaviour.
|
/// Derived from AlluvialPlain/Delta family + low slope + high moisture.
|
||||||
Unknown,
|
Wetland = 16,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Built-form archetype derived from a settlement's dominant commodity (D-233).
|
/// Built-form archetype derived from a settlement's dominant commodity (D-233).
|
||||||
|
|||||||
Reference in New Issue
Block a user