nx_compost.nx source
↩ module page · 238 lines · 8752 B
1// nx_compost.nx -- graceful retirement + nutrient harvest from retired primitives.
2//
3// Biology: when an organism dies, its constituent atoms are decomposed by
4// fungi+bacteria and returned to the soil pool, where they're available
5// for re-uptake by living plants. Forests recycle ~90% of their nutrients
6// through this loop. Without compost, ecosystems collapse from depletion.
7//
8// In Nishi: extends [[nx_prune]] (which only REMOVES dead/orphan code) by
9// adding nutrient-harvest -- when a primitive retires, identify its
10// reusable parts (constants, types, helper functions, schemas) and route
11// them back to the substrate pool for adoption by living primitives. This
12// is the difference between "delete file" (current prune) and "compost"
13// (extract value before disposing).
14//
15// Composes [[feedback-forest-meta-vision-drift-lifecycle]] +
16// [[feedback-thymus-sovereignty-audit-soma-germline]] (composted nutrients
17// retain soma/germline class) + [[feedback-regenerative-stewardship-
18// doctrine-captain-moroni]] (recycling is regeneration not extraction) +
19// Cardinal 13 (history is sacred -- compost record is permanent additive
20// log, not destructive delete).
21
22import "nx_syscalls.nx"
23import "nx_tier.nx"
24
25// ===== Sealed enum: NxNutrientKind ================================
26//
27// What kinds of value can be harvested from a retiring primitive.
28
29const NX_CP_NUT_CONST_DEFINITION: nx_int = 0 // sealed enum / const block
30const NX_CP_NUT_TYPE_DEFINITION: nx_int = 1 // struct / type alias
31const NX_CP_NUT_HELPER_FUNCTION: nx_int = 2 // pure utility function
32const NX_CP_NUT_SCHEMA: nx_int = 3 // serialization layout
33const NX_CP_NUT_TEST_SCAFFOLD: nx_int = 4 // assertion patterns / fixtures
34const NX_CP_NUT_DOCUMENTATION: nx_int = 5 // header comment / spec
35const NX_CP_NUT_BENCHMARK: nx_int = 6 // perf harness
36const NX_CP_NUT_N: nx_int = 7
37
38// ===== Sealed enum: NxCompostStage ================================
39
40const NX_CP_STAGE_FRESH: nx_int = 0 // just retired
41const NX_CP_STAGE_DECOMPOSING: nx_int = 1 // nutrients being extracted
42const NX_CP_STAGE_HARVESTED: nx_int = 2 // nutrients reabsorbed
43const NX_CP_STAGE_REFUSED: nx_int = 3 // unsafe to recycle (soma)
44const NX_CP_STAGE_N: nx_int = 4
45
46// ===== Sealed enum: NxCompostVerdict ==============================
47
48const NX_CP_V_OK: nx_int = 0
49const NX_CP_V_REFUSED_GERMLINE: nx_int = 1 // germline never composts
50const NX_CP_V_REFUSED_ACTIVE: nx_int = 2 // not yet retired
51const NX_CP_V_REFUSED_CLIMAX: nx_int = 3 // climax-stage never composts
52const NX_CP_V_INVALID: nx_int = 4
53const NX_CP_V_NULL: nx_int = 5
54const NX_CP_V_N: nx_int = 6
55
56// ===== Struct: NxNutrient =========================================
57
58struct NxNutrient {
59 kind: nx_int,
60 source_primitive_id: nx_int,
61 content_hash: nx_size,
62 extracted_at_us: nx_size,
63 reused_by: nx_int, // 0 if unclaimed, else primitive_id
64}
65
66const NX_CP_N_BYTES: nx_int = 40
67
68struct NxCompostPile {
69 primitive_id: nx_int, // the retiring primitive
70 stage: nx_int,
71 nutrients: *u8,
72 n_nutrients: nx_int,
73 capacity: nx_int,
74 is_germline: nx_int, // refused if 1
75 is_climax: nx_int, // refused if 1
76 retired_at_us: nx_size,
77}
78
79const NX_CP_BYTES: nx_int = 56
80
81// ===== Validators =================================================
82
83func nx_cp_nut_is_valid(k: nx_int) -> nx_int {
84 if k < 0 { return 0 }
85 if k >= NX_CP_NUT_N { return 0 }
86 return 1
87}
88
89func nx_cp_stage_is_valid(s: nx_int) -> nx_int {
90 if s < 0 { return 0 }
91 if s >= NX_CP_STAGE_N { return 0 }
92 return 1
93}
94
95func nx_cp_v_is_valid(v: nx_int) -> nx_int {
96 if v < 0 { return 0 }
97 if v >= NX_CP_V_N { return 0 }
98 return 1
99}
100
101// ===== Construction (begins compost cycle) ========================
102
103func nx_cp_new(primitive_id: nx_int,
104 capacity: nx_int,
105 is_germline: nx_int,
106 is_climax: nx_int,
107 now_us: nx_size) -> *NxCompostPile {
108 if capacity <= 0 { return 0 as *NxCompostPile }
109 if primitive_id == 0 { return 0 as *NxCompostPile }
110 let raw: *u8 = sys_mmap(NX_CP_BYTES)
111 let p: *NxCompostPile = raw as *NxCompostPile
112 p.primitive_id = primitive_id
113 p.nutrients = sys_mmap(capacity * NX_CP_N_BYTES)
114 p.n_nutrients = 0
115 p.capacity = capacity
116 p.is_germline = is_germline
117 p.is_climax = is_climax
118 p.retired_at_us = now_us
119 // If germline or climax, refuse to compost (stage REFUSED)
120 if is_germline == 1 { p.stage = NX_CP_STAGE_REFUSED }
121 if p.stage != NX_CP_STAGE_REFUSED {
122 if is_climax == 1 { p.stage = NX_CP_STAGE_REFUSED }
123 }
124 if p.stage != NX_CP_STAGE_REFUSED { p.stage = NX_CP_STAGE_FRESH }
125 return p
126}
127
128func _cp_nutrient_at(p: *NxCompostPile, idx: nx_int) -> *NxNutrient {
129 if idx < 0 { return 0 as *NxNutrient }
130 if idx >= p.n_nutrients { return 0 as *NxNutrient }
131 let off: nx_int = idx * NX_CP_N_BYTES
132 return (p.nutrients + off) as *NxNutrient
133}
134
135// ===== Begin decomposition ========================================
136
137func nx_cp_begin_decompose(p: *NxCompostPile) -> nx_int {
138 if (p as i64) == 0 { return NX_CP_V_NULL }
139 if p.is_germline == 1 { return NX_CP_V_REFUSED_GERMLINE }
140 if p.is_climax == 1 { return NX_CP_V_REFUSED_CLIMAX }
141 if p.stage != NX_CP_STAGE_FRESH { return NX_CP_V_INVALID }
142 p.stage = NX_CP_STAGE_DECOMPOSING
143 return NX_CP_V_OK
144}
145
146// ===== Extract nutrient ===========================================
147
148func nx_cp_extract_nutrient(p: *NxCompostPile,
149 kind: nx_int,
150 content_hash: nx_size,
151 now_us: nx_size) -> nx_int {
152 if (p as i64) == 0 { return NX_CP_V_NULL }
153 if nx_cp_nut_is_valid(kind) == 0 { return NX_CP_V_INVALID }
154 if p.is_germline == 1 { return NX_CP_V_REFUSED_GERMLINE }
155 if p.is_climax == 1 { return NX_CP_V_REFUSED_CLIMAX }
156 if p.stage != NX_CP_STAGE_DECOMPOSING { return NX_CP_V_INVALID }
157 if p.n_nutrients >= p.capacity { return NX_CP_V_INVALID }
158 let off: nx_int = p.n_nutrients * NX_CP_N_BYTES
159 let n: *NxNutrient = (p.nutrients + off) as *NxNutrient
160 n.kind = kind
161 n.source_primitive_id = p.primitive_id
162 n.content_hash = content_hash
163 n.extracted_at_us = now_us
164 n.reused_by = 0
165 p.n_nutrients = p.n_nutrients + 1
166 return NX_CP_V_OK
167}
168
169// ===== Reabsorb (mark nutrient claimed by living primitive) =======
170
171func nx_cp_reabsorb(p: *NxCompostPile,
172 content_hash: nx_size,
173 reusing_primitive_id: nx_int) -> nx_int {
174 if (p as i64) == 0 { return NX_CP_V_NULL }
175 if reusing_primitive_id == 0 { return NX_CP_V_INVALID }
176 var i: nx_int = 0
177 while i < p.n_nutrients {
178 let n: *NxNutrient = _cp_nutrient_at(p, i)
179 if n.content_hash == content_hash {
180 n.reused_by = reusing_primitive_id
181 return NX_CP_V_OK
182 }
183 i = i + 1
184 }
185 return NX_CP_V_INVALID
186}
187
188// ===== Mark harvested =============================================
189
190func nx_cp_mark_harvested(p: *NxCompostPile) -> nx_int {
191 if (p as i64) == 0 { return NX_CP_V_NULL }
192 if p.stage != NX_CP_STAGE_DECOMPOSING { return NX_CP_V_INVALID }
193 p.stage = NX_CP_STAGE_HARVESTED
194 return NX_CP_V_OK
195}
196
197// ===== Aggregations ===============================================
198
199func nx_cp_count_by_kind(p: *NxCompostPile, kind: nx_int) -> nx_int {
200 if (p as i64) == 0 { return 0 }
201 var count: nx_int = 0
202 var i: nx_int = 0
203 while i < p.n_nutrients {
204 let n: *NxNutrient = _cp_nutrient_at(p, i)
205 if n.kind == kind { count = count + 1 }
206 i = i + 1
207 }
208 return count
209}
210
211func nx_cp_reused_count(p: *NxCompostPile) -> nx_int {
212 if (p as i64) == 0 { return 0 }
213 var count: nx_int = 0
214 var i: nx_int = 0
215 while i < p.n_nutrients {
216 let n: *NxNutrient = _cp_nutrient_at(p, i)
217 if n.reused_by != 0 { count = count + 1 }
218 i = i + 1
219 }
220 return count
221}
222
223func nx_cp_unclaimed_count(p: *NxCompostPile) -> nx_int {
224 if (p as i64) == 0 { return 0 }
225 var count: nx_int = 0
226 var i: nx_int = 0
227 while i < p.n_nutrients {
228 let n: *NxNutrient = _cp_nutrient_at(p, i)
229 if n.reused_by == 0 { count = count + 1 }
230 i = i + 1
231 }
232 return count
233}
234
235func nx_cp_stage(p: *NxCompostPile) -> nx_int {
236 if (p as i64) == 0 { return NX_CP_V_NULL }
237 return p.stage
238}