code wiki / _hdl_build / nx_bootmine.nx

nx_bootmine.nx source

↩ module page · 455 lines · 21669 B

1// nx_bootmine.nx -- BOOT/PROCESS-STABILITY MINER over the sovereign supervisor log (miner-sota, 2026-07-24, 2// operator 'go SOTA from the FIRST BYTE up'). The miner suite reaches the LOWEST layer: the system's own 3// process lifecycle. A SOTA boot is STABLE from the first byte -- services come up and STAY up. A CRASH 4// LOOP (a subsystem spawn->die->respawn without end) burns fork bandwidth continuously and hides the real 5// fault. This mines the supervisor.log for exactly that: per-[tag] respawn counts, and any tag whose 6// respawns exceed minloop is flagged CRASH-LOOPING. Auto-detects the reader-keep loop (debt seq699). 7// Composes nx_sovjson_lib (sj_*). Read-only. No hw writes (Rule 26). 8// mine <logfile> [minloop] -> JSON: totals, by_tag ranked, crash_looping, stability 9// selftest <scratch-prefix> -> gate T1..T7 10// license_tier: ORIGINAL 11import "nx_sovjson_lib.nx" 12import "nx_syscalls.nx" 13import "nx_gate_verdict.nx" 14const BM_MAGIC_8192: i64 = 8192 15 16const BM_WIN: i64 = 8388608 17const BM_OUT: i64 = 65536 18const BM_PATH: i64 = 512 19const BM_TAGS: i64 = 128 20const BM_TOPN: i64 = 20 21const BM_MINLOOP: i64 = 10 22const BM_NAME_MAX: i64 = 120 23const BM_MODE_644: i64 = 420 24const BM_LBRK: i64 = 91 25const BM_RBRK: i64 = 93 26 27func bm_read(path: *u8, buf: *u8, cap: i64) -> i64 { 28 let fd: i64 = sys_openat_rd(path) 29 if fd < 0 { return -1 } 30 var n: i64 = 0 31 var go: i64 = 1 32 while go == 1 { let r: i64 = sys_read(fd, ((buf as i64)+n) as *u8, cap-n); if r <= 0 { go = 0 } else { n = n + r } if n >= cap { go = 0 } } 33 sys_close(fd) 34 return n 35} 36// substring search in q[s..e) -> 1 if found 37func bm_has(q: *u8, s: i64, e: i64, lit: *u8) -> i64 { 38 let ll: i64 = sj_vlen(lit) 39 if ll == 0 { return 0 } 40 var i: i64 = s 41 while i + ll <= e { 42 var k: i64 = 0 43 var ok: i64 = 1 44 while k < ll { if q[i+k] != lit[k] { ok = 0; k = ll } else { k = k + 1 } } 45 if ok == 1 { return 1 } 46 i = i + 1 47 } 48 return 0 49} 50func bm_find(q: *u8, n: i64, lit: *u8) -> i64 { return bm_has(q, 0, n, lit) } 51// first [tag] in line q[s..e): fills tp[0]/tp[1] with the span BETWEEN the brackets; returns 1 if found 52func bm_tag(q: *u8, s: i64, e: i64, tp: *i64) -> i64 { 53 var i: i64 = s 54 var lb: i64 = 0 - 1 55 while i < e { if q[i] == (BM_LBRK as u8) { lb = i; i = e } else { i = i + 1 } } 56 if lb < 0 { return 0 } 57 var j: i64 = lb + 1 58 while j < e { if q[j] == (BM_RBRK as u8) { tp[0] = lb + 1; tp[1] = j; return 1 } j = j + 1 } 59 return 0 60} 61func bm_intern(q: *u8, cs: i64, ce: i64, ts: *i64, te: *i64, np: *i64) -> i64 { 62 var i: i64 = 0 63 while i < np[0] { 64 if ce - cs == te[i] - ts[i] { 65 var m: i64 = 0 66 var eq: i64 = 1 67 while m < ce - cs { if q[cs+m] != q[ts[i]+m] { eq = 0; m = ce - cs } else { m = m + 1 } } 68 if eq == 1 { return i } 69 } 70 i = i + 1 71 } 72 if np[0] >= BM_TAGS { return -1 } 73 ts[np[0]] = cs 74 te[np[0]] = ce 75 np[0] = np[0] + 1 76 return np[0] - 1 77} 78func bm_key(d: *u8, o: i64, name: *u8) -> i64 { 79 d[o] = 34 as u8 80 var p: i64 = o + 1 81 p = sj_cat(d, p, name) 82 d[p] = 34 as u8 83 p = p + 1 84 d[p] = 58 as u8 85 p = p + 1 86 return p 87} 88func bm_mine_json(logf: *u8, minloop: i64, d: *u8) -> i64 { 89 let q: *u8 = sys_mmap(BM_WIN) 90 let cap: i64 = BM_WIN - 8 91 let n: i64 = bm_read(logf, q, cap) 92 if n < 0 { return -1 } 93 var trunc: i64 = 0 94 if n >= cap { trunc = 1 } 95 let ts: *i64 = sys_mmap(8 * BM_TAGS) as *i64 96 let te: *i64 = sys_mmap(8 * BM_TAGS) as *i64 97 let tresp: *i64 = sys_mmap(8 * BM_TAGS) as *i64 98 let tspawn: *i64 = sys_mmap(8 * BM_TAGS) as *i64 99 let trest: *i64 = sys_mmap(8 * BM_TAGS) as *i64 100 let done: *i64 = sys_mmap(8 * BM_TAGS) as *i64 101 let np: *i64 = sys_mmap(16) as *i64 102 let tp: *i64 = sys_mmap(16) as *i64 103 var lines: i64 = 0 104 var respawns: i64 = 0 105 var spawns: i64 = 0 106 var restarts: i64 = 0 107 var capped: i64 = 0 108 var i: i64 = 0 109 while i < n { 110 let le: i64 = sj_le(q, i, n) 111 if le > i { 112 lines = lines + 1 113 let isresp: i64 = bm_has(q, i, le, "-> respawn" as *u8) 114 let isrest: i64 = bm_has(q, i, le, "(was dead)" as *u8) 115 let isspawn: i64 = bm_has(q, i, le, "spawned" as *u8) 116 if isresp == 1 { respawns = respawns + 1 } 117 if isrest == 1 { restarts = restarts + 1 } 118 if isspawn == 1 { spawns = spawns + 1 } 119 if isresp + isrest + isspawn > 0 { 120 if bm_tag(q, i, le, tp) == 1 { 121 let ti: i64 = bm_intern(q, tp[0], tp[1], ts, te, np) 122 if ti < 0 { capped = 1 } else { 123 if isresp == 1 { tresp[ti] = tresp[ti] + 1 } 124 if isspawn == 1 { tspawn[ti] = tspawn[ti] + 1 } 125 if isrest == 1 { trest[ti] = trest[ti] + 1 } 126 } 127 } 128 } 129 } 130 i = le + 1 131 } 132 var crash: i64 = 0 133 var k: i64 = 0 134 while k < np[0] { if tresp[k] >= minloop { crash = crash + 1 } k = k + 1 } 135 var p: i64 = 0 136 d[p] = 123 as u8; p = p + 1 137 p = bm_key(d, p, "v" as *u8); p = sj_catn(d, p, 1); d[p] = 44 as u8; p = p + 1 138 p = bm_key(d, p, "tool" as *u8) 139 d[p] = 34 as u8; p = p + 1 140 p = sj_cat(d, p, "nx_bootmine" as *u8) 141 d[p] = 34 as u8; p = p + 1 142 d[p] = 44 as u8; p = p + 1 143 p = bm_key(d, p, "averb" as *u8) 144 d[p] = 34 as u8; p = p + 1 145 p = sj_cat(d, p, "mine" as *u8) 146 d[p] = 34 as u8; p = p + 1 147 d[p] = 44 as u8; p = p + 1 148 p = bm_key(d, p, "log" as *u8) 149 d[p] = 34 as u8; p = p + 1 150 p = sj_cat_esc(d, p, logf, 0, sj_vlen(logf), BM_NAME_MAX) 151 d[p] = 34 as u8; p = p + 1 152 d[p] = 44 as u8; p = p + 1 153 p = bm_key(d, p, "log_bytes" as *u8); p = sj_catn(d, p, n); d[p] = 44 as u8; p = p + 1 154 p = bm_key(d, p, "truncated" as *u8); p = sj_catn(d, p, trunc); d[p] = 44 as u8; p = p + 1 155 p = bm_key(d, p, "minloop" as *u8); p = sj_catn(d, p, minloop); d[p] = 44 as u8; p = p + 1 156 p = bm_key(d, p, "lines" as *u8); p = sj_catn(d, p, lines); d[p] = 44 as u8; p = p + 1 157 p = bm_key(d, p, "spawns" as *u8); p = sj_catn(d, p, spawns); d[p] = 44 as u8; p = p + 1 158 p = bm_key(d, p, "respawns" as *u8); p = sj_catn(d, p, respawns); d[p] = 44 as u8; p = p + 1 159 p = bm_key(d, p, "guard_restarts" as *u8); p = sj_catn(d, p, restarts); d[p] = 44 as u8; p = p + 1 160 p = bm_key(d, p, "tags" as *u8); p = sj_catn(d, p, np[0]); d[p] = 44 as u8; p = p + 1 161 p = bm_key(d, p, "crash_loops" as *u8); p = sj_catn(d, p, crash); d[p] = 44 as u8; p = p + 1 162 p = bm_key(d, p, "stability" as *u8) 163 d[p] = 34 as u8; p = p + 1 164 if crash == 0 { p = sj_cat(d, p, "STABLE" as *u8) } else { p = sj_cat(d, p, "UNSTABLE" as *u8) } 165 d[p] = 34 as u8; p = p + 1 166 d[p] = 44 as u8; p = p + 1 167 // by_tag ranked by respawns desc 168 p = bm_key(d, p, "by_tag" as *u8) 169 d[p] = 91 as u8; p = p + 1 170 var shown: i64 = 0 171 var efirst: i64 = 1 172 var pass: i64 = 0 173 while pass < np[0] { 174 var mi: i64 = 0 - 1 175 var mx: i64 = 0 - 1 176 var k2: i64 = 0 177 while k2 < np[0] { 178 if done[k2] == 0 { if tresp[k2] > mx { mx = tresp[k2]; mi = k2 } } 179 k2 = k2 + 1 180 } 181 if mi >= 0 { 182 done[mi] = 1 183 if shown < BM_TOPN { 184 if efirst == 0 { d[p] = 44 as u8; p = p + 1 } 185 efirst = 0 186 d[p] = 123 as u8; p = p + 1 187 p = bm_key(d, p, "tag" as *u8) 188 d[p] = 34 as u8; p = p + 1 189 p = sj_cat_esc(d, p, q, ts[mi], te[mi], BM_NAME_MAX) 190 d[p] = 34 as u8; p = p + 1 191 d[p] = 44 as u8; p = p + 1 192 p = bm_key(d, p, "respawns" as *u8); p = sj_catn(d, p, tresp[mi]); d[p] = 44 as u8; p = p + 1 193 p = bm_key(d, p, "spawns" as *u8); p = sj_catn(d, p, tspawn[mi]); d[p] = 44 as u8; p = p + 1 194 p = bm_key(d, p, "guard_restarts" as *u8); p = sj_catn(d, p, trest[mi]); d[p] = 44 as u8; p = p + 1 195 var cl: i64 = 0 196 if tresp[mi] >= minloop { cl = 1 } 197 p = bm_key(d, p, "crash_looping" as *u8); p = sj_catn(d, p, cl) 198 d[p] = 125 as u8; p = p + 1 199 shown = shown + 1 200 } 201 } 202 pass = pass + 1 203 } 204 d[p] = 93 as u8; p = p + 1 205 d[p] = 44 as u8; p = p + 1 206 p = bm_key(d, p, "tags_shown" as *u8); p = sj_catn(d, p, shown); d[p] = 44 as u8; p = p + 1 207 p = bm_key(d, p, "tags_capped" as *u8); p = sj_catn(d, p, capped) 208 d[p] = 125 as u8; p = p + 1 209 d[p] = 10 as u8; p = p + 1 210 return p 211} 212// bm_word_after: the non-space word immediately after <lit> in q[s..e) -> dp[0]/dp[1]; 1 if found. 213func bm_word_after(q: *u8, s: i64, e: i64, lit: *u8, dp: *i64) -> i64 { 214 let ll: i64 = sj_vlen(lit) 215 if ll == 0 { return 0 } 216 var i: i64 = s 217 while i + ll <= e { 218 var k: i64 = 0 219 var ok: i64 = 1 220 while k < ll { if q[i+k] != lit[k] { ok = 0; k = ll } else { k = k + 1 } } 221 if ok == 1 { 222 var ws: i64 = i + ll 223 var g1: i64 = 1 224 while g1 == 1 { if ws >= e { g1 = 0 } else { if q[ws] == (32 as u8) { ws = ws + 1 } else { g1 = 0 } } } 225 var we: i64 = ws 226 var g2: i64 = 1 227 while g2 == 1 { if we >= e { g2 = 0 } else { if q[we] == (32 as u8) { g2 = 0 } else { we = we + 1 } } } 228 if we > ws { dp[0] = ws; dp[1] = we; return 1 } 229 return 0 230 } 231 i = i + 1 232 } 233 return 0 234} 235// fleet: the FLEET-ORGAN supervisor log (daemon_supervisor.log) -- richer than the reader-keep log: 236// per-daemon PROBE failures (HUNG=up-but-not-serving, REFUSED=down) + WEDGE-KILL events. A daemon 237// chronically HUNG/REFUSED >= minfail is SICK. This catches the SECOND boot-layer instability the 238// reader-keep miner cannot see (e.g. the nx_mgmt_api / docportal / vroom flap that disrupts ops). 239func bm_fleet_json(logf: *u8, minfail: i64, d: *u8) -> i64 { 240 let q: *u8 = sys_mmap(BM_WIN) 241 let cap: i64 = BM_WIN - 8 242 let n: i64 = bm_read(logf, q, cap) 243 if n < 0 { return -1 } 244 var trunc: i64 = 0 245 if n >= cap { trunc = 1 } 246 let ds: *i64 = sys_mmap(8 * BM_TAGS) as *i64 247 let de: *i64 = sys_mmap(8 * BM_TAGS) as *i64 248 let dhung: *i64 = sys_mmap(8 * BM_TAGS) as *i64 249 let dref: *i64 = sys_mmap(8 * BM_TAGS) as *i64 250 let dwedge: *i64 = sys_mmap(8 * BM_TAGS) as *i64 251 let done: *i64 = sys_mmap(8 * BM_TAGS) as *i64 252 let np: *i64 = sys_mmap(16) as *i64 253 let dp: *i64 = sys_mmap(16) as *i64 254 var lines: i64 = 0 255 var thung: i64 = 0 256 var tref: i64 = 0 257 var twedge: i64 = 0 258 var capped: i64 = 0 259 var i: i64 = 0 260 while i < n { 261 let le: i64 = sj_le(q, i, n) 262 if le > i { 263 lines = lines + 1 264 let isw: i64 = bm_has(q, i, le, "WEDGE-KILL" as *u8) 265 let ish: i64 = bm_has(q, i, le, "probe=HUNG" as *u8) 266 let isr: i64 = bm_has(q, i, le, "probe=REFUSED" as *u8) 267 var got: i64 = 0 268 if isw == 1 { got = bm_word_after(q, i, le, "WEDGE-KILL" as *u8, dp) } else { 269 if ish + isr > 0 { got = bm_word_after(q, i, le, "supervisor:" as *u8, dp) } 270 } 271 if got == 1 { 272 let di: i64 = bm_intern(q, dp[0], dp[1], ds, de, np) 273 if di < 0 { capped = 1 } else { 274 if isw == 1 { dwedge[di] = dwedge[di] + 1; twedge = twedge + 1 } 275 if isw == 0 { if ish == 1 { dhung[di] = dhung[di] + 1; thung = thung + 1 } } 276 if isw == 0 { if isr == 1 { dref[di] = dref[di] + 1; tref = tref + 1 } } 277 } 278 } 279 } 280 i = le + 1 281 } 282 var sick: i64 = 0 283 var k: i64 = 0 284 while k < np[0] { if dhung[k] + dref[k] >= minfail { sick = sick + 1 } k = k + 1 } 285 var p: i64 = 0 286 d[p] = 123 as u8; p = p + 1 287 p = bm_key(d, p, "v" as *u8); p = sj_catn(d, p, 1); d[p] = 44 as u8; p = p + 1 288 p = bm_key(d, p, "tool" as *u8); d[p]=34 as u8;p=p+1; p = sj_cat(d,p,"nx_bootmine" as *u8); d[p]=34 as u8;p=p+1; d[p]=44 as u8;p=p+1 289 p = bm_key(d, p, "averb" as *u8); d[p]=34 as u8;p=p+1; p = sj_cat(d,p,"fleet" as *u8); d[p]=34 as u8;p=p+1; d[p]=44 as u8;p=p+1 290 p = bm_key(d, p, "log" as *u8); d[p]=34 as u8;p=p+1; p = sj_cat_esc(d,p,logf,0,sj_vlen(logf),BM_NAME_MAX); d[p]=34 as u8;p=p+1; d[p]=44 as u8;p=p+1 291 p = bm_key(d, p, "log_bytes" as *u8); p = sj_catn(d,p,n); d[p]=44 as u8;p=p+1 292 p = bm_key(d, p, "truncated" as *u8); p = sj_catn(d,p,trunc); d[p]=44 as u8;p=p+1 293 p = bm_key(d, p, "minfail" as *u8); p = sj_catn(d,p,minfail); d[p]=44 as u8;p=p+1 294 p = bm_key(d, p, "lines" as *u8); p = sj_catn(d,p,lines); d[p]=44 as u8;p=p+1 295 p = bm_key(d, p, "hung" as *u8); p = sj_catn(d,p,thung); d[p]=44 as u8;p=p+1 296 p = bm_key(d, p, "refused" as *u8); p = sj_catn(d,p,tref); d[p]=44 as u8;p=p+1 297 p = bm_key(d, p, "wedge_kills" as *u8); p = sj_catn(d,p,twedge); d[p]=44 as u8;p=p+1 298 p = bm_key(d, p, "daemons" as *u8); p = sj_catn(d,p,np[0]); d[p]=44 as u8;p=p+1 299 p = bm_key(d, p, "sick_daemons" as *u8); p = sj_catn(d,p,sick); d[p]=44 as u8;p=p+1 300 p = bm_key(d, p, "stability" as *u8); d[p]=34 as u8;p=p+1 301 if sick == 0 { if twedge == 0 { p = sj_cat(d,p,"STABLE" as *u8) } else { p = sj_cat(d,p,"DEGRADED" as *u8) } } else { p = sj_cat(d,p,"UNSTABLE" as *u8) } 302 d[p]=34 as u8;p=p+1; d[p]=44 as u8;p=p+1 303 p = bm_key(d, p, "by_daemon" as *u8) 304 d[p] = 91 as u8; p = p + 1 305 var shown: i64 = 0 306 var efirst: i64 = 1 307 var pass: i64 = 0 308 while pass < np[0] { 309 var mi: i64 = 0 - 1 310 var mx: i64 = 0 - 1 311 var k2: i64 = 0 312 while k2 < np[0] { 313 if done[k2] == 0 { let sc: i64 = dhung[k2] + dref[k2] + dwedge[k2]; if sc > mx { mx = sc; mi = k2 } } 314 k2 = k2 + 1 315 } 316 if mi >= 0 { 317 done[mi] = 1 318 if shown < BM_TOPN { 319 if efirst == 0 { d[p] = 44 as u8; p = p + 1 } 320 efirst = 0 321 d[p] = 123 as u8; p = p + 1 322 p = bm_key(d, p, "daemon" as *u8); d[p]=34 as u8;p=p+1; p = sj_cat_esc(d,p,q,ds[mi],de[mi],BM_NAME_MAX); d[p]=34 as u8;p=p+1; d[p]=44 as u8;p=p+1 323 p = bm_key(d, p, "hung" as *u8); p = sj_catn(d,p,dhung[mi]); d[p]=44 as u8;p=p+1 324 p = bm_key(d, p, "refused" as *u8); p = sj_catn(d,p,dref[mi]); d[p]=44 as u8;p=p+1 325 p = bm_key(d, p, "wedge_kills" as *u8); p = sj_catn(d,p,dwedge[mi]); d[p]=44 as u8;p=p+1 326 var sk: i64 = 0 327 if dhung[mi] + dref[mi] >= minfail { sk = 1 } 328 p = bm_key(d, p, "sick" as *u8); p = sj_catn(d,p,sk) 329 d[p] = 125 as u8; p = p + 1 330 shown = shown + 1 331 } 332 } 333 pass = pass + 1 334 } 335 d[p] = 93 as u8; p = p + 1 336 d[p] = 44 as u8; p = p + 1 337 p = bm_key(d, p, "daemons_shown" as *u8); p = sj_catn(d,p,shown); d[p]=44 as u8;p=p+1 338 p = bm_key(d, p, "daemons_capped" as *u8); p = sj_catn(d,p,capped) 339 d[p] = 125 as u8; p = p + 1 340 d[p] = 10 as u8; p = p + 1 341 return p 342} 343func bm_selftest(prefix: *u8) -> i64 { 344 let ctr: *i64 = gv_ctr() 345 gv_head("nx_bootmine selftest -- crash-loop detection over the supervisor log (a stable boot is SOTA)" as *u8) 346 let fx: *u8 = sys_mmap(BM_PATH) 347 var o: i64 = sj_cat(fx, 0, prefix) 348 o = sj_catn(fx, o, sys_now_realtime_sec()) 349 o = sj_cat(fx, o, ".bm" as *u8) 350 fx[o] = 0 as u8 351 let miss: *u8 = sys_mmap(BM_PATH) 352 o = sj_cat(miss, 0, fx) 353 o = sj_cat(miss, o, ".absent" as *u8) 354 miss[o] = 0 as u8 355 // [reader-keep] crash-loops (12 respawns), [guard] restarts once (stable), a non-event line 356 let fd: i64 = sys_openat_wr(fx, BM_MODE_644) 357 let lb: *u8 = sys_mmap(BM_MAGIC_8192) 358 var lo: i64 = 0 359 var r: i64 = 0 360 while r < 12 { 361 lo = sj_cat(lb, lo, " [reader-keep] spawned reader pid=1\n" as *u8) 362 lo = sj_cat(lb, lo, " [reader-keep] reader pid=1 died sig=0 code=1 -> respawn\n" as *u8) 363 r = r + 1 364 } 365 lo = sj_cat(lb, lo, " [guard] restarted nx_torrent_daemon :8097 (was dead)\n" as *u8) 366 lo = sj_cat(lb, lo, "[hostctl] sovereign supervisor: PID-liveness\n" as *u8) 367 sys_write(fd, lb, lo) 368 sys_close(fd) 369 let d: *u8 = sys_mmap(BM_OUT) 370 // T1 missing log fails closed 371 let r1: i64 = bm_mine_json(miss, BM_MINLOOP, d) 372 var ok1: i64 = 0 373 if r1 == (0 - 1) { ok1 = 1 } 374 gv_check("T1 missing log refused (-1) fail closed" as *u8, ok1, ctr) 375 let dl: i64 = bm_mine_json(fx, BM_MINLOOP, d) 376 var ok2: i64 = 0 377 if dl > 0 { if bm_find(d, dl, "\"respawns\":12,\"guard_restarts\":1" as *u8) == 1 { if bm_find(d, dl, "\"spawns\":12" as *u8) == 1 { ok2 = 1 } } } 378 gv_check("T2 exact tallies: 12 respawns, 12 spawns, 1 guard restart" as *u8, ok2, ctr) 379 var ok3: i64 = 0 380 if bm_find(d, dl, "\"tag\":\"reader-keep\",\"respawns\":12,\"spawns\":12,\"guard_restarts\":0,\"crash_looping\":1" as *u8) == 1 { ok3 = 1 } 381 gv_check("T3 reader-keep tag is CRASH-LOOPING (12 respawns >= minloop 10)" as *u8, ok3, ctr) 382 var ok4: i64 = 0 383 if bm_find(d, dl, "\"tag\":\"guard\",\"respawns\":0,\"spawns\":0,\"guard_restarts\":1,\"crash_looping\":0" as *u8) == 1 { ok4 = 1 } 384 gv_check("T4 guard is NOT crash-looping (1 restart, 0 respawns) -- a restart is not a loop" as *u8, ok4, ctr) 385 var ok5: i64 = 0 386 if bm_find(d, dl, "\"crash_loops\":1,\"stability\":\"UNSTABLE\"" as *u8) == 1 { ok5 = 1 } 387 gv_check("T5 one crash loop => UNSTABLE verdict" as *u8, ok5, ctr) 388 // T6 raise minloop above 12 => the same log reads STABLE (threshold is data-driven, honest) 389 let dl6: i64 = bm_mine_json(fx, 99, d) 390 var ok6: i64 = 0 391 if dl6 > 0 { if bm_find(d, dl6, "\"crash_loops\":0,\"stability\":\"STABLE\"" as *u8) == 1 { ok6 = 1 } } 392 gv_check("T6 minloop 99 => 0 crash loops STABLE (threshold data-driven, not baked)" as *u8, ok6, ctr) 393 // T7 tags counted (2: reader-keep, guard); hostctl line has a tag but no event => not counted 394 var ok7: i64 = 0 395 if bm_find(d, dl, "\"tags\":2" as *u8) == 1 { if bm_find(d, dl, "\"tag\":\"hostctl\"" as *u8) == 0 { ok7 = 1 } } 396 gv_check("T7 only event-bearing tags counted (hostctl no-event line excluded)" as *u8, ok7, ctr) 397 // T8/T9 FLEET: the daemon_supervisor.log format (probe=HUNG/REFUSED + WEDGE-KILL per daemon) 398 let ff: *u8 = sys_mmap(BM_PATH) 399 var o8: i64 = sj_cat(ff, 0, prefix) 400 o8 = sj_catn(ff, o8, sys_now_realtime_sec()) 401 o8 = sj_cat(ff, o8, ".ff" as *u8) 402 ff[o8] = 0 as u8 403 let ffd: i64 = sys_openat_wr(ff, BM_MODE_644) 404 var fo: i64 = sj_cat(lb, 0, "supervisor: docportal_admin_daemon probe=HUNG(up-but-not-serving) fails=1\n" as *u8) 405 fo = sj_cat(lb, fo, "supervisor: docportal_admin_daemon probe=HUNG(up-but-not-serving) fails=2\n" as *u8) 406 fo = sj_cat(lb, fo, "supervisor: docportal_admin_daemon probe=HUNG(up-but-not-serving) fails=3\n" as *u8) 407 fo = sj_cat(lb, fo, "supervisor: vroom_daemon probe=REFUSED(down) fails=1\n" as *u8) 408 fo = sj_cat(lb, fo, "supervisor: WEDGE-KILL reader killed=0 (relaunch: primary owner, else backstop)\n" as *u8) 409 fo = sj_cat(lb, fo, "supervisor: crash-loop guard armed\n" as *u8) 410 sys_write(ffd, lb, fo) 411 sys_close(ffd) 412 let fdl: i64 = bm_fleet_json(ff, 3, d) 413 var ok8: i64 = 0 414 if fdl > 0 { if bm_find(d, fdl, "\"hung\":3,\"refused\":1,\"wedge_kills\":1,\"daemons\":3" as *u8) == 1 { if bm_find(d, fdl, "\"daemon\":\"docportal_admin_daemon\",\"hung\":3,\"refused\":0,\"wedge_kills\":0,\"sick\":1" as *u8) == 1 { ok8 = 1 } } } 415 gv_check("T8 fleet: docportal 3 HUNG = SICK, vroom 1 REFUSED, reader 1 WEDGE-KILL, 3 daemons" as *u8, ok8, ctr) 416 var ok9: i64 = 0 417 if fdl > 0 { if bm_find(d, fdl, "\"sick_daemons\":1,\"stability\":\"UNSTABLE\"" as *u8) == 1 { if bm_find(d, fdl, "\"daemon\":\"reader\",\"hung\":0,\"refused\":0,\"wedge_kills\":1,\"sick\":0" as *u8) == 1 { ok9 = 1 } } } 418 gv_check("T9 fleet: 1 sick => UNSTABLE; a WEDGE-KILL-only daemon (reader) is not itself sick (no probe fails)" as *u8, ok9, ctr) 419 let rc: i64 = gv_verdict("BOOTMINE-GATE" as *u8, ctr, "boot stability: crash-loop + fleet probe-failure/wedge-kill detection, data-driven thresholds" as *u8) 420 return rc 421} 422 423func main(argc: i64, argv: *i64) -> i64 { 424 if argc < 3 { sj_puts("usage: nx_bootmine {mine <logfile> [minloop] | fleet <daemon_supervisor.log> [minfail] | selftest <scratch-prefix>}\n" as *u8); sys_exit(2); return 2 } 425 let verb: *u8 = argv[1] as *u8 426 let vl: i64 = sj_vlen(verb) 427 if sj_lit_eq(verb, 0, vl, "selftest" as *u8) == 1 { 428 let rc: i64 = bm_selftest(argv[2] as *u8) 429 sys_exit(rc) 430 return rc 431 } 432 if sj_lit_eq(verb, 0, vl, "mine" as *u8) == 1 { 433 var minloop: i64 = BM_MINLOOP 434 if argc >= 4 { let mz: i64 = sj_atoi_z(argv[3] as *u8); if mz > 0 { minloop = mz } } 435 let d: *u8 = sys_mmap(BM_OUT) 436 let dl: i64 = bm_mine_json(argv[2] as *u8, minloop, d) 437 if dl < 0 { sj_puts("REFUSED log missing or empty\n" as *u8); sys_exit(3); return 3 } 438 sys_write(1, d, dl) 439 sys_exit(0) 440 return 0 441 } 442 if sj_lit_eq(verb, 0, vl, "fleet" as *u8) == 1 { 443 var minfail: i64 = BM_MINLOOP 444 if argc >= 4 { let mz: i64 = sj_atoi_z(argv[3] as *u8); if mz > 0 { minfail = mz } } 445 let d: *u8 = sys_mmap(BM_OUT) 446 let dl: i64 = bm_fleet_json(argv[2] as *u8, minfail, d) 447 if dl < 0 { sj_puts("REFUSED log missing or empty\n" as *u8); sys_exit(3); return 3 } 448 sys_write(1, d, dl) 449 sys_exit(0) 450 return 0 451 } 452 sj_puts("unknown verb\n" as *u8) 453 sys_exit(2) 454 return 2 455}