code wiki / (root) / nx_ecotone.nx

nx_ecotone.nx source

↩ module page · 286 lines · 12029 B

1// nx_ecotone.nx -- ecological design at ecosystem transition zones. 2// 3// Per META-CARDINAL feedback-regenerative-stewardship-doctrine-captain-moroni: 4// an ecotone is the transition between two ecosystems (forest-to-meadow, 5// grassland-to-savanna, riparian-to-upland, desert-to-oasis). Ecotones 6// host highest biodiversity because organisms from both adjacent systems 7// can occupy the gradient. They are also where regenerative intervention 8// has HIGHEST LEVERAGE. 9// 10// V1 ships sealed enum of ecotone transition types + sealed enum of 11// candidate-species roles + companion-plant compatibility matrix + 12// per-ecotone succession trajectory at 5/10/25/50/100 year horizons. 13// Per [[feedback-real-playtest-loop-not-just-logs]] honest scope: per- 14// site selection is operator-attested; substrate provides the design 15// substrate, never claims unique knowledge of any specific site. 16// 17// Composes: 18// nx_phenology -- species timing co-design 19// nx_pollinator -- pollinator requirements per species 20// nx_disturbance -- some ecotones depend on disturbance regime 21// nx_microclimate -- microclimate gates species selection 22// nx_covenant -- Indigenous + landowner consent for any planting 23// 24// Gap list (V1 honest perf verdict): 25// - species enum is illustrative (V2 ingests species DB via nx_hypha 26// from USDA PLANTS / GBIF / regional flora authorities) 27// - companion-plant matrix is per-functional-role (V2 species-level) 28// - succession trajectories are at functional-class granularity 29// 30// genealogy_id: nishi_metacardinal_2026-05-19_regenerative_stewardship 31// lineage_id: substrate_ecotone_v1 32// 33// nx_safety_envelope: 34// intended_use: "Ecotone transition modeling + species role 35// matching + companion matrix + succession 36// trajectory; substrate informs gardener, 37// per-site selection is operator + ecologist" 38// sil_target: SIL2 39// evidence: [enum_sealed, succession_at_5_horizons, 40// invasive_flag_per_role_recommended] 41// verdict: NOT_YET_EVALUATED 42 43import "nx_syscalls.nx" 44import "nx_tier.nx" 45 46// ===== Sealed enum: NxEcotoneTransition =========================== 47 48const NX_ET_FOREST_MEADOW: nx_int = 0 49const NX_ET_GRASSLAND_SAVANNA: nx_int = 1 50const NX_ET_RIPARIAN_UPLAND: nx_int = 2 51const NX_ET_DESERT_OASIS: nx_int = 3 52const NX_ET_WETLAND_UPLAND: nx_int = 4 53const NX_ET_ALPINE_TIMBERLINE: nx_int = 5 54const NX_ET_COASTAL_DUNE: nx_int = 6 55const NX_ET_FOREST_CLEARCUT: nx_int = 7 // restoration context 56const NX_ET_STRIPMINE_RECLAMATION: nx_int = 8 57const NX_ET_URBAN_GREENSPACE: nx_int = 9 58const NX_ET_N_TRANSITIONS: nx_int = 10 59 60// ===== Sealed enum: NxSpeciesRole ================================= 61// 62// Functional roles species can fill in the ecotone. V1 covers 63// structural + nutrient-fixing + soil-builder + pioneer + understory. 64// Per [[feedback-no-false-ok-substrate-honesty-audit]] the enum 65// includes "INVASIVE_RISK_FLAG" as an explicit role so callers can 66// query "is this species invasive-flagged in this jurisdiction?" 67 68const NX_SR_CANOPY_DOMINANT: nx_int = 0 // mature canopy tree 69const NX_SR_CANOPY_PIONEER: nx_int = 1 // fast-growing pioneer (e.g. paulownia) 70const NX_SR_NITROGEN_FIXER: nx_int = 2 // legume / actinorhizal 71const NX_SR_UNDERSTORY_SHRUB: nx_int = 3 72const NX_SR_GROUND_COVER: nx_int = 4 73const NX_SR_HERBACEOUS_PERENNIAL: nx_int = 5 74const NX_SR_GRAMINOID: nx_int = 6 // grasses + sedges 75const NX_SR_SOIL_FUNGI_PARTNER: nx_int = 7 // mycorrhizal partner 76const NX_SR_POLLINATOR_NECTAR: nx_int = 8 // bee/butterfly/hummingbird-attractor 77const NX_SR_WILDLIFE_FOOD: nx_int = 9 // bird/mammal-food 78const NX_SR_RIPARIAN_BANK_STABILIZER: nx_int = 10 // willow/cottonwood class 79const NX_SR_INVASIVE_RISK_FLAG: nx_int = 11 // explicit flag 80const NX_SR_N_ROLES: nx_int = 12 81 82// ===== Sealed enum: NxSuccessionPhase ============================= 83// 84// Time horizon at which the species is expected to contribute. 85 86const NX_SU_PHASE_PIONEER_0_5_YR: nx_int = 0 87const NX_SU_PHASE_EARLY_5_25_YR: nx_int = 1 88const NX_SU_PHASE_MID_25_50_YR: nx_int = 2 89const NX_SU_PHASE_LATE_50_100_YR: nx_int = 3 90const NX_SU_PHASE_OLDGROWTH_100_PLUS: nx_int = 4 91const NX_SU_PHASE_N_PHASES: nx_int = 5 92 93// ===== Sealed enum: NxEcotoneVerdict ============================== 94 95const NX_ET_V_DESIGN_OK: nx_int = 0 96const NX_ET_V_MISSING_FUNCTIONAL_ROLE: nx_int = 1 // gap in role coverage 97const NX_ET_V_INVASIVE_FLAGGED: nx_int = 2 // chosen species invasive 98const NX_ET_V_SUCCESSION_GAP: nx_int = 3 // phase not covered 99const NX_ET_V_INVALID: nx_int = 99 100const NX_ET_V_N_VERDICTS: nx_int = 4 101 102// ===== nx_et_transition_is_valid ================================== 103 104func nx_et_transition_is_valid(t: nx_int) -> nx_int { 105 if t < 0 { return 0 } 106 if t >= NX_ET_N_TRANSITIONS { return 0 } 107 return 1 108} 109 110// ===== nx_sr_role_is_valid ======================================== 111 112func nx_sr_role_is_valid(r: nx_int) -> nx_int { 113 if r < 0 { return 0 } 114 if r >= NX_SR_N_ROLES { return 0 } 115 return 1 116} 117 118// ===== nx_su_phase_is_valid ======================================= 119 120func nx_su_phase_is_valid(p: nx_int) -> nx_int { 121 if p < 0 { return 0 } 122 if p >= NX_SU_PHASE_N_PHASES { return 0 } 123 return 1 124} 125 126// ===== nx_et_v_is_valid =========================================== 127 128func nx_et_v_is_valid(v: nx_int) -> nx_int { 129 if v < 0 { return 0 } 130 if v >= NX_ET_V_N_VERDICTS { return 0 } 131 return 1 132} 133 134// ===== nx_sr_is_structural ======================================== 135// 136// Predicate: returns 1 if the role provides physical structure 137// (canopy, shrub, ground cover, bank stabilizer). 138 139func nx_sr_is_structural(r: nx_int) -> nx_int { 140 if r == NX_SR_CANOPY_DOMINANT { return 1 } 141 if r == NX_SR_CANOPY_PIONEER { return 1 } 142 if r == NX_SR_UNDERSTORY_SHRUB { return 1 } 143 if r == NX_SR_GROUND_COVER { return 1 } 144 if r == NX_SR_RIPARIAN_BANK_STABILIZER { return 1 } 145 return 0 146} 147 148// ===== nx_sr_is_provisioning ====================================== 149// 150// Predicate: returns 1 if the role provides resources to other 151// organisms (nitrogen, pollen/nectar, food, mycorrhizal partnership). 152 153func nx_sr_is_provisioning(r: nx_int) -> nx_int { 154 if r == NX_SR_NITROGEN_FIXER { return 1 } 155 if r == NX_SR_POLLINATOR_NECTAR { return 1 } 156 if r == NX_SR_WILDLIFE_FOOD { return 1 } 157 if r == NX_SR_SOIL_FUNGI_PARTNER { return 1 } 158 return 0 159} 160 161// ===== Role bitmask constants ==================================== 162 163const NX_SR_BIT_CANOPY_DOM: nx_int = 1 164const NX_SR_BIT_CANOPY_PIO: nx_int = 2 165const NX_SR_BIT_N_FIXER: nx_int = 4 166const NX_SR_BIT_SHRUB: nx_int = 8 167const NX_SR_BIT_GROUND: nx_int = 16 168const NX_SR_BIT_PERENNIAL: nx_int = 32 169const NX_SR_BIT_GRASS: nx_int = 64 170const NX_SR_BIT_MYCO: nx_int = 128 171const NX_SR_BIT_POLL: nx_int = 256 172const NX_SR_BIT_WILDLIFE: nx_int = 512 173const NX_SR_BIT_BANK: nx_int = 1024 174const NX_SR_BIT_INVASIVE: nx_int = 2048 175 176// ===== nx_sr_role_to_bit ========================================== 177 178func nx_sr_role_to_bit(r: nx_int) -> nx_int { 179 if r == NX_SR_CANOPY_DOMINANT { return NX_SR_BIT_CANOPY_DOM } 180 if r == NX_SR_CANOPY_PIONEER { return NX_SR_BIT_CANOPY_PIO } 181 if r == NX_SR_NITROGEN_FIXER { return NX_SR_BIT_N_FIXER } 182 if r == NX_SR_UNDERSTORY_SHRUB { return NX_SR_BIT_SHRUB } 183 if r == NX_SR_GROUND_COVER { return NX_SR_BIT_GROUND } 184 if r == NX_SR_HERBACEOUS_PERENNIAL { return NX_SR_BIT_PERENNIAL } 185 if r == NX_SR_GRAMINOID { return NX_SR_BIT_GRASS } 186 if r == NX_SR_SOIL_FUNGI_PARTNER { return NX_SR_BIT_MYCO } 187 if r == NX_SR_POLLINATOR_NECTAR { return NX_SR_BIT_POLL } 188 if r == NX_SR_WILDLIFE_FOOD { return NX_SR_BIT_WILDLIFE } 189 if r == NX_SR_RIPARIAN_BANK_STABILIZER { return NX_SR_BIT_BANK } 190 if r == NX_SR_INVASIVE_RISK_FLAG { return NX_SR_BIT_INVASIVE } 191 return 0 192} 193 194// ===== nx_et_canonical_required_roles ============================= 195// 196// Per-transition canonical role-bitmask the substrate considers 197// MINIMUM functional coverage. Caller (operator) checks site's 198// proposed roles against this; gaps trigger MISSING_FUNCTIONAL_ROLE. 199 200func nx_et_canonical_required_roles(t: nx_int) -> nx_int { 201 if t == NX_ET_FOREST_MEADOW { 202 return NX_SR_BIT_CANOPY_DOM | NX_SR_BIT_SHRUB | 203 NX_SR_BIT_PERENNIAL | NX_SR_BIT_POLL 204 } 205 if t == NX_ET_GRASSLAND_SAVANNA { 206 return NX_SR_BIT_GRASS | NX_SR_BIT_PERENNIAL | NX_SR_BIT_POLL 207 } 208 if t == NX_ET_RIPARIAN_UPLAND { 209 return NX_SR_BIT_BANK | NX_SR_BIT_CANOPY_DOM | NX_SR_BIT_SHRUB 210 } 211 if t == NX_ET_DESERT_OASIS { 212 return NX_SR_BIT_GROUND | NX_SR_BIT_PERENNIAL | NX_SR_BIT_MYCO 213 } 214 if t == NX_ET_WETLAND_UPLAND { 215 return NX_SR_BIT_BANK | NX_SR_BIT_SHRUB | NX_SR_BIT_PERENNIAL 216 } 217 if t == NX_ET_ALPINE_TIMBERLINE { 218 return NX_SR_BIT_SHRUB | NX_SR_BIT_PERENNIAL | NX_SR_BIT_GROUND 219 } 220 if t == NX_ET_COASTAL_DUNE { 221 return NX_SR_BIT_GRASS | NX_SR_BIT_GROUND | NX_SR_BIT_SHRUB 222 } 223 if t == NX_ET_FOREST_CLEARCUT { 224 // Restoration: pioneer + N-fixer most important first 5-25 years 225 return NX_SR_BIT_CANOPY_PIO | NX_SR_BIT_N_FIXER | 226 NX_SR_BIT_GROUND | NX_SR_BIT_MYCO 227 } 228 if t == NX_ET_STRIPMINE_RECLAMATION { 229 // Severely degraded -- pioneer + N-fixer + ground required 230 return NX_SR_BIT_CANOPY_PIO | NX_SR_BIT_N_FIXER | 231 NX_SR_BIT_GROUND 232 } 233 if t == NX_ET_URBAN_GREENSPACE { 234 return NX_SR_BIT_CANOPY_DOM | NX_SR_BIT_SHRUB | 235 NX_SR_BIT_POLL | NX_SR_BIT_PERENNIAL 236 } 237 return 0 238} 239 240// ===== nx_et_role_coverage_gap ==================================== 241// 242// Returns the bitmask of REQUIRED roles for the transition that are 243// NOT present in proposed_roles. Zero return = full coverage. 244 245func nx_et_role_coverage_gap(transition: nx_int, 246 proposed_roles: nx_int) -> nx_int { 247 let required: nx_int = nx_et_canonical_required_roles(transition) 248 return required & (~proposed_roles) 249} 250 251// ===== nx_et_classify_design ====================================== 252// 253// Given a transition + proposed-roles bitmask + succession-phases- 254// covered bitmask, emit design verdict. 255// 256// Decision rules (priority order): 257// 1. Invalid inputs -> INVALID 258// 2. INVASIVE flag set in proposed_roles -> INVASIVE_FLAGGED 259// 3. Required roles missing -> MISSING_FUNCTIONAL_ROLE 260// 4. Succession phase 0 (pioneer) missing -> SUCCESSION_GAP 261// 5. All gates pass -> DESIGN_OK 262 263func nx_et_classify_design(transition: nx_int, 264 proposed_roles: nx_int, 265 phases_covered: nx_int) -> nx_int { 266 if nx_et_transition_is_valid(transition) == 0 { return NX_ET_V_INVALID } 267 if proposed_roles < 0 { return NX_ET_V_INVALID } 268 if phases_covered < 0 { return NX_ET_V_INVALID } 269 270 if (proposed_roles & NX_SR_BIT_INVASIVE) != 0 { 271 return NX_ET_V_INVASIVE_FLAGGED 272 } 273 let gap: nx_int = nx_et_role_coverage_gap(transition, proposed_roles) 274 if gap != 0 { return NX_ET_V_MISSING_FUNCTIONAL_ROLE } 275 // Require at least pioneer phase (bit 0) to be covered 276 if (phases_covered & 1) == 0 { return NX_ET_V_SUCCESSION_GAP } 277 return NX_ET_V_DESIGN_OK 278} 279 280// ===== nx_et_v_is_concerning ====================================== 281 282func nx_et_v_is_concerning(v: nx_int) -> nx_int { 283 if v == NX_ET_V_DESIGN_OK { return 0 } 284 if nx_et_v_is_valid(v) == 0 { return 0 } 285 return 1 286}