nx_immune.nx source
↩ module page · 288 lines · 10944 B
1// nx_immune.nx -- Tier-2 colony-level adaptive immune coordinator.
2//
3// Per [[feedback-unified-immune-architecture-three-tier]] Tier 2:
4// "ADAPTIVE / MULTICELLULAR -- specialized cells + learning + memory;
5// existing nx_thymus (substrate audit) + nx_immune (runtime defense)."
6// nx_antibody is the per-cell defense-generation primitive (Tier 1+);
7// nx_immune is the COLONY-LEVEL orchestrator that:
8//
9// 1. Tracks which cells in the host are currently HEALTHY/ALERTED/
10// RESPONDING/COMPROMISED
11// 2. Propagates antibody discoveries (clonal-expansion analog):
12// when one cell's antibody matures to MEMORY state, immune
13// distributes a copy to every other cell so the same threat
14// is detected colony-wide on first encounter
15// 3. Coordinates lysis-response: when any cell calls for lysis on
16// a foreign entity touching multiple cells, immune issues a
17// colony-wide enforcement (vs each cell deciding alone)
18// 4. Surfaces a COLONY STATUS to the operator (HEALTHY when all
19// cells healthy; ALERTED when any cell sees a hit; RESPONDING
20// when active lysis ongoing; COMPROMISED when any cell entered
21// the abortive-terminal state)
22//
23// Per [[feedback-captain-moroni-doctrine]]: defensive-only. Colony
24// response is to PROTECT remaining cells, never to attack.
25//
26// Composes:
27// nx_antibody -- per-cell antibodies clone-expand via immune
28// nx_lysis -- colony-wide enforcement decision
29// nx_xenocell -- intrusions observed across cells aggregate here
30// nx_abortive -- cell-state-machine; immune watches transitions
31// nx_evict_journal -- colony events logged
32// nx_pollinate (queued) -- cross-host community distribution
33//
34// V1 ships:
35// - struct NxImmune holding cell registry + antibody clone-store
36// - cell-state tracking
37// - antibody clonal-expansion broadcast
38// - colony status aggregation
39//
40// Gap list (V1 honest perf verdict):
41// - per-cell antibody arrays are caller-allocated; immune holds
42// pointers, doesn't deep-clone (V2 deep-clones when crossing
43// cell isolation boundary)
44// - no automatic alert-decay (caller drives status refresh)
45// - no clonal-suppression of false positives (V2 demotes antibodies
46// that fire on legitimate traffic frequently)
47// - federation across hosts is nx_pollinate's job, not immune
48//
49// genealogy_id: cardinal_2026-05-19_unified_immune_architecture_tier_2 +
50// biology_multicellular_adaptive_immunity
51// lineage_id: substrate_immune_v1
52//
53// nx_safety_envelope:
54// intended_use: "Colony-level coordination of per-cell adaptive
55// immune primitives; defensive only"
56// sil_target: SIL3
57// evidence: [defensive_only, observation_not_retaliation,
58// captain_moroni_aligned]
59// verdict: NOT_YET_EVALUATED
60
61import "nx_syscalls.nx"
62import "nx_tier.nx"
63import "nx_evict_journal.nx"
64import "nx_antibody.nx"
65import "nx_lysis.nx"
66
67// ===== Sealed enum: NxColonyStatus ================================
68
69const NX_COL_HEALTHY: nx_int = 0
70const NX_COL_ALERTED: nx_int = 1 // at least one cell saw a hit
71const NX_COL_RESPONDING: nx_int = 2 // active lysis ongoing
72const NX_COL_COMPROMISED: nx_int = 3 // at least one cell terminal
73const NX_COL_N_STATUSES: nx_int = 4
74
75// ===== Sealed enum: NxImmuneVerdict ===============================
76
77const NX_IM_OK: nx_int = 0
78const NX_IM_ERR_FULL: nx_int = 1
79const NX_IM_ERR_BAD_CELL: nx_int = 2
80const NX_IM_ERR_BAD_STATUS: nx_int = 3
81
82// ===== Struct: NxImmuneCellRow ====================================
83//
84// One row per cell registered with the immune system. cell_id is
85// stable. status is the cell's current health classification.
86// antibody_arr is a pointer to the cell's own nx_antibody_array
87// (immune doesn't own them; cells do).
88
89struct NxImmuneCellRow {
90 cell_id: nx_int,
91 status: nx_int,
92 antibody_arr: *NxAntibodyArray,
93 last_alert_us: nx_size,
94 alert_count: nx_int,
95}
96
97// ===== Struct: NxImmune ===========================================
98//
99// The colony coordinator. cells is an array of cell rows; capacity
100// fixed at construction. global_status is the aggregate status the
101// operator sees. journal is the host-level eviction/forensic log.
102
103struct NxImmune {
104 cells: *NxImmuneCellRow,
105 cell_capacity: nx_size,
106 n_cells: nx_size,
107 global_status: nx_int,
108 journal: *NxEvictJournal,
109}
110
111const NX_IM_CELL_BYTES: nx_size = 40
112
113// ===== Validators ================================================
114
115func nx_col_status_is_valid(s: nx_int) -> nx_int {
116 if s < 0 { return 0 }
117 if s >= NX_COL_N_STATUSES { return 0 }
118 return 1
119}
120
121// ===== nx_immune_new =============================================
122
123func nx_immune_new(cell_capacity: nx_size, journal: *NxEvictJournal) -> *NxImmune {
124 let i: *NxImmune = (sys_mmap(40)) as *NxImmune
125 let bytes: nx_size = cell_capacity * NX_IM_CELL_BYTES
126 i.cells = (sys_mmap(bytes)) as *NxImmuneCellRow
127 i.cell_capacity = cell_capacity
128 i.n_cells = 0
129 i.global_status = NX_COL_HEALTHY
130 i.journal = journal
131 return i
132}
133
134// ===== _immune_at ================================================
135
136func _immune_at(i: *NxImmune, idx: nx_size) -> *NxImmuneCellRow {
137 return (i.cells as i64 + (idx as i64) * NX_IM_CELL_BYTES) as *NxImmuneCellRow
138}
139
140// ===== _immune_find_cell =========================================
141
142func _immune_find_cell(i: *NxImmune, cell_id: nx_int) -> nx_int {
143 var k: nx_size = 0
144 while k < i.n_cells {
145 let r: *NxImmuneCellRow = _immune_at(i, k)
146 if r.cell_id == cell_id { return k as i64 }
147 k = k + 1
148 }
149 return -1
150}
151
152// ===== nx_immune_register_cell ===================================
153//
154// Register a cell + its antibody array with the immune system. The
155// cell starts HEALTHY. Returns the registration index, or -1 if
156// full / duplicate.
157
158func nx_immune_register_cell(i: *NxImmune,
159 cell_id: nx_int,
160 antibody_arr: *NxAntibodyArray) -> nx_int {
161 if i.n_cells >= i.cell_capacity { return -1 }
162 if _immune_find_cell(i, cell_id) >= 0 { return -1 }
163 let r: *NxImmuneCellRow = _immune_at(i, i.n_cells)
164 r.cell_id = cell_id
165 r.status = NX_COL_HEALTHY
166 r.antibody_arr = antibody_arr
167 r.last_alert_us = 0
168 r.alert_count = 0
169 i.n_cells = i.n_cells + 1
170 return (i.n_cells - 1) as i64
171}
172
173// ===== nx_immune_set_cell_status =================================
174
175func nx_immune_set_cell_status(i: *NxImmune,
176 cell_id: nx_int,
177 status: nx_int,
178 now_us: nx_size) -> nx_int {
179 if nx_col_status_is_valid(status) == 0 { return NX_IM_ERR_BAD_STATUS }
180 let idx: nx_int = _immune_find_cell(i, cell_id)
181 if idx < 0 { return NX_IM_ERR_BAD_CELL }
182 let r: *NxImmuneCellRow = _immune_at(i, idx as nx_size)
183 r.status = status
184 if status > NX_COL_HEALTHY {
185 r.last_alert_us = now_us
186 r.alert_count = r.alert_count + 1
187 }
188 return NX_IM_OK
189}
190
191// ===== nx_immune_global_status ===================================
192//
193// Recompute global status as max(per-cell statuses). Caller invokes
194// after any cell-status change; returns the new global status.
195
196func nx_immune_global_status(i: *NxImmune) -> nx_int {
197 var worst: nx_int = NX_COL_HEALTHY
198 var k: nx_size = 0
199 while k < i.n_cells {
200 let r: *NxImmuneCellRow = _immune_at(i, k)
201 if r.status > worst { worst = r.status }
202 k = k + 1
203 }
204 i.global_status = worst
205 return worst
206}
207
208// ===== nx_immune_clonal_expand ===================================
209//
210// THE clonal-expansion operation. When one cell's antibody matures
211// to MEMORY state, broadcast the signature to all OTHER cells'
212// antibody arrays so they catch the same threat on first encounter.
213// Returns the number of cells that received the clone.
214//
215// Source cell is identified by cell_id; antibody is identified by
216// its array index. Caller has the matured antibody in source's
217// array; immune walks every other cell and calls nx_antibody_generate
218// on each with the same (kind, signature_hash, affinity) parameters.
219
220func nx_immune_clonal_expand(i: *NxImmune,
221 source_cell_id: nx_int,
222 kind: nx_int,
223 signature_hash: nx_size,
224 initial_affinity_q10: nx_int,
225 now_us: nx_size) -> nx_int {
226 let src_idx: nx_int = _immune_find_cell(i, source_cell_id)
227 if src_idx < 0 { return 0 }
228 var distributed: nx_int = 0
229 var k: nx_size = 0
230 while k < i.n_cells {
231 if (k as i64) != src_idx {
232 let r: *NxImmuneCellRow = _immune_at(i, k)
233 if (r.antibody_arr as i64) != 0 {
234 // Skip if recipient already has this signature
235 let existing: nx_int = nx_antibody_match(r.antibody_arr,
236 kind, signature_hash)
237 if existing < 0 {
238 let new_idx: nx_int = nx_antibody_generate(r.antibody_arr,
239 kind, signature_hash, initial_affinity_q10, now_us)
240 if new_idx >= 0 { distributed = distributed + 1 }
241 }
242 }
243 }
244 k = k + 1
245 }
246 return distributed
247}
248
249// ===== nx_immune_alert_count =====================================
250
251func nx_immune_alert_count(i: *NxImmune, cell_id: nx_int) -> nx_int {
252 let idx: nx_int = _immune_find_cell(i, cell_id)
253 if idx < 0 { return 0 }
254 let r: *NxImmuneCellRow = _immune_at(i, idx as nx_size)
255 return r.alert_count
256}
257
258// ===== nx_immune_count_cells_in_status ============================
259
260func nx_immune_count_cells_in_status(i: *NxImmune, status: nx_int) -> nx_size {
261 var hits: nx_size = 0
262 var k: nx_size = 0
263 while k < i.n_cells {
264 let r: *NxImmuneCellRow = _immune_at(i, k)
265 if r.status == status { hits = hits + 1 }
266 k = k + 1
267 }
268 return hits
269}
270
271// ===== nx_immune_should_quarantine_host ==========================
272//
273// Coarse colony-level decision: if >=50% of cells are at ALERTED or
274// higher, recommend host-level quarantine (operator should pause new
275// cell instantiation until the threat is understood). Returns 1 if
276// quarantine is recommended.
277
278func nx_immune_should_quarantine_host(i: *NxImmune) -> nx_int {
279 if i.n_cells == 0 { return 0 }
280 let alerted: nx_size = nx_immune_count_cells_in_status(i, NX_COL_ALERTED) +
281 nx_immune_count_cells_in_status(i, NX_COL_RESPONDING) +
282 nx_immune_count_cells_in_status(i, NX_COL_COMPROMISED)
283 let half: nx_size = i.n_cells / 2
284 if alerted >= half {
285 if alerted > 0 { return 1 }
286 }
287 return 0
288}