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}