code wiki / (root) / nx_hunter.nx

nx_hunter.nx source

↩ module page · 297 lines · 10678 B

1// nx_hunter.nx -- outward-axis collection primitive. 2// 3// Per [[feedback-hunter-gatherer-meta-primitives-outward-inward-axes]] 4// CARDINAL: "nx_hunter (outward — collect/kill bugs+features+feedback+ 5// threats+competitor LOSE-axes)." Hunter is the racing-crew arm of 6// the substrate: it goes OUT, finds threats and opportunities, and 7// either KILLS them (bugs fixed, EXCEED-axis shipped) or CARRIES 8// them home (feedback absorbed, cardinals updated). 9// 10// THE STRATEGIC PRIMITIVE per user 2026-05-17: "hunting being the 11// collection and 'killing' of bugs features feedback etc as part of 12// the racing crew team." Every session must emit at least one hunt 13// event (a target scouted, an active hunt logged, or a kill recorded) 14// or the session was a non-session per the cardinal's audit gate. 15// 16// Composes: 17// nx_hunt_journal -- append-only event log; what was hunted, when 18// nx_gatherer -- the inward-axis dual; hunter and gatherer 19// together form the session-audit gate 20// nx_xenocell -- a threat actor caught = a hunt KILL event 21// nx_antibody -- detection signature derived from a kill 22// nx_provenance_chain -- the kill is a transform; chain-logged 23// nx_pollinate -- federation-ready kills propagate to peers 24// (community-shared hunt intelligence) 25// 26// V1 ships: 27// - sealed enum NxHuntKind (5 target classes from cardinal) 28// - sealed enum NxHuntStatus (4 states: scouted/active/killed/archived) 29// - sealed enum NxKillPillar (4 kill-classes from cardinal) 30// - struct NxHuntTarget + NxHunter container 31// - scout/promote/kill/archive verbs 32// - count_by_status + count_kills_by_pillar queries 33// 34// Gap list (V1 honest perf verdict): 35// - target descriptions are caller-supplied byte buffers (V2 adds 36// structured taxonomy via content-addressed schema) 37// - no per-pillar specialized lifecycle (V2 differentiates) 38// - no automatic federation-readiness predicate (V2 composes with 39// pollinate per kill-pillar policy) 40// - no time-windowed metrics (V2 adds rolling-window kill rate) 41// 42// genealogy_id: cardinal_2026-05-17_hunter_gatherer_meta_primitives + 43// racing_crew_metaphor + biology_predator_hunting 44// lineage_id: substrate_hunter_v1 45// 46// nx_safety_envelope: 47// intended_use: "Outward-axis collection of bugs / features / 48// feedback / threats / competitor LOSE-axes; 49// defensive only per Captain Moroni; never 50// offensive hunt" 51// sil_target: SIL2 52// evidence: [defensive_only, captain_moroni_aligned, 53// kills_are_substrate_outputs_not_attacks] 54// verdict: NOT_YET_EVALUATED 55 56import "nx_syscalls.nx" 57import "nx_tier.nx" 58 59// ===== Sealed enum: NxHuntKind ==================================== 60// 61// Per cardinal "competitor product / bug class / user feedback / 62// threat actor / missing feature." 63 64const NX_HK_COMPETITOR_PRODUCT: nx_int = 0 65const NX_HK_BUG_CLASS: nx_int = 1 66const NX_HK_USER_FEEDBACK: nx_int = 2 67const NX_HK_THREAT_ACTOR: nx_int = 3 68const NX_HK_MISSING_FEATURE: nx_int = 4 69const NX_HK_N_KINDS: nx_int = 5 70 71// ===== Sealed enum: NxHuntStatus ================================== 72 73const NX_HS_SCOUTED: nx_int = 0 // target identified, not yet engaged 74const NX_HS_ACTIVE: nx_int = 1 // active hunt in progress 75const NX_HS_KILLED: nx_int = 2 // hunt succeeded (one of 4 pillars) 76const NX_HS_ARCHIVED: nx_int = 3 // closed without kill; learning kept 77const NX_HS_N_STATES: nx_int = 4 78 79// ===== Sealed enum: NxKillPillar ================================== 80// 81// Per cardinal "four-pillar bug-fix / EXCEED-axis-ship / threat- 82// hardened / cardinal-absorbed." 83 84const NX_KP_NONE: nx_int = 0 85const NX_KP_BUG_FIXED: nx_int = 1 86const NX_KP_EXCEED_AXIS_SHIPPED: nx_int = 2 87const NX_KP_THREAT_HARDENED: nx_int = 3 88const NX_KP_CARDINAL_ABSORBED: nx_int = 4 89const NX_KP_N_PILLARS: nx_int = 5 90 91// ===== Sealed enum: NxHunterVerdict =============================== 92 93const NX_HUNTER_OK: nx_int = 0 94const NX_HUNTER_ERR_FULL: nx_int = 1 95const NX_HUNTER_ERR_BAD_KIND: nx_int = 2 96const NX_HUNTER_ERR_BAD_STATUS: nx_int = 3 97const NX_HUNTER_ERR_BAD_PILLAR: nx_int = 4 98const NX_HUNTER_ERR_NOT_FOUND: nx_int = 5 99const NX_HUNTER_ERR_BAD_TRANSITION: nx_int = 6 100 101// ===== Struct: NxHuntTarget ======================================= 102 103struct NxHuntTarget { 104 target_id: nx_int, 105 kind: nx_int, 106 status: nx_int, 107 kill_pillar: nx_int, // NX_KP_NONE until status=KILLED 108 content_hash: nx_size, 109 scouted_us: nx_size, 110 last_event_us: nx_size, 111} 112 113// ===== Struct: NxHunter =========================================== 114 115struct NxHunter { 116 targets: *NxHuntTarget, 117 capacity: nx_size, 118 head: nx_size, 119 count: nx_size, 120} 121 122const NX_HUNT_TARGET_BYTES: nx_size = 56 123 124// ===== Validators ================================================ 125 126func nx_hk_is_valid(k: nx_int) -> nx_int { 127 if k < 0 { return 0 } 128 if k >= NX_HK_N_KINDS { return 0 } 129 return 1 130} 131 132func nx_hs_is_valid(s: nx_int) -> nx_int { 133 if s < 0 { return 0 } 134 if s >= NX_HS_N_STATES { return 0 } 135 return 1 136} 137 138func nx_kp_is_valid(p: nx_int) -> nx_int { 139 if p < 0 { return 0 } 140 if p >= NX_KP_N_PILLARS { return 0 } 141 return 1 142} 143 144// ===== nx_hunter_new ============================================== 145 146func nx_hunter_new(capacity: nx_size) -> *NxHunter { 147 let h: *NxHunter = (sys_mmap(32)) as *NxHunter 148 let bytes: nx_size = capacity * NX_HUNT_TARGET_BYTES 149 h.targets = (sys_mmap(bytes)) as *NxHuntTarget 150 h.capacity = capacity 151 h.head = 0 152 h.count = 0 153 return h 154} 155 156// ===== _hunter_at ================================================= 157 158func _hunter_at(h: *NxHunter, idx: nx_size) -> *NxHuntTarget { 159 return (h.targets as i64 + (idx as i64) * NX_HUNT_TARGET_BYTES) as *NxHuntTarget 160} 161 162// ===== _hunter_find =============================================== 163 164func _hunter_find(h: *NxHunter, target_id: nx_int) -> nx_int { 165 var i: nx_size = 0 166 while i < h.count { 167 let t: *NxHuntTarget = _hunter_at(h, i) 168 if t.target_id == target_id { return i as i64 } 169 i = i + 1 170 } 171 return -1 172} 173 174// ===== nx_hunter_scout ============================================ 175// 176// Identify a new target. Status begins SCOUTED. Returns the index 177// or -1 if full / bad kind / duplicate. 178 179func nx_hunter_scout(h: *NxHunter, 180 target_id: nx_int, 181 kind: nx_int, 182 content_hash: nx_size, 183 now_us: nx_size) -> nx_int { 184 if nx_hk_is_valid(kind) == 0 { return -1 } 185 if _hunter_find(h, target_id) >= 0 { return -1 } 186 if h.count >= h.capacity { return -1 } 187 let t: *NxHuntTarget = _hunter_at(h, h.head) 188 t.target_id = target_id 189 t.kind = kind 190 t.status = NX_HS_SCOUTED 191 t.kill_pillar = NX_KP_NONE 192 t.content_hash = content_hash 193 t.scouted_us = now_us 194 t.last_event_us = now_us 195 h.head = h.head + 1 196 if h.head >= h.capacity { h.head = 0 } 197 h.count = h.count + 1 198 return (h.count - 1) as i64 199} 200 201// ===== nx_hunter_engage =========================================== 202// 203// Transition SCOUTED -> ACTIVE. Allowed only from SCOUTED. 204 205func nx_hunter_engage(h: *NxHunter, target_id: nx_int, now_us: nx_size) -> nx_int { 206 let idx: nx_int = _hunter_find(h, target_id) 207 if idx < 0 { return NX_HUNTER_ERR_NOT_FOUND } 208 let t: *NxHuntTarget = _hunter_at(h, idx as nx_size) 209 if t.status != NX_HS_SCOUTED { return NX_HUNTER_ERR_BAD_TRANSITION } 210 t.status = NX_HS_ACTIVE 211 t.last_event_us = now_us 212 return NX_HUNTER_OK 213} 214 215// ===== nx_hunter_kill ============================================ 216// 217// Record a kill. Allowed from ACTIVE or SCOUTED (sometimes a target 218// is found-and-killed in same beat, like a regression test catching 219// a bug as it's being introduced). pillar must be one of NX_KP_*. 220 221func nx_hunter_kill(h: *NxHunter, 222 target_id: nx_int, 223 pillar: nx_int, 224 now_us: nx_size) -> nx_int { 225 if nx_kp_is_valid(pillar) == 0 { return NX_HUNTER_ERR_BAD_PILLAR } 226 if pillar == NX_KP_NONE { return NX_HUNTER_ERR_BAD_PILLAR } 227 let idx: nx_int = _hunter_find(h, target_id) 228 if idx < 0 { return NX_HUNTER_ERR_NOT_FOUND } 229 let t: *NxHuntTarget = _hunter_at(h, idx as nx_size) 230 if t.status == NX_HS_KILLED { return NX_HUNTER_ERR_BAD_TRANSITION } 231 if t.status == NX_HS_ARCHIVED { return NX_HUNTER_ERR_BAD_TRANSITION } 232 t.status = NX_HS_KILLED 233 t.kill_pillar = pillar 234 t.last_event_us = now_us 235 return NX_HUNTER_OK 236} 237 238// ===== nx_hunter_archive ========================================= 239// 240// Close a hunt without a kill. The learning is preserved but the 241// target is no longer actively pursued. Allowed from any pre- 242// archived status. 243 244func nx_hunter_archive(h: *NxHunter, target_id: nx_int, now_us: nx_size) -> nx_int { 245 let idx: nx_int = _hunter_find(h, target_id) 246 if idx < 0 { return NX_HUNTER_ERR_NOT_FOUND } 247 let t: *NxHuntTarget = _hunter_at(h, idx as nx_size) 248 if t.status == NX_HS_ARCHIVED { return NX_HUNTER_OK } 249 t.status = NX_HS_ARCHIVED 250 t.last_event_us = now_us 251 return NX_HUNTER_OK 252} 253 254// ===== Queries =================================================== 255 256func nx_hunter_count_by_status(h: *NxHunter, status: nx_int) -> nx_int { 257 var hits: nx_int = 0 258 var i: nx_size = 0 259 while i < h.count { 260 let t: *NxHuntTarget = _hunter_at(h, i) 261 if t.status == status { hits = hits + 1 } 262 i = i + 1 263 } 264 return hits 265} 266 267func nx_hunter_count_kills_by_pillar(h: *NxHunter, pillar: nx_int) -> nx_int { 268 var hits: nx_int = 0 269 var i: nx_size = 0 270 while i < h.count { 271 let t: *NxHuntTarget = _hunter_at(h, i) 272 if t.status == NX_HS_KILLED { 273 if t.kill_pillar == pillar { hits = hits + 1 } 274 } 275 i = i + 1 276 } 277 return hits 278} 279 280func nx_hunter_total_kills(h: *NxHunter) -> nx_int { 281 return nx_hunter_count_by_status(h, NX_HS_KILLED) 282} 283 284func nx_hunter_count(h: *NxHunter) -> nx_size { 285 return h.count 286} 287 288// ===== nx_hunter_session_emitted ================================= 289// 290// Predicate: did at least one hunt event occur in this hunter? 291// True if any target has been scouted (count > 0). Used by the 292// session-audit gate to confirm hunt_count >= 1. 293 294func nx_hunter_session_emitted(h: *NxHunter) -> nx_int { 295 if h.count > 0 { return 1 } 296 return 0 297}