code wiki / (root) / nx_hunt_journal.nx

nx_hunt_journal.nx source

↩ module page · 105 lines · 3392 B

1// nx_hunt_journal.nx -- append-only event ring for hunt events. 2// 3// Per [[feedback-hunter-gatherer-meta-primitives-outward-inward-axes]] 4// CARDINAL: "nx_hunt_journal (~/.nishi/hunt.jsonl)." Append-only log 5// of every hunt event (scout / engage / kill / archive) so the 6// session-audit gate can verify hunt_count >= 1 per session, and 7// imbalance flagger can detect 5x ratio for 3 consecutive sessions. 8// 9// V1 ships in-memory ring; on-disk JSONL persistence is queued (matches 10// nx_evict_journal pattern; both write to ~/.nishi/<name>.jsonl in V2). 11// 12// Composes: 13// nx_hunter -- emits events; journal records them 14// nx_gather_journal -- the inward-axis dual; session-audit pairs 15// both for valid-session predicate 16// nx_provenance_chain -- hunt-kill events are transforms; chain-logged 17 18import "nx_syscalls.nx" 19import "nx_tier.nx" 20import "nx_hunter.nx" 21 22// ===== Sealed enum: NxHuntEventKind =============================== 23 24const NX_HEV_SCOUTED: nx_int = 0 25const NX_HEV_ENGAGED: nx_int = 1 26const NX_HEV_KILLED: nx_int = 2 27const NX_HEV_ARCHIVED: nx_int = 3 28const NX_HEV_N_KINDS: nx_int = 4 29 30// ===== Struct: NxHuntEvent ======================================== 31 32struct NxHuntEvent { 33 ts_us: nx_size, 34 target_id: nx_int, 35 event_kind: nx_int, 36 target_kind: nx_int, // NX_HK_* at moment of event 37 kill_pillar: nx_int, // NX_KP_NONE except on KILLED events 38} 39 40// ===== Struct: NxHuntJournalRing ================================== 41 42struct NxHuntJournalRing { 43 events: *NxHuntEvent, 44 capacity: nx_size, 45 head: nx_size, 46 count: nx_size, 47} 48 49const NX_HEV_BYTES: nx_size = 40 50 51func nx_hev_kind_is_valid(k: nx_int) -> nx_int { 52 if k < 0 { return 0 } 53 if k >= NX_HEV_N_KINDS { return 0 } 54 return 1 55} 56 57func nx_hunt_journal_new(capacity: nx_size) -> *NxHuntJournalRing { 58 let j: *NxHuntJournalRing = (sys_mmap(32)) as *NxHuntJournalRing 59 let bytes: nx_size = capacity * NX_HEV_BYTES 60 j.events = (sys_mmap(bytes)) as *NxHuntEvent 61 j.capacity = capacity 62 j.head = 0 63 j.count = 0 64 return j 65} 66 67func _hunt_jr_at(j: *NxHuntJournalRing, idx: nx_size) -> *NxHuntEvent { 68 return (j.events as i64 + (idx as i64) * NX_HEV_BYTES) as *NxHuntEvent 69} 70 71func nx_hunt_journal_log(j: *NxHuntJournalRing, 72 ts_us: nx_size, 73 target_id: nx_int, 74 event_kind: nx_int, 75 target_kind: nx_int, 76 kill_pillar: nx_int) -> nx_int { 77 if nx_hev_kind_is_valid(event_kind) == 0 { return 1 } 78 let e: *NxHuntEvent = _hunt_jr_at(j, j.head) 79 e.ts_us = ts_us 80 e.target_id = target_id 81 e.event_kind = event_kind 82 e.target_kind = target_kind 83 e.kill_pillar = kill_pillar 84 j.head = j.head + 1 85 if j.head >= j.capacity { j.head = 0 } 86 j.count = j.count + 1 87 return 0 88} 89 90func nx_hunt_journal_count_kind(j: *NxHuntJournalRing, kind: nx_int) -> nx_int { 91 var hits: nx_int = 0 92 var live: nx_size = j.count 93 if live > j.capacity { live = j.capacity } 94 var i: nx_size = 0 95 while i < live { 96 let e: *NxHuntEvent = _hunt_jr_at(j, i) 97 if e.event_kind == kind { hits = hits + 1 } 98 i = i + 1 99 } 100 return hits 101} 102 103func nx_hunt_journal_event_count(j: *NxHuntJournalRing) -> nx_size { 104 return j.count 105}