nx_disturbance.nx source
↩ module page · 264 lines · 10866 B
1// nx_disturbance.nx -- constructive disturbance regime per Regenerative-
2// Stewardship Doctrine.
3//
4// Per META-CARDINAL feedback-regenerative-stewardship-doctrine-captain-moroni:
5// most ecosystems Earth produces REQUIRE disturbance to renew --
6// prairies need fire every 2-5 years; oak savannas every 1-3 years;
7// longleaf pine ground fire every 1-3 years; salt marshes need tidal
8// scouring; Pacific NW old-growth shaped by windfall + Indigenous
9// burning + salmon-marine-nitrogen pulses. Substrate REFUSES both
10// extraction-as-disturbance (clear-cut, drain, monocrop) AND
11// preservation-as-freeze (no-fire, no-grazing, no-coppice).
12//
13// V1 ships sealed enum of disturbance types + per-ecosystem regime
14// frequency + Indigenous-consultation-required predicate. Operator
15// uses to plan stewardship actions; substrate informs, never executes
16// disturbance.
17//
18// Composes:
19// nx_niche -- ecosystem niche gates which regimes apply
20// nx_covenant -- Indigenous fire-stewardship + ancestral-land FPIC
21// nx_phenology -- disturbance timing aligned with seasonal cycle
22// nx_pollinator -- some disturbance regimes preserve pollinator habitat
23//
24// Gap list (V1 honest perf verdict):
25// - safety + regulatory constraints (urban/wildland-interface fire
26// risk, permits) are operator + jurisdiction-supplied; V2 composes
27// with nx_jurisdiction_egress + permitting layer
28// - Indigenous TEK integration requires partnership; V1 flags the
29// requirement, V2 (gated on nx_covenant maturity) handles workflow
30// - regime-frequency targets are research-derived; per-site
31// calibration is multi-year fieldwork
32//
33// genealogy_id: nishi_metacardinal_2026-05-19_regenerative_stewardship
34// lineage_id: substrate_disturbance_v1
35//
36// nx_safety_envelope:
37// intended_use: "Constructive-disturbance regime classification
38// + frequency-per-ecosystem + Indigenous-
39// consultation-required predicate; refuses both
40// extraction and preservation framings"
41// sil_target: SIL2
42// evidence: [enum_sealed, refuses_extraction_AND_preservation,
43// Indigenous_consultation_flagged]
44// verdict: NOT_YET_EVALUATED
45
46import "nx_syscalls.nx"
47import "nx_tier.nx"
48
49// ===== Sealed enum: NxDisturbanceType =============================
50//
51// Constructive disturbance regimes used in restoration / stewardship.
52// V1 covers fire / flood / herbivory / coppicing. V2 extends with
53// region-specific (e.g., Aboriginal fire-stick mosaic) which require
54// FPIC + community partnership.
55
56const NX_DI_FIRE_PRESCRIBED: nx_int = 0 // controlled burn
57const NX_DI_FIRE_INDIGENOUS: nx_int = 1 // TEK-managed fire (FPIC required)
58const NX_DI_FLOOD_PULSE: nx_int = 2 // managed flood release
59const NX_DI_HERBIVORY_ROTATIONAL: nx_int = 3 // Allan Savory-class grazing
60const NX_DI_COPPICE: nx_int = 4 // cut-to-stump then regrow
61const NX_DI_POLLARD: nx_int = 5 // cut top + branches above browse line
62const NX_DI_WINDFALL_NATURAL: nx_int = 6 // accept storm-disturbance
63const NX_DI_SELECTIVE_HARVEST: nx_int = 7 // single-tree selection
64const NX_DI_BEAVER_REINTRO: nx_int = 8 // beaver-driven hydrology
65const NX_DI_NONE_FROZEN: nx_int = 9 // explicit no-disturbance (rare; refused as default)
66const NX_DI_N_TYPES: nx_int = 10
67
68// ===== Sealed enum: NxEcosystemType ===============================
69
70const NX_ECO_TALLGRASS_PRAIRIE: nx_int = 0
71const NX_ECO_OAK_SAVANNA: nx_int = 1
72const NX_ECO_LONGLEAF_PINE: nx_int = 2
73const NX_ECO_PACIFIC_NW_OLDGROWTH: nx_int = 3
74const NX_ECO_SALT_MARSH: nx_int = 4
75const NX_ECO_RIPARIAN_BOTTOMLAND: nx_int = 5
76const NX_ECO_MIXED_HARDWOOD: nx_int = 6
77const NX_ECO_CONIFER_BOREAL: nx_int = 7
78const NX_ECO_DESERT_ARID: nx_int = 8
79const NX_ECO_ABORIGINAL_AUSTRALIAN: nx_int = 9
80const NX_ECO_N_TYPES: nx_int = 10
81
82// ===== Sealed enum: NxDisturbanceVerdict ==========================
83
84const NX_DI_V_REGIME_OK: nx_int = 0
85const NX_DI_V_REQUIRES_FPIC: nx_int = 1 // Indigenous consultation
86const NX_DI_V_REQUIRES_PERMIT: nx_int = 2 // legal/regulatory
87const NX_DI_V_REFUSED_FROZEN: nx_int = 3 // preservation-as-freeze refused
88const NX_DI_V_REFUSED_EXTRACTION: nx_int = 4 // extraction disguised as disturbance
89const NX_DI_V_INCOMPATIBLE: nx_int = 5 // disturbance not appropriate for ecosystem
90const NX_DI_V_INVALID: nx_int = 99
91const NX_DI_V_N_VERDICTS: nx_int = 6
92
93// ===== nx_di_type_is_valid ========================================
94
95func nx_di_type_is_valid(t: nx_int) -> nx_int {
96 if t < 0 { return 0 }
97 if t >= NX_DI_N_TYPES { return 0 }
98 return 1
99}
100
101// ===== nx_eco_type_is_valid =======================================
102
103func nx_eco_type_is_valid(e: nx_int) -> nx_int {
104 if e < 0 { return 0 }
105 if e >= NX_ECO_N_TYPES { return 0 }
106 return 1
107}
108
109// ===== nx_di_v_is_valid ===========================================
110
111func nx_di_v_is_valid(v: nx_int) -> nx_int {
112 if v < 0 { return 0 }
113 if v >= NX_DI_V_N_VERDICTS { return 0 }
114 return 1
115}
116
117// ===== nx_di_requires_fpic ========================================
118//
119// Predicate: returns 1 if this disturbance type requires Indigenous
120// Free Prior and Informed Consent before substrate proceeds.
121
122func nx_di_requires_fpic(t: nx_int) -> nx_int {
123 if t == NX_DI_FIRE_INDIGENOUS { return 1 }
124 return 0
125}
126
127// ===== nx_di_requires_permit ======================================
128//
129// Predicate: returns 1 if this disturbance type typically requires
130// legal/regulatory permit (substrate flags; operator + counsel
131// handle actual permit acquisition).
132
133func nx_di_requires_permit(t: nx_int) -> nx_int {
134 if t == NX_DI_FIRE_PRESCRIBED { return 1 }
135 if t == NX_DI_FIRE_INDIGENOUS { return 1 }
136 if t == NX_DI_FLOOD_PULSE { return 1 }
137 if t == NX_DI_BEAVER_REINTRO { return 1 }
138 if t == NX_DI_SELECTIVE_HARVEST { return 1 }
139 return 0
140}
141
142// ===== nx_di_is_extraction_class ==================================
143//
144// Predicate: returns 1 if this is extraction-disguised-as-disturbance
145// (substrate refuses). V1: NONE_FROZEN is the inverse-refusal; we
146// don't yet enumerate extraction-class disturbances explicitly
147// because they aren't on the legitimate-disturbance enum. V2 may
148// add explicit extraction-class refusal markers.
149
150func nx_di_is_extraction_class(t: nx_int) -> nx_int {
151 return 0
152}
153
154// ===== nx_di_ecosystem_regime_frequency_years =====================
155//
156// Per-ecosystem expected disturbance-frequency target (years).
157// Research-derived; substrate documents the threshold, doesn't
158// claim universal correctness.
159//
160// 0 = invalid pairing; ecosystem doesn't depend on this disturbance.
161
162func nx_di_ecosystem_regime_frequency_years(eco: nx_int, dis: nx_int) -> nx_int {
163 if nx_eco_type_is_valid(eco) == 0 { return 0 }
164 if nx_di_type_is_valid(dis) == 0 { return 0 }
165
166 // TALLGRASS_PRAIRIE: fire every 2-5 years (use midpoint 3)
167 if eco == NX_ECO_TALLGRASS_PRAIRIE {
168 if dis == NX_DI_FIRE_PRESCRIBED { return 3 }
169 if dis == NX_DI_FIRE_INDIGENOUS { return 3 }
170 if dis == NX_DI_HERBIVORY_ROTATIONAL { return 1 }
171 return 0
172 }
173 // OAK_SAVANNA: fire every 1-3 years (midpoint 2)
174 if eco == NX_ECO_OAK_SAVANNA {
175 if dis == NX_DI_FIRE_PRESCRIBED { return 2 }
176 if dis == NX_DI_FIRE_INDIGENOUS { return 2 }
177 return 0
178 }
179 // LONGLEAF_PINE: ground fire 1-3 years (midpoint 2)
180 if eco == NX_ECO_LONGLEAF_PINE {
181 if dis == NX_DI_FIRE_PRESCRIBED { return 2 }
182 return 0
183 }
184 // PACIFIC_NW_OLDGROWTH: mixed-severity 100-300 years (midpoint 200)
185 if eco == NX_ECO_PACIFIC_NW_OLDGROWTH {
186 if dis == NX_DI_WINDFALL_NATURAL { return 50 }
187 if dis == NX_DI_FIRE_INDIGENOUS { return 30 }
188 if dis == NX_DI_BEAVER_REINTRO { return 100 }
189 return 0
190 }
191 // SALT_MARSH: tidal scouring; not in our type set
192 if eco == NX_ECO_SALT_MARSH {
193 if dis == NX_DI_FLOOD_PULSE { return 1 }
194 return 0
195 }
196 // RIPARIAN_BOTTOMLAND: flood pulse
197 if eco == NX_ECO_RIPARIAN_BOTTOMLAND {
198 if dis == NX_DI_FLOOD_PULSE { return 5 }
199 if dis == NX_DI_BEAVER_REINTRO { return 25 }
200 return 0
201 }
202 // MIXED_HARDWOOD: selective harvest + coppice
203 if eco == NX_ECO_MIXED_HARDWOOD {
204 if dis == NX_DI_SELECTIVE_HARVEST { return 15 }
205 if dis == NX_DI_COPPICE { return 7 }
206 if dis == NX_DI_POLLARD { return 10 }
207 return 0
208 }
209 // CONIFER_BOREAL: stand-replacing fire 100-300 years
210 if eco == NX_ECO_CONIFER_BOREAL {
211 if dis == NX_DI_FIRE_PRESCRIBED { return 150 }
212 if dis == NX_DI_WINDFALL_NATURAL { return 100 }
213 return 0
214 }
215 // DESERT_ARID: minimal natural disturbance; herbivory rotational
216 if eco == NX_ECO_DESERT_ARID {
217 if dis == NX_DI_HERBIVORY_ROTATIONAL { return 2 }
218 return 0
219 }
220 // ABORIGINAL_AUSTRALIAN: fire-stick mosaic 1-5 years (midpoint 3)
221 if eco == NX_ECO_ABORIGINAL_AUSTRALIAN {
222 if dis == NX_DI_FIRE_INDIGENOUS { return 3 }
223 return 0
224 }
225 return 0
226}
227
228// ===== nx_di_classify_proposal ====================================
229//
230// Given an operator-proposed (ecosystem, disturbance_type), emit
231// verdict accounting for FPIC + permit requirements + compatibility
232// + the no-disturbance refusal.
233
234func nx_di_classify_proposal(eco: nx_int, dis: nx_int) -> nx_int {
235 if nx_eco_type_is_valid(eco) == 0 { return NX_DI_V_INVALID }
236 if nx_di_type_is_valid(dis) == 0 { return NX_DI_V_INVALID }
237
238 // Refuse explicit "no disturbance" default (preservation-as-freeze pole)
239 if dis == NX_DI_NONE_FROZEN { return NX_DI_V_REFUSED_FROZEN }
240
241 // Extraction-class refusal
242 if nx_di_is_extraction_class(dis) == 1 { return NX_DI_V_REFUSED_EXTRACTION }
243
244 // Compatibility check FIRST: if the ecosystem doesn't depend on this
245 // disturbance, there's no need to ask about permits/FPIC.
246 let freq: nx_int = nx_di_ecosystem_regime_frequency_years(eco, dis)
247 if freq == 0 { return NX_DI_V_INCOMPATIBLE }
248
249 // FPIC priority -- highest gate of remaining
250 if nx_di_requires_fpic(dis) == 1 { return NX_DI_V_REQUIRES_FPIC }
251
252 // Permit priority -- next gate
253 if nx_di_requires_permit(dis) == 1 { return NX_DI_V_REQUIRES_PERMIT }
254
255 return NX_DI_V_REGIME_OK
256}
257
258// ===== nx_di_v_is_concerning ======================================
259
260func nx_di_v_is_concerning(v: nx_int) -> nx_int {
261 if v == NX_DI_V_REGIME_OK { return 0 }
262 if nx_di_v_is_valid(v) == 0 { return 0 }
263 return 1
264}