nx_organism.nx source
↩ module page · 344 lines · 12699 B
1// nx_organism.nx -- ecosystem-wide pathway + symbiote container.
2//
3// Biological analogue: an organism is the multi-pathway entity that
4// coordinates many pathways across many tissues with shared homeostasis.
5// In Nishi terms: an organism holds N nx_pathways (Nishi-native cells)
6// AND N nx_symbiotes (foreign processes integrated into the ecosystem
7// like Steam-hosted NMS, Chrome, OBS) and arbitrates resources across
8// the WHOLE union.
9//
10// THIS IS THE ECOSYSTEM-WIDE OPTIMIZATION SUBSTRATE. Per user 2026-05-
11// 19: "i want it work across the whole nishi ecosystem and then across
12// the whole nishi ecosystem + (nishi native and non native things that
13// are integrated)." Single host machine running Nishi cells + Steam +
14// NMS + dev tools simultaneously: organism is the layer that decides
15// which gets displaced when the host's VRAM crosses 90%.
16//
17// Composes:
18// nx_pathway -- each contributes its own cells + budgets
19// nx_symbiote -- foreign-process virtual cells with observed
20// (not promised) resource consumption
21// nx_budget -- organism has its OWN host-aggregate budget
22// (the physical hardware ceiling)
23// nx_evict_journal -- organism-level events log here
24// nx_attention_class -- per-cell + per-symbiote class drives priority
25// nx_treaty -- bilateral agreements between organism members
26//
27// V1 ships a flat container with built-in arbitration. The hypothalamus
28// (master regulator) function is folded in as nx_organism_pick_dis-
29// placement; if it grows, a separate nx_hypothalamus primitive is
30// extracted.
31//
32// Gap list (V1 honest perf verdict):
33// - no actual host-resource probe (host_budget supplied by caller)
34// - no peer-mesh federation (one organism per host)
35// - flat membership (no nested organism-of-organisms)
36// - no fairness scheduling within same attention class
37//
38// genealogy_id: nishi_cardinal_2026-05-19_ecosystem_wide + biology_multi_pathway_organism
39// lineage_id: substrate_organism_v1
40//
41// nx_safety_envelope:
42// intended_use: "Ecosystem-wide arbitration across Nishi
43// pathways and integrated foreign processes"
44// sil_target: SIL2
45// asil_target: QM
46// evidence: [bounded_capacity, deterministic_pick,
47// host_budget_honored_above_pathway_budgets]
48// verdict: NOT_YET_EVALUATED
49
50import "nx_syscalls.nx"
51import "nx_tier.nx"
52import "nx_budget.nx"
53import "nx_attention_class.nx"
54import "nx_evict_journal.nx"
55import "nx_pathway.nx"
56import "nx_symbiote.nx"
57const NX_MAGIC_1024: i64 = 1024
58
59// ===== Sealed enum: NxOrganismVerdict =============================
60
61const NX_ORG_OK: nx_int = 0
62const NX_ORG_ERR_FULL: nx_int = 1
63const NX_ORG_ERR_NOT_FOUND: nx_int = 2
64const NX_ORG_ERR_BAD_MEMBER: nx_int = 3
65
66// ===== Sealed enum: NxDisplacementVerdict =========================
67//
68// Outcome from nx_organism_pick_displacement. Picked member's cell_id
69// is written into displaced_cell_id pointer; member kind tells caller
70// whether to call nx_yield_request (native) or nx_symbiote_throttle
71// (foreign) for the actual enforcement.
72
73const NX_DISP_NONE: nx_int = 0 // no displacement needed
74const NX_DISP_NATIVE_CELL: nx_int = 1
75const NX_DISP_SYMBIOTE: nx_int = 2
76
77// ===== Struct: NxOrganism =========================================
78//
79// host_budget is the physical hardware ceiling (e.g., total host RAM,
80// total VRAM). aggregate budgets across pathways + symbiotes must not
81// exceed this; if they do, organism fires displacement.
82//
83// pathways and symbiotes are arrays of pointers, not value arrays --
84// the lifetimes of pathway/symbiote structs live with their owners.
85
86struct NxOrganism {
87 host_budget: *NxBudget,
88 pathways: **NxPathway,
89 pathway_capacity: nx_size,
90 n_pathways: nx_size,
91 symbiotes: **NxSymbiote,
92 symbiote_capacity: nx_size,
93 n_symbiotes: nx_size,
94 journal: *NxEvictJournal,
95}
96
97// ===== Constructor ===============================================
98
99func nx_organism_new(host_budget: *NxBudget,
100 pathway_capacity: nx_size,
101 symbiote_capacity: nx_size,
102 journal: *NxEvictJournal) -> *NxOrganism {
103 let o: *NxOrganism = (sys_mmap(72)) as *NxOrganism
104 o.host_budget = host_budget
105 let pw_bytes: nx_size = pathway_capacity * 8
106 let sb_bytes: nx_size = symbiote_capacity * 8
107 o.pathways = (sys_mmap(pw_bytes)) as **NxPathway
108 o.pathway_capacity = pathway_capacity
109 o.n_pathways = 0
110 o.symbiotes = (sys_mmap(sb_bytes)) as **NxSymbiote
111 o.symbiote_capacity = symbiote_capacity
112 o.n_symbiotes = 0
113 o.journal = journal
114 return o
115}
116
117// ===== _organism_pathway_at / _organism_symbiote_at ==============
118
119func _organism_pathway_at(o: *NxOrganism, idx: nx_size) -> *NxPathway {
120 let slot: *i64 = (o.pathways as i64 + (idx as i64) * 8) as *i64
121 return slot[0] as *NxPathway
122}
123
124func _organism_symbiote_at(o: *NxOrganism, idx: nx_size) -> *NxSymbiote {
125 let slot: *i64 = (o.symbiotes as i64 + (idx as i64) * 8) as *i64
126 return slot[0] as *NxSymbiote
127}
128
129func _organism_pathway_set(o: *NxOrganism, idx: nx_size, p: *NxPathway) -> nx_int {
130 let slot: *i64 = (o.pathways as i64 + (idx as i64) * 8) as *i64
131 slot[0] = p as i64
132 return 0
133}
134
135func _organism_symbiote_set(o: *NxOrganism, idx: nx_size, s: *NxSymbiote) -> nx_int {
136 let slot: *i64 = (o.symbiotes as i64 + (idx as i64) * 8) as *i64
137 slot[0] = s as i64
138 return 0
139}
140
141// ===== nx_organism_add_pathway ===================================
142
143func nx_organism_add_pathway(o: *NxOrganism, p: *NxPathway) -> nx_int {
144 if (p as i64) == 0 { return NX_ORG_ERR_BAD_MEMBER }
145 if o.n_pathways >= o.pathway_capacity { return NX_ORG_ERR_FULL }
146 _organism_pathway_set(o, o.n_pathways, p)
147 o.n_pathways = o.n_pathways + 1
148 return NX_ORG_OK
149}
150
151// ===== nx_organism_add_symbiote ==================================
152
153func nx_organism_add_symbiote(o: *NxOrganism, s: *NxSymbiote) -> nx_int {
154 if (s as i64) == 0 { return NX_ORG_ERR_BAD_MEMBER }
155 if o.n_symbiotes >= o.symbiote_capacity { return NX_ORG_ERR_FULL }
156 _organism_symbiote_set(o, o.n_symbiotes, s)
157 o.n_symbiotes = o.n_symbiotes + 1
158 return NX_ORG_OK
159}
160
161// ===== nx_organism_total_ram_max =================================
162//
163// Sum of declared RAM ceilings across all pathways + symbiotes. The
164// caller compares this against host_budget.ram_max to know whether
165// the ecosystem is over-committing the physical machine.
166
167func nx_organism_total_ram_max(o: *NxOrganism) -> nx_size {
168 var total: nx_size = 0
169 var i: nx_size = 0
170 while i < o.n_pathways {
171 total = total + nx_pathway_aggregate_ram_max(_organism_pathway_at(o, i))
172 i = i + 1
173 }
174 var j: nx_size = 0
175 while j < o.n_symbiotes {
176 let s: *NxSymbiote = _organism_symbiote_at(o, j)
177 if (s.virtual_budget as i64) != 0 {
178 total = total + s.virtual_budget.ram_max
179 }
180 j = j + 1
181 }
182 return total
183}
184
185// ===== nx_organism_total_vram_max ================================
186
187func nx_organism_total_vram_max(o: *NxOrganism) -> nx_size {
188 var total: nx_size = 0
189 var i: nx_size = 0
190 while i < o.n_pathways {
191 total = total + nx_pathway_aggregate_vram_max(_organism_pathway_at(o, i))
192 i = i + 1
193 }
194 var j: nx_size = 0
195 while j < o.n_symbiotes {
196 let s: *NxSymbiote = _organism_symbiote_at(o, j)
197 if (s.virtual_budget as i64) != 0 {
198 total = total + s.virtual_budget.vram_max
199 }
200 j = j + 1
201 }
202 return total
203}
204
205// ===== nx_organism_total_observed_ram ============================
206//
207// Same shape as _max but uses ACTUAL observed consumption from
208// symbiotes (since we don't trust their declared maxes -- foreign
209// processes may overshoot). For native pathways, used == ram_used
210// from each cell's budget (an aggregate would need walking each
211// cell; V1 uses ram_max as conservative upper bound for natives).
212
213func nx_organism_total_observed_ram(o: *NxOrganism) -> nx_size {
214 var total: nx_size = 0
215 var i: nx_size = 0
216 while i < o.n_pathways {
217 total = total + nx_pathway_aggregate_ram_max(_organism_pathway_at(o, i))
218 i = i + 1
219 }
220 var j: nx_size = 0
221 while j < o.n_symbiotes {
222 let s: *NxSymbiote = _organism_symbiote_at(o, j)
223 total = total + s.observed_ram_bytes
224 j = j + 1
225 }
226 return total
227}
228
229// ===== nx_organism_host_pressure_q10 =============================
230//
231// Q10 ratio of (total observed consumption) / (host budget ceiling)
232// for the requested resource kind. >= 921 (90%) is migration trigger.
233
234func nx_organism_host_pressure_q10(o: *NxOrganism, kind: nx_int) -> nx_int {
235 if (o.host_budget as i64) == 0 { return 0 }
236 var max: nx_size = 0
237 var used: nx_size = 0
238 if kind == NX_RES_RAM {
239 max = o.host_budget.ram_max
240 used = nx_organism_total_observed_ram(o)
241 }
242 if kind == NX_RES_VRAM {
243 max = o.host_budget.vram_max
244 var i: nx_size = 0
245 while i < o.n_pathways {
246 used = used + nx_pathway_aggregate_vram_max(_organism_pathway_at(o, i))
247 i = i + 1
248 }
249 var j: nx_size = 0
250 while j < o.n_symbiotes {
251 let s: *NxSymbiote = _organism_symbiote_at(o, j)
252 used = used + s.observed_vram_bytes
253 j = j + 1
254 }
255 }
256 if max <= 0 { return 0 }
257 return ((used as i64) * NX_MAGIC_1024) / (max as i64)
258}
259
260// ===== nx_organism_pick_displacement =============================
261//
262// The arbitration decision. Walks all members; picks the LOWEST-
263// priority member (highest numeric attention_class value) as the
264// displacement target. On tie, foreign symbiotes go before native
265// cells (symbiotes are observed-only; cells get the benefit of
266// cooperative yield first).
267//
268// Returns NX_DISP_NONE if no member needs displacing (host pressure
269// is below threshold). Otherwise writes the picked member's cell_id
270// (or symbiote pid) into out_id and returns NX_DISP_NATIVE_CELL or
271// NX_DISP_SYMBIOTE.
272
273func nx_organism_pick_displacement(o: *NxOrganism,
274 kind: nx_int,
275 out_id: *i64) -> nx_int {
276 let pressure: nx_int = nx_organism_host_pressure_q10(o, kind)
277 if pressure < 921 { return NX_DISP_NONE }
278
279 var worst_priority: nx_int = -1
280 var winner_id: nx_int = 0
281 var winner_kind: nx_int = NX_DISP_NONE
282
283 // Walk pathways' cells -- pick the highest-numeric attention_class
284 // (== lowest priority) cell as the candidate for native displace-
285 // ment. Tie -> first encountered.
286 var i: nx_size = 0
287 while i < o.n_pathways {
288 let p: *NxPathway = _organism_pathway_at(o, i)
289 var ci: nx_size = 0
290 while ci < p.n_cells {
291 let c: *NxCellSpec = (p.cells as i64 + (ci as i64) * 64) as *NxCellSpec
292 let prio: nx_int = nx_ac_priority(c.attention_class)
293 if prio > worst_priority {
294 worst_priority = prio
295 winner_id = c.cell_id
296 winner_kind = NX_DISP_NATIVE_CELL
297 }
298 ci = ci + 1
299 }
300 i = i + 1
301 }
302
303 // Walk symbiotes -- compare same priority axis. Foreign tie-break
304 // goes to symbiote (foreign processes lack the cooperative yield
305 // contract; preferable to displace observed-only first).
306 var j: nx_size = 0
307 while j < o.n_symbiotes {
308 let s: *NxSymbiote = _organism_symbiote_at(o, j)
309 let prio_s: nx_int = nx_ac_priority(s.attention_class)
310 if prio_s >= worst_priority {
311 worst_priority = prio_s
312 winner_id = s.pid
313 winner_kind = NX_DISP_SYMBIOTE
314 }
315 j = j + 1
316 }
317
318 out_id[0] = winner_id as i64
319 return winner_kind
320}
321
322// ===== nx_organism_count_members =================================
323
324func nx_organism_count_members(o: *NxOrganism) -> nx_size {
325 return o.n_pathways + o.n_symbiotes
326}
327
328// ===== nx_organism_total_observed_vram ===========================
329
330func nx_organism_total_observed_vram(o: *NxOrganism) -> nx_size {
331 var total: nx_size = 0
332 var i: nx_size = 0
333 while i < o.n_pathways {
334 total = total + nx_pathway_aggregate_vram_max(_organism_pathway_at(o, i))
335 i = i + 1
336 }
337 var j: nx_size = 0
338 while j < o.n_symbiotes {
339 let s: *NxSymbiote = _organism_symbiote_at(o, j)
340 total = total + s.observed_vram_bytes
341 j = j + 1
342 }
343 return total
344}