code wiki / (root) / nx_succession.nx

nx_succession.nx source

↩ module page · 206 lines · 8064 B

1// nx_succession.nx -- ecological succession stage classification for primitives. 2// 3// Biology: ecosystems pass through PIONEER -> MID -> CLIMAX stages. Each 4// stage has different role: pioneers stabilize bare ground (fast-growing, 5// resource-light, short-lived); mid-stage builds soil / canopy (medium 6// lifespan, medium investment); climax is mature, slow-turnover, hosts the 7// most biodiversity. Removing a pioneer from a climax stand causes minor 8// disturbance; removing climax keystones cascades. 9// 10// In Nishi: classify every primitive by succession stage so prune-rebuild 11// decisions know what's safe to recycle vs what's load-bearing. Composes 12// with [[nx_taxonomy]] (orthogonal axis to taxonomic class) and with the 13// drift lifecycle (spore/seed/hypha/fruiting/lichen are PIONEER-class for 14// the most part). 15 16import "nx_syscalls.nx" 17import "nx_tier.nx" 18 19// ===== Sealed enum: NxSuccessionStage ============================= 20 21const NX_SU_STAGE_PIONEER: nx_int = 0 // fast bootstrap, low investment, removable 22const NX_SU_STAGE_EARLY: nx_int = 1 // first build-out, partial replacement-risk 23const NX_SU_STAGE_MID: nx_int = 2 // load-bearing for current generation 24const NX_SU_STAGE_LATE: nx_int = 3 // load-bearing for multiple generations 25const NX_SU_STAGE_CLIMAX: nx_int = 4 // foundational; removal cascades 26const NX_SU_STAGE_RELICT: nx_int = 5 // mature but isolated; legacy-class 27const NX_SU_STAGE_N: nx_int = 6 28 29// ===== Sealed enum: NxSuccessionVerdict =========================== 30 31const NX_SU_V_OK: nx_int = 0 32const NX_SU_V_PROMOTION_OK: nx_int = 1 // primitive ready to advance stage 33const NX_SU_V_PREMATURE: nx_int = 2 // promotion before evidence 34const NX_SU_V_REGRESSION_BLOCKED: nx_int = 3 // never demote climax to pioneer 35const NX_SU_V_INVALID: nx_int = 4 36const NX_SU_V_NULL: nx_int = 5 37const NX_SU_V_N: nx_int = 6 38 39// ===== Struct: NxSuccessionRecord ================================= 40 41struct NxSuccessionRecord { 42 primitive_id: nx_int, 43 stage: nx_int, 44 age_seconds: nx_size, 45 n_dependents: nx_int, // count of other primitives that import this 46 smoke_pass_count: nx_int, // consecutive green builds 47 last_evaluated_us: nx_size, 48} 49 50const NX_SU_R_BYTES: nx_int = 40 51 52struct NxSuccessionRegistry { 53 records: *u8, 54 n_records: nx_int, 55 capacity: nx_int, 56 promotion_min_pass_count: nx_int, // min consecutive green smokes to promote 57 climax_min_dependents: nx_int, // min dependents to count as climax 58} 59 60const NX_SU_BYTES: nx_int = 32 61 62// ===== Validators ================================================= 63 64func nx_su_stage_is_valid(s: nx_int) -> nx_int { 65 if s < 0 { return 0 } 66 if s >= NX_SU_STAGE_N { return 0 } 67 return 1 68} 69 70func nx_su_v_is_valid(v: nx_int) -> nx_int { 71 if v < 0 { return 0 } 72 if v >= NX_SU_V_N { return 0 } 73 return 1 74} 75 76func nx_su_stage_is_removable(s: nx_int) -> nx_int { 77 if s == NX_SU_STAGE_PIONEER { return 1 } 78 if s == NX_SU_STAGE_EARLY { return 1 } 79 return 0 80} 81 82func nx_su_stage_is_load_bearing(s: nx_int) -> nx_int { 83 if s == NX_SU_STAGE_MID { return 1 } 84 if s == NX_SU_STAGE_LATE { return 1 } 85 if s == NX_SU_STAGE_CLIMAX { return 1 } 86 return 0 87} 88 89// ===== Constructor ================================================ 90 91func nx_su_new(capacity: nx_int, 92 promotion_min_pass_count: nx_int, 93 climax_min_dependents: nx_int) -> *NxSuccessionRegistry { 94 if capacity <= 0 { return 0 as *NxSuccessionRegistry } 95 if promotion_min_pass_count <= 0 { return 0 as *NxSuccessionRegistry } 96 if climax_min_dependents <= 0 { return 0 as *NxSuccessionRegistry } 97 let raw: *u8 = sys_mmap(NX_SU_BYTES) 98 let r: *NxSuccessionRegistry = raw as *NxSuccessionRegistry 99 r.records = sys_mmap(capacity * NX_SU_R_BYTES) 100 r.n_records = 0 101 r.capacity = capacity 102 r.promotion_min_pass_count = promotion_min_pass_count 103 r.climax_min_dependents = climax_min_dependents 104 return r 105} 106 107func _su_record_at(reg: *NxSuccessionRegistry, idx: nx_int) -> *NxSuccessionRecord { 108 if idx < 0 { return 0 as *NxSuccessionRecord } 109 if idx >= reg.n_records { return 0 as *NxSuccessionRecord } 110 let off: nx_int = idx * NX_SU_R_BYTES 111 return (reg.records + off) as *NxSuccessionRecord 112} 113 114// ===== Register + lookup ========================================== 115 116func nx_su_register(reg: *NxSuccessionRegistry, 117 primitive_id: nx_int, 118 stage: nx_int, 119 age_seconds: nx_size, 120 n_dependents: nx_int, 121 smoke_pass_count: nx_int, 122 now_us: nx_size) -> nx_int { 123 if (reg as i64) == 0 { return NX_SU_V_NULL } 124 if nx_su_stage_is_valid(stage) == 0 { return NX_SU_V_INVALID } 125 if reg.n_records >= reg.capacity { return NX_SU_V_INVALID } 126 let off: nx_int = reg.n_records * NX_SU_R_BYTES 127 let r: *NxSuccessionRecord = (reg.records + off) as *NxSuccessionRecord 128 r.primitive_id = primitive_id 129 r.stage = stage 130 r.age_seconds = age_seconds 131 r.n_dependents = n_dependents 132 r.smoke_pass_count = smoke_pass_count 133 r.last_evaluated_us = now_us 134 reg.n_records = reg.n_records + 1 135 return NX_SU_V_OK 136} 137 138func nx_su_find(reg: *NxSuccessionRegistry, primitive_id: nx_int) -> *NxSuccessionRecord { 139 if (reg as i64) == 0 { return 0 as *NxSuccessionRecord } 140 var i: nx_int = 0 141 while i < reg.n_records { 142 let r: *NxSuccessionRecord = _su_record_at(reg, i) 143 if r.primitive_id == primitive_id { return r } 144 i = i + 1 145 } 146 return 0 as *NxSuccessionRecord 147} 148 149// ===== Promotion check ============================================ 150 151func nx_su_check_promotion(reg: *NxSuccessionRegistry, 152 primitive_id: nx_int) -> nx_int { 153 if (reg as i64) == 0 { return NX_SU_V_NULL } 154 let r: *NxSuccessionRecord = nx_su_find(reg, primitive_id) 155 if (r as i64) == 0 { return NX_SU_V_INVALID } 156 if r.stage == NX_SU_STAGE_CLIMAX { return NX_SU_V_OK } 157 if r.stage == NX_SU_STAGE_RELICT { return NX_SU_V_OK } 158 if r.smoke_pass_count < reg.promotion_min_pass_count { return NX_SU_V_PREMATURE } 159 // Climax requires dependents threshold 160 if r.stage == NX_SU_STAGE_LATE { 161 if r.n_dependents < reg.climax_min_dependents { return NX_SU_V_PREMATURE } 162 } 163 return NX_SU_V_PROMOTION_OK 164} 165 166// ===== Demotion gate (refuses climax->pioneer regression) ========= 167 168func nx_su_check_demotion(current_stage: nx_int, proposed_stage: nx_int) -> nx_int { 169 if nx_su_stage_is_valid(current_stage) == 0 { return NX_SU_V_INVALID } 170 if nx_su_stage_is_valid(proposed_stage) == 0 { return NX_SU_V_INVALID } 171 if proposed_stage >= current_stage { return NX_SU_V_OK } 172 // Refuse climax / late skip-back to pioneer / early. Use relict instead. 173 if current_stage == NX_SU_STAGE_CLIMAX { 174 if proposed_stage < NX_SU_STAGE_RELICT { return NX_SU_V_REGRESSION_BLOCKED } 175 } 176 if current_stage == NX_SU_STAGE_LATE { 177 if proposed_stage < NX_SU_STAGE_MID { return NX_SU_V_REGRESSION_BLOCKED } 178 } 179 return NX_SU_V_OK 180} 181 182// ===== Aggregations =============================================== 183 184func nx_su_count_by_stage(reg: *NxSuccessionRegistry, stage: nx_int) -> nx_int { 185 if (reg as i64) == 0 { return 0 } 186 var count: nx_int = 0 187 var i: nx_int = 0 188 while i < reg.n_records { 189 let r: *NxSuccessionRecord = _su_record_at(reg, i) 190 if r.stage == stage { count = count + 1 } 191 i = i + 1 192 } 193 return count 194} 195 196func nx_su_total_dependents(reg: *NxSuccessionRegistry) -> nx_int { 197 if (reg as i64) == 0 { return 0 } 198 var sum: nx_int = 0 199 var i: nx_int = 0 200 while i < reg.n_records { 201 let r: *NxSuccessionRecord = _su_record_at(reg, i) 202 sum = sum + r.n_dependents 203 i = i + 1 204 } 205 return sum 206}