code wiki / _hdl_build / nx_daemon_supervisor.nx

nx_daemon_supervisor.nx source

↩ module page · 662 lines · 35763 B

1// nx_daemon_supervisor.nx -- SOVEREIGN data-driven daemon supervisor. THE organ that makes daemon 2// lifecycle the ecosystem's job, not Claude's: a daemon is a REGISTRY ROW (data), not compiled into a 3// guard's target list and not nursed by a bash loop. Reads daemons.reg HOT every cycle, responds-health 4// probes each via hp_probe (SERVING / HUNG / REFUSED -- catches the wedge that PID/port checks miss), and 5// REVIVES the dead by fork+execve of the declared argv. 2-consecutive-fail discipline (in-memory, keyed by 6// name) so a single transient probe never triggers a relaunch. On HUNG (wedged, holding the port) it kills 7// the matching process first (the new instance could not bind otherwise), then launches. Zombies reaped 8// every cycle (wait4 WNOHANG). Add a daemon = a registry line + reload -- NO recompile, NO shell. 9// 10// BOUNDED-VSZ DISCIPLINE (2026-07-16): every reusable buffer is allocated ONCE before the loop and reused 11// each cycle. The hot loop performs ZERO sys_mmap. The prior version mmap'd per cycle -- fatally, it read 12// the registry with sys_read_file, whose 4 GiB default cap (used whenever lseek can't size the file) maps 13// 4 GiB of VSZ per cycle and never frees it. That drove VSZ to 116 GB in ~29 cycles, and under heuristic 14// overcommit fork() then returns -ENOMEM (proven: REVIVED ... pid=-12), so revives silently stopped. The 15// registry is now read into a fixed buffer via sys_read; ds_decw is temp-free; VSZ stays flat forever. 16// 17// daemons.reg (pipe-delimited; lines starting # or blank ignored; args are space-separated, no spaces-in-args): 18// <name> | <cwd> | <argv0 [arg1 arg2 ...]> | <health_port> | <arm: revive|watch> 19// health = hp_probe(port): ANY HTTP response on 127.0.0.1:port = healthy (401/404 count). 20// revive = relaunch (and kill-the-wedge) on 2 consecutive non-SERVING probes; watch = detect+log only. 21// license_tier: ORIGINAL module: nishi-core.ops.daemon_supervisor 22import "nx_syscalls.nx" 23import "nx_health_probe.nx" // hp_probe, HP_SERVING, HP_HUNG, HP_REFUSED, HP_BADRESP 24import "nx_metrics_ring.nx" // mr_append/mr_hash -- the supervisor WRITES its own health history (no separate collector) 25const DS_MAGIC_1024: i64 = 1024 26const DS_MAGIC_65536: i64 = 65536 27const DS_MAGIC_65535: i64 = 65535 28const DS_MAGIC_8000: i64 = 8000 29const DS_MAGIC_2048: i64 = 2048 30const DS_MAGIC_2047: i64 = 2047 31const DS_MAGIC_10000: i64 = 10000 32 33const DS_REG: *u8 = "/volume1/homes/elderwesto/nishihost/daemons.reg" as *u8 34const DS_LOG: *u8 = "/volume1/homes/elderwesto/nishihost/daemon_supervisor.log" as *u8 35const DS_CYCLE_SEC: i64 = 15 36const DS_MAX: i64 = 64 37const DS_PROBE_TMO: i64 = 3 38const DS_REGCAP: i64 = 65536 39const DS_STATUS_PORT: i64 = 18095 40const DS_SHARED_SZ: i64 = 8192 41const DS_RING: *u8 = "metrics.ring" as *u8 // sovereign bounded TSDB the supervisor writes inline 42 43func ds_slen(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n } 44func ds_p(s: *u8) -> i64 { sys_write(1, s, ds_slen(s)); return 0 } 45func ds_log(s: *u8) -> i64 { 46 let fd: i64 = sys_openat_append(DS_LOG, 420) 47 if fd >= 0 { sys_write(fd, s, ds_slen(s)); sys_close(fd) } 48 sys_write(1, s, ds_slen(s)) 49 return 0 50} 51// write signed decimal v into out, return len. Temp-free (counts digits, then writes in place) so it can be 52// called many times per cycle without a single allocation. 53func ds_decw(v: i64, out: *u8) -> i64 { 54 var o: i64 = 0 55 var m: i64 = v 56 if m < 0 { out[0] = 45 as u8; o = 1; m = 0 - m } 57 if m == 0 { out[o] = 48 as u8; return o + 1 } 58 var nd: i64 = 1 59 var mm: i64 = m 60 while mm >= 10 { nd = nd + 1; mm = mm / 10 } 61 var i: i64 = nd - 1 62 while m > 0 { out[o + i] = (48 + (m % 10)) as u8; m = m / 10; i = i - 1 } 63 return o + nd 64} 65 66// read the registry into a pre-allocated buffer (reused every cycle). Returns byte count (0 on error). 67// Deliberately NOT sys_read_file: that mmaps a fresh buffer per call (4 GiB when lseek can't size the file) 68// and never frees it -- the exact leak this rewrite exists to kill. 69func ds_read_reg(buf: *u8, cap: i64) -> i64 { 70 let fd: i64 = sys_openat_rd(DS_REG) 71 if fd < 0 { return 0 } 72 let n: i64 = sys_read(fd, buf, cap - 1) 73 sys_close(fd) 74 if n < 0 { return 0 } 75 return n 76} 77 78func ds_sappend(dst: *u8, w: i64, s: *u8) -> i64 { 79 var i: i64 = 0 80 var o: i64 = w 81 while s[i] != (0 as u8) { dst[o] = s[i]; o = o + 1; i = i + 1 } 82 return o 83} 84 85// ---- registry line/field walking (pipe fields) ---- 86func ds_next_line(buf: *u8, pos: i64, end: i64) -> i64 { 87 var p: i64 = pos 88 var go: i64 = 1 89 while go == 1 { if p >= end { go = 0 } else { if (buf[p] as i64) == 10 { p = p + 1; go = 0 } else { p = p + 1 } } } 90 return p 91} 92// end-offset of this line (the index of '\n' or end) 93func ds_line_end(buf: *u8, pos: i64, end: i64) -> i64 { 94 var p: i64 = pos 95 while p < end { if (buf[p] as i64) == 10 { return p } p = p + 1 } 96 return end 97} 98// copy pipe-field #idx (0-based) of the line buf[ls..le) into out (NUL-term, trimmed of edge spaces). ret len. 99func ds_field(buf: *u8, ls: i64, le: i64, idx: i64, out: *u8, cap: i64) -> i64 { 100 // advance fs past `idx` pipes to the start of the target field 101 var fs: i64 = ls 102 var seen: i64 = 0 103 while seen < idx { 104 if fs >= le { out[0] = 0 as u8; return 0 } 105 if (buf[fs] as i64) == 124 { seen = seen + 1 } 106 fs = fs + 1 107 } 108 // field end = next pipe or line end 109 var fe: i64 = fs 110 var g: i64 = 1 111 while g == 1 { if fe >= le { g = 0 } else { if (buf[fe] as i64) == 124 { g = 0 } else { fe = fe + 1 } } } 112 // trim leading spaces 113 var a: i64 = fs 114 var g2: i64 = 1 115 while g2 == 1 { if a >= fe { g2 = 0 } else { if (buf[a] as i64) == 32 { a = a + 1 } else { g2 = 0 } } } 116 // trim trailing spaces / CR 117 var b: i64 = fe 118 var g3: i64 = 1 119 while g3 == 1 { if b <= a { g3 = 0 } else { let c: i64 = buf[b - 1] as i64; if c == 32 { b = b - 1 } else { if c == 13 { b = b - 1 } else { g3 = 0 } } } } 120 var o: i64 = 0 121 var k: i64 = a 122 while k < b { if o < cap - 1 { out[o] = buf[k]; o = o + 1 } k = k + 1 } 123 out[o] = 0 as u8 124 return o 125} 126func ds_atoi(s: *u8) -> i64 { 127 var v: i64 = 0; var i: i64 = 0; var go: i64 = 1 128 while go == 1 { let c: i64 = s[i] as i64; if c < 48 { go = 0 } else { if c > 57 { go = 0 } else { v = v * 10 + (c - 48); i = i + 1 } } } 129 return v 130} 131func ds_streq(a: *u8, b: *u8) -> i64 { 132 var i: i64 = 0 133 while a[i] != (0 as u8) { if a[i] != b[i] { return 0 } i = i + 1 } 134 if b[i] != (0 as u8) { return 0 } 135 return 1 136} 137 138// ---- launch: fork, then (in the CHILD, matching the proven ah_run) build argv, chdir, execve ---- 139func ds_launch(cwd: *u8, cmd: *u8) -> i64 { 140 let pid: i64 = sys_fork() 141 if pid == 0 { 142 let work: *u8 = sys_mmap(DS_MAGIC_1024) 143 var n: i64 = 0 144 while cmd[n] != (0 as u8) { work[n] = cmd[n]; n = n + 1 } 145 work[n] = 0 as u8 146 let argv: *i64 = sys_mmap(64 * 8) as *i64 147 var ac: i64 = 0 148 var i: i64 = 0 149 var scan: i64 = 1 150 while scan == 1 { 151 var sk: i64 = 1 152 while sk == 1 { if i >= n { sk = 0 } else { if (work[i] as i64) == 32 { work[i] = 0 as u8; i = i + 1 } else { sk = 0 } } } 153 if i >= n { scan = 0 } 154 else { 155 if (work[i] as i64) == 34 { 156 // quoted token: "..." = ONE argv entry, quotes stripped -- needed for spaces-in-args 157 // (reader's live argv has the single argument `Nishi Wiki`, /proc-proven) 158 work[i] = 0 as u8 159 i = i + 1 160 if ac < 63 { argv[ac] = (((work as i64) + i)); ac = ac + 1 } 161 var qk: i64 = 1 162 while qk == 1 { if i >= n { qk = 0 } else { if (work[i] as i64) == 34 { work[i] = 0 as u8; i = i + 1; qk = 0 } else { i = i + 1 } } } 163 } 164 else { 165 if ac < 63 { argv[ac] = (((work as i64) + i)); ac = ac + 1 } 166 var tk: i64 = 1 167 while tk == 1 { if i >= n { tk = 0 } else { if (work[i] as i64) == 32 { tk = 0 } else { i = i + 1 } } } 168 } 169 } 170 } 171 argv[ac] = 0 172 let envp: *i64 = sys_mmap(8 * 4) as *i64 173 envp[0] = ("PATH=/usr/bin:/bin:/usr/local/bin" as *u8) as i64 174 envp[1] = ("HOME=/volume1/homes/elderwesto" as *u8) as i64 175 envp[2] = 0 176 sys_chdir(cwd) 177 let nul: i64 = sys_openat_rd("/dev/null\x00" as *u8) 178 if nul >= 0 { sys_dup3(nul, 0, 0) } 179 sys_execve_clean(argv[0] as *u8, argv, envp) 180 sys_exit(127) 181 } 182 return pid 183} 184 185// ---- kill any process whose /proc/<pid>/cmdline contains `needle` (used on HUNG to free the wedged port). 186// dbuf(dents)/path/cmdbuf allocated ONCE per call and munmap'd on exit -- NEVER sys_read_file (/proc lseek 187// is unknowable, so its 4 GiB fallback cap would map 4 GiB of VSZ per pid scanned). Runs only on HUNG revive. 188func ds_kill_wedged(needle: *u8) -> i64 { 189 let nlen: i64 = ds_slen(needle) 190 let dfd: i64 = sys_openat_rd("/proc\x00" as *u8) 191 if dfd < 0 { return 0 } 192 let dbuf: *u8 = sys_mmap(DS_MAGIC_65536) 193 let path: *u8 = sys_mmap(64) 194 let cmdbuf: *u8 = sys_mmap(DS_MAGIC_65536) 195 var killed: i64 = 0 196 var reading: i64 = 1 197 while reading == 1 { 198 let dn: i64 = sys_getdents64(dfd, dbuf, DS_MAGIC_65536) 199 if dn <= 0 { reading = 0 } 200 else { 201 var off: i64 = 0 202 while off < dn { 203 let recp: *u8 = (((dbuf as i64) + off)) as *u8 204 let reclen: i64 = dirent_reclen(recp) 205 let nm: *u8 = dirent_name(recp) 206 // numeric dir name -> a pid 207 if nm[0] >= (48 as u8) { if nm[0] <= (57 as u8) { 208 var pi: i64 = 0 209 let pre: *u8 = "/proc/" as *u8 210 while pre[pi] != (0 as u8) { path[pi] = pre[pi]; pi = pi + 1 } 211 var qi: i64 = 0 212 while nm[qi] != (0 as u8) { path[pi] = nm[qi]; pi = pi + 1; qi = qi + 1 } 213 let suf: *u8 = "/cmdline" as *u8 214 var si: i64 = 0 215 while suf[si] != (0 as u8) { path[pi] = suf[si]; pi = pi + 1; si = si + 1 } 216 path[pi] = 0 as u8 217 let cfd: i64 = sys_openat_rd(path) 218 if cfd >= 0 { 219 let clen: i64 = sys_read(cfd, cmdbuf, DS_MAGIC_65535) 220 sys_close(cfd) 221 if clen > 0 { 222 // cmdline is NUL-separated; replace NULs with spaces for substring search 223 var ci: i64 = 0 224 while ci < clen { if (cmdbuf[ci] as i64) == 0 { cmdbuf[ci] = 32 as u8 } ci = ci + 1 } 225 var found: i64 = 0 226 if clen >= nlen { 227 var s: i64 = 0 228 let last: i64 = clen - nlen 229 while s <= last { 230 var m: i64 = 0 231 var eq: i64 = 1 232 while m < nlen { if cmdbuf[s + m] != needle[m] { eq = 0; m = nlen } m = m + 1 } 233 if eq == 1 { found = 1; s = last + 1 } else { s = s + 1 } 234 } 235 } 236 if found == 1 { nx_kill(ds_atoi(nm), 9); killed = killed + 1 } 237 } 238 } 239 } } 240 off = off + reclen 241 } 242 } 243 } 244 sys_close(dfd) 245 sys_munmap(dbuf, DS_MAGIC_65536) 246 sys_munmap(path, 64) 247 sys_munmap(cmdbuf, DS_MAGIC_65536) 248 return killed 249} 250 251// ---- resolve the registry cmd's argv0 to an absolute binary path: "./x"|"x" -> cwd/x ; "/abs" -> as-is ---- 252func ds_resolve_bin(cwd: *u8, cmd: *u8, out: *u8) -> i64 { 253 var o: i64 = 0 254 var s: i64 = 0 255 if cmd[0] != (47 as u8) { 256 var ci: i64 = 0 257 while cwd[ci] != (0 as u8) { out[o] = cwd[ci]; o = o + 1; ci = ci + 1 } 258 if o > 0 { if out[o - 1] != (47 as u8) { out[o] = 47 as u8; o = o + 1 } } 259 if cmd[0] == (46 as u8) { if cmd[1] == (47 as u8) { s = 2 } } 260 } 261 var go: i64 = 1 262 while go == 1 { 263 if cmd[s] == (0 as u8) { go = 0 } 264 else { if (cmd[s] as i64) == 32 { go = 0 } 265 else { out[o] = cmd[s]; o = o + 1; s = s + 1 } } 266 } 267 out[o] = 0 as u8 268 return o 269} 270 271// ---- exe-identity sweep (ports the tools_selfheal.sh stale-inode port-theft guard into the organ) ---- 272// A daemon can look "healthy" while the WRONG binary serves: an instance running from a DELETED inode 273// (pre-deploy binary, or a port thief) responds fine but is stale code -- responds-health cannot see it 274// (this exact class ate a day of post-deploy checks on :18096). Identity = readlink /proc/<pid>/exe vs 275// the registry-resolved binary path. mode 0: return 1 if any "<bin> (deleted)" runner exists. mode 1: 276// kill -9 EVERY match (live or deleted -- mirrors tools_selfheal) and return the kill count. BY DESIGN 277// a deploy (mv new ELF over old) flips every revive row to the new binary within one cycle. Buffers are 278// caller-hoisted (bounded-VSZ); the readlink itself munmaps its own scratch. 279func ds_exe_sweep(bin: *u8, mode: i64, dbuf: *u8, path: *u8, rl: *u8) -> i64 { 280 let blen: i64 = ds_slen(bin) 281 let dfd: i64 = sys_openat_rd("/proc\x00" as *u8) 282 if dfd < 0 { return 0 } 283 var hit: i64 = 0 284 var reading: i64 = 1 285 while reading == 1 { 286 let dn: i64 = sys_getdents64(dfd, dbuf, DS_MAGIC_65536) 287 if dn <= 0 { reading = 0 } 288 else { 289 var off: i64 = 0 290 while off < dn { 291 let recp: *u8 = (((dbuf as i64) + off)) as *u8 292 let reclen: i64 = dirent_reclen(recp) 293 let nm: *u8 = dirent_name(recp) 294 if nm[0] >= (48 as u8) { if nm[0] <= (57 as u8) { 295 var pi: i64 = 0 296 let pre: *u8 = "/proc/" as *u8 297 while pre[pi] != (0 as u8) { path[pi] = pre[pi]; pi = pi + 1 } 298 var qi: i64 = 0 299 while nm[qi] != (0 as u8) { path[pi] = nm[qi]; pi = pi + 1; qi = qi + 1 } 300 let suf: *u8 = "/exe" as *u8 301 var si: i64 = 0 302 while suf[si] != (0 as u8) { path[pi] = suf[si]; pi = pi + 1; si = si + 1 } 303 path[pi] = 0 as u8 304 let n: i64 = sys_readlinkat(path, rl, 300) 305 if n >= blen { 306 var eq: i64 = 1 307 var k: i64 = 0 308 while k < blen { if rl[k] != bin[k] { eq = 0; k = blen } k = k + 1 } 309 if eq == 1 { 310 var kind: i64 = 0 311 if n == blen { kind = 1 } 312 if n == blen + 10 { 313 let dsx: *u8 = " (deleted)" as *u8 314 var dj: i64 = 0 315 var deq: i64 = 1 316 while dj < 10 { if rl[blen + dj] != dsx[dj] { deq = 0; dj = 10 } dj = dj + 1 } 317 if deq == 1 { kind = 2 } 318 } 319 if mode == 0 { if kind == 2 { hit = 1 } } 320 if mode == 1 { if kind > 0 { nx_kill(ds_atoi(nm), 9); hit = hit + 1 } } 321 } 322 } 323 } } 324 off = off + reclen 325 } 326 } 327 } 328 sys_close(dfd) 329 return hit 330} 331 332// ---- registry integrity gate (2026-07-16): the maturity census surfaced that daemons.reg is an 333// owner-writable plain file -> a local write injects revive-exec. We fork+exec nx_reg_sign VERIFY each 334// cycle (composition -- keeps the never-brick supervisor free of crypto) and apply a FAIL-SAFE policy 335// (below in main). The check itself can NEVER take the fleet down: any non-clean result falls to grace. 336// exit-code extract: signaled/stopped -> -1 (treated as check-unavailable, not tamper). 337func ds_exitcode(status: i64) -> i64 { 338 if (status & 127) != 0 { return 0 - 1 } 339 return (status >> 8) & 255 340} 341// returns: 0 valid · 3 invalid(TAMPER) · 4 sig-absent(grace) · 126 tool-missing · -1 signaled/timeout 342func ds_verify_reg() -> i64 { 343 let pid: i64 = sys_fork() 344 if pid == 0 { 345 let nul: i64 = sys_openat_rd("/dev/null\x00" as *u8) 346 if nul >= 0 { sys_dup3(nul, 1, 0); sys_dup3(nul, 2, 0) } 347 let argv: *i64 = sys_mmap(8 * 6) as *i64 348 argv[0] = ("./nx_reg_sign.elf" as *u8) as i64 349 argv[1] = ("verify" as *u8) as i64 350 argv[2] = ("daemons.reg" as *u8) as i64 351 argv[3] = ("tools_cap_secret.key" as *u8) as i64 352 argv[4] = 0 353 let envp: *i64 = sys_mmap(8 * 2) as *i64 354 envp[0] = 0 355 sys_execve_clean("./nx_reg_sign.elf" as *u8, argv, envp) 356 sys_exit(126) 357 } 358 if pid < 0 { return 0 - 1 } 359 let st: *i64 = sys_mmap(8) as *i64 360 var waited: i64 = 0 361 var rc: i64 = 0 - 1 362 var done: i64 = 0 363 while done == 0 { 364 let r: i64 = sys_wait4(pid, st, 1) 365 if r == pid { rc = ds_exitcode(st[0]); done = 1 } 366 else { 367 if waited >= DS_MAGIC_8000 { nx_kill(pid, 9); sys_wait4(pid, st, 0); done = 1 } 368 sys_sleep_ms(50) 369 waited = waited + 50 370 } 371 } 372 sys_munmap(st as *u8, 8) 373 return rc 374} 375 376// ---- sovereign /status server (forked child): serves the seqlock-shared fleet snapshot over HTTP on 377// 127.0.0.1:DS_STATUS_PORT. Replaces status FILES (tsv) entirely -- sovereign up and down: organ memory -> 378// shared page -> HTTP text only at the boundary (interop@boundary, sovereign@core). Exact Content-Length 379// (CL-LAW). The seqlock (seq odd=writer-active, re-check after copy) keeps reads tear-free without locks. 380func ds_status_server(shm: *u8) -> i64 { 381 let shq: *i64 = shm as *i64 382 let lfd: i64 = sys_socket(AF_INET, SOCK_STREAM, 0) 383 if lfd < 0 { sys_exit(3) } 384 let one: *i64 = sys_mmap(8) as *i64 385 one[0] = 1 386 sys_setsockopt(lfd, SOL_SOCKET, SO_REUSEADDR, one as *u8, 4) 387 let sa: *u8 = sys_mmap(16) 388 hp_sockaddr(sa, DS_STATUS_PORT, 127, 0, 0, 1) 389 if sys_bind(lfd, sa, 16) < 0 { sys_exit(4) } 390 sys_listen(lfd, 16) 391 let req: *u8 = sys_mmap(DS_MAGIC_2048) 392 let body: *u8 = sys_mmap(DS_SHARED_SZ) 393 let out: *u8 = sys_mmap(DS_SHARED_SZ + 256) 394 var run: i64 = 1 395 while run == 1 { 396 let afd: i64 = sys_accept(lfd) 397 if afd >= 0 { 398 sys_set_socket_timeout(afd, 3) 399 sys_read(afd, req, DS_MAGIC_2047) 400 var blen: i64 = 0 401 var got: i64 = 0 402 var tries: i64 = 0 403 while got == 0 { 404 let s1: i64 = shq[0] 405 if (s1 % 2) == 0 { 406 var bl: i64 = shq[1] 407 if bl > DS_SHARED_SZ - 16 { bl = DS_SHARED_SZ - 16 } 408 if bl < 0 { bl = 0 } 409 var ci: i64 = 0 410 while ci < bl { body[ci] = shm[16 + ci]; ci = ci + 1 } 411 if shq[0] == s1 { blen = bl; got = 1 } 412 } 413 tries = tries + 1 414 if tries > DS_MAGIC_10000 { got = 1 } 415 } 416 var w: i64 = 0 417 w = ds_sappend(out, w, "HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\nConnection: close\r\nContent-Length: " as *u8) 418 w = w + ds_decw(blen, (((out as i64) + w)) as *u8) 419 out[w] = 13 as u8; w = w + 1 420 out[w] = 10 as u8; w = w + 1 421 out[w] = 13 as u8; w = w + 1 422 out[w] = 10 as u8; w = w + 1 423 var bi: i64 = 0 424 while bi < blen { out[w] = body[bi]; w = w + 1; bi = bi + 1 } 425 sys_write(afd, out, w) 426 sys_close(afd) 427 } 428 } 429 return 0 430} 431 432func main() -> i64 { 433 ds_log("nx_daemon_supervisor: LIVE -- data-driven fleet supervision from daemons.reg (responds-health + tls-probe + exe-identity + revive + /status, bounded-VSZ)\n" as *u8) 434 // per-name consecutive-fail state (parallel arrays, matched by name each cycle). names[] entries are 435 // persisted name copies (mmap'd once per NEW name, bounded to DS_MAX -- not a per-cycle allocation). 436 let names: *i64 = sys_mmap(DS_MAX * 8) as *i64 437 let fails: *i64 = sys_mmap(DS_MAX * 8) as *i64 438 var nstate: i64 = 0 439 // sovereign /status surface: THIS loop writes the fleet snapshot into a fork-shared seqlock page each 440 // cycle; a forked child serves it on 127.0.0.1:DS_STATUS_PORT. No tsv, no status files, no shell. 441 let shm: *u8 = sys_mmap_shared(DS_SHARED_SZ) 442 let shq: *i64 = shm as *i64 443 shq[0] = 0 444 shq[1] = 0 445 let sspid: i64 = sys_fork() 446 if sspid == 0 { ds_status_server(shm); sys_exit(0) } 447 var cyc: i64 = 0 448 // --- hoisted reusable buffers: allocated ONCE, reused every cycle. The loop below does ZERO sys_mmap. --- 449 let rst: *i64 = sys_mmap(8) as *i64 450 let regbuf: *u8 = sys_mmap(DS_REGCAP) 451 let nm: *u8 = sys_mmap(64) 452 let cwd: *u8 = sys_mmap(256) 453 let cmd: *u8 = sys_mmap(512) 454 let pb: *u8 = sys_mmap(16) 455 let arm: *u8 = sys_mmap(16) 456 let pt: *u8 = sys_mmap(16) 457 let lb: *u8 = sys_mmap(256) 458 let rb: *u8 = sys_mmap(256) 459 let sbin: *u8 = sys_mmap(320) 460 let sdbuf: *u8 = sys_mmap(DS_MAGIC_65536) 461 let spath: *u8 = sys_mmap(64) 462 let srl: *u8 = sys_mmap(320) 463 let stat: *u8 = sys_mmap(DS_SHARED_SZ) 464 let goodbuf: *u8 = sys_mmap(DS_REGCAP) // last integrity-VALID registry bytes (held on tamper) 465 var goodlen: i64 = 0 466 var trust_state: i64 = 0 - 1 // prev integrity state, for edge-triggered (no-spam) logging 467 var forever: i64 = 1 468 while forever == 1 { 469 // reap any exited launched children so they never zombie (reuses rst) 470 var reap: i64 = 1 471 while reap == 1 { if sys_wait4(0 - 1, rst, 1) > 0 { reap = 1 } else { reap = 0 } } 472 473 cyc = cyc + 1 474 let now: i64 = sys_now_realtime_sec() // one timestamp for this cycle's TSDB samples 475 var sw: i64 = 0 476 sw = ds_sappend(stat, sw, "nx_daemon_supervisor fleet (daemons.reg) cycle=" as *u8) 477 sw = sw + ds_decw(cyc, (((stat as i64) + sw)) as *u8) 478 479 var rlen: i64 = ds_read_reg(regbuf, DS_REGCAP) 480 // ---- INTEGRITY GATE (verify-before-apply; FAIL-SAFE; never bricks) ---- 481 // signing is a DELIBERATE act (nx_reg_sign sign), so an un-re-signed change = "changed outside the 482 // signer" = the threat. valid -> apply + cache good. sig-absent -> grace (migration). invalid -> 483 // HOLD last-good (tamper caught + surfaced), or cold-start grace if no good yet. check-unavailable 484 // (tool missing/timeout) -> grace + a DISTINCT note (never a false tamper alarm). 485 let vrc: i64 = ds_verify_reg() 486 var trust: *u8 = "signed" as *u8 487 var tcode: i64 = 0 488 if vrc == 0 { 489 goodlen = rlen 490 var gi: i64 = 0; while gi < rlen { goodbuf[gi] = regbuf[gi]; gi = gi + 1 } 491 } else { if vrc == 4 { 492 trust = "unsigned-grace" as *u8; tcode = 1 493 goodlen = rlen 494 var gj: i64 = 0; while gj < rlen { goodbuf[gj] = regbuf[gj]; gj = gj + 1 } 495 } else { if vrc == 3 { 496 if goodlen > 0 { 497 trust = "HELD-TAMPER" as *u8; tcode = 2 498 var gk: i64 = 0; while gk < goodlen { regbuf[gk] = goodbuf[gk]; gk = gk + 1 } 499 rlen = goodlen 500 } else { trust = "UNVERIFIED-coldstart" as *u8; tcode = 3 } 501 } else { 502 // tool missing / signaled / timeout: cannot claim integrity, but do not brick or false-alarm 503 trust = "check-unavailable" as *u8; tcode = 4 504 if goodlen == 0 { goodlen = rlen; var gm: i64 = 0; while gm < rlen { goodbuf[gm] = regbuf[gm]; gm = gm + 1 } } 505 } } } 506 // edge-triggered security log (only on transition -- no 15s spam) 507 if tcode != trust_state { 508 var lw: i64 = 0 509 if tcode == 2 { lw = ds_sappend(lb, lw, "supervisor: SECURITY daemons.reg signature INVALID -> HOLDING last-good, refusing to apply (run nx_reg_sign after legit edits)\n" as *u8) } 510 else { if tcode == 3 { lw = ds_sappend(lb, lw, "supervisor: SECURITY daemons.reg INVALID at cold-start, no last-good -> grace-applied (CRITICAL: sign the registry)\n" as *u8) } 511 else { if tcode == 1 { lw = ds_sappend(lb, lw, "supervisor: NOTE daemons.reg UNSIGNED -> grace; run nx_reg_sign sign to enable tamper-evidence\n" as *u8) } 512 else { if tcode == 4 { lw = ds_sappend(lb, lw, "supervisor: NOTE integrity check unavailable (nx_reg_sign.elf?) -> grace-applied\n" as *u8) } 513 else { lw = ds_sappend(lb, lw, "supervisor: daemons.reg integrity OK (signed)\n" as *u8) } } } } 514 lb[lw] = 0 as u8 515 ds_log(lb) 516 trust_state = tcode 517 } 518 sw = ds_sappend(stat, sw, " integrity=" as *u8) 519 sw = ds_sappend(stat, sw, trust) 520 stat[sw] = 10 as u8 521 sw = sw + 1 522 523 if rlen > 0 { 524 var pos: i64 = 0 525 while pos < rlen { 526 // skip blank / comment lines 527 if (regbuf[pos] as i64) == 35 { pos = ds_next_line(regbuf, pos, rlen) } 528 else { if (regbuf[pos] as i64) == 10 { pos = pos + 1 } 529 else { if (regbuf[pos] as i64) == 13 { pos = pos + 1 } 530 else { 531 let le: i64 = ds_line_end(regbuf, pos, rlen) 532 let nn: i64 = ds_field(regbuf, pos, le, 0, nm, 64) 533 ds_field(regbuf, pos, le, 1, cwd, 256) 534 ds_field(regbuf, pos, le, 2, cmd, 512) 535 ds_field(regbuf, pos, le, 3, pb, 16) 536 ds_field(regbuf, pos, le, 4, arm, 16) 537 ds_field(regbuf, pos, le, 5, pt, 16) // probe type: "tls" or "" (default http) 538 if nn > 0 { 539 let port: i64 = ds_atoi(pb) 540 // find/allocate fail-state slot for this name 541 var slot: i64 = 0 - 1 542 var si: i64 = 0 543 while si < nstate { if ds_streq((names[si]) as *u8, nm) == 1 { slot = si; si = nstate } si = si + 1 } 544 if slot < 0 { if nstate < DS_MAX { 545 let np: *u8 = sys_mmap(64); var ci: i64 = 0; while nm[ci] != (0 as u8) { np[ci] = nm[ci]; ci = ci + 1 } np[ci] = 0 as u8 546 names[nstate] = np as i64; fails[nstate] = 0; slot = nstate; nstate = nstate + 1 547 } } 548 // arm semantics ladder: watch (observe) < guard (kill wedges + stale inodes; the 549 // PRIMARY owner relaunches -- control-plane wedge-arm parity) < revive (guard + the 550 // organ itself relaunches when nothing else does). 551 let is_rev: i64 = ds_streq(arm, "revive" as *u8) 552 let is_grd: i64 = ds_streq(arm, "guard" as *u8) 553 // exe-identity guard (revive+guard rows): a stale-inode runner serves "healthy" 554 // from pre-deploy code. KILL every match, then DON'T launch here -- a faster primary 555 // owner (nx_hostctl's ppid-respawn, seconds) relaunches from the new inode and the 556 // next probe sees SERVING; with no primary, the normal 2-fail discipline backstops. 557 // Launching here would contest the bind against the primary's respawn loop. 558 if is_rev + is_grd >= 1 { 559 ds_resolve_bin(cwd, cmd, sbin) 560 if ds_exe_sweep(sbin, 0, sdbuf, spath, srl) == 1 { 561 let nk: i64 = ds_exe_sweep(sbin, 1, sdbuf, spath, srl) 562 var rw: i64 = 0 563 let f1: *u8 = "supervisor: EXE-PURGE " as *u8; var fi: i64 = 0; while f1[fi] != (0 as u8) { rb[rw] = f1[fi]; rw = rw + 1; fi = fi + 1 } 564 var fn: i64 = 0; while nm[fn] != (0 as u8) { rb[rw] = nm[fn]; rw = rw + 1; fn = fn + 1 } 565 let f2: *u8 = " stale-inode killed=" as *u8; fi = 0; while f2[fi] != (0 as u8) { rb[rw] = f2[fi]; rw = rw + 1; fi = fi + 1 } 566 rw = rw + ds_decw(nk, (((rb as i64) + rw)) as *u8) 567 let f3: *u8 = " (relaunch: primary owner, else 2-fail backstop)" as *u8; fi = 0; while f3[fi] != (0 as u8) { rb[rw] = f3[fi]; rw = rw + 1; fi = fi + 1 } 568 rb[rw] = 10 as u8; rw = rw + 1; rb[rw] = 0 as u8 569 ds_log(rb) 570 } 571 } 572 var v: i64 = 0 573 if ds_streq(pt, "tls" as *u8) == 1 { v = hp_probe_tls(port, DS_PROBE_TMO) } 574 else { if ds_streq(pt, "ws" as *u8) == 1 { v = hp_probe_ws(port, DS_PROBE_TMO) } 575 else { v = hp_probe(port, DS_PROBE_TMO) } } 576 if v == HP_SERVING { if slot >= 0 { fails[slot] = 0 } } 577 else { 578 if slot >= 0 { fails[slot] = fails[slot] + 1 } 579 let fc: i64 = fails[slot] 580 // log the down/hung sighting (reuses lb) 581 var w: i64 = 0 582 let m1: *u8 = "supervisor: " as *u8; var mi: i64 = 0; while m1[mi] != (0 as u8) { lb[w] = m1[mi]; w = w + 1; mi = mi + 1 } 583 var qi: i64 = 0; while nm[qi] != (0 as u8) { lb[w] = nm[qi]; w = w + 1; qi = qi + 1 } 584 let m2: *u8 = " probe=" as *u8; mi = 0; while m2[mi] != (0 as u8) { lb[w] = m2[mi]; w = w + 1; mi = mi + 1 } 585 let pv: *u8 = hp_name(v); var vi: i64 = 0; while pv[vi] != (0 as u8) { lb[w] = pv[vi]; w = w + 1; vi = vi + 1 } 586 let m3: *u8 = " fails=" as *u8; mi = 0; while m3[mi] != (0 as u8) { lb[w] = m3[mi]; w = w + 1; mi = mi + 1 } 587 w = w + ds_decw(fc, (((lb as i64) + w)) as *u8) 588 lb[w] = 10 as u8; w = w + 1; lb[w] = 0 as u8 589 // suppress steady-state down-spam on watch rows: log the transition (fails 1-3), 590 // then resurface every 40th cycle (~10 min). /status always shows live truth. 591 if fc <= 3 { ds_log(lb) } else { if (fc % 40) == 0 { ds_log(lb) } } 592 // ARMED remediation on 2 consecutive fails, split by verdict: 593 // HUNG -> KILL-ONLY (frees the wedged port; primary respawns, else the 594 // REFUSED path backstops next cycle -- never contest the bind) 595 // REFUSED -> revive rows launch (nothing is listening; safe to bind) 596 // BADRESP -> wrong process holds the port; surfaced via log//status only 597 if fc >= 2 { if is_rev + is_grd >= 1 { 598 if v == HP_HUNG { 599 let wk: i64 = ds_kill_wedged(cmd) 600 var ww: i64 = 0 601 let w1: *u8 = "supervisor: WEDGE-KILL " as *u8; var wi: i64 = 0; while w1[wi] != (0 as u8) { rb[ww] = w1[wi]; ww = ww + 1; wi = wi + 1 } 602 var wn: i64 = 0; while nm[wn] != (0 as u8) { rb[ww] = nm[wn]; ww = ww + 1; wn = wn + 1 } 603 let w2: *u8 = " killed=" as *u8; wi = 0; while w2[wi] != (0 as u8) { rb[ww] = w2[wi]; ww = ww + 1; wi = wi + 1 } 604 ww = ww + ds_decw(wk, (((rb as i64) + ww)) as *u8) 605 let w3: *u8 = " (relaunch: primary owner, else backstop)" as *u8; wi = 0; while w3[wi] != (0 as u8) { rb[ww] = w3[wi]; ww = ww + 1; wi = wi + 1 } 606 rb[ww] = 10 as u8; ww = ww + 1; rb[ww] = 0 as u8 607 ds_log(rb) 608 } 609 if v == HP_REFUSED { if is_rev == 1 { 610 let newpid: i64 = ds_launch(cwd, cmd) 611 var rw: i64 = 0 612 let r1: *u8 = "supervisor: REVIVED " as *u8; var ri: i64 = 0; while r1[ri] != (0 as u8) { rb[rw] = r1[ri]; rw = rw + 1; ri = ri + 1 } 613 var ni: i64 = 0; while nm[ni] != (0 as u8) { rb[rw] = nm[ni]; rw = rw + 1; ni = ni + 1 } 614 let r2: *u8 = " pid=" as *u8; ri = 0; while r2[ri] != (0 as u8) { rb[rw] = r2[ri]; rw = rw + 1; ri = ri + 1 } 615 rw = rw + ds_decw(newpid, (((rb as i64) + rw)) as *u8) 616 rb[rw] = 10 as u8; rw = rw + 1; rb[rw] = 0 as u8 617 ds_log(rb) 618 fails[slot] = 0 619 } } 620 } } 621 } 622 // SOVEREIGN TSDB (folded in 2026-07-16, operator "no sprawl"): the PRODUCER writes 623 // its own sample -- the supervisor already computed v (this cycle's probe) + the fail 624 // count, so it appends inline. No separate collector, no HTTP self-poll (that was 625 // sprawl re-deriving this organ's own output). Fail-safe: mr_append returns <0 on any 626 // error and is ignored -- a bounded data-file append can never brick (rule 26 = hw). 627 var rf: i64 = 0 628 if slot >= 0 { rf = fails[slot] } 629 mr_append(DS_RING, now, mr_hash(nm), v, rf) 630 // /status row: name verdict fails arm probe :port (bounded append) 631 if sw < DS_SHARED_SZ - 256 { 632 sw = ds_sappend(stat, sw, nm) 633 sw = ds_sappend(stat, sw, " " as *u8) 634 sw = ds_sappend(stat, sw, hp_name(v)) 635 sw = ds_sappend(stat, sw, " fails=" as *u8) 636 var fv: i64 = 0 637 if slot >= 0 { fv = fails[slot] } 638 sw = sw + ds_decw(fv, (((stat as i64) + sw)) as *u8) 639 sw = ds_sappend(stat, sw, " " as *u8) 640 sw = ds_sappend(stat, sw, arm) 641 sw = ds_sappend(stat, sw, " " as *u8) 642 if pt[0] == (0 as u8) { sw = ds_sappend(stat, sw, "http" as *u8) } else { sw = ds_sappend(stat, sw, pt) } 643 sw = ds_sappend(stat, sw, " :" as *u8) 644 sw = sw + ds_decw(port, (((stat as i64) + sw)) as *u8) 645 stat[sw] = 10 as u8 646 sw = sw + 1 647 } 648 } 649 pos = ds_next_line(regbuf, pos, rlen) 650 } } } 651 } 652 } 653 // seqlock publish of this cycle's snapshot (odd seq = writer active; readers re-check) 654 shq[0] = shq[0] + 1 655 var pj: i64 = 0 656 while pj < sw { shm[16 + pj] = stat[pj]; pj = pj + 1 } 657 shq[1] = sw 658 shq[0] = shq[0] + 1 659 sys_sleep_ms(DS_CYCLE_SEC * 1000) 660 } 661 return 0 662}