code wiki / (root) / nx_health_check.nx

nx_health_check.nx source

↩ module page · 125 lines · 4093 B

1// nx_health_check.nx -- overall substrate health verdict. 2// 3// Per [[feedback-self-surfacing-intelligence-staged-autonomy]]: 4// substrate emits a coarse GREEN / YELLOW / RED verdict aggregating 5// all known indicators. Operator sees one color first; can drill 6// into the dashboard for details. 7// 8// Verdict rules (Q10 alert_score from nx_audit_dashboard): 9// GREEN : alert_score < 200 AND colony_status == HEALTHY 10// YELLOW : alert_score 200-768 OR colony_status == ALERTED 11// RED : alert_score > 768 OR colony_status >= RESPONDING 12// 13// Composes: 14// nx_audit_dashboard -- the snapshot consumed for verdict 15// nx_recovery -- RED verdict triggers recovery procedure 16// nx_book -- RED entry written when transitioning into RED 17 18import "nx_syscalls.nx" 19import "nx_tier.nx" 20import "nx_audit_dashboard.nx" 21 22// ===== Sealed enum: NxHealthVerdict =============================== 23 24const NX_HC_GREEN: nx_int = 0 25const NX_HC_YELLOW: nx_int = 1 26const NX_HC_RED: nx_int = 2 27const NX_HC_N_VERDICTS: nx_int = 3 28 29func nx_hc_verdict_is_valid(v: nx_int) -> nx_int { 30 if v < 0 { return 0 } 31 if v >= NX_HC_N_VERDICTS { return 0 } 32 return 1 33} 34 35// ===== Struct: NxHealthState ====================================== 36// 37// Persistent state tracking transitions across health-check calls. 38// Used to detect "transitioned into RED" events (vs already RED) so 39// the substrate writes one book entry per transition, not on every 40// poll. 41 42struct NxHealthState { 43 last_verdict: nx_int, 44 last_check_us: nx_size, 45 consecutive_red: nx_int, 46 transition_count: nx_int, 47} 48 49func nx_health_state_new() -> *NxHealthState { 50 let s: *NxHealthState = (sys_mmap(32)) as *NxHealthState 51 s.last_verdict = NX_HC_GREEN 52 s.last_check_us = 0 53 s.consecutive_red = 0 54 s.transition_count = 0 55 return s 56} 57 58// ===== nx_health_check ============================================ 59// 60// Compute the verdict from a dashboard snapshot. Update state 61// counters. Returns the verdict. 62 63func nx_health_check(state: *NxHealthState, 64 dash: *NxAuditDashboardSnapshot, 65 now_us: nx_size) -> nx_int { 66 state.last_check_us = now_us 67 let score: nx_int = nx_audit_dashboard_alert_score_q10(dash) 68 69 var v: nx_int = NX_HC_GREEN 70 if dash.colony_status >= 1 { v = NX_HC_YELLOW } // ALERTED 71 if score >= 200 { 72 if v == NX_HC_GREEN { v = NX_HC_YELLOW } 73 } 74 if dash.colony_status >= 2 { v = NX_HC_RED } // RESPONDING+ 75 if score > 768 { v = NX_HC_RED } 76 77 if v != state.last_verdict { 78 state.transition_count = state.transition_count + 1 79 } 80 if v == NX_HC_RED { 81 state.consecutive_red = state.consecutive_red + 1 82 } else { 83 state.consecutive_red = 0 84 } 85 state.last_verdict = v 86 return v 87} 88 89// ===== nx_health_just_transitioned_to ============================ 90// 91// Predicate: did the LAST nx_health_check transition INTO this 92// verdict? Used by callers to fire one-shot side effects (write 93// book entry, trigger recovery, alert operator). 94 95func nx_health_just_transitioned_to(state: *NxHealthState, 96 verdict: nx_int) -> nx_int { 97 if state.last_verdict == verdict { 98 if state.transition_count > 0 { return 1 } 99 } 100 return 0 101} 102 103func nx_health_last_verdict(state: *NxHealthState) -> nx_int { 104 return state.last_verdict 105} 106 107func nx_health_consecutive_red(state: *NxHealthState) -> nx_int { 108 return state.consecutive_red 109} 110 111// ===== nx_health_should_trigger_recovery ========================== 112// 113// Returns 1 if recovery procedure should fire. Rules: 114// - last_verdict == RED AND consecutive_red >= 2 (sustained, not flap) 115// OR 116// - just_transitioned_to(RED) for first time 117 118func nx_health_should_trigger_recovery(state: *NxHealthState) -> nx_int { 119 if state.last_verdict != NX_HC_RED { return 0 } 120 if state.consecutive_red >= 2 { return 1 } 121 if state.transition_count > 0 { 122 if state.consecutive_red == 1 { return 1 } 123 } 124 return 0 125}