nx_antibody.nx source
↩ module page · 291 lines · 11093 B
1// nx_antibody.nx -- adaptive defense generation.
2//
3// Per [[feedback-unified-immune-architecture-three-tier]] item 2.7:
4// "adaptive defense GENERATION from observed attacks; the substrate's
5// defensive judo. Captures real attack samples → processes into
6// machine-readable defense definitions → affinity-matures across
7// encounters → distributes via peer mesh → composes legal/social
8// defense materials. Biology: clonal selection + affinity maturation
9// + memory cell formation. Defensive-only discipline: NEVER initiates
10// contact with attackers; only learns from contact attackers initiate."
11//
12// Per [[feedback-cell-immune-system-ransomware-judo-ddos-by-bit]]:
13// the judo is of INFORMATION not retaliation. We never attack back;
14// we make every attacker action visible + analyzable + distributable.
15//
16// Per [[feedback-captain-moroni-doctrine]]: DEFENSIVE ONLY. Substrate
17// refuses to compile offensive antibody operations -- antibodies are
18// detection signatures, not exploitation payloads.
19//
20// Lifecycle of an antibody (clonal-selection analog):
21// 1. nx_pamp or nx_pamp_meta detects an attack -- attack sample
22// captured into nx_xenocell signed observation
23// 2. nx_antibody_generate distills the sample into a detection
24// signature (hash + kind + Q10 affinity)
25// 3. Antibody added to nx_antibody_array; nx_crispr-style memory
26// 4. On each subsequent encounter, antibody's hit_count increments
27// and effectiveness Q10 updates (affinity maturation)
28// 5. V2: antibodies above effectiveness threshold federate via
29// peer-mesh (Citizen Lab analog -- community-shared intel)
30// 6. V2: antibodies compose into legal/social defense materials
31// (sub-poena docs, public advisories) via nx_evict_journal
32// forensic chain
33//
34// Composes:
35// nx_pamp / nx_pamp_meta -- detection feeds antibody generation
36// nx_xenocell -- attack samples come from signed observations
37// nx_crispr -- adaptive memory mechanism reused for antibodies
38// nx_lysis -- antibody confirms threat -> lysis selects mechanism
39// nx_restriction -- antibody-positive input refused at IO boundary
40//
41// V1 ships:
42// - struct NxAntibody with kind + signature_hash + affinity_q10 +
43// hit_count + effectiveness_q10
44// - generate (from a pamp hit or pamp_meta verdict)
45// - match (does this byte buffer trigger any antibody?)
46// - affinity_mature (after successful match, bump effectiveness)
47// - effectiveness_threshold predicate (above 768 = federation-ready)
48//
49// Gap list (V1 honest perf verdict):
50// - peer-mesh federation queued (V2)
51// - legal/social defense composition queued (V3)
52// - affinity maturation formula is linear (V2 uses learned rate)
53// - no antibody-class grouping (V2 antibodies cluster into
54// "antibody class A defends against attacker family X")
55// - signature is content_hash only; V2 adds behavioral fingerprint
56//
57// genealogy_id: cardinal_2026-05-19_unified_immune_architecture +
58// cardinal_2026-05-17_cell_immune_judo +
59// cardinal_2026-05-07_captain_moroni_defensive_only +
60// biology_clonal_selection_affinity_maturation
61// lineage_id: substrate_antibody_v1
62//
63// nx_safety_envelope:
64// intended_use: "Adaptive defense signature generation from
65// observed attack samples; DEFENSIVE ONLY;
66// Captain Moroni discipline enforced"
67// sil_target: SIL3
68// evidence: [no_offensive_path, signatures_are_detectors_not_exploits,
69// captain_moroni_aligned, peer_mesh_optional_not_required]
70// verdict: NOT_YET_EVALUATED
71
72import "nx_syscalls.nx"
73import "nx_tier.nx"
74import "nx_pamp.nx"
75import "nx_pamp_meta.nx"
76const NX_MAGIC_1024: i64 = 1024
77
78// ===== Sealed enum: NxAntibodyVerdict =============================
79
80const NX_AB_VD_OK: nx_int = 0
81const NX_AB_VD_ERR_FULL: nx_int = 1
82const NX_AB_VD_MATCH: nx_int = 2
83const NX_AB_VD_NO_MATCH: nx_int = 3
84const NX_AB_VD_ERR_BAD_KIND: nx_int = 4
85
86// ===== Sealed enum: NxAntibodyState ==============================
87//
88// NAIVE = freshly generated, never matched in production
89// MATURE = matched >= 3 times, affinity above 614 (60%)
90// MEMORY = matched >= 10 times, affinity above 870 (85%); federation candidate
91
92const NX_AB_ST_NAIVE: nx_int = 0
93const NX_AB_ST_MATURE: nx_int = 1
94const NX_AB_ST_MEMORY: nx_int = 2
95const NX_AB_ST_N_STATES: nx_int = 3
96
97// Affinity-maturation thresholds (per Cardinal 11, named constants
98// for one-line tuning).
99const NX_AB_MATURE_HITS: nx_int = 3
100const NX_AB_MATURE_AFFINITY: nx_int = 614
101const NX_AB_MEMORY_HITS: nx_int = 10
102const NX_AB_MEMORY_AFFINITY: nx_int = 870
103const NX_AB_FEDERATION_AFFINITY: nx_int = 768
104
105// ===== Struct: NxAntibody ========================================
106//
107// One detection signature with maturation metadata. kind aliases
108// NX_PAMP_* (or caller's extended taxonomy). signature_hash is
109// content-addressed (BLAKE3 of the attack body). affinity_q10
110// starts at "how confident was the initial detection" and matures
111// upward with successful repeats.
112
113struct NxAntibody {
114 kind: nx_int,
115 signature_hash: nx_size,
116 affinity_q10: nx_int,
117 hit_count: nx_int,
118 effectiveness_q10: nx_int,
119 state: nx_int,
120 generated_us: nx_size,
121 last_match_us: nx_size,
122}
123
124// ===== Struct: NxAntibodyArray ===================================
125
126struct NxAntibodyArray {
127 antibodies: *NxAntibody,
128 capacity: nx_size,
129 head: nx_size,
130 count: nx_size,
131}
132
133const NX_AB_BYTES: nx_size = 56
134const NX_AB_DEFAULT_CAPACITY: nx_size = 128
135
136// ===== Validators ================================================
137
138func nx_ab_vd_state_is_valid(s: nx_int) -> nx_int {
139 if s < 0 { return 0 }
140 if s >= NX_AB_ST_N_STATES { return 0 }
141 return 1
142}
143
144// ===== nx_antibody_array_new =====================================
145
146func nx_antibody_array_new(capacity: nx_size) -> *NxAntibodyArray {
147 let a: *NxAntibodyArray = (sys_mmap(32)) as *NxAntibodyArray
148 let bytes: nx_size = capacity * NX_AB_BYTES
149 a.antibodies = (sys_mmap(bytes)) as *NxAntibody
150 a.capacity = capacity
151 a.head = 0
152 a.count = 0
153 return a
154}
155
156// ===== _ab_at ====================================================
157
158func _ab_at(a: *NxAntibodyArray, idx: nx_size) -> *NxAntibody {
159 return (a.antibodies as i64 + (idx as i64) * NX_AB_BYTES) as *NxAntibody
160}
161
162// ===== nx_antibody_generate ======================================
163//
164// Distill a pamp hit (or pamp_meta verdict) into a new antibody.
165// The "affinity_q10" parameter is the initial detection confidence;
166// for nx_pamp hits this is the PampHit.confidence; for nx_pamp_meta
167// HIGH_DECEPTION it's the deception_q10. Returns the index of the
168// new antibody, or -1 if array is full.
169
170func nx_antibody_generate(arr: *NxAntibodyArray,
171 kind: nx_int,
172 signature_hash: nx_size,
173 initial_affinity_q10: nx_int,
174 now_us: nx_size) -> nx_int {
175 if arr.count >= arr.capacity { return -1 }
176 let ab: *NxAntibody = _ab_at(arr, arr.head)
177 ab.kind = kind
178 ab.signature_hash = signature_hash
179 ab.affinity_q10 = initial_affinity_q10
180 ab.hit_count = 0
181 ab.effectiveness_q10 = initial_affinity_q10
182 ab.state = NX_AB_ST_NAIVE
183 ab.generated_us = now_us
184 ab.last_match_us = now_us
185 let idx: nx_int = arr.head as i64
186 arr.head = arr.head + 1
187 if arr.head >= arr.capacity { arr.head = 0 }
188 arr.count = arr.count + 1
189 return idx
190}
191
192// ===== nx_antibody_match =========================================
193//
194// Walk the array; find any antibody whose (kind, signature_hash)
195// matches the candidate. Returns the index on hit or -1 on miss.
196// Caller then calls nx_antibody_affinity_mature to update the
197// matched antibody's metadata.
198
199func nx_antibody_match(arr: *NxAntibodyArray,
200 kind: nx_int,
201 signature_hash: nx_size) -> nx_int {
202 var live: nx_size = arr.count
203 if live > arr.capacity { live = arr.capacity }
204 var i: nx_size = 0
205 while i < live {
206 let ab: *NxAntibody = _ab_at(arr, i)
207 if ab.kind == kind {
208 if ab.signature_hash == signature_hash {
209 return i as i64
210 }
211 }
212 i = i + 1
213 }
214 return -1
215}
216
217// ===== nx_antibody_affinity_mature ===============================
218//
219// Called after a successful match. Increments hit_count and bumps
220// affinity_q10 toward 1024 by a maturation rate (V1: +51 Q10 per
221// hit, ~5%). State transitions per the thresholds.
222
223func nx_antibody_affinity_mature(arr: *NxAntibodyArray,
224 idx: nx_int,
225 now_us: nx_size) -> nx_int {
226 if idx < 0 { return NX_AB_VD_ERR_BAD_KIND }
227 if (idx as nx_size) >= arr.capacity { return NX_AB_VD_ERR_BAD_KIND }
228 let ab: *NxAntibody = _ab_at(arr, idx as nx_size)
229 ab.hit_count = ab.hit_count + 1
230 ab.last_match_us = now_us
231 // affinity climbs +51 per hit, capped at 1024
232 ab.affinity_q10 = ab.affinity_q10 + 51
233 if ab.affinity_q10 > NX_MAGIC_1024 { ab.affinity_q10 = NX_MAGIC_1024 }
234 ab.effectiveness_q10 = ab.affinity_q10
235 // state transitions
236 if ab.hit_count >= NX_AB_MEMORY_HITS {
237 if ab.affinity_q10 >= NX_AB_MEMORY_AFFINITY {
238 ab.state = NX_AB_ST_MEMORY
239 }
240 }
241 if ab.state == NX_AB_ST_NAIVE {
242 if ab.hit_count >= NX_AB_MATURE_HITS {
243 if ab.affinity_q10 >= NX_AB_MATURE_AFFINITY {
244 ab.state = NX_AB_ST_MATURE
245 }
246 }
247 }
248 return NX_AB_VD_OK
249}
250
251// ===== nx_antibody_is_federation_ready ============================
252//
253// Predicate: this antibody's affinity is high enough to share with
254// peer mesh / community intel. Used by V2 federation layer; today
255// just exposes the predicate so callers can plan.
256
257func nx_antibody_is_federation_ready(ab: *NxAntibody) -> nx_int {
258 if (ab as i64) == 0 { return 0 }
259 if ab.affinity_q10 >= NX_AB_FEDERATION_AFFINITY { return 1 }
260 return 0
261}
262
263// ===== nx_antibody_count_by_state =================================
264
265func nx_antibody_count_by_state(arr: *NxAntibodyArray, state: nx_int) -> nx_int {
266 var hits: nx_int = 0
267 var live: nx_size = arr.count
268 if live > arr.capacity { live = arr.capacity }
269 var i: nx_size = 0
270 while i < live {
271 let ab: *NxAntibody = _ab_at(arr, i)
272 if ab.state == state { hits = hits + 1 }
273 i = i + 1
274 }
275 return hits
276}
277
278// ===== nx_antibody_total_hits ====================================
279
280func nx_antibody_total_hits(arr: *NxAntibodyArray) -> nx_int {
281 var sum: nx_int = 0
282 var live: nx_size = arr.count
283 if live > arr.capacity { live = arr.capacity }
284 var i: nx_size = 0
285 while i < live {
286 let ab: *NxAntibody = _ab_at(arr, i)
287 sum = sum + ab.hit_count
288 i = i + 1
289 }
290 return sum
291}