code wiki / _hdl_build / nx_hostctl.nx
nx_hostctl.nx source
↩ module page · 3750 lines · 262144 B
1// nx_hostctl.nx -- the PURE-NISHI host control plane (operator: "no .sh or any non nishi stuff in the
2// mix... pure enterprise S-class hosting and deployment"). Retires nishi_supervisor.sh. Two subcommands,
3// argv-driven, all via sovereign syscalls -- NO shell, NO cp/mv/pkill:
4// supervise : fork/execve the sites daemon, record its PID, wait4; respawn on death (crash OR deploy-kill).
5// deploy : atomically publish the staged *.new artifacts (sys_renameat), +x the new binary (nx_chmod),
6// then nx_kill the running daemon -> supervise respawns the NEW binary. Brief restart only
7// (FD-passing/SCM_RIGHTS is the future zero-downtime rung). CONTENT hot-update needs NO deploy:
8// the router serves the doc-root file per request, so pushing index.html is live next request.
9// selftest : LOCAL Engineer gate of the deploy primitives (atomic rename + pidfile + kill) -- no NAS.
10// license_tier: ORIGINAL
11//
12// SUPERVISION UPGRADE 2026-06-16 (closes hosting_research gaps #5 health-probe + #4 restart-loop-guard):
13// cmd_supervise no longer trusts PID-liveness alone. For PLAINTEXT daemons it BLACK-BOX health-probes the
14// port (nx_health_probe) and restarts a HUNG daemon (process up + bound but not serving) -- the failure
15// systemd PID-liveness and a LISTEN check both miss. Every restart (crash OR hang) is gated by the
16// crash-loop guard (nx_restart_guard) so a daemon that keeps dying/wedging backs off instead of spinning.
17// The TLS daemon (sites.elf:8443) stays PID-only -- a plaintext GET to a TLS port would false-HUNG; a
18// TLS-aware serving probe is the next rung (noted, not faked).
19import "nx_syscalls.nx"
20import "nx_file_install.nx"
21import "nx_connect.nx" // bounded connect: a raw sys_connect hangs ~127s on a black-holed host
22import "nx_health_probe.nx" // hp_probe / HP_HUNG -- real serving health
23import "nx_restart_guard.nx" // rg_should_restart / rg_backoff_ms -- crash-loop guard
24import "nx_os_introspect.nx" // pon_port_owner_pid -- the os-axis /proc perception rung (who REALLY holds a port)
25import "nx_fd_hygiene.nx" // nx_fd_scrub_inherited -- drop inherited fds so a leaked listen socket never propagates into forked daemons
26import "nx_proc_snapshot.nx" // ps_alive_or_direct / ps_refresh -- ONE /proc walk per poll (seq1318)
27import "nx_buildrun_verdict_lib.nx" // bv_verdict -- did THIS buildrun produce the artifact, or is _build/ a previous build? (2026-09-05)
28// seq961: how long a crawl may show NO log progress before the guard treats it as stalled and reaps it.
29// 600s is far above a polite fetch cycle (a healthy crawl writes a TLS trace per page) and far below the
30// hours a wedged lock would otherwise cost. Data-driven threshold, not a magic number buried in a branch.
31const HC_CRAWL_STALE_S: i64 = 600
32const HC_MAGIC_65536: i64 = 65536
33const HC_MAGIC_8192: i64 = 8192
34const HC_MAGIC_60000: i64 = 60000
35const HC_MAGIC_300000: i64 = 300000
36const HC_MAGIC_8791: i64 = 8791
37const HC_MAGIC_5000: i64 = 5000
38const HC_MAGIC_5000000: i64 = 5000000
39const HC_MAGIC_300000000: i64 = 300000000
40const HC_MAGIC_4096: i64 = 4096
41const HC_MAGIC_8443: i64 = 8443
42const HC_MAGIC_18791: i64 = 18791
43const HC_MAGIC_18190: i64 = 18190
44const HC_MAGIC_18090: i64 = 18090
45const HC_MAGIC_18095: i64 = 18095 // nx_daemon_supervisor /status (the fleet supervisor's liveness surface)
46const HC_MAGIC_8080: i64 = 8080
47const HC_MAGIC_18793: i64 = 18793
48const HC_MAGIC_18098: i64 = 18098
49const HC_MAGIC_18456: i64 = 18456
50const HC_MAGIC_8456: i64 = 8456
51const HC_MAGIC_15274: i64 = 15274
52const HC_MAGIC_18465: i64 = 18465
53const HC_MAGIC_18466: i64 = 18466
54const HC_MAGIC_8446: i64 = 8446
55const HC_MAGIC_18096: i64 = 18096
56const HC_MAGIC_16384: i64 = 16384
57const HC_MAGIC_7443: i64 = 7443
58const HC_MAGIC_18792: i64 = 18792
59const HC_MAGIC_9091: i64 = 9091
60const HC_MAGIC_8097: i64 = 8097
61const HC_MAGIC_18795: i64 = 18795
62const HC_MAGIC_18794: i64 = 18794
63const HC_MAGIC_18796: i64 = 18796
64const HC_MAGIC_18797: i64 = 18797
65const HC_MAGIC_18099: i64 = 18099
66const HC_MAGIC_18097: i64 = 18097
67const HC_MAGIC_18120: i64 = 18120
68const HC_MAGIC_7702: i64 = 7702
69const HC_MAGIC_6881: i64 = 6881
70const HC_MAGIC_8445: i64 = 8445
71const HC_MAGIC_8027: i64 = 8027
72const HC_MAGIC_8028: i64 = 8028
73const HC_MAGIC_8102: i64 = 8102
74const HC_MAGIC_8029: i64 = 8029
75const HC_MAGIC_8055: i64 = 8055
76const HC_MAGIC_8447: i64 = 8447
77const HC_MAGIC_1195: i64 = 1195
78const HC_MAGIC_5080: i64 = 5080
79const HC_MAGIC_15000: i64 = 15000
80const HC_MAGIC_1500: i64 = 1500
81const HC_MAGIC_2500: i64 = 2500
82const HC_MAGIC_4000: i64 = 4000
83const HC_MAGIC_1200: i64 = 1200
84const HC_MAGIC_2000: i64 = 2000
85const HC_MAGIC_131072: i64 = 131072
86const HC_MAGIC_3600000: i64 = 3600000
87const HC_MAGIC_262144: i64 = 262144
88const HC_MAGIC_2048: i64 = 2048
89const HC_MAGIC_40302: i64 = 40302
90const HC_MAGIC_1048576: i64 = 1048576
91const HC_MAGIC_16000: i64 = 16000
92const HC_MAGIC_16777232: i64 = 16777232
93const HC_MAGIC_16777216: i64 = 16777216
94const HC_MAGIC_90000: i64 = 90000
95const HC_MAGIC_1024: i64 = 1024
96const HC_MAGIC_65535: i64 = 65535
97const HC_MAGIC_8191: i64 = 8191
98const HC_MAGIC_2026: i64 = 2026
99const HC_MAGIC_25000: i64 = 25000
100const HC_MAGIC_86400000: i64 = 86400000
101const HC_MAGIC_3000: i64 = 3000
102const HC_MAGIC_6000: i64 = 6000
103
104const HC_ELF: *u8 = "/volume1/homes/elderwesto/nishihost/sites.elf" as *u8
105const HC_ELF_NEW: *u8 = "/volume1/homes/elderwesto/nishihost/sites.elf.new" as *u8
106const HC_ELF_PREV: *u8 = "/volume1/homes/elderwesto/nishihost/sites.elf.prev" as *u8 // rollback copy (never-brick)
107const HC_REDIRECT: *u8 = "/volume1/homes/elderwesto/nishihost/redirect.elf" as *u8
108// time-machine archive server :18801 -- serves the reconstructed page3.com/megastar.co.uk archives and
109// their local media out of web_assets/ (path traversal rejected). PORT CHOSEN AGAINST THIS REGISTRY, not
110// against the live process list: it was first written for :8080 (held by redirect.elf, above) and then
111// :18795, which is held by hc_guard_gen_orch -- a daemon that BACKS OFF until gendeploy'd and therefore
112// does NOT appear in `nx_hostctl status`. A port reserved by a not-currently-running supervised daemon is
113// invisible in the live listener list, so that collision would have surfaced only when gen was deployed.
114const HC_ARCSRV: *u8 = "/volume1/homes/elderwesto/nishihost/nx_archive_server.elf" as *u8
115const HC_VROOM: *u8 = "/volume1/homes/elderwesto/nishihost/nx_vroom_daemon.elf" as *u8
116const HC_SNIROUTER:*u8 = "/volume1/homes/elderwesto/nishihost/sni_router.elf" as *u8 // sovereign public-edge SNI router (:7443, TLS passthrough)
117const HC_XLATE: *u8 = "/volume1/homes/elderwesto/nishihost/nx_translate_daemon.elf" as *u8
118const HC_XLATE_NEW: *u8 = "/volume1/homes/elderwesto/nishihost/nx_translate_daemon.sov.elf.new" as *u8
119const HC_XLATE_PREV: *u8 = "/volume1/homes/elderwesto/nishihost/nx_translate_daemon.elf.prev" as *u8
120const HC_SIGKILL: i64 = 9
121const HC_CLOCK: *u8 = "/volume1/homes/elderwesto/nishihost/nx_clock_tickless.elf" as *u8 // the ONE consolidated scheduler (const, NOT an inline argv literal -- see the .nx gotcha note below)
122const HC_CONF: *u8 = "/volume1/homes/elderwesto/nishihost/sites.conf" as *u8
123const HC_CONF_NEW: *u8 = "/volume1/homes/elderwesto/nishihost/sites.conf.new" as *u8
124const HC_DOCROOT: *u8 = "/volume1/homes/elderwesto/nishihost/sites/andelinwest" as *u8
125const HC_INDEX: *u8 = "/volume1/homes/elderwesto/nishihost/sites/andelinwest/index.html" as *u8
126const HC_INDEX_NEW:*u8 = "/volume1/homes/elderwesto/nishihost/andelinwest_index.html.new" as *u8
127const HC_PID: *u8 = "/volume1/homes/elderwesto/nishihost/sites.pid" as *u8
128// TLS cert paths (sites.elf loads these at startup; certswap installs a renewed cert + restarts to reload)
129const HC_CERT_LIVE: *u8 = "/volume1/homes/elderwesto/nishihost/certs/le_fullchain.der" as *u8
130const HC_CERT_NEW: *u8 = "/volume1/homes/elderwesto/nishihost/certs/le_fullchain.der.new" as *u8
131const HC_CERT_BAK: *u8 = "/volume1/homes/elderwesto/nishihost/certs/le_fullchain.der.bak" as *u8
132const HC_KEY_LIVE: *u8 = "/volume1/homes/elderwesto/nishihost/certs/le_ecdsa_key.bin" as *u8
133const HC_KEY_NEW: *u8 = "/volume1/homes/elderwesto/nishihost/certs/le_ecdsa_key.bin.new" as *u8
134const HC_KEY_BAK: *u8 = "/volume1/homes/elderwesto/nishihost/certs/le_ecdsa_key.bin.bak" as *u8
135// the auth'd library reader (S-class permanence: supervise it like every other sovereign daemon)
136const HC_READER: *u8 = "/volume1/homes/elderwesto/nishi-reader/nx_media_server_auth.elf" as *u8
137const HC_READER_DIR: *u8 = "/volume1/homes/elderwesto/nishi-reader" as *u8
138const HC_READER_KEYS: *u8 = "/volume1/homes/elderwesto/nishihost/auth/keys" as *u8
139const HC_READER_STORE:*u8 = "/volume1/homes/elderwesto/nishihost/auth/store" as *u8
140// the supervisor's OWN binary path (for sovereign self-update via `selfswap`). PID 8636 runs "./nx_hostctl
141// supervise" from cwd nishihost, so the live binary is nishihost/nx_hostctl (no .elf).
142const HC_SELF: *u8 = "/volume1/homes/elderwesto/nishihost/nx_hostctl" as *u8
143const HC_SELF_NEW: *u8 = "/volume1/homes/elderwesto/nishihost/nx_hostctl.new" as *u8
144// The name /api/build ACTUALLY stages (<target>.sov.elf.new). Without this, the natural API-first
145// sequence "build hostctl then /api/deploy target=hostctl" ran selfswap with HC_SELF_NEW absent --
146// see the fail-safe guard in cmd_selfswap and debt seq992/seq983.
147const HC_SELF_NEW_SOV: *u8 = "/volume1/homes/elderwesto/nishihost/nx_hostctl.sov.elf.new" as *u8
148const HC_SELF_PREV: *u8 = "/volume1/homes/elderwesto/nishihost/nx_hostctl.prev" as *u8 // never-brick (#26): keep the old supervisor binary for rollback (selfswap had NONE)
149const HC_BUILD_DEBUG_FLAG: *u8 = "/volume1/homes/elderwesto/nishihost/knowledge/status/build_debug.flag" as *u8 // 1 = every buildrun passes --debug (2026-09-02): DWARF .debug_line appended past the image so a crash address resolves on the deployed binary; any other content or an absent file = no flag
150const HC_SUP_LOCK: *u8 = "/volume1/homes/elderwesto/nishihost/supervisor.heartbeat" as *u8 // single-supervisor lease: epoch heartbeat (getpid is BROKEN on this backend -> can't pid-exclude self)
151// reader argv literals MUST be consts, not inline "..." as *u8 as i64 in the argv[] array: an inline literal
152// stored into an i64 array doesn't materialize as a valid pointer (.nx gotcha) -> execve gets garbage argv ->
153// EFAULT -> child exits 127 silently (no banner). HC_READER* consts work; these must too.
154const HC_REALM: *u8 = "Nishi Wiki" as *u8
155const HC_PORT: *u8 = "8791" as *u8
156const HC_SUPERVISE: *u8 = "supervise" as *u8 // selfswap's re-exec argv[1] -- same const-not-inline-literal rule
157const HC_RUNSITE: *u8 = "runsite" as *u8 // startsite's hc_dfork_exec arg -> cmd_runsite execs sites.elf (sovereign, no sh -c)
158// SOVEREIGN daemonization -- NO OS tools (operator: "nishi ecosystem only from the hardware rung up"). The OS
159// `setsid` program survived ONLY because it DOUBLE-forks + EXECVEs a fresh image. We do the SAME in pure .nx:
160// fork + nx_setsid (the setsid SYSCALL) + fork + execve(nx_hostctl <arg>) -- a FRESH execve image, NOT a direct
161// cmd_supervise() call (the inherited image dies on the channel teardown -- PROVEN). That is hc_dfork_exec.
162const HC_SLEEPER: *u8 = "sleeper" as *u8 // daemontest payload: a sovereign sleep loop (no OS /bin/sleep)
163// NAS-RESIDENT MIRROR (operator: "i want the NAS doing these things not the laptop where we dev"). Shallow-execve
164// target + its bin, launched DETACHED via hc_dfork_exec so it survives the SSH channel teardown and streams to
165// LOCAL /volume1 disk (no 9p, no WSL). Additive; disturbs no supervised daemon.
166const HC_RUNMIRROR: *u8 = "runmirror" as *u8
167const HC_MIRROR_BIN: *u8 = "/volume1/ai/apertus/nx_apertus_mirror_nas.elf" as *u8
168// PARALLEL concurrent download ON THE NAS (the max-speed gap WSL couldn't run -- its service crashed on concurrent
169// fork/TLS; the NAS's real Linux handles it). Same shallow-execve/detached pattern as the mirror action.
170const HC_RUNMIRRORPAR: *u8 = "runmirrorpar" as *u8
171const HC_MIRRORPAR_BIN: *u8 = "/volume1/ai/apertus/nx_par_pull_nas.elf" as *u8
172// MAKE-IT-REAL: publish a real NAS file into the hub distribution index (enabler -> magnet+download+api+index).
173const HC_DISTPUB_BIN: *u8 = "/volume1/ai/dist/nx_dist_publish_run.elf" as *u8
174const HC_RUNDISTPUB: *u8 = "rundistpub" as *u8
175// /dist DOWNLOAD server (loopback :18099, content-addressed) + a loopback self-test probe. argv literals MUST be
176// consts (an inline "..." as *u8 as i64 in argv[] corrupts) -- hence the HC_A_* / HC_DIST_PROBE_PATH consts.
177const HC_DISTSERVE_BIN: *u8 = "/volume1/ai/dist/nx_dist_serve.elf" as *u8
178const HC_RUNDISTSERVE: *u8 = "rundistserve" as *u8
179const HC_RUNDISTPROBE: *u8 = "rundistprobe" as *u8
180const HC_A_SERVE: *u8 = "serve" as *u8
181const HC_A_PROBE: *u8 = "probe" as *u8
182const HC_A_PORT: *u8 = "18120" as *u8
183const HC_DIST_PROBE_PATH: *u8 = "/dist/509b6d9d22987cf7b1067a7cc6b74b88cf0c8c2739748fe5e85a4da0f69ebf1a/model.safetensors.index.json" as *u8
184// The reader spawn goes through /bin/sh -c (exactly how the system launches vroom: a `setsid ... &` line).
185// The pure fork+sys_chdir+execve path silently failed under the supervisor (no banner) despite chdir + argv
186// both proving correct in isolation -- some .nx codegen edge in the deep forked-child call path. sh does the
187// cd + arg-parse robustly; `exec` REPLACES the sh so the reader is the supervisor's DIRECT child -> the loop's
188// wait4 reaps it on death and LOGS its sig/code (instrumenting WHY the supervised reader exits, when manual
189// launch of the same line stays up). >>auth.log keeps its banner/errors. cmdline stays the reader's so
190// proc_alive finds it. (Once the exit cause is known + fixed, may revert to a detached setsid form.)
191const HC_SH: *u8 = "/bin/sh" as *u8
192const HC_DASHC: *u8 = "-c" as *u8
193const HC_READER_CMD: *u8 = "cd /volume1/homes/elderwesto/nishi-reader && exec ./nx_media_server_auth.elf /volume1/homes/elderwesto/nishihost/auth/keys /volume1/homes/elderwesto/nishihost/auth/store 'Nishi Wiki' 8791 >> auth.log 2>&1" as *u8
194// --- the NSFW gallery stack (serve :18090 + OPAQUE gateway :18190), at /volume1/ai/galx -- supervised here
195// alongside the site so the bash while-loop supervisor is retired (operator: ONE sovereign supervisor). Spawned
196// via sh -c (exec) for robust cwd+args, exactly like the reader. allow_register=0 (operator-only; the gallery is
197// private -- existing accounts still log in, only NEW signups are blocked = the intended closed state).
198const HC_GALX_GW: *u8 = "/volume1/ai/galx/nx_gallery_gateway.elf" as *u8
199const HC_GALX_GW_NEW: *u8 = "/volume1/ai/galx/nx_gallery_gateway.elf.new" as *u8
200// seq1049: rollback artifact + the build-staged twin. The gateway is the AUTH surface for /gallery -- the one
201// binary that must never be promoted without a banked restore point, and it was the one binary that had none.
202const HC_GALX_GW_PREV: *u8 = "/volume1/ai/galx/nx_gallery_gateway.elf.prev" as *u8
203const HC_GALX_GW_SOVNEW: *u8 = "/volume1/homes/elderwesto/nishihost/nx_gallery_gateway.sov.elf.new" as *u8
204const HC_GALX_SERVE: *u8 = "/volume1/ai/galx/nx_gallery_serve.elf" as *u8
205const HC_GALX_SERVE_NEW: *u8 = "/volume1/ai/galx/nx_gallery_serve.elf.new" as *u8
206const HC_GALX_SERVE_CMD: *u8 = "cd /volume1/ai/galx && exec ./nx_gallery_serve.elf 18090 >>/tmp/galx_serve.log 2>&1" as *u8
207// archive server :18801 -- MEASURED DEAD under hc_spawn_path (nx_netobs bench -> ok=0 err=1 in 203us =
208// instant connection REFUSAL, not a timeout; the elf was promoted and the guard entry was correct, so it
209// was spawning and dying). hc_spawn_path execs BARE, inheriting the supervisor's stdout -- and this daemon
210// WRITES to stdout, so its first write to a dead pipe SIGPIPEs it. That is the SAME failure already
211// recorded twice in this file, against redirect.elf and the reader. cd gives it the CWD its web_assets/
212// and seg_store (BL_PREFIX) paths are relative to; the logfile makes the NEXT crash diagnosable instead
213// of invisible, which is how this one cost a whole cycle to find.
214const HC_ARCSRV_CMD: *u8 = "cd /volume1/homes/elderwesto/nishihost && exec ./nx_archive_server.elf >>/tmp/arcsrv.log 2>&1" as *u8
215// argon2id KSF cost = m=65536 t=3 p=4 -- the ORIGINAL gallery params, RESTORED. Do NOT lower to the login's
216// 19456/2/1: registration is CLOSED ({"error":"registration closed"}), so accounts can't be re-enrolled, and the
217// operator's EXISTING gallery account was registered under THESE params -- OPAQUE re-derives the password with the
218// exact KSF params, so changing them => "invalid credentials". The >10s login was the v2 PROXY keep-alive bug
219// (FIXED: sd2_force_close + keep=0 + write-all), NEVER the KSF cost (galxauthprobe answered in 0ms).
220const HC_GALX_GW_CMD: *u8 = "cd /volume1/ai/galx && exec ./nx_gallery_gateway.elf 18190 knowledge/status/galx_gw_keys knowledge/status/galx_gw_store 1000000000 18090 0 65536 3 4 >>/tmp/galx_gw.log 2>&1" as *u8
221// --- the Nishi Family WIKI gateway (:18791): OPAQUE login + the gated 1195-page wiki, at /volume1/ai/wiki.
222// Supervised here so it auto-restarts forever (no more manual setsid/kill -> the permanent F->S fix).
223const HC_WIKI_GW: *u8 = "/volume1/ai/wiki/nx_wiki_gw.elf" as *u8
224const HC_WIKI_GW_NEW: *u8 = "/volume1/ai/wiki/nx_wiki_gw.elf.new" as *u8
225const HC_WIKI_GW_CMD: *u8 = "cd /volume1/ai/wiki && exec ./nx_wiki_gw.elf 18791 keys store 1000000000 65536 3 4 pages >>/tmp/wiki_gw.log 2>&1" as *u8
226// hub OPAQUE gateway (:18792): leveled /hub via the maturity registry. keys/store = the :9091 /login daemon's
227// (realm nishi_site_admin) so it validates the SAME no-cookie X-Nishi-Session tokens; the gateway reads them read-only.
228const HC_HUB_GW: *u8 = "/volume1/ai/hub/nx_hub_gw.elf" as *u8
229const HC_HUB_GW_NEW: *u8 = "/volume1/ai/hub/nx_hub_gw.elf.new" as *u8
230// Relationship OS daemon (:8027 loopback -- the /relate app). Staged in nishihost cwd like every mgmt target.
231const HC_RELATE: *u8 = "/volume1/homes/elderwesto/nishihost/nx_relate_daemon.elf" as *u8
232const HC_RELATE_NEW: *u8 = "/volume1/homes/elderwesto/nishihost/nx_relate_daemon.elf.new" as *u8
233const HC_RELATE_PREV: *u8 = "/volume1/homes/elderwesto/nishihost/nx_relate_daemon.elf.prev" as *u8
234const HC_RELATE_CMD: *u8 = "cd /volume1/homes/elderwesto/nishihost && exec ./nx_relate_daemon.elf >>/tmp/relate_daemon.log 2>&1" as *u8
235// Ethical CLEAN-SERVE daemon (:8102 -- /clean, SSRF-guarded fetch proxy). Staged in nishihost cwd like every target.
236const HC_CLEANSERVE: *u8 = "/volume1/homes/elderwesto/nishihost/nx_clean_serve_daemon.elf" as *u8
237const HC_CLEANSERVE_NEW: *u8 = "/volume1/homes/elderwesto/nishihost/nx_clean_serve_daemon.elf.new" as *u8
238const HC_DOCPORTAL: *u8 = "/volume1/homes/elderwesto/nishihost/nx_docportal_admin_daemon.elf" as *u8
239const HC_DOCPORTAL_NEW: *u8 = "/volume1/homes/elderwesto/nishihost/nx_docportal_admin_daemon.sov.elf.new" as *u8
240const HC_DOCPORTAL_PREV: *u8 = "/volume1/homes/elderwesto/nishihost/nx_docportal_admin_daemon.elf.prev" as *u8
241const HC_CLEANSERVE_PREV: *u8 = "/volume1/homes/elderwesto/nishihost/nx_clean_serve_daemon.elf.prev" as *u8
242const HC_CLEANSERVE_CMD: *u8 = "cd /volume1/homes/elderwesto/nishihost && exec ./nx_clean_serve_daemon.elf 8102 >>/tmp/cleanserve.log 2>&1" as *u8
243// --- the WORKER MESH: sovereign job console. serve :8029 (backend = console + SSE gen pipeline + gated image) +
244// OPAQUE gateway :8055 (sites /mesh -> here; gated exactly like the gallery, store = a copy of galx_gw_{keys,store},
245// allow_register=0). Supervised here so the setsid daemons survive crash + reboot (closes the F: unsupervised gap).
246const HC_MESH_SERVE_CMD: *u8 = "cd /volume1/homes/elderwesto/nishihost && exec ./nx_mesh_serve.elf 8029 >>/tmp/mesh_serve.log 2>&1" as *u8
247const HC_MESH_GW_CMD: *u8 = "cd /volume1/homes/elderwesto/nishihost && exec ./nx_mesh_gateway.elf 8055 meshgw_keys meshgw_store 100000 8029 0 65536 3 4 >>/tmp/mesh_gw.log 2>&1" as *u8
248const HC_PROJECT_CMD: *u8 = "cd /volume1/homes/elderwesto/nishihost && exec ./nx_project_serve.elf 8028 opaque_keys.bin opaque_store.log 1000000000 knowledge/project/serve.conf nishi_uid_handle.tsv 19456 2 1 >>/tmp/project_gw.log 2>&1" as *u8
249const HC_HUB_GW_CMD: *u8 = "cd /volume1/ai/hub && exec ./nx_hub_gw.elf 18792 /volume1/homes/elderwesto/nishihost/opaque_keys.bin /volume1/homes/elderwesto/nishihost/opaque_store.log 1000000000 65536 3 4 >>/tmp/hub_gw.log 2>&1" as *u8
250// Sovereign MANAGEMENT API daemon (:18098 loopback HTTP). Reached as <domain>/api via proxy_routes.conf so
251// the ecosystem is operated over the wire (WebFetch), not the shell dance. Args: port keys store realm snap budget.
252// DEDICATED vault-sealed mgmt admin (operator chose "arm a vault-sealed mgmt admin"): its OWN keys+store+realm
253// (mgmt_keys + mgmt_store + realm 'nishi-mgmt', canonical KSF 8192/1/1) -- ISOLATED from the shared auth/store so
254// the control plane NEVER touches the library/operator admin. Handle 'mgmtops', passphrase sealed in the vault
255// (mgmt-admin-pass.nv). /api/login with mgmtops -> token drives /api/{restart,reconcile,deploy,...} over TLS (no shell).
256const HC_MGMT_CMD: *u8 = "cd /volume1/homes/elderwesto/nishihost && chmod +x ./nx_mgmt_api.elf 2>/dev/null; exec ./nx_mgmt_api.elf 18098 /volume1/homes/elderwesto/nishihost/opaque_keys.bin /volume1/homes/elderwesto/nishihost/opaque_store.log nishi_site_admin mgmt_snap.json 1000000000 >>/tmp/mgmt_api.log 2>&1" as *u8
257// admin.<domain> doc-portal ADMIN daemon (:8456 loopback HTTP): OWNER self-service -- invite-gated OPAQUE
258// self-registration (/admin/register) + login + doc upload. Reverse-proxied as admin.<d>/ via proxy_routes.conf.
259// Per-domain keys+store+realm => isolated accounts (andelinwest_docportal here); invites in <store>.invites.
260// Args: port keys store realm budget. Loopback-only; the sites daemon is the only public ingress.
261// budget 20000000: the docportal is a USER-FACING search daemon -- a low budget means it recycles mid-use
262// and the ~15s supervisor respawn gap is a visible hang ("takes forever", operator 2026-07-03). Its per-
263// request mmap leak is FIXED (dsv_respond* now munmap the body), so a high budget no longer grows RSS; and
264// vm.overcommit_memory=1 (hc_assert_overcommit) prevents the fork-wedge regardless. So: recycle rarely.
265const HC_ADMIN_CMD: *u8 = "cd /volume1/homes/elderwesto/nishihost && chmod +x ./nx_docportal_admin_daemon.elf 2>/dev/null; exec ./nx_docportal_admin_daemon.elf 18456 /volume1/homes/elderwesto/nishihost/andelinwest_docportal_keys /volume1/homes/elderwesto/nishihost/andelinwest_docportal_store andelinwest_docportal 20000000 >>/tmp/docportal_admin.log 2>&1" as *u8
266const HC_MAILPORTAL_CMD: *u8 = "cd /volume1/homes/elderwesto/nishihost && chmod +x ./nx_email_portal_daemon.elf 2>/dev/null; exec ./nx_email_portal_daemon.elf 18465 /volume1/homes/elderwesto/nishihost/andelinwest_mail_keys /volume1/homes/elderwesto/nishihost/andelinwest_mail_store andelinwest_mail andelinwest.com /volume1/homes/elderwesto/nishihost/mail_aw/ 20000000 >>/tmp/mail_portal.log 2>&1" as *u8
267const HC_MAGIC_18122: i64 = 18122
268// :18122 loopback-only inventory/ownership checker. argv taken VERBATIM from the live process
269// (/proc/<pid>/cmdline) -- a supervisor that respawns a daemon with DIFFERENT arguments than the
270// one it replaced is not supervision, it is a silent reconfiguration at the worst possible moment.
271const HC_INVENTORY_CMD: *u8 = "cd /volume1/homes/elderwesto/nishihost && chmod +x ./nx_inventory_serve.elf 2>/dev/null; exec ./nx_inventory_serve.elf 18122 opaque_keys.bin opaque_store.log nishi_site_admin 1000000 >>/tmp/inventory.log 2>&1" as *u8
272const HC_SITEEDIT_CMD: *u8 = "cd /volume1/homes/elderwesto/nishihost && chmod +x ./nx_siteedit_daemon.elf 2>/dev/null; exec ./nx_siteedit_daemon.elf 18466 /volume1/homes/elderwesto/nishihost/andelinwest_docportal_keys /volume1/homes/elderwesto/nishihost/andelinwest_docportal_store andelinwest_docportal andelinwest.com /volume1/homes/elderwesto/nishihost/andelinwest.site /volume1/homes/elderwesto/nishihost/sites/andelinwest 20000000 >>/tmp/siteedit.log 2>&1" as *u8
273// CONTINUOUS M&E: nx_health_eval `loop` = the FUNCTIONAL/QUALITY evaluator (nx_https_get probes of the live
274// surface, writes sites/nishifamily/health.json + ledger trend every 300s). Supervised = it runs FOREVER
275// (respawned if it ever dies) -- this is what kills "fire and pray": the surface is re-measured every poll,
276// not when a human remembers. PID-liveness guard (no port -- it makes outbound TLS, listens on nothing).
277const HC_HEALTH_CMD: *u8 = "cd /volume1/homes/elderwesto/nishihost && chmod +x ./nx_health_eval.elf 2>/dev/null; exec ./nx_health_eval.elf loop 300 >>/tmp/health_eval.log 2>&1" as *u8
278// VIDEO SIGNALING/MEDIA RELAY (:8445 loopback, reached as wss://<d>/signal/<room> via the sites proxy).
279// Task #26 near-miss closed: it was UNSUPERVISED (kill -> dead video, no respawn). Now guarded like every
280// other service; reconcile cycles it onto a freshly deployed ELF (clients auto-reconnect lanes in ~1.2s).
281const HC_SIG2_CMD: *u8 = "cd /volume1/homes/elderwesto/nishihost && chmod +x ./nx_signaling_v2.elf 2>/dev/null; exec ./nx_signaling_v2.elf >>/tmp/signaling_v2.log 2>&1" as *u8
282// media/torrent daemon (:8097): the sovereign acquirer (torrent + direct + HLS download -> gallery), migrated
283// from the dev laptop to the NAS hub. The spawn runs the PORTABLE launcher nx_media_env with the "hub" profile,
284// which deploys the bundle's worker elfs -> /tmp then execs nx_torrent_daemon with the hub's area roots. Until
285// the bundle is deployed to /volume1/ai/torrent the exec just fails -> the guard backs off (fail-safe, no harm).
286const HC_TORRENT_CMD: *u8 = "cd /volume1/ai/torrent && exec ./nx_media_env.sov.elf hub >>/tmp/torrentd.log 2>&1" as *u8
287// torrent OPAQUE gateway (:18793): the public auth front for /torrent (sites_daemon /torrent -> here -> daemon
288// :8097). Runs from /volume1 (exec-friendly). Same keys/store/costs as the :9091 login + hub gw (admin realm).
289const HC_TORRENT_GW_CMD: *u8 = "cd /volume1/ai/torrent && exec ./nx_torrent_gw.elf 18793 /volume1/homes/elderwesto/nishihost/opaque_keys.bin /volume1/homes/elderwesto/nishihost/opaque_store.log 1000000000 65536 3 4 >>/tmp/torrentgw.log 2>&1" as *u8
290// --- Elder AI GEN: orchestrator (:18795, NAS-side gen-img: UI + batch dispatch -> laptop 5080 + gallery
291// ingest) + OPAQUE gateway (:18794, family realm -> he_has_access(/gen) -> orchestrator). sites /gen ->
292// gateway :18794, exactly like /torrent. Gateway keys/store = the :9091 login daemon's (SSO). Fail-safe:
293// backs off until the elfs are deployed to /volume1/ai/gen (gendeploy). The orchestrator dispatches to the
294// laptop engine: address resolved from knowledge/swarm_nodes.conf via nx_swarm_endpoint_lib
295// (role gpu-image), firewall-allowed NAS-only. Was hardcoded .193 here; the box is .192 and this
296// comment lied for as long as the drift lasted -- seq1485.
297const HC_GEN_GW_CMD: *u8 = "cd /volume1/ai/gen && exec ./nx_gen_gateway_daemon.elf 18794 /volume1/homes/elderwesto/nishihost/opaque_keys.bin /volume1/homes/elderwesto/nishihost/opaque_store.log 1000000000 18795 0 19456 2 1 86400 >>/tmp/gen_gw.log 2>&1" as *u8
298const HC_GEN_ORCH_CMD: *u8 = "cd /volume1/ai/gen && exec ./nx_gen_orchestrator_daemon.elf 18795 192 168 8 192 7861 /volume1/ai/gen/store- /volume1/ai/gen/blob- /volume1/ai/gen/cids.tsv laptop-5080 5000 >>/tmp/gen_orch.log 2>&1" as *u8
299// SYNTH STUDIO daemon (:18796 loopback, sites /synth/api -> here via proxy_routes.conf). Renders motion/creatures
300// on demand (nx_synth_serve). Fail-safe: backs off until nx_synth_serve_daemon.elf lands in /volume1/ai/synth.
301const HC_SYNTH_CMD: *u8 = "cd /volume1/ai/synth && exec ./nx_synth_serve_daemon.elf 18796 >>/tmp/synth.log 2>&1" as *u8
302// DEV/CI API daemon (:18797 loopback, sites /api/dev -> here via proxy_routes.conf). build/gate/run organs over
303// HTTP, cap-gated (X-Nishi-Cap dev_build). Fail-safe: backs off until nx_dev_api_serve.elf lands in /volume1/ai/devapi.
304const HC_DEVAPI_CMD: *u8 = "cd /volume1/ai/devapi && chmod +x ./nx_dev_api_serve.elf ./_offc/*.elf 2>/dev/null; exec ./nx_dev_api_serve.elf serve 18797 >>/tmp/devapi.log 2>&1" as *u8
305// login OPAQUE daemon (:9091, the token MINTER -- now mints 24h sessions). keys/store relative to cwd (nishihost).
306// logintest spawns the .new on THROWAWAY :9099 to prove it starts BEFORE logindeploy touches live :9091 (no lockout).
307const HC_LOGIN: *u8 = "/volume1/homes/elderwesto/nishihost/nx_opaque_login.elf" as *u8
308const HC_LOGIN_NEW: *u8 = "/volume1/homes/elderwesto/nishihost/nx_opaque_login.elf.new" as *u8
309const HC_LOGIN_PREV: *u8 = "/volume1/homes/elderwesto/nishihost/nx_opaque_login.elf.prev" as *u8
310// argon2id KSF cost = m=19456 KiB (19 MiB) t=2 p=1 -- the OWASP-2024 interactive-login FLOOR. ~5x faster login
311// than the old 64MiB/t3/p4 (the operator's latency complaint); still a standard memory-hard config for a
312// single-operator media realm. CHANGING these REQUIRES re-registering accounts (KSF params are baked at register).
313// argv[8]=wikidir argv[9]=HR ROSTER (2026-07-30). The roster is what olgd_signup_ok consults for the
314// 'only the family' half of the signup gate; with argv[9] absent hrstore is null and EVERY signup is denied
315// by construction, so the gate could never admit anyone. argv[8] must be passed to reach argv[9], and it is
316// passed as the EXACT compiled-in default so this change is behaviour-preserving for the wiki-serving path.
317// ⚠THAT DEFAULT IS A LAPTOP PATH (/mnt/c/Users/elder/...) baked into a production daemon and it does not
318// exist on the NAS -- preserved verbatim here deliberately rather than silently "fixed" in a supervisor edit;
319// filed separately. The roster file itself is ABSENT on purpose: hra_is_invited returns 0 for a missing store,
320// so signup stays FAIL-CLOSED until an operator provisions invites. Wiring the slot is a technical step;
321// deciding WHO is invited is not mine to make.
322const HC_LOGIN_CMD: *u8 = "cd /volume1/homes/elderwesto/nishihost && exec ./nx_opaque_login.elf 9091 opaque_keys.bin opaque_store.log 1000000000 19456 2 1 /mnt/c/Users/elder/nishi-core/nxc2/knowledge/wiki_pages /volume1/homes/elderwesto/nishihost/nishi_hr.log >>/tmp/login.log 2>&1" as *u8
323const HC_LOGIN_TEST_CMD: *u8 = "cd /volume1/homes/elderwesto/nishihost && exec ./nx_opaque_login.elf.new 9099 opaque_keys.bin opaque_store.log 50 19456 2 1 >>/tmp/logintest.out 2>&1" as *u8
324// --- SOVEREIGN mTLS reverse-proxy TEST launch (NO /bin/sh): hc_dfork_exec(HC_RUNMTLSPROXY) -> cmd_runmtlsproxy
325// shallow-execve's the proxy from the fresh main-dispatch image, exactly like cmd_runsite. :9444 -> loopback
326// wiki_gw :18791; the LE cert is read from an absolute path; the proxy is left RUNNING for a browser test.
327const HC_RUNMTLSPROXY: *u8 = "runmtlsproxy" as *u8
328const HC_MTLS_PROXY_BIN: *u8 = "/volume1/homes/elderwesto/nishihost/nx_aw_mtls_proxy.elf" as *u8
329const HC_MP_PORT: *u8 = "9444" as *u8
330const HC_MP_BACKEND: *u8 = "18791" as *u8
331// --- platformtest: sovereign-launch the carved andelinwest CLIENT daemon (:8453, LE ECDSA) + the SNI router
332// (:8444 -> backend 8443 sites.elf; routes by the property registry) on INTERNAL ports -- :443 untouched.
333const HC_RUNANDELIN: *u8 = "runandelin" as *u8
334const HC_ANDELIN_BIN: *u8 = "/volume1/homes/elderwesto/nishihost/nx_andelinwest_daemon.elf" as *u8
335const HC_RUNSNIR: *u8 = "runsnir" as *u8
336const HC_SNIR_BIN: *u8 = "/volume1/homes/elderwesto/nishihost/nx_sni_router.elf" as *u8
337const HC_SNIR_PORT: *u8 = "8444" as *u8
338const HC_SNIR_BACKEND: *u8 = "8443" as *u8
339const HC_NFTREAD_BIN: *u8 = "/volume1/homes/elderwesto/nishihost/nx_nft_read.elf" as *u8 // sovereign netfilter R0: read-only nat-table probe (grounds legacy-vs-nft)
340const HC_NETTAP_BIN: *u8 = "/volume1/homes/elderwesto/nishihost/nx_netscope_capture.elf" as *u8 // NX-NETSCOPE L-CAPTURE: the sovereign wire tap (AF_PACKET -> nx_packet_dissect)
341// sites.elf spawn via sh -c (exec) -- the SAME proven mechanism the gallery/reader use. The pure-.nx
342// fork+setsid+execve(sites.elf) path hits the deep-forked-child codegen edge (sites.elf dies); sh's exec
343// dodges it. cd sets cwd so sites.elf finds its relative certs/. (Full sovereignty here is blocked ONLY by
344// that nx_cc codegen edge -- a separate compiler fix.)
345const HC_SITES_CMD: *u8 = "cd /volume1/homes/elderwesto/nishihost && exec ./sites.elf >>/tmp/sites_run.log 2>&1" as *u8
346// --- SOVEREIGN LIBRARY backend (nishifamily.com/research -> :8095, 16K-taxon full-text catalog).
347// Runs from its own dir so it resolves knowledge/libstore-* + libindex.nxinv relatively; sites.elf's
348// /research route reverse-proxies to it. libdeploy: promote nx_lib_httpd.elf.new -> .elf, kill any old
349// (FULL cmdline -- name is 16 chars, comm-truncation would silently miss it), relaunch detached. ADDITIVE:
350// the supervise loop is untouched (a crash leaves /research empty via the proxy fail-safe; nothing else).
351const HC_LIB_ELF: *u8 = "/volume1/homes/elderwesto/nishihost/lib/nx_lib_httpd.elf" as *u8
352const HC_LIB_ELF_NEW: *u8 = "/volume1/homes/elderwesto/nishihost/lib/nx_lib_httpd.elf.new" as *u8
353const HC_LIB_CMD: *u8 = "cd /volume1/homes/elderwesto/nishihost/lib && exec ./nx_lib_httpd.elf >>/tmp/lib_run.log 2>&1" as *u8
354// genprobe: one-shot LIVE frontend proof -- runs nx_gen_live_probe.elf (drives the deployed /gen gateway end-to-end)
355// and captures its PASS/FAIL to a file the subcommand reads back (relayed to the operator via nx_aw_hostctl).
356const HC_GENPROBE_CMD: *u8 = "exec /volume1/ai/gen/nx_gen_live_probe.elf >/volume1/ai/gen/genprobe.out 2>&1" as *u8
357// Sovereign agent-facing TOOLS API (:18096 loopback HTTP -> /api/tools + /mcp). R0 of the MCP-benchmark-and-beyond
358// arc: exposes nx_tool_registry as an MCP-compatible + superset surface. Reached as <domain>/api/tools + /mcp via
359// proxy_routes.conf. ADDITIVE isolated service -- backs off until nx_tools_api_serve.elf is deployed (fail-safe).
360const HC_TAPI_CMD: *u8 = "cd /volume1/homes/elderwesto/nishihost && chmod +x ./nx_tools_api_serve.elf 2>/dev/null; mkdir -p knowledge 2>/dev/null; exec ./nx_tools_api_serve.elf serve 18096 >>/tmp/tools_api.log 2>&1" as *u8
361// Finance dashboard server (:18097 loopback HTTP -> serves fin_stack.html). Reached as <domain>/finance (gated)
362// via proxy_routes.conf. ADDITIVE isolated service -- backs off until nx_fin_serve.elf is deployed (fail-safe).
363const HC_FIN_CMD: *u8 = "cd /volume1/homes/elderwesto/nishihost && chmod +x ./nx_fin_serve.elf 2>/dev/null; exec ./nx_fin_serve.elf serve 18097 >>/tmp/fin_serve.log 2>&1" as *u8
364// /dist content-addressed DOWNLOAD server (:18120 loopback -> sites.elf /dist). ADDITIVE isolated service; backs
365// off until nx_dist_serve.elf is deployed to /volume1/ai/dist -> fail-safe. Makes the download transport DURABLE.
366const HC_DIST_CMD: *u8 = "cd /volume1/ai/dist && chmod +x ./nx_dist_serve.elf 2>/dev/null; exec ./nx_dist_serve.elf serve 18120 >>/tmp/dist_serve.log 2>&1" as *u8
367// BitTorrent SEEDER (:6881, INBOUND peers) -- the UPLOAD/SHARE half of the torrent stack. Serves every torrent
368// registered in /volume1/ai/torrent/seed_index.conf (info_hash -> file). ADDITIVE isolated service; backs off
369// until nx_torrent_seed.elf is deployed -> fail-safe. NEVER-BRICK: writes zero state, only net sends + file reads.
370const HC_SEED_CMD: *u8 = "cd /volume1/ai/torrent && chmod +x ./nx_torrent_seed.elf 2>/dev/null; exec ./nx_torrent_seed.elf serve 6881 /volume1/ai/torrent/seed_index.conf >>/tmp/seed.log 2>&1" as *u8
371// DHT ANNOUNCER: periodically announce_peer every registered info_hash FROM the NAS (BEP-5 infers our IP from
372// the packet source) so strangers DISCOVER the seeder via the DHT. ADDITIVE; backs off until deployed -> fail-safe.
373const HC_SEEDANN_CMD: *u8 = "cd /volume1/ai/torrent && chmod +x ./nx_seed_announce_all.elf 2>/dev/null; exec ./nx_seed_announce_all.elf /volume1/ai/torrent/seed_index.conf >>/tmp/seedann.log 2>&1" as *u8
374// torstat: run nx_torrent_seedeval on EVERY active download (media/<btih>) -> SCARCE vs IGNORING vs COMPLETE
375// per torrent -- diagnoses a stuck DL: are missing pieces held by peers (pull/unchoke bug) or absent (dead swarm)?
376const HC_TORSTAT_CMD: *u8 = "cd /volume1/ai/torrent && set -f; chmod +x ./nx_torrent_seedeval.elf 2>/dev/null; : > /tmp/torstat.out; for area in media gallery; do while read b; do echo === $area/$b === >> /tmp/torstat.out; ./nx_torrent_seedeval.elf $area/$b >> /tmp/torstat.out 2>&1; done < $area/torrents.idx 2>/dev/null; done; echo === SEED REGISTRY - what we SHARE back === >> /tmp/torstat.out; cat seed_index.conf >> /tmp/torstat.out 2>/dev/null; echo === seeding $(wc -l < seed_index.conf 2>/dev/null) torrents === >> /tmp/torstat.out" as *u8
377// MULTIPLAYER game relay (:7702 loopback HTTP -> /mineworld-mp page + /pstate POST + /roster GET; shared-mmap
378// rooms, fork-per-connection). Reached via proxy_routes.conf. ADDITIVE isolated service -- backs off until
379// nx_mp_serve.elf is deployed (fail-safe). Worst failure = multiplayer down; touches nothing else (never-brick).
380const HC_MP_CMD: *u8 = "cd /volume1/homes/elderwesto/nishihost && chmod +x ./nx_mp_serve.elf 2>/dev/null; mkdir -p web_assets/_game_build 2>/dev/null; exec ./nx_mp_serve.elf >>/tmp/mp_serve.log 2>&1" as *u8
381
382func hc_puts(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 }
383func hc_putn(v: i64) -> i64 {
384 let t: *u8=sys_mmap(28); var m: i64=v; var neg9: i64=0; if m<0{m=0-m;neg9=1} var k: i64=0; if m==0{t[0]=48 as u8;k=1}
385 while m>0{t[k]=(48+(m%10)) as u8;m=m/10;k=k+1} if neg9==1{t[k]=45 as u8;k=k+1}
386 let b: *u8=sys_mmap(28); var i: i64=0; while i<k{b[i]=t[k-1-i];i=i+1} sys_write(1,b,k)
387 sys_munmap(t,28); sys_munmap(b,28); return 0
388}
389func hc_streq(a: *u8, b: *u8) -> i64 { var i: i64=0; while a[i]!=(0 as u8) { if a[i]!=b[i] { return 0 } i=i+1 } if b[i]!=(0 as u8) { return 0 } return 1 }
390
391// write a decimal pid to a path
392func hc_write_pid(path: *u8, pid: i64) -> i64 {
393 let buf: *u8 = sys_mmap(28); var m: i64=pid; let t: *u8=sys_mmap(28); var k: i64=0
394 if m==0 { t[0]=48; k=1 }
395 while m>0 { t[k]=(48+(m%10)) as u8; m=m/10; k=k+1 }
396 var i: i64=0; while i<k { buf[i]=t[k-1-i]; i=i+1 }
397 let fd: i64 = sys_openat_wr(path, 0x1a4)
398 if fd<0 { return 0-1 }
399 sys_write(fd, buf, k); sys_close(fd); return 0
400}
401// read a decimal pid from a path (0 if absent/empty)
402func hc_read_pid(path: *u8) -> i64 {
403 let box: *i64 = sys_mmap(16) as *i64; box[0]=0
404 let d: *u8 = sys_read_file(path, box)
405 if (d as i64)==0 { return 0 }
406 let n: i64 = box[0]; var v: i64=0; var i: i64=0
407 while i<n { let c: u8=d[i]; if c>=(48 as u8) { if c<=(57 as u8) { v=v*10+((c-(48 as u8)) as i64) } } i=i+1 }
408 return v
409}
410
411// SINGLE-SUPERVISOR LEASE (getpid is BROKEN here -> can't pid-exclude self in a /proc scan, so use an EPOCH
412// HEARTBEAT): the live supervisor writes `now` to HC_SUP_LOCK every poll. A supervisor starting up that sees a
413// FRESH heartbeat (<90s = 6x the 15s poll, tolerates slow polls) DEFERS instead of racing -- the by-construction
414// prevention of the dueling-supervisor outage. reconcile/selfswap CLEAR the lease (write 0) AFTER killing the old
415// one, so the INTENDED relaunch always claims (never false-defers on a dead supervisor's stale heartbeat).
416func hc_sup_touch() -> i64 { return hc_write_pid(HC_SUP_LOCK, sys_now_realtime_sec()) }
417func hc_sup_clear() -> i64 { return hc_write_pid(HC_SUP_LOCK, 0) } // mark stale -> the next supervisor claims
418func hc_sup_fresh() -> i64 {
419 let e: i64 = hc_read_pid(HC_SUP_LOCK)
420 if e <= 0 { return 0 } // absent / cleared -> free to claim
421 let age: i64 = sys_now_realtime_sec() - e
422 if age < 0 { return 0 } // clock skew -> treat stale, never falsely defer (zero-supervisor is the worst outcome)
423 if age < 90 { return 1 } // a live supervisor heartbeat -> defer
424 return 0 // stale (holder crashed >90s ago) -> claim
425}
426
427// spawn the sites daemon; return its pid
428func hc_spawn() -> i64 {
429 let pid: i64 = sys_fork()
430 if pid==0 {
431 let argv: *i64 = sys_mmap(16) as *i64; argv[0]=HC_ELF as i64; argv[1]=0
432 let envp: *i64 = sys_mmap(16) as *i64; envp[0]="PATH=/usr/bin:/bin" as *u8 as i64; envp[1]=0
433 sys_execve_clean(HC_ELF, argv, envp)
434 sys_exit(127)
435 }
436 return pid
437}
438
439func hc_slen(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} return n }
440func hc_atoi(s: *u8) -> i64 { var v: i64=0; var i: i64=0; while s[i]!=(0 as u8) { let c: u8=s[i]; if c<(48 as u8){return v} if c>(57 as u8){return v} v=v*10+((c-(48 as u8)) as i64); i=i+1 } return v }
441func hc_contains(hay: *u8, hn: i64, needle: *u8, nn: i64) -> i64 {
442 if nn==0 { return 1 }
443 var i: i64=0
444 while i+nn<=hn { var k: i64=0; var ok: i64=1; while k<nn { if hay[i+k]!=needle[k]{ok=0;k=nn} k=k+1 } if ok==1 { return 1 } i=i+1 }
445 return 0
446}
447// BOUNDED raw read of /proc/<pid>/cmdline into a caller-owned buf (reused across PIDs) -> total bytes. CRITICAL:
448// the proc scanners MUST NOT use sys_read_file here -- it mmaps 4 GiB PER CALL and never frees, so scanning
449// ~200 /proc entries exhausts virtual memory and the next fork fails ENOMEM (the supervisor then can't respawn
450// daemons + dies = the F-class root). This reader allocates nothing; the caller's fixed buffer is reused.
451func hc_read_cmdline(path: *u8, buf: *u8, cap: i64) -> i64 {
452 let fd: i64 = sys_openat_rd(path)
453 if fd < 0 { return 0 }
454 var total: i64 = 0
455 var n: i64 = sys_read(fd, buf, cap)
456 while n > 0 { total = total + n; if total >= cap { n = 0 } else { n = sys_read(fd, (buf as i64 + total) as *u8, cap - total) } }
457 sys_close(fd)
458 return total
459}
460
461// Sovereign replacement for pkill: scan /proc, kill every process whose /proc/<pid>/cmdline contains
462// `needle`. No shell. Uses getdents64 + read_file + nx_kill (the now-working sovereign kill).
463func proc_kill_by_name(needle: *u8, sig: i64) -> i64 {
464 let nn: i64 = hc_slen(needle)
465 let fd: i64 = sys_openat_rd("/proc" as *u8)
466 if fd < 0 { return 0 }
467 let buf: *u8 = sys_mmap(HC_MAGIC_65536)
468 let path: *u8 = sys_mmap(256)
469 let clbox: *i64 = sys_mmap(16) as *i64; let clbuf: *u8 = sys_mmap(HC_MAGIC_8192)
470 var killed: i64 = 0
471 var run: i64 = 1
472 while run == 1 {
473 let n: i64 = sys_getdents64(fd, buf, HC_MAGIC_65536)
474 if n <= 0 { run = 0 } else {
475 var off: i64 = 0
476 while off < n {
477 let rec: *u8 = ((buf as i64 + off) as *u8)
478 let reclen: i64 = dirent_reclen(rec)
479 if reclen <= 0 { off = n } else {
480 let name: *u8 = dirent_name(rec)
481 if name[0] >= (48 as u8) { if name[0] <= (57 as u8) {
482 var p: i64 = 0
483 let pre: *u8 = "/proc/" as *u8
484 var a: i64 = 0; while pre[a]!=(0 as u8){path[p]=pre[a];p=p+1;a=a+1}
485 a = 0; while name[a]!=(0 as u8){path[p]=name[a];p=p+1;a=a+1}
486 let suf: *u8 = "/cmdline" as *u8
487 a = 0; while suf[a]!=(0 as u8){path[p]=suf[a];p=p+1;a=a+1}
488 path[p] = 0 as u8
489 let cln: i64 = hc_read_cmdline(path, clbuf, HC_MAGIC_8192)
490 if cln > 0 { if hc_contains(clbuf, cln, needle, nn) == 1 {
491 nx_kill(hc_atoi(name), sig)
492 killed = killed + 1
493 } }
494 } }
495 off = off + reclen
496 }
497 }
498 }
499 }
500 sys_close(fd)
501 sys_munmap(buf, HC_MAGIC_65536); sys_munmap(path, 256); sys_munmap(clbox as *u8, 16); sys_munmap(clbuf, HC_MAGIC_8192) // FREE scan buffers (no leak)
502 return killed
503}
504
505// Kill every process whose /proc/<pid>/cmdline contains BOTH needles. CRITICAL: a single broad needle like
506// "supervise" also matches the OS's s6-supervise service processes (openssh/nginx/docker/gitea/calibre-web/
507// lanraragi/redis/...) -- killing those would take down SSH and every container. Requiring "nx_hostctl" AND
508// "supervise" TOGETHER uniquely targets our own supervisor ("./nx_hostctl supervise") and nothing else: the
509// "selfswap" process has nx_hostctl but not supervise; s6-supervise has supervise but not nx_hostctl.
510func proc_kill_by_two(n1: *u8, n2: *u8, sig: i64) -> i64 {
511 let l1: i64 = hc_slen(n1); let l2: i64 = hc_slen(n2)
512 let fd: i64 = sys_openat_rd("/proc" as *u8)
513 if fd < 0 { return 0 }
514 let buf: *u8 = sys_mmap(HC_MAGIC_65536); let path: *u8 = sys_mmap(256); let clbox: *i64 = sys_mmap(16) as *i64; let clbuf: *u8 = sys_mmap(HC_MAGIC_8192)
515 var killed: i64 = 0; var run: i64 = 1
516 while run == 1 {
517 let n: i64 = sys_getdents64(fd, buf, HC_MAGIC_65536)
518 if n <= 0 { run = 0 } else {
519 var off: i64 = 0
520 while off < n {
521 let rec: *u8 = ((buf as i64 + off) as *u8)
522 let reclen: i64 = dirent_reclen(rec)
523 if reclen <= 0 { off = n } else {
524 let name: *u8 = dirent_name(rec)
525 if name[0] >= (48 as u8) { if name[0] <= (57 as u8) {
526 var p: i64 = 0; let pre: *u8 = "/proc/" as *u8
527 var a: i64 = 0; while pre[a]!=(0 as u8){path[p]=pre[a];p=p+1;a=a+1}
528 a = 0; while name[a]!=(0 as u8){path[p]=name[a];p=p+1;a=a+1}
529 let suf: *u8 = "/cmdline" as *u8
530 a = 0; while suf[a]!=(0 as u8){path[p]=suf[a];p=p+1;a=a+1}
531 path[p] = 0 as u8
532 let cln: i64 = hc_read_cmdline(path, clbuf, HC_MAGIC_8192)
533 if cln > 0 {
534 if hc_contains(clbuf, cln, n1, l1) == 1 { if hc_contains(clbuf, cln, n2, l2) == 1 {
535 nx_kill(hc_atoi(name), sig)
536 killed = killed + 1
537 } }
538 }
539 } }
540 off = off + reclen
541 }
542 }
543 }
544 }
545 sys_close(fd)
546 sys_munmap(buf, HC_MAGIC_65536); sys_munmap(path, 256); sys_munmap(clbox as *u8, 16); sys_munmap(clbuf, HC_MAGIC_8192) // FREE scan buffers (no leak)
547 return killed
548}
549
550// READ-ONLY: 1 if any process cmdline contains `needle` (no kill). Lets the supervisor ADOPT a running
551// daemon instead of blindly re-spawning it (which would EADDRINUSE on a live :8443).
552// seq1318 (RE-APPLIED 4th time): ONE /proc walk per poll, shared by every guard, instead of a full
553// /proc walk PER GUARD PER POLL (~25 x ~950 = ~23,775 cmdline reads/poll). Measured 180 -> 11
554// jiffies/60s. ps_alive_or_direct is ASYMMETRIC: ALIVE is free from the snapshot; a NOT-ALIVE
555// verdict -- the one that makes this supervisor kill and spawn -- is re-verified against a
556// snapshot <=250ms old, so a stale negative can never double-spawn a just-started daemon.
557// The old inline scan lives in nx_proc_snapshot.nx:ps_alive_direct as the fallback AND the gate oracle.
558func proc_alive_by_name(needle: *u8) -> i64 {
559 return ps_alive_or_direct(needle)
560}
561
562// Respawn a daemon (sites.elf/redirect/vroom/translate) via SINGLE fork + nx_setsid (the daemon becomes a
563// SESSION LEADER, no controlling terminal) + execve -- the exact property the durable `setsid ./sites.elf`
564// has, which PROVABLY survives. The old plain fork+execve left the daemon in the supervisor's session with a
565// ctty and it DIED on the next poll ("restarted (was dead)" forever). The daemon stays this supervisor's CHILD
566// (ppid=supervisor) so the poll-loop reap (wait4 WNOHANG) still collects it if it dies -- we do NOT wait4 here
567// (the daemon runs forever). Returns the daemon pid for hc_write_pid.
568func hc_spawn_path(pth: *u8) -> i64 {
569 let pid: i64 = sys_fork()
570 if pid==0 {
571 nx_setsid()
572 let dn: i64 = sys_openat_wr("/dev/null" as *u8, 0x1a4)
573 if dn >= 0 { sys_dup3(dn,0,0); sys_dup3(dn,1,0); sys_dup3(dn,2,0) }
574 let argv: *i64 = sys_mmap(16) as *i64; argv[0]=pth as i64; argv[1]=0
575 let envp: *i64 = sys_mmap(16) as *i64; envp[0]="PATH=/usr/bin:/bin" as *u8 as i64; envp[1]=0
576 sys_execve_clean(pth, argv, envp)
577 sys_exit(127)
578 return 0
579 }
580 return pid
581}
582
583// CrashLoopBackOff guard params, passed POSITIONALLY to rg_should_restart(ws,cnt,now,cap_ms,base_ms) -- see
584// nx_restart_guard.nx (S-class containment: K8s CrashLoopBackOff + OTP intensity + capped exponential backoff).
585// HC_GUARD_INTERVAL_MS = backoff CAP (max wait between restarts of a hard loop); HC_GUARD_BURST = backoff BASE
586// (first step, doubling each repeat crash). With the ~15s poll: the first ~4 crashes restart at poll rate, then the
587// wait escalates 16s->32s->...->5min cap = a hard crash-loop is CONTAINED to ~1 restart/5min (was: 5 per 2min,
588// reset each window = a SLOW INFINITE loop that spammed logs + starved CPU). A daemon that ran healthy >=
589// RG_HEALTH_RESET_MS(60s) before dying resets -> immediate restart (auto-recovery). (Names kept to avoid touching
590// the 12 call sites; reinterpreted per this comment -- TODO rename to HC_BACKOFF_CAP_MS/HC_BACKOFF_BASE_MS.)
591const HC_GUARD_INTERVAL_MS: i64 = 300000 // cap_ms: 5 min (K8s CrashLoopBackOff ceiling)
592const HC_GUARD_BURST: i64 = 1000 // base_ms: 1s first backoff step (doubles each repeated crash)
593
594// Does this daemon need a restart? DEAD (PID gone) -> yes. ALIVE but its PLAINTEXT port probes HUNG (up but
595// not serving) -> yes. port<=0 = PID-liveness only (TLS / unprobeable daemon) so alive is sufficient.
596func hc_needs_restart(alive: i64, port: i64) -> i64 {
597 if alive == 0 { return 1 }
598 if port <= 0 { return 0 }
599 if hp_probe(port, 3) == HP_HUNG { return 1 }
600 return 0
601}
602
603// Guard one daemon: liveness + (plaintext) serving-probe -> crash-loop-guarded restart. ws/cnt = caller-owned
604// 2-word guard state. write_pid=1 records the new pid (sites.elf). Returns 1 if it restarted, else 0.
605func hc_guard_one(name: *u8, path: *u8, port: i64, ws: *i64, cnt: *i64, pidpath: *u8, write_pid: i64) -> i64 {
606 let alive: i64 = proc_alive_by_name(name)
607 if hc_needs_restart(alive, port) == 0 { return 0 }
608 let now: i64 = sys_now_realtime_ms()
609 if rg_should_restart(ws, cnt, now, HC_GUARD_INTERVAL_MS, HC_GUARD_BURST) == 0 {
610 hc_puts(" [guard] " as *u8); hc_puts(name); hc_puts(" crash-looping -> BACKING OFF (not restarting this window)\n" as *u8)
611 return 0
612 }
613 if alive == 1 { proc_kill_by_name(name, 9) } // wedged husk: kill it so the respawn binds the port cleanly
614 let p: i64 = hc_spawn_path(path)
615 if write_pid == 1 { hc_write_pid(pidpath, p) }
616 hc_puts(" [guard] restarted " as *u8); hc_puts(name)
617 if alive == 1 { hc_puts(" (was HUNG)\n" as *u8) } else { hc_puts(" (was dead)\n" as *u8) }
618 return 1
619}
620
621// Spawn the auth'd library reader WITH its args (keysfile storefile realm port) + the correct CWD (its
622// relative knowledge/_offc paths). hc_spawn_path can't -- it execs bare, no args, wrong CWD.
623func hc_spawn_reader() -> i64 {
624 let pid: i64 = sys_fork()
625 if pid==0 {
626 let argv: *i64 = sys_mmap(32) as *i64
627 argv[0]=HC_SH as i64; argv[1]=HC_DASHC as i64; argv[2]=HC_READER_CMD as i64; argv[3]=0
628 let envp: *i64 = sys_mmap(16) as *i64; envp[0]="PATH=/usr/bin:/bin" as *u8 as i64; envp[1]=0
629 sys_execve_clean(HC_SH, argv, envp)
630 hc_puts(" [spawn_reader] EXECVE /bin/sh FAILED\n" as *u8)
631 sys_exit(127)
632 }
633 return pid
634}
635// Spawn the gallery serve (:18090) / gateway (:18190) WITH cwd+args via sh -c exec (same robust pattern as the
636// reader; hc_spawn_path execs bare/no-args/wrong-cwd). The gateway needs its OPAQUE realm keys+store + backend.
637func hc_spawn_galx_serve() -> i64 {
638 let pid: i64 = sys_fork()
639 if pid==0 {
640 nx_setsid() // SESSION LEADER + detach ctty -> survives the poll loop (the property hc_spawn_path has)
641 let dn: i64 = sys_openat_wr("/dev/null" as *u8, 0x1a4)
642 if dn >= 0 { sys_dup3(dn,0,0); sys_dup3(dn,1,0); sys_dup3(dn,2,0) }
643 let argv: *i64 = sys_mmap(32) as *i64
644 argv[0]=HC_SH as i64; argv[1]=HC_DASHC as i64; argv[2]=HC_GALX_SERVE_CMD as i64; argv[3]=0
645 let envp: *i64 = sys_mmap(16) as *i64; envp[0]="PATH=/usr/bin:/bin" as *u8 as i64; envp[1]=0
646 sys_execve_clean(HC_SH, argv, envp)
647 sys_exit(127)
648 }
649 return pid
650}
651// archive server :18801 -- byte-for-byte the hc_spawn_galx_serve pattern, only the command differs.
652// setsid + /dev/null on 0,1,2 + sh -c (exec) with the right cwd: the three properties hc_spawn_path lacks.
653func hc_spawn_arcsrv() -> i64 {
654 let pid: i64 = sys_fork()
655 if pid==0 {
656 nx_setsid() // SESSION LEADER + detach ctty -> survives the poll loop
657 let dn: i64 = sys_openat_wr("/dev/null" as *u8, 0x1a4)
658 if dn >= 0 { sys_dup3(dn,0,0); sys_dup3(dn,1,0); sys_dup3(dn,2,0) }
659 let argv: *i64 = sys_mmap(32) as *i64
660 argv[0]=HC_SH as i64; argv[1]=HC_DASHC as i64; argv[2]=HC_ARCSRV_CMD as i64; argv[3]=0
661 let envp: *i64 = sys_mmap(16) as *i64; envp[0]="PATH=/usr/bin:/bin" as *u8 as i64; envp[1]=0
662 sys_execve_clean(HC_SH, argv, envp)
663 sys_exit(127)
664 }
665 return pid
666}
667func hc_spawn_galx_gw() -> i64 {
668 let pid: i64 = sys_fork()
669 if pid==0 {
670 nx_setsid() // SESSION LEADER + detach ctty -> survives the poll loop (the property hc_spawn_path has)
671 let dn: i64 = sys_openat_wr("/dev/null" as *u8, 0x1a4)
672 if dn >= 0 { sys_dup3(dn,0,0); sys_dup3(dn,1,0); sys_dup3(dn,2,0) }
673 let argv: *i64 = sys_mmap(32) as *i64
674 argv[0]=HC_SH as i64; argv[1]=HC_DASHC as i64; argv[2]=HC_GALX_GW_CMD as i64; argv[3]=0
675 let envp: *i64 = sys_mmap(16) as *i64; envp[0]="PATH=/usr/bin:/bin" as *u8 as i64; envp[1]=0
676 sys_execve_clean(HC_SH, argv, envp)
677 sys_exit(127)
678 }
679 return pid
680}
681// spawn the wiki OPAQUE gateway (:18791) -- same sh -c (exec) detach pattern as the gallery gateway, so the
682// exec'd nx_wiki_gw.elf is THIS supervisor's direct child + proc_alive_by_name("nx_wiki_gw.elf") finds it.
683func hc_spawn_wiki_gw() -> i64 {
684 let pid: i64 = sys_fork()
685 if pid==0 {
686 nx_setsid()
687 let dn: i64 = sys_openat_wr("/dev/null" as *u8, 0x1a4)
688 if dn >= 0 { sys_dup3(dn,0,0); sys_dup3(dn,1,0); sys_dup3(dn,2,0) }
689 let argv: *i64 = sys_mmap(32) as *i64
690 argv[0]=HC_SH as i64; argv[1]=HC_DASHC as i64; argv[2]=HC_WIKI_GW_CMD as i64; argv[3]=0
691 let envp: *i64 = sys_mmap(16) as *i64; envp[0]="PATH=/usr/bin:/bin" as *u8 as i64; envp[1]=0
692 sys_execve_clean(HC_SH, argv, envp)
693 sys_exit(127)
694 }
695 return pid
696}
697// spawn the hub OPAQUE gateway (:18792) -- mirrors hc_spawn_wiki_gw (sh -c exec detach; direct child of this supervisor).
698func hc_spawn_hub_gw() -> i64 {
699 let pid: i64 = sys_fork()
700 if pid==0 {
701 nx_setsid()
702 let dn: i64 = sys_openat_wr("/dev/null" as *u8, 0x1a4)
703 if dn >= 0 { sys_dup3(dn,0,0); sys_dup3(dn,1,0); sys_dup3(dn,2,0) }
704 let argv: *i64 = sys_mmap(32) as *i64
705 argv[0]=HC_SH as i64; argv[1]=HC_DASHC as i64; argv[2]=HC_HUB_GW_CMD as i64; argv[3]=0
706 let envp: *i64 = sys_mmap(16) as *i64; envp[0]="PATH=/usr/bin:/bin" as *u8 as i64; envp[1]=0
707 sys_execve_clean(HC_SH, argv, envp)
708 sys_exit(127)
709 }
710 return pid
711}
712// spawn the gen orchestrator (:18795) + gateway (:18794) -- mirror hc_spawn_hub_gw (sh -c exec detach;
713// direct child of this supervisor so proc_alive_by_name finds them).
714func hc_spawn_gen_orch() -> i64 {
715 let pid: i64 = sys_fork()
716 if pid==0 {
717 nx_setsid()
718 let dn: i64 = sys_openat_wr("/dev/null" as *u8, 0x1a4)
719 if dn >= 0 { sys_dup3(dn,0,0); sys_dup3(dn,1,0); sys_dup3(dn,2,0) }
720 let argv: *i64 = sys_mmap(32) as *i64
721 argv[0]=HC_SH as i64; argv[1]=HC_DASHC as i64; argv[2]=HC_GEN_ORCH_CMD as i64; argv[3]=0
722 let envp: *i64 = sys_mmap(16) as *i64; envp[0]="PATH=/usr/bin:/bin" as *u8 as i64; envp[1]=0
723 sys_execve_clean(HC_SH, argv, envp)
724 sys_exit(127)
725 }
726 return pid
727}
728func hc_spawn_gen_gw() -> i64 {
729 let pid: i64 = sys_fork()
730 if pid==0 {
731 nx_setsid()
732 let dn: i64 = sys_openat_wr("/dev/null" as *u8, 0x1a4)
733 if dn >= 0 { sys_dup3(dn,0,0); sys_dup3(dn,1,0); sys_dup3(dn,2,0) }
734 let argv: *i64 = sys_mmap(32) as *i64
735 argv[0]=HC_SH as i64; argv[1]=HC_DASHC as i64; argv[2]=HC_GEN_GW_CMD as i64; argv[3]=0
736 let envp: *i64 = sys_mmap(16) as *i64; envp[0]="PATH=/usr/bin:/bin" as *u8 as i64; envp[1]=0
737 sys_execve_clean(HC_SH, argv, envp)
738 sys_exit(127)
739 }
740 return pid
741}
742// spawn the SYNTH STUDIO daemon (:18796) -- mirror hc_spawn_gen_orch (sh -c exec detach).
743func hc_spawn_synth() -> i64 {
744 let pid: i64 = sys_fork()
745 if pid==0 {
746 nx_setsid()
747 let dn: i64 = sys_openat_wr("/dev/null" as *u8, 0x1a4)
748 if dn >= 0 { sys_dup3(dn,0,0); sys_dup3(dn,1,0); sys_dup3(dn,2,0) }
749 let argv: *i64 = sys_mmap(32) as *i64
750 argv[0]=HC_SH as i64; argv[1]=HC_DASHC as i64; argv[2]=HC_SYNTH_CMD as i64; argv[3]=0
751 let envp: *i64 = sys_mmap(16) as *i64; envp[0]="PATH=/usr/bin:/bin" as *u8 as i64; envp[1]=0
752 sys_execve_clean(HC_SH, argv, envp)
753 sys_exit(127)
754 }
755 return pid
756}
757// spawn the DEV/CI API daemon (:18797) -- mirror hc_spawn_synth (sh -c exec detach).
758func hc_spawn_devapi() -> i64 {
759 let pid: i64 = sys_fork()
760 if pid==0 {
761 nx_setsid()
762 let dn: i64 = sys_openat_wr("/dev/null" as *u8, 0x1a4)
763 if dn >= 0 { sys_dup3(dn,0,0); sys_dup3(dn,1,0); sys_dup3(dn,2,0) }
764 let argv: *i64 = sys_mmap(32) as *i64
765 argv[0]=HC_SH as i64; argv[1]=HC_DASHC as i64; argv[2]=HC_DEVAPI_CMD as i64; argv[3]=0
766 let envp: *i64 = sys_mmap(16) as *i64; envp[0]="PATH=/usr/bin:/bin" as *u8 as i64; envp[1]=0
767 sys_execve_clean(HC_SH, argv, envp)
768 sys_exit(127)
769 }
770 return pid
771}
772// spawn the media/torrent daemon (:8097) via the portable launcher nx_media_env hub -- mirrors hc_spawn_hub_gw.
773func hc_spawn_torrent() -> i64 {
774 let pid: i64 = sys_fork()
775 if pid==0 {
776 nx_setsid()
777 let dn: i64 = sys_openat_wr("/dev/null" as *u8, 0x1a4)
778 if dn >= 0 { sys_dup3(dn,0,0); sys_dup3(dn,1,0); sys_dup3(dn,2,0) }
779 let argv: *i64 = sys_mmap(32) as *i64
780 argv[0]=HC_SH as i64; argv[1]=HC_DASHC as i64; argv[2]=HC_TORRENT_CMD as i64; argv[3]=0
781 let envp: *i64 = sys_mmap(16) as *i64; envp[0]="PATH=/usr/bin:/bin" as *u8 as i64; envp[1]=0
782 sys_execve_clean(HC_SH, argv, envp)
783 sys_exit(127)
784 }
785 return pid
786}
787// spawn the torrent OPAQUE gateway (:18793) -- mirrors hc_spawn_torrent / hc_spawn_hub_gw.
788func hc_spawn_torrent_gw() -> i64 {
789 let pid: i64 = sys_fork()
790 if pid==0 {
791 nx_setsid()
792 let dn: i64 = sys_openat_wr("/dev/null" as *u8, 0x1a4)
793 if dn >= 0 { sys_dup3(dn,0,0); sys_dup3(dn,1,0); sys_dup3(dn,2,0) }
794 let argv: *i64 = sys_mmap(32) as *i64
795 argv[0]=HC_SH as i64; argv[1]=HC_DASHC as i64; argv[2]=HC_TORRENT_GW_CMD as i64; argv[3]=0
796 let envp: *i64 = sys_mmap(16) as *i64; envp[0]="PATH=/usr/bin:/bin" as *u8 as i64; envp[1]=0
797 sys_execve_clean(HC_SH, argv, envp)
798 sys_exit(127)
799 }
800 return pid
801}
802// Guard the library reader: liveness + plaintext serving-probe (it serves the login shell on GET / => 200,
803// so hp_probe sees it serving) -> crash-loop-guarded restart-WITH-ARGS. hc_guard_one can't pass args.
804// PID-ONLY (port 0), NOT a serving-probe: ROOT-CAUSE (spawntest-proven) -- hp_probe connects, sends /healthz,
805// reads only 4096 bytes, then CLOSES; the reader writes the (larger) login-shell response into that closed
806// socket -> SIGPIPE -> the reader (no SIGPIPE handler) is TERMINATED. So the supervisor's own health-probe was
807// killing the reader every poll (a curl that reads fully never trips it -- which is why manual launch worked).
808// Liveness-only avoids touching the reader's socket. (The deeper fix = reader ignores SIGPIPE; tracked.)
809func hc_guard_reader(ws: *i64, cnt: *i64) -> i64 {
810 let alive: i64 = proc_alive_by_name("nx_media_server_auth.elf" as *u8)
811 if hc_needs_restart(alive, 0) == 0 { return 0 }
812 let now: i64 = sys_now_realtime_ms()
813 if rg_should_restart(ws, cnt, now, HC_GUARD_INTERVAL_MS, HC_GUARD_BURST) == 0 {
814 hc_puts(" [guard] nx_media_server_auth.elf crash-looping -> BACKING OFF (this window)\n" as *u8); return 0
815 }
816 if alive == 1 { proc_kill_by_name("nx_media_server_auth.elf" as *u8, 9) }
817 hc_spawn_reader()
818 hc_puts(" [guard] restarted nx_media_server_auth.elf (library reader, :8791)")
819 if alive == 1 { hc_puts(" (was HUNG)\n" as *u8) } else { hc_puts(" (was dead)\n" as *u8) }
820 return 1
821}
822// Guard the gallery serve/gateway: liveness-only (the listener is fork-per-request; a serving-probe could
823// SIGPIPE a request child, so we trust PID-liveness like sites.elf:8443) -> crash-loop-guarded respawn-with-args.
824func hc_guard_galx_serve(ws: *i64, cnt: *i64) -> i64 {
825 if proc_alive_by_name("nx_gallery_serve.elf" as *u8) == 1 { return 0 }
826 let now: i64 = sys_now_realtime_ms()
827 if rg_should_restart(ws, cnt, now, HC_GUARD_INTERVAL_MS, HC_GUARD_BURST) == 0 {
828 hc_puts(" [guard] nx_gallery_serve.elf crash-looping -> BACKING OFF\n" as *u8); return 0
829 }
830 hc_spawn_galx_serve()
831 hc_puts(" [guard] restarted nx_gallery_serve.elf :18090 (was dead)\n" as *u8)
832 return 1
833}
834// archive server :18801 -- same shape as hc_guard_galx_serve. PID-liveness only, no serving probe:
835// hp_probe sends /healthz, reads, then CLOSES, which is exactly what SIGPIPE-killed redirect.elf and the
836// reader every poll. Verify this one is serving with an external GET, never with the probe.
837func hc_guard_arcsrv(ws: *i64, cnt: *i64) -> i64 {
838 if proc_alive_by_name("nx_archive_server.elf" as *u8) == 1 { return 0 }
839 let now: i64 = sys_now_realtime_ms()
840 if rg_should_restart(ws, cnt, now, HC_GUARD_INTERVAL_MS, HC_GUARD_BURST) == 0 {
841 hc_puts(" [guard] nx_archive_server.elf crash-looping -> BACKING OFF\n" as *u8); return 0
842 }
843 hc_spawn_arcsrv()
844 hc_puts(" [guard] restarted nx_archive_server.elf :18801 (was dead)\n" as *u8)
845 return 1
846}
847func hc_guard_galx_gw(ws: *i64, cnt: *i64) -> i64 {
848 if proc_alive_by_name("nx_gallery_gateway.elf" as *u8) == 1 { return 0 }
849 let now: i64 = sys_now_realtime_ms()
850 if rg_should_restart(ws, cnt, now, HC_GUARD_INTERVAL_MS, HC_GUARD_BURST) == 0 {
851 hc_puts(" [guard] nx_gallery_gateway.elf crash-looping -> BACKING OFF\n" as *u8); return 0
852 }
853 hc_spawn_galx_gw()
854 hc_puts(" [guard] restarted nx_gallery_gateway.elf :18190 (was dead)\n" as *u8)
855 return 1
856}
857// Guard the wiki OPAQUE gateway (:18791): liveness-only (fork-per-request listener; a serving-probe could
858// SIGPIPE a request child, like the gallery) -> crash-loop-guarded respawn. This + the poll loop = the wiki
859// gateway is now permanently supervised: it auto-restarts on crash/kill forever, no manual setsid ever again.
860func hc_guard_wiki_gw(ws: *i64, cnt: *i64) -> i64 {
861 if proc_alive_by_name("nx_wiki_gw.elf" as *u8) == 1 { return 0 }
862 let now: i64 = sys_now_realtime_ms()
863 if rg_should_restart(ws, cnt, now, HC_GUARD_INTERVAL_MS, HC_GUARD_BURST) == 0 {
864 hc_puts(" [guard] nx_wiki_gw.elf crash-looping -> BACKING OFF\n" as *u8); return 0
865 }
866 hc_spawn_wiki_gw()
867 hc_puts(" [guard] restarted nx_wiki_gw.elf :18791 (was dead)\n" as *u8)
868 return 1
869}
870// Guard the hub OPAQUE gateway (:18792): liveness-only, crash-loop-guarded respawn (mirrors hc_guard_wiki_gw).
871// Until the binary is deployed to HC_HUB_GW it simply backs off (exec fails -> child exits) -- fail-safe, no harm.
872func hc_guard_hub_gw(ws: *i64, cnt: *i64) -> i64 {
873 if proc_alive_by_name("nx_hub_gw.elf" as *u8) == 1 { return 0 }
874 let now: i64 = sys_now_realtime_ms()
875 if rg_should_restart(ws, cnt, now, HC_GUARD_INTERVAL_MS, HC_GUARD_BURST) == 0 {
876 hc_puts(" [guard] nx_hub_gw.elf crash-looping -> BACKING OFF\n" as *u8); return 0
877 }
878 hc_spawn_hub_gw()
879 hc_puts(" [guard] restarted nx_hub_gw.elf :18792 (was dead)\n" as *u8)
880 return 1
881}
882// spawn the Relationship OS daemon (:8027 loopback) -- mirrors hc_spawn_hub_gw.
883func hc_spawn_relate() -> i64 {
884 let pid: i64 = sys_fork()
885 if pid==0 {
886 nx_setsid()
887 let dn: i64 = sys_openat_wr("/dev/null" as *u8, 0x1a4)
888 if dn >= 0 { sys_dup3(dn,0,0); sys_dup3(dn,1,0); sys_dup3(dn,2,0) }
889 let argv: *i64 = sys_mmap(32) as *i64
890 argv[0]=HC_SH as i64; argv[1]=HC_DASHC as i64; argv[2]=HC_RELATE_CMD as i64; argv[3]=0
891 let envp: *i64 = sys_mmap(16) as *i64; envp[0]="PATH=/usr/bin:/bin" as *u8 as i64; envp[1]=0
892 sys_execve_clean(HC_SH, argv, envp)
893 sys_exit(127)
894 }
895 return pid
896}
897// Guard the Relationship OS daemon (:8027). liveness-only, crash-loop-guarded (mirrors hc_guard_mgmt).
898// Backs off until nx_relate_daemon.elf is promoted (exec fails -> child exits) -- fail-safe, no harm pre-deploy.
899func hc_guard_relate(ws: *i64, cnt: *i64) -> i64 {
900 if proc_alive_by_name("nx_relate_daemon.elf" as *u8) == 1 { return 0 }
901 let now: i64 = sys_now_realtime_ms()
902 if rg_should_restart(ws, cnt, now, HC_GUARD_INTERVAL_MS, HC_GUARD_BURST) == 0 {
903 hc_puts(" [guard] nx_relate_daemon.elf crash-looping -> BACKING OFF\n" as *u8); return 0
904 }
905 hc_spawn_relate()
906 hc_puts(" [guard] restarted nx_relate_daemon.elf :8027 (was dead)\n" as *u8)
907 return 1
908}
909// spawn the ethical CLEAN-SERVE daemon (:8102 -- /clean) -- mirrors hc_spawn_relate.
910func hc_spawn_cleanserve() -> i64 {
911 let pid: i64 = sys_fork()
912 if pid==0 {
913 nx_setsid()
914 let dn: i64 = sys_openat_wr("/dev/null" as *u8, 0x1a4)
915 if dn >= 0 { sys_dup3(dn,0,0); sys_dup3(dn,1,0); sys_dup3(dn,2,0) }
916 let argv: *i64 = sys_mmap(32) as *i64
917 argv[0]=HC_SH as i64; argv[1]=HC_DASHC as i64; argv[2]=HC_CLEANSERVE_CMD as i64; argv[3]=0
918 let envp: *i64 = sys_mmap(16) as *i64; envp[0]="PATH=/usr/bin:/bin" as *u8 as i64; envp[1]=0
919 sys_execve_clean(HC_SH, argv, envp)
920 sys_exit(127)
921 }
922 return pid
923}
924// Guard the CLEAN-SERVE daemon (:8102). liveness-only, crash-loop-guarded (mirrors hc_guard_relate).
925// Backs off until nx_clean_serve_daemon.elf is promoted (exec fails -> child exits) -- fail-safe, no harm pre-deploy.
926func hc_guard_cleanserve(ws: *i64, cnt: *i64) -> i64 {
927 if proc_alive_by_name("nx_clean_serve_daemon.elf" as *u8) == 1 { return 0 }
928 let now: i64 = sys_now_realtime_ms()
929 if rg_should_restart(ws, cnt, now, HC_GUARD_INTERVAL_MS, HC_GUARD_BURST) == 0 {
930 hc_puts(" [guard] nx_clean_serve_daemon.elf crash-looping -> BACKING OFF\n" as *u8); return 0
931 }
932 hc_spawn_cleanserve()
933 hc_puts(" [guard] restarted nx_clean_serve_daemon.elf :8102 (was dead)\n" as *u8)
934 return 1
935}
936// spawn the WORKER MESH serve backend (:8029 -- console + SSE gen + gated image) -- mirrors hc_spawn_relate.
937func hc_spawn_mesh_serve() -> i64 {
938 let pid: i64 = sys_fork()
939 if pid==0 {
940 nx_setsid()
941 let dn: i64 = sys_openat_wr("/dev/null" as *u8, 0x1a4)
942 if dn >= 0 { sys_dup3(dn,0,0); sys_dup3(dn,1,0); sys_dup3(dn,2,0) }
943 let argv: *i64 = sys_mmap(32) as *i64
944 argv[0]=HC_SH as i64; argv[1]=HC_DASHC as i64; argv[2]=HC_MESH_SERVE_CMD as i64; argv[3]=0
945 let envp: *i64 = sys_mmap(16) as *i64; envp[0]="PATH=/usr/bin:/bin" as *u8 as i64; envp[1]=0
946 sys_execve_clean(HC_SH, argv, envp)
947 sys_exit(127)
948 }
949 return pid
950}
951// Guard the mesh serve (:8029). liveness-only, crash-loop-guarded (mirrors hc_guard_relate). Backs off until
952// nx_mesh_serve.elf is present -- fail-safe, no harm pre-deploy. ADOPTS the running setsid daemon (no double-spawn).
953func hc_guard_mesh_serve(ws: *i64, cnt: *i64) -> i64 {
954 if proc_alive_by_name("nx_mesh_serve.elf" as *u8) == 1 { return 0 }
955 let now: i64 = sys_now_realtime_ms()
956 if rg_should_restart(ws, cnt, now, HC_GUARD_INTERVAL_MS, HC_GUARD_BURST) == 0 {
957 hc_puts(" [guard] nx_mesh_serve.elf crash-looping -> BACKING OFF\n" as *u8); return 0
958 }
959 hc_spawn_mesh_serve()
960 hc_puts(" [guard] restarted nx_mesh_serve.elf :8029 (was dead)\n" as *u8)
961 return 1
962}
963// spawn the WORKER MESH OPAQUE gateway (:8055 -- gated /mesh console) -- mirrors hc_spawn_relate.
964func hc_spawn_mesh_gw() -> i64 {
965 let pid: i64 = sys_fork()
966 if pid==0 {
967 nx_setsid()
968 let dn: i64 = sys_openat_wr("/dev/null" as *u8, 0x1a4)
969 if dn >= 0 { sys_dup3(dn,0,0); sys_dup3(dn,1,0); sys_dup3(dn,2,0) }
970 let argv: *i64 = sys_mmap(32) as *i64
971 argv[0]=HC_SH as i64; argv[1]=HC_DASHC as i64; argv[2]=HC_MESH_GW_CMD as i64; argv[3]=0
972 let envp: *i64 = sys_mmap(16) as *i64; envp[0]="PATH=/usr/bin:/bin" as *u8 as i64; envp[1]=0
973 sys_execve_clean(HC_SH, argv, envp)
974 sys_exit(127)
975 }
976 return pid
977}
978// Guard the mesh gateway (:8055). liveness-only, crash-loop-guarded (mirrors hc_guard_relate). ADOPTS the running
979// setsid gateway; respawns it after crash/reboot -- this is the durability rung "run it like gallery" implies.
980func hc_guard_mesh_gw(ws: *i64, cnt: *i64) -> i64 {
981 if proc_alive_by_name("nx_mesh_gateway.elf" as *u8) == 1 { return 0 }
982 let now: i64 = sys_now_realtime_ms()
983 if rg_should_restart(ws, cnt, now, HC_GUARD_INTERVAL_MS, HC_GUARD_BURST) == 0 {
984 hc_puts(" [guard] nx_mesh_gateway.elf crash-looping -> BACKING OFF\n" as *u8); return 0
985 }
986 hc_spawn_mesh_gw()
987 hc_puts(" [guard] restarted nx_mesh_gateway.elf :8055 (was dead)\n" as *u8)
988 return 1
989}
990// spawn the /project OPAQUE gateway (:8028) -- mirrors hc_spawn_relate (sh -c exec detach).
991func hc_spawn_project() -> i64 {
992 let pid: i64 = sys_fork()
993 if pid==0 {
994 nx_setsid()
995 let dn: i64 = sys_openat_wr("/dev/null" as *u8, 0x1a4)
996 if dn >= 0 { sys_dup3(dn,0,0); sys_dup3(dn,1,0); sys_dup3(dn,2,0) }
997 let argv: *i64 = sys_mmap(32) as *i64
998 argv[0]=HC_SH as i64; argv[1]=HC_DASHC as i64; argv[2]=HC_PROJECT_CMD as i64; argv[3]=0
999 let envp: *i64 = sys_mmap(16) as *i64; envp[0]="PATH=/usr/bin:/bin" as *u8 as i64; envp[1]=0
1000 sys_execve_clean(HC_SH, argv, envp)
1001 sys_exit(127)
1002 }
1003 return pid
1004}
1005// Guard the /project OPAQUE gateway (:8028; sites gated row /project). liveness-only, crash-loop-guarded
1006// (mirrors hc_guard_relate). Backs off until nx_project_serve.elf is deployed -- fail-safe, no harm; ADOPTS
1007// an already-running detached daemon (liveness by name) exactly like the synth/devapi guards.
1008func hc_guard_project(ws: *i64, cnt: *i64) -> i64 {
1009 if proc_alive_by_name("nx_project_serve.elf" as *u8) == 1 { return 0 }
1010 let now: i64 = sys_now_realtime_ms()
1011 if rg_should_restart(ws, cnt, now, HC_GUARD_INTERVAL_MS, HC_GUARD_BURST) == 0 {
1012 hc_puts(" [guard] nx_project_serve.elf crash-looping -> BACKING OFF\n" as *u8); return 0
1013 }
1014 hc_spawn_project()
1015 hc_puts(" [guard] restarted nx_project_serve.elf :8028 (was dead)\n" as *u8)
1016 return 1
1017}
1018// spawn the sovereign management API (:18099) -- mirrors hc_spawn_hub_gw.
1019func hc_spawn_mgmt() -> i64 {
1020 let pid: i64 = sys_fork()
1021 if pid==0 {
1022 nx_setsid()
1023 let dn: i64 = sys_openat_wr("/dev/null" as *u8, 0x1a4)
1024 if dn >= 0 { sys_dup3(dn,0,0); sys_dup3(dn,1,0); sys_dup3(dn,2,0) }
1025 let argv: *i64 = sys_mmap(32) as *i64
1026 argv[0]=HC_SH as i64; argv[1]=HC_DASHC as i64; argv[2]=HC_MGMT_CMD as i64; argv[3]=0
1027 let envp: *i64 = sys_mmap(16) as *i64; envp[0]="PATH=/usr/bin:/bin" as *u8 as i64; envp[1]=0
1028 sys_execve_clean(HC_SH, argv, envp)
1029 sys_exit(127)
1030 }
1031 return pid
1032}
1033// Guard the sovereign MANAGEMENT API (:18099 loopback HTTP -> /api). liveness-only, crash-loop-guarded
1034// (mirrors hc_guard_hub_gw). Backs off until nx_mgmt_api.elf is deployed -- fail-safe, no harm.
1035func hc_guard_mgmt(ws: *i64, cnt: *i64) -> i64 {
1036 if proc_alive_by_name("nx_mgmt_api.elf" as *u8) == 1 { return 0 }
1037 let now: i64 = sys_now_realtime_ms()
1038 if rg_should_restart(ws, cnt, now, HC_GUARD_INTERVAL_MS, HC_GUARD_BURST) == 0 {
1039 hc_puts(" [guard] nx_mgmt_api.elf crash-looping -> BACKING OFF\n" as *u8); return 0
1040 }
1041 hc_spawn_mgmt()
1042 hc_puts(" [guard] restarted nx_mgmt_api.elf :18099 (was dead)\n" as *u8)
1043 return 1
1044}
1045// spawn the doc-portal ADMIN daemon (:8456) -- mirrors hc_spawn_mgmt.
1046func hc_spawn_admin() -> i64 {
1047 let pid: i64 = sys_fork()
1048 if pid==0 {
1049 nx_setsid()
1050 let dn: i64 = sys_openat_wr("/dev/null" as *u8, 0x1a4)
1051 if dn >= 0 { sys_dup3(dn,0,0); sys_dup3(dn,1,0); sys_dup3(dn,2,0) }
1052 let argv: *i64 = sys_mmap(32) as *i64
1053 argv[0]=HC_SH as i64; argv[1]=HC_DASHC as i64; argv[2]=HC_ADMIN_CMD as i64; argv[3]=0
1054 let envp: *i64 = sys_mmap(16) as *i64; envp[0]="PATH=/usr/bin:/bin" as *u8 as i64; envp[1]=0
1055 sys_execve_clean(HC_SH, argv, envp)
1056 sys_exit(127)
1057 }
1058 return pid
1059}
1060// Guard the doc-portal ADMIN daemon (:8456 loopback HTTP -> admin.<d>/). liveness-only, crash-loop-guarded
1061// (mirrors hc_guard_mgmt). Backs off until nx_docportal_admin_daemon.elf is deployed -- fail-safe, no harm.
1062// LISTEN DEADLINE FOR THE ADMIN DAEMON (2026-09-02, debt 1788361379). MEASURED: after a SIGSEGV this guard respawned
1063// nx_docportal_admin_daemon and the respawn SPUN 15.9h of user CPU inside its shard pre-warm with :18456 NEVER opened --
1064// and the name-only check below was satisfied the whole time, so nishifamily.com/search answered 503 for ~16h while
1065// /api/services and nx_health (both fed by the same proc_alive_by_name) read UP. A live process that never binds is
1066// the one state PID-liveness cannot see, and it is exactly the state a wedged start produces.
1067// WHY A GRACE AND NOT A PROBE-ON-EVERY-POLL: this daemon deliberately opens its port AFTER a warm-before-listen phase
1068// (10-15s measured at load 20) that can also wait on the tool-registry lock (6 min measured on 2026-09-01), so one
1069// refusal is not evidence and killing on it would manufacture the crash loop this file records for the reader. A
1070// refusal that PERSISTS past the grace is evidence. hp_socket_dead is connect-only (it never writes a byte -- the
1071// SIGPIPE class recorded twice in this file) and demands two refusals HP_CONFIRM_GAP_MS apart, paid only on the
1072// refused path. DERIVED, NOT GUESSED: 40 polls x the ~15s supervise cadence = 600s, the measured worst legitimate
1073// cold start (6 min lock wait + 13s warm) with margin; every waiting poll is ANNOUNCED so the bound is visible.
1074const HC_ADMIN_BIND_GRACE_POLLS: i64 = 40
1075static hc_adm_dead_polls: i64
1076func hc_guard_admin(ws: *i64, cnt: *i64) -> i64 {
1077 if proc_alive_by_name("nx_docportal_admin_daemon.elf" as *u8) == 1 {
1078 if hp_socket_dead(HC_MAGIC_18456) == 0 { hc_adm_dead_polls = 0; return 0 }
1079 hc_adm_dead_polls = hc_adm_dead_polls + 1
1080 hc_puts(" [guard] nx_docportal_admin_daemon.elf ALIVE but :18456 not listening -- bind-grace poll " as *u8); hc_putn(hc_adm_dead_polls)
1081 hc_puts(" of " as *u8); hc_putn(HC_ADMIN_BIND_GRACE_POLLS); hc_puts("\n" as *u8)
1082 if rg_bind_grace_expired(1, 1, hc_adm_dead_polls, HC_ADMIN_BIND_GRACE_POLLS) == 0 { return 0 } // PURE policy in nx_restart_guard, refereed by nx_restart_guard_gate T6-T10
1083 let now2: i64 = sys_now_realtime_ms()
1084 if rg_should_restart(ws, cnt, now2, HC_GUARD_INTERVAL_MS, HC_GUARD_BURST) == 0 {
1085 hc_puts(" [guard] nx_docportal_admin_daemon.elf crash-looping -> BACKING OFF\n" as *u8); return 0
1086 }
1087 let hk: i64 = proc_kill_by_name("nx_docportal_admin_daemon.elf" as *u8, 9)
1088 hc_adm_dead_polls = 0
1089 hc_spawn_admin()
1090 hc_puts(" [guard] restarted nx_docportal_admin_daemon.elf (:18456 never listened inside the bind grace; killed wedged procs=" as *u8); hc_putn(hk); hc_puts(") (was HUNG-AT-START)\n" as *u8)
1091 return 1
1092 }
1093 hc_adm_dead_polls = 0
1094 let now: i64 = sys_now_realtime_ms()
1095 if rg_should_restart(ws, cnt, now, HC_GUARD_INTERVAL_MS, HC_GUARD_BURST) == 0 {
1096 hc_puts(" [guard] nx_docportal_admin_daemon.elf crash-looping -> BACKING OFF\n" as *u8); return 0
1097 }
1098 hc_spawn_admin()
1099 // ⚠PORT CORRECTED 8456 -> 18456 AND THE CHECK NAMED (2026-07-30). This line claimed :8456 while
1100 // HC_ADMIN_CMD launches the daemon on 18456 -- and the guard above does not probe a port AT ALL,
1101 // it tests proc_alive_by_name. A message that names a port it never checks invites exactly the
1102 // wrong diagnosis: I read this line, saw the live daemon on :18456, and formed a port-table
1103 // hypothesis (seq1314 class) that was simply false. The guard was right; the message lied.
1104 // ★LAW: a diagnostic must describe the check that was ACTUALLY performed. Naming a port beside a
1105 // name-based liveness test is not a harmless typo -- it is a false lead with a plausible story.
1106 hc_puts(" [guard] restarted nx_docportal_admin_daemon.elf (:18456, liveness by PROCESS NAME not port) (was dead)\n" as *u8)
1107 return 1
1108}
1109// spawn the mail.<d> EMAIL-PORTAL daemon (:18465) -- mirrors hc_spawn_admin.
1110func hc_spawn_mailportal() -> i64 {
1111 let pid: i64 = sys_fork()
1112 if pid==0 {
1113 nx_setsid()
1114 let dn: i64 = sys_openat_wr("/dev/null" as *u8, 0x1a4)
1115 if dn >= 0 { sys_dup3(dn,0,0); sys_dup3(dn,1,0); sys_dup3(dn,2,0) }
1116 let argv: *i64 = sys_mmap(32) as *i64
1117 argv[0]=HC_SH as i64; argv[1]=HC_DASHC as i64; argv[2]=HC_MAILPORTAL_CMD as i64; argv[3]=0
1118 let envp: *i64 = sys_mmap(16) as *i64; envp[0]="PATH=/usr/bin:/bin" as *u8 as i64; envp[1]=0
1119 sys_execve_clean(HC_SH, argv, envp)
1120 sys_exit(127)
1121 }
1122 return pid
1123}
1124// Guard the mail.<d> EMAIL-PORTAL daemon (:18465 loopback HTTP -> mail.<d>/). liveness-only,
1125// crash-loop-guarded; backs off until nx_email_portal_daemon.elf is deployed -- fail-safe, no harm.
1126func hc_guard_mailportal(ws: *i64, cnt: *i64) -> i64 {
1127 if proc_alive_by_name("nx_email_portal_daemon.elf" as *u8) == 1 { return 0 }
1128 let now: i64 = sys_now_realtime_ms()
1129 if rg_should_restart(ws, cnt, now, HC_GUARD_INTERVAL_MS, HC_GUARD_BURST) == 0 {
1130 hc_puts(" [guard] nx_email_portal_daemon.elf crash-looping -> BACKING OFF\n" as *u8); return 0
1131 }
1132 hc_spawn_mailportal()
1133 hc_puts(" [guard] restarted nx_email_portal_daemon.elf :18465 (was dead)\n" as *u8)
1134 return 1
1135}
1136// spawn the admin.<d>/site SITE-VISUALS editor daemon (:18466) -- mirrors hc_spawn_admin.
1137func hc_spawn_siteedit() -> i64 {
1138 let pid: i64 = sys_fork()
1139 if pid==0 {
1140 nx_setsid()
1141 let dn: i64 = sys_openat_wr("/dev/null" as *u8, 0x1a4)
1142 if dn >= 0 { sys_dup3(dn,0,0); sys_dup3(dn,1,0); sys_dup3(dn,2,0) }
1143 let argv: *i64 = sys_mmap(32) as *i64
1144 argv[0]=HC_SH as i64; argv[1]=HC_DASHC as i64; argv[2]=HC_SITEEDIT_CMD as i64; argv[3]=0
1145 let envp: *i64 = sys_mmap(16) as *i64; envp[0]="PATH=/usr/bin:/bin" as *u8 as i64; envp[1]=0
1146 sys_execve_clean(HC_SH, argv, envp)
1147 sys_exit(127)
1148 }
1149 return pid
1150}
1151// Guard the site-visuals editor (:18466 loopback HTTP -> admin.<d>/site). liveness-only,
1152// crash-loop-guarded; backs off until nx_siteedit_daemon.elf is deployed -- fail-safe, no harm.
1153func hc_guard_siteedit(ws: *i64, cnt: *i64) -> i64 {
1154 if proc_alive_by_name("nx_siteedit_daemon.elf" as *u8) == 1 { return 0 }
1155 let now: i64 = sys_now_realtime_ms()
1156 if rg_should_restart(ws, cnt, now, HC_GUARD_INTERVAL_MS, HC_GUARD_BURST) == 0 {
1157 hc_puts(" [guard] nx_siteedit_daemon.elf crash-looping -> BACKING OFF\n" as *u8); return 0
1158 }
1159 hc_spawn_siteedit()
1160 hc_puts(" [guard] restarted nx_siteedit_daemon.elf :18466 (was dead)\n" as *u8)
1161 return 1
1162}
1163func hc_spawn_inventory() -> i64 {
1164 let pid: i64 = sys_fork()
1165 if pid==0 {
1166 nx_setsid()
1167 let dn: i64 = sys_openat_wr("/dev/null" as *u8, 0x1a4)
1168 if dn >= 0 { sys_dup3(dn,0,0); sys_dup3(dn,1,0); sys_dup3(dn,2,0) }
1169 let argv: *i64 = sys_mmap(32) as *i64
1170 argv[0]=HC_SH as i64; argv[1]=HC_DASHC as i64; argv[2]=HC_INVENTORY_CMD as i64; argv[3]=0
1171 let envp: *i64 = sys_mmap(16) as *i64; envp[0]="PATH=/usr/bin:/bin" as *u8 as i64; envp[1]=0
1172 sys_execve_clean(HC_SH, argv, envp)
1173 sys_exit(127)
1174 }
1175 return pid
1176}
1177// Guard the inventory/ownership checker (:18122 LOOPBACK-ONLY -> /inventory via the proxy).
1178// Liveness-only + crash-loop-guarded, and it BACKS OFF rather than spinning if the elf is absent --
1179// fail-safe by construction: a service that is not deployed must not be able to wedge the supervisor
1180// that every other service depends on.
1181func hc_guard_inventory(ws: *i64, cnt: *i64) -> i64 {
1182 if proc_alive_by_name("nx_inventory_serve.elf" as *u8) == 1 { return 0 }
1183 let now: i64 = sys_now_realtime_ms()
1184 if rg_should_restart(ws, cnt, now, HC_GUARD_INTERVAL_MS, HC_GUARD_BURST) == 0 {
1185 hc_puts(" [guard] nx_inventory_serve.elf crash-looping -> BACKING OFF\n" as *u8); return 0
1186 }
1187 hc_spawn_inventory()
1188 hc_puts(" [guard] restarted nx_inventory_serve.elf :18122 (was dead)\n" as *u8)
1189 return 1
1190}
1191// spawn the sovereign agent-facing TOOLS API (:18096) -- mirrors hc_spawn_mgmt.
1192func hc_spawn_tapi() -> i64 {
1193 let pid: i64 = sys_fork()
1194 if pid==0 {
1195 nx_setsid()
1196 let dn: i64 = sys_openat_wr("/dev/null" as *u8, 0x1a4)
1197 if dn >= 0 { sys_dup3(dn,0,0); sys_dup3(dn,1,0); sys_dup3(dn,2,0) }
1198 let argv: *i64 = sys_mmap(32) as *i64
1199 argv[0]=HC_SH as i64; argv[1]=HC_DASHC as i64; argv[2]=HC_TAPI_CMD as i64; argv[3]=0
1200 let envp: *i64 = sys_mmap(16) as *i64; envp[0]="PATH=/usr/bin:/bin" as *u8 as i64; envp[1]=0
1201 sys_execve_clean(HC_SH, argv, envp)
1202 sys_exit(127)
1203 }
1204 return pid
1205}
1206// Guard the sovereign TOOLS API (:18096 loopback HTTP -> /api/tools + /mcp). liveness-only, crash-loop-guarded
1207// (mirrors hc_guard_mgmt). Backs off until nx_tools_api_serve.elf is deployed -- fail-safe, no harm.
1208func hc_guard_tapi(ws: *i64, cnt: *i64) -> i64 {
1209 if proc_alive_by_name("nx_tools_api_serve.elf" as *u8) == 1 { return 0 }
1210 let now: i64 = sys_now_realtime_ms()
1211 if rg_should_restart(ws, cnt, now, HC_GUARD_INTERVAL_MS, HC_GUARD_BURST) == 0 {
1212 hc_puts(" [guard] nx_tools_api_serve.elf crash-looping -> BACKING OFF\n" as *u8); return 0
1213 }
1214 hc_spawn_tapi()
1215 hc_puts(" [guard] restarted nx_tools_api_serve.elf :18096 (was dead)\n" as *u8)
1216 return 1
1217}
1218// spawn the finance dashboard server (:18097) -- mirrors hc_spawn_tapi exactly.
1219func hc_spawn_fin() -> i64 {
1220 let pid: i64 = sys_fork()
1221 if pid==0 {
1222 nx_setsid()
1223 let dn: i64 = sys_openat_wr("/dev/null" as *u8, 0x1a4)
1224 if dn >= 0 { sys_dup3(dn,0,0); sys_dup3(dn,1,0); sys_dup3(dn,2,0) }
1225 let argv: *i64 = sys_mmap(32) as *i64
1226 argv[0]=HC_SH as i64; argv[1]=HC_DASHC as i64; argv[2]=HC_FIN_CMD as i64; argv[3]=0
1227 let envp: *i64 = sys_mmap(16) as *i64; envp[0]="PATH=/usr/bin:/bin" as *u8 as i64; envp[1]=0
1228 sys_execve_clean(HC_SH, argv, envp)
1229 sys_exit(127)
1230 }
1231 return pid
1232}
1233// Guard the finance dashboard server (:18097 loopback HTTP -> /finance). liveness-only, crash-loop-guarded
1234// (mirrors hc_guard_tapi). Backs off until nx_fin_serve.elf is deployed -- fail-safe, no harm.
1235func hc_guard_fin(ws: *i64, cnt: *i64) -> i64 {
1236 if proc_alive_by_name("nx_fin_serve.elf" as *u8) == 1 { return 0 }
1237 let now: i64 = sys_now_realtime_ms()
1238 if rg_should_restart(ws, cnt, now, HC_GUARD_INTERVAL_MS, HC_GUARD_BURST) == 0 {
1239 hc_puts(" [guard] nx_fin_serve.elf crash-looping -> BACKING OFF\n" as *u8); return 0
1240 }
1241 hc_spawn_fin()
1242 hc_puts(" [guard] restarted nx_fin_serve.elf :18097 (was dead)\n" as *u8)
1243 return 1
1244}
1245// spawn the CONTINUOUS M&E evaluator (nx_health_eval loop) -- mirrors hc_spawn_fin exactly (sh -c exec
1246// detach; direct child so proc_alive_by_name finds it). It loops forever; if it ever dies, respawned.
1247func hc_spawn_health() -> i64 {
1248 let pid: i64 = sys_fork()
1249 if pid==0 {
1250 nx_setsid()
1251 let dn: i64 = sys_openat_wr("/dev/null" as *u8, 0x1a4)
1252 if dn >= 0 { sys_dup3(dn,0,0); sys_dup3(dn,1,0); sys_dup3(dn,2,0) }
1253 let argv: *i64 = sys_mmap(32) as *i64
1254 argv[0]=HC_SH as i64; argv[1]=HC_DASHC as i64; argv[2]=HC_HEALTH_CMD as i64; argv[3]=0
1255 let envp: *i64 = sys_mmap(16) as *i64; envp[0]="PATH=/usr/bin:/bin" as *u8 as i64; envp[1]=0
1256 sys_execve_clean(HC_SH, argv, envp)
1257 sys_exit(127)
1258 }
1259 return pid
1260}
1261// Guard the M&E evaluator loop. PID-liveness only (no port -- outbound TLS, listens on nothing), crash-loop
1262// guarded (mirrors hc_guard_fin). Backs off until nx_health_eval.elf + data/mozilla_certdata.txt are
1263// deployed -- fail-safe, no harm to anything else (a missing binary just means no respawn, never a brick).
1264func hc_guard_health(ws: *i64, cnt: *i64) -> i64 {
1265 if proc_alive_by_name("nx_health_eval.elf" as *u8) == 1 { return 0 }
1266 let now: i64 = sys_now_realtime_ms()
1267 if rg_should_restart(ws, cnt, now, HC_GUARD_INTERVAL_MS, HC_GUARD_BURST) == 0 {
1268 hc_puts(" [guard] nx_health_eval.elf crash-looping -> BACKING OFF\n" as *u8); return 0
1269 }
1270 hc_spawn_health()
1271 hc_puts(" [guard] restarted nx_health_eval.elf (continuous M&E loop, was dead)\n" as *u8)
1272 return 1
1273}
1274// spawn the video signaling/media relay (:8445) -- mirrors hc_spawn_health exactly.
1275func hc_spawn_sig2() -> i64 {
1276 let pid: i64 = sys_fork()
1277 if pid==0 {
1278 nx_setsid()
1279 let dn: i64 = sys_openat_wr("/dev/null" as *u8, 0x1a4)
1280 if dn >= 0 { sys_dup3(dn,0,0); sys_dup3(dn,1,0); sys_dup3(dn,2,0) }
1281 let argv: *i64 = sys_mmap(32) as *i64
1282 argv[0]=HC_SH as i64; argv[1]=HC_DASHC as i64; argv[2]=HC_SIG2_CMD as i64; argv[3]=0
1283 let envp: *i64 = sys_mmap(16) as *i64; envp[0]="PATH=/usr/bin:/bin" as *u8 as i64; envp[1]=0
1284 sys_execve_clean(HC_SH, argv, envp)
1285 sys_exit(127)
1286 }
1287 return pid
1288}
1289// Guard the signaling relay (task #26). PID-liveness ("nx_signaling_v2" needle ADOPTS one already running
1290// from any path), crash-loop guarded. Backs off until the ELF is deployed to the canonical path -- fail-safe.
1291func hc_guard_sig2(ws: *i64, cnt: *i64) -> i64 {
1292 if proc_alive_by_name("nx_signaling_v2" as *u8) == 1 { return 0 }
1293 let now: i64 = sys_now_realtime_ms()
1294 if rg_should_restart(ws, cnt, now, HC_GUARD_INTERVAL_MS, HC_GUARD_BURST) == 0 {
1295 hc_puts(" [guard] nx_signaling_v2 crash-looping -> BACKING OFF\n" as *u8); return 0
1296 }
1297 hc_spawn_sig2()
1298 hc_puts(" [guard] restarted nx_signaling_v2 :8445 (video signaling relay, was dead)\n" as *u8)
1299 return 1
1300}
1301// ---- FLEET SUPERVISOR UNDER THE HOST SUPERVISOR (2026-09-02) -------------------------------------------
1302// MEASURED: nx_execsurface's census row for nx_daemon_supervisor reads clock=0 cron=0 daemon=0 roster=0
1303// actlog=0 fork=- : NOTHING in the estate launches the fleet supervisor. Its running instance was started
1304// by a one-shot operator shell, so it could not be recycled (5.9 GB swapped, EXEMPT-TERM in resgov because
1305// nothing would revive it) and no deploy row could name-kill it. hostctl is the natural parent: the cron
1306// sentinel keeps exactly one hostctl supervise alive, and hostctl already parents the clock the same way.
1307// ADOPTS a running instance by name (PID-liveness only, no port probe: its /status is a courtesy, not a
1308// contract), respawns after death or a deploy-kill, crash-loop guarded. This is NOT a second supervisor
1309// for the daemons.reg fleet -- it supervises the supervisor, one level up, and touches none of its rows.
1310// SOVEREIGN SPAWN (2026-09-02): this used to exec `/bin/sh -c "cd ... && chmod +x ./nx_daemon_supervisor.elf; exec
1311// ./nx_daemon_supervisor.elf >>/tmp/..."` -- a shell in the run path of the ROOT guard (the estate's own law: NishiLang
1312// for everything, shell is break-glass), and a fork literal opening with "cd " that the execution-surface census cannot
1313// credit, so `nx_execsurface who nx_daemon_supervisor` answered NO-SURFACE for the very organ this guard respawns.
1314// Direct execve now: chdir + chmod + the same stdout log, argv[0] = "./nx_daemon_supervisor.elf" (the literal the census
1315// keys on). Behaviour is otherwise byte-for-byte: setsid, stdin on /dev/null, cwd nishihost, no inherited fds.
1316const HC_DSUP_ELF: *u8 = "/volume1/homes/elderwesto/nishihost/nx_daemon_supervisor.elf" as *u8
1317const HC_DSUP_ARGV0: *u8 = "./nx_daemon_supervisor.elf" as *u8
1318const HC_DSUP_STDOUT: *u8 = "/tmp/daemon_supervisor_stdout.log" as *u8
1319func hc_spawn_dsup() -> i64 {
1320 let pid: i64 = sys_fork()
1321 if pid==0 {
1322 nx_setsid()
1323 sys_chdir("/volume1/homes/elderwesto/nishihost" as *u8)
1324 nx_chmod(HC_DSUP_ELF, 0x1ed)
1325 let dn: i64 = sys_openat_wr("/dev/null" as *u8, 0x1a4)
1326 if dn >= 0 { sys_dup3(dn,0,0) }
1327 let lf: i64 = sys_openat_append(HC_DSUP_STDOUT, 420)
1328 if lf >= 0 { sys_dup3(lf,1,0); sys_dup3(lf,2,0) }
1329 let argv: *i64 = sys_mmap(32) as *i64
1330 argv[0]=HC_DSUP_ARGV0 as i64; argv[1]=0
1331 let envp: *i64 = sys_mmap(16) as *i64; envp[0]="PATH=/usr/bin:/bin" as *u8 as i64; envp[1]=0
1332 sys_execve_clean(HC_DSUP_ELF, argv, envp)
1333 sys_exit(127)
1334 }
1335 return pid
1336}
1337// LIVENESS BY BEHAVIOUR, NOT BY NAME (2026-09-02, second cut). The first cut adopted the supervisor by PID
1338// name alone -- and its /status server is a FORKED CHILD of the same binary that outlives its parent, so a
1339// dead fleet supervisor with a living orphan child read ALIVE by name forever: the guard that never fires,
1340// measured the day it shipped (a sink deploy rolled back NEVER-LISTENED because the fleet it relied on had
1341// no living supervisor while this guard said it did). The discriminator is the cycle counter the PARENT
1342// writes into the fork-shared /status page every loop: an orphan can only ever serve the last value. The
1343// DECISION is rg_stale_cycle in nx_restart_guard (pure, gate-pinned): alive means name-alive AND the cycle
1344// advanced within HC_DSUP_STALE_POLLS polls. Stale that long = dead or wedged parent -> kill BY NAME (takes
1345// the orphan too, freeing :18095 for the respawn) -> respawn under the crash-loop guard. A /status that does
1346// not ANSWER is not treated as dead (its own header calls it a courtesy); only a cycle that answers and never
1347// moves is. st: [0]=last cycle seen, [1]=consecutive polls without an advance.
1348// DERIVED, not picked (2026-09-02, after a 4-poll bound was measured to be tighter than one honest cycle under an I/O
1349// storm): the supervisor's worst-case cycle is DS_MAX (64) rows x DS_PROBE_TMO (3 s) plus the 8 s registry verify,
1350// about 200 s, so the bound is the first poll count whose 15 s loop clears that with a full cycle of margin.
1351const HC_DSUP_STALE_POLLS: i64 = 20 // 20 polls x 15 s = 300 s with no advance
1352// SILENCE WITH A NAME: an orphaned /status child answers with no counter forever; after this many consecutive
1353// silent polls with the name alive, kill by name and respawn (rg_silent_stale, measured 2026-09-02). Ten minutes:
1354// longer than any honest first cycle, shorter than the hours the fleet went unsupervised that day.
1355const HC_DSUP_SILENT_POLLS: i64 = 40
1356const HC_DSUP_READ_TMO_MS: i64 = 3000
1357const HC_DSUP_STATUS_REQ: *u8 = "GET /status HTTP/1.1\r\nHost: 127.0.0.1:18095\r\nConnection: close\r\n\r\n"
1358const HC_DSUP_CYCLE_KEY: *u8 = "cycle="
1359// PROGRESS TICK (2026-09-02): the supervisor now publishes a MONOTONIC `tick=` after EVERY row (nx_daemon_supervisor
1360// ds_trailer), so the guard measures row progress, not cycle progress. Measured the same day: `cycle=` sat at 1 for 14 min
1361// under an I/O storm while the bound below was derived from a 200 s worst-case CYCLE -- the guard would have killed a
1362// supervisor that was alive and working, i.e. converted a slow start into an unrecoverable one (the wedge-kill class).
1363// `tick=` is read FIRST; a body without it (an older supervisor) falls back to `cycle=`, so the guard never goes blind.
1364const HC_DSUP_TICK_KEY: *u8 = "tick="
1365// the integer after the FIRST `key` in buf[bs..n); -1 when the key is absent
1366func hc_dsup_scan(buf: *u8, bs: i64, n: i64, key: *u8) -> i64 {
1367 var v: i64 = 0 - 1
1368 let kn: i64 = hc_slen(key)
1369 var i: i64 = bs
1370 while i + kn <= n {
1371 var k: i64 = 0; var hit: i64 = 1
1372 while k < kn { if buf[i+k] != key[k] { hit=0; k=kn } else { k=k+1 } }
1373 if hit == 1 {
1374 v = 0
1375 var p: i64 = i + kn
1376 while p < n { let c: i64 = buf[p] as i64; if c >= 48 { if c <= 57 { v = v*10 + (c-48); p=p+1 } else { p=n } } else { p=n } }
1377 i = n
1378 }
1379 i = i + 1
1380 }
1381 return v
1382}
1383// the supervisor's progress counter from the /status body: `tick=` (row-granular, 2026-09-02) else `cycle=` (older
1384// supervisors); -1 when nothing answered or neither key is present
1385func hc_dsup_cycle() -> i64 {
1386 let buf: *u8 = sys_mmap(HC_MAGIC_16384); let tp: *i64 = sys_mmap(16) as *i64
1387 let bs: i64 = hc_loopback_req_port(HC_MAGIC_18095, HC_DSUP_STATUS_REQ, buf, HC_MAGIC_16384, tp, HC_DSUP_READ_TMO_MS)
1388 var v: i64 = 0 - 1
1389 if bs >= 0 {
1390 v = hc_dsup_scan(buf, bs, tp[0], HC_DSUP_TICK_KEY)
1391 if v < 0 { v = hc_dsup_scan(buf, bs, tp[0], HC_DSUP_CYCLE_KEY) }
1392 }
1393 sys_munmap(buf, HC_MAGIC_16384); sys_munmap(tp as *u8, 16)
1394 return v
1395}
1396func hc_guard_dsup(ws: *i64, cnt: *i64, st: *i64) -> i64 {
1397 if proc_alive_by_name("nx_daemon_supervisor" as *u8) == 1 {
1398 let cyc: i64 = hc_dsup_cycle()
1399 let stale: i64 = rg_stale_cycle(st, cyc, HC_DSUP_STALE_POLLS)
1400 let silent: i64 = rg_silent_stale(st, cyc, HC_DSUP_SILENT_POLLS)
1401 if stale + silent == 0 { return 0 }
1402 if stale == 1 {
1403 hc_puts(" [guard] nx_daemon_supervisor: name-alive but /status cycle=" as *u8); hc_putn(cyc)
1404 hc_puts(" has not advanced for " as *u8); hc_putn(HC_DSUP_STALE_POLLS)
1405 hc_puts(" polls -- an orphan /status child serving a dead parent's snapshot, or a wedged parent; killing by name and respawning\n" as *u8)
1406 }
1407 if silent == 1 {
1408 hc_puts(" [guard] nx_daemon_supervisor: name-alive but /status has carried NO cycle counter for " as *u8); hc_putn(HC_DSUP_SILENT_POLLS)
1409 hc_puts(" polls -- the orphaned status child of a parent that died before its first publish (measured 2026-09-02); killing by name and respawning\n" as *u8)
1410 }
1411 proc_kill_by_name("nx_daemon_supervisor" as *u8, 9)
1412 }
1413 let now: i64 = sys_now_realtime_ms()
1414 if rg_should_restart(ws, cnt, now, HC_GUARD_INTERVAL_MS, HC_GUARD_BURST) == 0 {
1415 hc_puts(" [guard] nx_daemon_supervisor crash-looping -> BACKING OFF\n" as *u8); return 0
1416 }
1417 hc_spawn_dsup()
1418 hc_puts(" [guard] restarted nx_daemon_supervisor (fleet supervisor over daemons.reg; it was dead, or stale by the line above -- it had no parent before 2026-09-02)\n" as *u8)
1419 return 1
1420}
1421// spawn the /dist download server (:18120) -- mirrors hc_spawn_fin exactly.
1422func hc_spawn_dist() -> i64 {
1423 let pid: i64 = sys_fork()
1424 if pid==0 {
1425 nx_setsid()
1426 let dn: i64 = sys_openat_wr("/dev/null" as *u8, 0x1a4)
1427 if dn >= 0 { sys_dup3(dn,0,0); sys_dup3(dn,1,0); sys_dup3(dn,2,0) }
1428 let argv: *i64 = sys_mmap(32) as *i64
1429 argv[0]=HC_SH as i64; argv[1]=HC_DASHC as i64; argv[2]=HC_DIST_CMD as i64; argv[3]=0
1430 let envp: *i64 = sys_mmap(16) as *i64; envp[0]="PATH=/usr/bin:/bin" as *u8 as i64; envp[1]=0
1431 sys_execve_clean(HC_SH, argv, envp)
1432 sys_exit(127)
1433 }
1434 return pid
1435}
1436// Guard the /dist download server (:18120 -> /dist). liveness-only, crash-loop-guarded (mirrors hc_guard_fin).
1437// Backs off until nx_dist_serve.elf is deployed -- fail-safe. proc_alive_by_name matches the full cmdline (long name safe).
1438func hc_guard_dist(ws: *i64, cnt: *i64) -> i64 {
1439 if proc_alive_by_name("nx_dist_serve.elf" as *u8) == 1 { return 0 }
1440 let now: i64 = sys_now_realtime_ms()
1441 if rg_should_restart(ws, cnt, now, HC_GUARD_INTERVAL_MS, HC_GUARD_BURST) == 0 {
1442 hc_puts(" [guard] nx_dist_serve.elf crash-looping -> BACKING OFF\n" as *u8); return 0
1443 }
1444 hc_spawn_dist()
1445 hc_puts(" [guard] restarted nx_dist_serve.elf :18120 (was dead)\n" as *u8)
1446 return 1
1447}
1448// spawn the BitTorrent SEEDER (:6881) -- mirrors hc_spawn_dist exactly.
1449func hc_spawn_seed() -> i64 {
1450 let pid: i64 = sys_fork()
1451 if pid==0 {
1452 nx_setsid()
1453 let dn: i64 = sys_openat_wr("/dev/null" as *u8, 0x1a4)
1454 if dn >= 0 { sys_dup3(dn,0,0); sys_dup3(dn,1,0); sys_dup3(dn,2,0) }
1455 let argv: *i64 = sys_mmap(32) as *i64
1456 argv[0]=HC_SH as i64; argv[1]=HC_DASHC as i64; argv[2]=HC_SEED_CMD as i64; argv[3]=0
1457 let envp: *i64 = sys_mmap(16) as *i64; envp[0]="PATH=/usr/bin:/bin" as *u8 as i64; envp[1]=0
1458 sys_execve_clean(HC_SH, argv, envp)
1459 sys_exit(127)
1460 }
1461 return pid
1462}
1463// Guard the BitTorrent seeder (:6881, inbound peers). liveness-only, crash-loop-guarded (mirrors hc_guard_dist).
1464// Backs off until nx_torrent_seed.elf is deployed -- fail-safe. proc_alive_by_name matches the full cmdline.
1465func hc_guard_seed(ws: *i64, cnt: *i64) -> i64 {
1466 if proc_alive_by_name("nx_torrent_seed.elf" as *u8) == 1 { return 0 }
1467 let now: i64 = sys_now_realtime_ms()
1468 if rg_should_restart(ws, cnt, now, HC_GUARD_INTERVAL_MS, HC_GUARD_BURST) == 0 {
1469 hc_puts(" [guard] nx_torrent_seed.elf crash-looping -> BACKING OFF\n" as *u8); return 0
1470 }
1471 hc_spawn_seed()
1472 hc_puts(" [guard] restarted nx_torrent_seed.elf :6881 (was dead)\n" as *u8)
1473 return 1
1474}
1475// spawn the DHT announcer -- mirrors hc_spawn_seed exactly.
1476func hc_spawn_seedann() -> i64 {
1477 let pid: i64 = sys_fork()
1478 if pid==0 {
1479 nx_setsid()
1480 let dn: i64 = sys_openat_wr("/dev/null" as *u8, 0x1a4)
1481 if dn >= 0 { sys_dup3(dn,0,0); sys_dup3(dn,1,0); sys_dup3(dn,2,0) }
1482 let argv: *i64 = sys_mmap(32) as *i64
1483 argv[0]=HC_SH as i64; argv[1]=HC_DASHC as i64; argv[2]=HC_SEEDANN_CMD as i64; argv[3]=0
1484 let envp: *i64 = sys_mmap(16) as *i64; envp[0]="PATH=/usr/bin:/bin" as *u8 as i64; envp[1]=0
1485 sys_execve_clean(HC_SH, argv, envp)
1486 sys_exit(127)
1487 }
1488 return pid
1489}
1490// Guard the DHT announcer (makes the seeder discoverable). liveness-only, crash-loop-guarded (mirrors hc_guard_seed).
1491func hc_guard_seedann(ws: *i64, cnt: *i64) -> i64 {
1492 if proc_alive_by_name("nx_seed_announce_all.elf" as *u8) == 1 { return 0 }
1493 let now: i64 = sys_now_realtime_ms()
1494 if rg_should_restart(ws, cnt, now, HC_GUARD_INTERVAL_MS, HC_GUARD_BURST) == 0 {
1495 hc_puts(" [guard] nx_seed_announce_all.elf crash-looping -> BACKING OFF\n" as *u8); return 0
1496 }
1497 hc_spawn_seedann()
1498 hc_puts(" [guard] restarted nx_seed_announce_all.elf (DHT announcer, was dead)\n" as *u8)
1499 return 1
1500}
1501// spawn the multiplayer game relay (:7702) -- mirrors hc_spawn_fin exactly.
1502func hc_spawn_mp() -> i64 {
1503 let pid: i64 = sys_fork()
1504 if pid==0 {
1505 nx_setsid()
1506 let dn: i64 = sys_openat_wr("/dev/null" as *u8, 0x1a4)
1507 if dn >= 0 { sys_dup3(dn,0,0); sys_dup3(dn,1,0); sys_dup3(dn,2,0) }
1508 let argv: *i64 = sys_mmap(32) as *i64
1509 argv[0]=HC_SH as i64; argv[1]=HC_DASHC as i64; argv[2]=HC_MP_CMD as i64; argv[3]=0
1510 let envp: *i64 = sys_mmap(16) as *i64; envp[0]="PATH=/usr/bin:/bin" as *u8 as i64; envp[1]=0
1511 sys_execve_clean(HC_SH, argv, envp)
1512 sys_exit(127)
1513 }
1514 return pid
1515}
1516// Guard the multiplayer game relay (:7702 loopback HTTP -> /mineworld-mp + /pstate + /roster). liveness-only,
1517// crash-loop-guarded (mirrors hc_guard_fin). Backs off until nx_mp_serve.elf is deployed -- fail-safe, no harm.
1518func hc_guard_mp(ws: *i64, cnt: *i64) -> i64 {
1519 if proc_alive_by_name("nx_mp_serve.elf" as *u8) == 1 { return 0 }
1520 let now: i64 = sys_now_realtime_ms()
1521 if rg_should_restart(ws, cnt, now, HC_GUARD_INTERVAL_MS, HC_GUARD_BURST) == 0 {
1522 hc_puts(" [guard] nx_mp_serve.elf crash-looping -> BACKING OFF\n" as *u8); return 0
1523 }
1524 hc_spawn_mp()
1525 hc_puts(" [guard] restarted nx_mp_serve.elf :7702 (was dead)\n" as *u8)
1526 return 1
1527}
1528// Guard the gen orchestrator (:18795) + gateway (:18794): liveness-only, crash-loop-guarded respawn
1529// (mirrors hc_guard_hub_gw). Fail-safe: backs off until the elfs land in /volume1/ai/gen (gendeploy).
1530func hc_guard_gen_orch(ws: *i64, cnt: *i64) -> i64 {
1531 if proc_alive_by_name("nx_gen_orchestrator_daemon.elf" as *u8) == 1 { return 0 }
1532 let now: i64 = sys_now_realtime_ms()
1533 if rg_should_restart(ws, cnt, now, HC_GUARD_INTERVAL_MS, HC_GUARD_BURST) == 0 {
1534 hc_puts(" [guard] nx_gen_orchestrator_daemon.elf crash-looping -> BACKING OFF\n" as *u8); return 0
1535 }
1536 hc_spawn_gen_orch()
1537 hc_puts(" [guard] restarted nx_gen_orchestrator_daemon.elf :18795 (was dead)\n" as *u8)
1538 return 1
1539}
1540func hc_guard_gen_gw(ws: *i64, cnt: *i64) -> i64 {
1541 if proc_alive_by_name("nx_gen_gateway_daemon.elf" as *u8) == 1 { return 0 }
1542 let now: i64 = sys_now_realtime_ms()
1543 if rg_should_restart(ws, cnt, now, HC_GUARD_INTERVAL_MS, HC_GUARD_BURST) == 0 {
1544 hc_puts(" [guard] nx_gen_gateway_daemon.elf crash-looping -> BACKING OFF\n" as *u8); return 0
1545 }
1546 hc_spawn_gen_gw()
1547 hc_puts(" [guard] restarted nx_gen_gateway_daemon.elf :18794 (was dead)\n" as *u8)
1548 return 1
1549}
1550// Guard the SYNTH STUDIO daemon (:18796): liveness-only, crash-loop-guarded respawn (mirrors hc_guard_gen_orch).
1551// Fail-safe: backs off until nx_synth_serve_daemon.elf is in /volume1/ai/synth. ADOPTS the already-running
1552// detached daemon (proc_alive -> no double-spawn); respawns it after a crash or NAS reboot = durability.
1553func hc_guard_synth(ws: *i64, cnt: *i64) -> i64 {
1554 if proc_alive_by_name("nx_synth_serve_daemon.elf" as *u8) == 1 { return 0 }
1555 let now: i64 = sys_now_realtime_ms()
1556 if rg_should_restart(ws, cnt, now, HC_GUARD_INTERVAL_MS, HC_GUARD_BURST) == 0 {
1557 hc_puts(" [guard] nx_synth_serve_daemon.elf crash-looping -> BACKING OFF\n" as *u8); return 0
1558 }
1559 hc_spawn_synth()
1560 hc_puts(" [guard] restarted nx_synth_serve_daemon.elf :18796 (was dead)\n" as *u8)
1561 return 1
1562}
1563// Guard the DEV/CI API daemon (:18797): liveness-only, crash-loop-guarded respawn (mirrors hc_guard_synth).
1564// Fail-safe: backs off until nx_dev_api_serve.elf is in /volume1/ai/devapi. ADOPTS the already-running daemon.
1565func hc_guard_devapi(ws: *i64, cnt: *i64) -> i64 {
1566 if proc_alive_by_name("nx_dev_api_serve.elf" as *u8) == 1 { return 0 }
1567 let now: i64 = sys_now_realtime_ms()
1568 if rg_should_restart(ws, cnt, now, HC_GUARD_INTERVAL_MS, HC_GUARD_BURST) == 0 {
1569 hc_puts(" [guard] nx_dev_api_serve.elf crash-looping -> BACKING OFF\n" as *u8); return 0
1570 }
1571 hc_spawn_devapi()
1572 hc_puts(" [guard] restarted nx_dev_api_serve.elf :18797 (was dead)\n" as *u8)
1573 return 1
1574}
1575// kickdevapi: kill the running dev-API daemon so the guard respawns the freshly-shipped binary (the update path).
1576func cmd_kickdevapi() -> i64 {
1577 let pk: i64 = proc_kill_by_name("nx_dev_api_serve.elf" as *u8, 9)
1578 hc_puts(" kickdevapi: killed nx_dev_api_serve.elf procs=" as *u8); hc_putn(pk)
1579 hc_puts(" -> guard respawns the NEW binary\n" as *u8)
1580 return 0
1581}
1582// devapitoolchain: extract the shipped nx_cc toolchain tarball in the dev-API dir so /api/dev/build+/gate compile ON
1583// the hub (the hub becomes a self-sufficient build host). Idempotent; chmods the binaries. Prints the tar exit code.
1584func cmd_devapitoolchain() -> i64 {
1585 let pid: i64 = sys_fork()
1586 if pid == 0 {
1587 let argv: *i64 = sys_mmap(32) as *i64
1588 argv[0]=HC_SH as i64; argv[1]=HC_DASHC as i64
1589 argv[2]="cd /volume1/ai/devapi && tar xzf nx_toolchain.tar.gz && chmod +x _offc/*.elf && echo TOOLCHAIN-EXTRACTED-OK && ./_offc/nx_sov_build_run.elf nx_bytes_eq 2>&1 | tail -1" as *u8 as i64; argv[3]=0
1590 let envp: *i64 = sys_mmap(16) as *i64; envp[0]="PATH=/usr/bin:/bin:/usr/local/bin:/opt/bin" as *u8 as i64; envp[1]=0
1591 sys_execve_clean(HC_SH, argv, envp)
1592 sys_exit(127)
1593 }
1594 let st: *i64 = sys_mmap(16) as *i64
1595 sys_wait4(pid, st, 0)
1596 hc_puts(" devapitoolchain: tar xzf nx_toolchain.tar.gz -> /volume1/ai/devapi/ (exit=" as *u8); hc_putn((st[0]>>8)&255); hc_puts(")\n" as *u8)
1597 return 0
1598}
1599// Guard the media/torrent daemon (:8097): liveness-only (PID by name), crash-loop-guarded respawn via the
1600// portable launcher. Until the bundle is deployed to /volume1/ai/torrent the exec fails -> child exits ->
1601// it simply backs off (fail-safe, no harm to the rest of the fleet -- each guard is independent).
1602func hc_guard_torrent(ws: *i64, cnt: *i64) -> i64 {
1603 if proc_alive_by_name("nx_torrent_daemon" as *u8) == 1 { return 0 }
1604 let now: i64 = sys_now_realtime_ms()
1605 if rg_should_restart(ws, cnt, now, HC_GUARD_INTERVAL_MS, HC_GUARD_BURST) == 0 {
1606 hc_puts(" [guard] nx_torrent_daemon crash-looping -> BACKING OFF\n" as *u8); return 0
1607 }
1608 hc_spawn_torrent()
1609 hc_puts(" [guard] restarted nx_torrent_daemon :8097 (was dead)\n" as *u8)
1610 return 1
1611}
1612// Guard the torrent OPAQUE gateway (:18793): liveness-only, crash-loop-guarded respawn. Fail-safe: backs off
1613// until the gateway elf is deployed to /volume1/ai/torrent.
1614func hc_guard_torrent_gw(ws: *i64, cnt: *i64) -> i64 {
1615 if proc_alive_by_name("nx_torrent_gw.elf" as *u8) == 1 { return 0 }
1616 let now: i64 = sys_now_realtime_ms()
1617 if rg_should_restart(ws, cnt, now, HC_GUARD_INTERVAL_MS, HC_GUARD_BURST) == 0 {
1618 hc_puts(" [guard] nx_torrent_gw.elf crash-looping -> BACKING OFF\n" as *u8); return 0
1619 }
1620 hc_spawn_torrent_gw()
1621 hc_puts(" [guard] restarted nx_torrent_gw.elf :18793 (was dead)\n" as *u8)
1622 return 1
1623}
1624// Guard the login OPAQUE daemon (:9091, the token minter): liveness-only respawn. Was UNSUPERVISED (a real
1625// fragility -- a crash = site-wide login outage); now auto-restarts forever. Adopts the running one (proc_alive).
1626func hc_guard_login(ws: *i64, cnt: *i64) -> i64 {
1627 if proc_alive_by_name("nx_opaque_login.elf" as *u8) == 1 { return 0 }
1628 let now: i64 = sys_now_realtime_ms()
1629 if rg_should_restart(ws, cnt, now, HC_GUARD_INTERVAL_MS, HC_GUARD_BURST) == 0 {
1630 hc_puts(" [guard] nx_opaque_login.elf crash-looping -> BACKING OFF\n" as *u8); return 0
1631 }
1632 hc_spawn_login()
1633 hc_puts(" [guard] restarted nx_opaque_login.elf :9091 (was dead)\n" as *u8)
1634 return 1
1635}
1636
1637// DEDICATED READER-KEEPER: fork+exec the reader and BLOCKING-wait4 it, respawn on death, forever. This is
1638// EXACTLY the spawntest pattern that PROVABLY keeps the reader alive -- whereas spawning it from the poll loop
1639// (which then nanosleeps + rescans /proc) reliably kills it ~15s later (cause still unidentified, but the
1640// blocking-wait parent keeps it up; spawntest-proven). The reader is THIS keeper's child, so the main poll
1641// loop never touches it. The keeper logs each death's sig/code. Run as a forked child of cmd_supervise.
1642// PURE respawn-delay policy, extracted so it can be reasoned about and gated independently.
1643// Returns ms to wait before the next respawn attempt.
1644// WHY IT EXISTS (defect found 2026-07-20 while diagnosing a wedged NAS): the original breaker
1645// counted ONLY fast (<5s) code=1 bind-fails -- but this very function's own header documents the
1646// reader's real failure mode as "reliably kills it ~15s later". 15s > 5s, so isfast was never set,
1647// fastfails never reached 8, and THE CIRCUIT-BREAKER WAS DEAD CODE FOR THE ONLY FAILURE THAT
1648// ACTUALLY HAPPENS: an unbounded ~1-per-16s respawn that never escalates and never gives up.
1649// Now ANY repeatedly short-lived death escalates. Still never stops retrying and never deletes
1650// anything, so it self-heals the instant the underlying cause clears (never-brick preserved).
1651func hc_keep_delay(fastfails: i64, shortfails: i64) -> i64 {
1652 if fastfails >= 8 { return HC_MAGIC_60000 }
1653 if shortfails >= 20 { return HC_MAGIC_300000 }
1654 if shortfails >= 8 { return HC_MAGIC_60000 }
1655 return 1000
1656}
1657
1658// where the keeper publishes its monotonic spawn count so `status` can read it in ONE call (seq1623).
1659// Deliberately in the daemon cwd, not /tmp: /tmp is tmpfs and this must survive across samples; a
1660// counter that vanishes is exactly the kind of instrument this session kept catching.
1661const HC_RK_COUNT_PATH: *u8 = "reader_keep.count" as *u8
1662func cmd_reader_keep() -> i64 {
1663 hc_puts("[reader-keep] dedicated blocking-wait keeper for the library reader (:8791)\n" as *u8)
1664 // BUILD-IDENTITY PROBE (2026-08-06). NXA_SMALL_MAX is defined ONLY in nx_syscalls.nx, so a binary
1665 // that can print it PROVES its compile included that file. Four separate experiments could not
1666 // settle that from the outside: this supervisor rebuilds to the same 247434 bytes and never gains
1667 // the ~1052-byte small-allocation-arena delta that two control organs both gain, one of them a
1668 // sibling in this very directory. It also gives an operator something binary size cannot -- whether
1669 // a RUNNING supervisor actually has the arena, printed by the process itself.
1670 hc_puts("[reader-keep] arena_threshold=" as *u8); hc_putn(NXA_SMALL_MAX); hc_puts("\n" as *u8)
1671 let st: *i64 = sys_mmap(16) as *i64
1672 var run: i64 = 1
1673 var rk_spawns: i64 = 0 // published to HC_RK_COUNT_PATH each spawn; 0 on a fresh supervisor
1674 var shortfails: i64 = 0 // consecutive deaths inside 5 MINUTES (any sig/code) -> the real-mode breaker
1675 var fastfails: i64 = 0 // consecutive FAST code=1 exits (bind-fail => :HC_MAGIC_8791 already held) -> throttle the hopeless hot-spin
1676 while run == 1 {
1677 // ROOT FIX (was the CPU sink): the poll-loop guard hc_guard_reader ALSO keeps :8791 alive, so if a reader is
1678 // already up, spawning another just fork/exec/bind-fails (code=1) forever. Skip when one is already alive;
1679 // re-check every 5s. Self-heals the instant :8791 frees; never deletes anything (never-brick).
1680 if proc_alive_by_name("nx_media_server_auth.elf" as *u8) == 1 {
1681 sys_sleep_ms(HC_MAGIC_5000)
1682 } else {
1683 let t0: i64 = sys_now_us()
1684 rk_spawns = rk_spawns + 1
1685 // hc_write_pid is a GENERIC decimal writer that happens to be pid-named -- reused, not cloned.
1686 hc_write_pid(HC_RK_COUNT_PATH, rk_spawns)
1687 let pid: i64 = hc_spawn_reader()
1688 hc_puts(" [reader-keep] spawned reader pid=" as *u8); hc_putn(pid); hc_puts("\n" as *u8)
1689 st[0]=0
1690 sys_wait4(pid, st, 0) // BLOCKING -- the survival pattern; returns only when the reader actually dies
1691 let sig: i64 = st[0]&0x7f
1692 let code: i64 = (st[0]>>8)&0xff
1693 let life_us: i64 = sys_now_us() - t0
1694 hc_puts(" [reader-keep] reader pid=" as *u8); hc_putn(pid); hc_puts(" died sig=" as *u8); hc_putn(sig); hc_puts(" code=" as *u8); hc_putn(code); hc_puts(" -> respawn\n" as *u8)
1695 // CIRCUIT-BREAKER (never-brick PREVENT): a fast code=1 exit means the reader could not bind :8791 (a live
1696 // duplicate already holds it) -- retrying every 1s just churns fork/exec/bind-fail forever (the measured CPU
1697 // sink). After 8 consecutive fast bind-fails, back off to once/min: 60x less churn, and it STILL self-heals
1698 // the instant :8791 frees (we never stop retrying, never delete anything).
1699 var isfast: i64 = 0
1700 if sig == 0 { if code == 1 { if life_us < HC_MAGIC_5000000 { isfast = 1 } } }
1701 if isfast == 1 { fastfails = fastfails + 1 } else { fastfails = 0 }
1702 // REAL-MODE BREAKER: a reader that dies inside 5 MINUTES is failing, not completing a lifecycle --
1703 // regardless of sig/code and regardless of whether it was "fast". This is the counter that
1704 // actually moves for the observed ~15s death mode; fastfails alone never did.
1705 var isshort: i64 = 0
1706 if life_us < HC_MAGIC_300000000 { isshort = 1 }
1707 if isshort == 1 { shortfails = shortfails + 1 } else { shortfails = 0 }
1708 if fastfails == 8 { hc_puts(" [reader-keep] 8 consecutive fast bind-fails (:8791 held elsewhere) -> backoff 60s (self-heals when the port frees)\n" as *u8) }
1709 if shortfails == 8 { hc_puts(" [reader-keep] 8 consecutive short-lived deaths -> backoff 60s (breaker ENGAGED; was dead code before 07-20)\n" as *u8) }
1710 if shortfails == 20 { hc_puts(" [reader-keep] 20 consecutive short-lived deaths -> backoff 300s (still retrying, still self-healing)\n" as *u8) }
1711 let delay: i64 = hc_keep_delay(fastfails, shortfails)
1712 // OBSERVABILITY FIX 2026-07-30: the two backoff notices above fire at EXACTLY ==8 and ==20,
1713 // once each, and these lines carry NO TIMESTAMP -- so a tail read past that point shows an
1714 // unbroken wall of spawn/die and looks IDENTICAL whether the breaker is engaged (1 retry per
1715 // minute) or dead (1 per second). I misread exactly that today and called it a fork storm.
1716 // Emit the CHOSEN DELAY on every respawn: the delay IS the rate, so the log states its own
1717 // throttle instead of making a reader infer it from wall-clock it does not have.
1718 hc_puts(" [reader-keep] shortfails=" as *u8); hc_putn(shortfails)
1719 hc_puts(" fastfails=" as *u8); hc_putn(fastfails)
1720 hc_puts(" next-retry-ms=" as *u8); hc_putn(delay); hc_puts("\n" as *u8)
1721 sys_sleep_ms(delay)
1722 }
1723 }
1724 return 0
1725}
1726
1727// ---- LIVE STATUS PAGE: the supervisor already knows every daemon's state each poll, so it emits a fresh
1728// status.html into the nishifamily doc-root every cycle. Browser auto-refreshes (meta refresh) -> a truly
1729// live nishifamily.com/status with zero extra moving parts. The /status monitoring foundation.
1730func hc_cat(dst: *u8, off: i64, s: *u8) -> i64 { var i: i64=0; while s[i]!=(0 as u8){dst[off+i]=s[i];i=i+1} return off+i }
1731func hc_catn(dst: *u8, off: i64, v: i64) -> i64 {
1732 var m: i64=v; if m<0 {m=0-m}
1733 let t: *u8=sys_mmap(28); var k: i64=0; if m==0 {t[0]=48 as u8;k=1}
1734 while m>0 {t[k]=(48+(m%10)) as u8;m=m/10;k=k+1}
1735 var i: i64=0; while i<k {dst[off+i]=t[k-1-i];i=i+1}
1736 return off+k
1737}
1738func hc_status_row(dst: *u8, off: i64, name: *u8, label: *u8) -> i64 {
1739 var o: i64=off
1740 o=hc_cat(dst,o,"<div class=row><span class=svc>" as *u8); o=hc_cat(dst,o,label); o=hc_cat(dst,o,"</span>" as *u8)
1741 if proc_alive_by_name(name)==1 { o=hc_cat(dst,o,"<span class='pill up'>UP</span>" as *u8) } else { o=hc_cat(dst,o,"<span class='pill down'>DOWN</span>" as *u8) }
1742 o=hc_cat(dst,o,"</div>" as *u8)
1743 return o
1744}
1745// hc_snap_svc: one "SVC <name> <port> <UP|DOWN> <procs> <rwin> <rtot>" line for the mgmt-API health snapshot
1746// (read by /api/health + /api/services -> rendered at nishifamily.com/health). procs = BOOLEAN liveness (1=UP /
1747// 0=DOWN) ON PURPOSE: a raw proc count would false-positive mc_is_dup "duplicate-instance" on sites.elf's
1748// per-request fork children -- the exact false +/- to avoid. state=="DOWN" drives the honest down reason.
1749// hc_rwin: the TRUE windowed crash-loop signal for the snapshot -- the guard's own restart counter (cnt) with the
1750// SAME 60s health-reset rg_should_restart applies (nx_restart_guard.nx:44): a daemon that ran healthy >=
1751// RG_HEALTH_RESET_MS since its last restart reads 0, so a service that crash-looped then RECOVERED is NOT falsely
1752// flagged (no false +/-). A genuinely crash-looping daemon (dying repeatedly within the window) shows cnt>0, and
1753// mc_is_loop trips at >=5. nx_clock_tickless is passed 0 by the caller (its by-design tickless respawn is not a
1754// crash-loop) -- belt-and-suspenders against a false flag on the one daemon that respawns on purpose.
1755func hc_rwin(cnt: *i64, ws: *i64, now: i64) -> i64 {
1756 if now - ws[0] >= RG_HEALTH_RESET_MS { return 0 }
1757 return cnt[0]
1758}
1759func hc_snap_svc(buf: *u8, o: i64, name: *u8, port: i64, rwin: i64) -> i64 {
1760 var p: i64 = o
1761 p = hc_cat(buf, p, "SVC " as *u8); p = hc_cat(buf, p, name); p = hc_cat(buf, p, " " as *u8); p = hc_catn(buf, p, port); p = hc_cat(buf, p, " " as *u8)
1762 // Fields: <state> <procs> <rwin> <rtot> <holder>. procs = BOOLEAN liveness (1/0) ON PURPOSE (a raw count false-
1763 // positives mc_is_dup on fork children). rwin = the TRUE windowed restart count (crash-loop signal) from the
1764 // guard state -- the gap this closes. 8th token (holder) = port-holder PID, computed ONLY on the DOWN path.
1765 if proc_alive_by_name(name) == 1 {
1766 p = hc_cat(buf, p, "UP 1 " as *u8); p = hc_catn(buf, p, rwin); p = hc_cat(buf, p, " " as *u8); p = hc_catn(buf, p, rwin); p = hc_cat(buf, p, " 0\n" as *u8)
1767 } else {
1768 var holder: i64 = 0
1769 if port > 0 { holder = pon_port_owner_pid(port) }
1770 p = hc_cat(buf, p, "DOWN 0 " as *u8); p = hc_catn(buf, p, rwin); p = hc_cat(buf, p, " " as *u8); p = hc_catn(buf, p, rwin); p = hc_cat(buf, p, " " as *u8); p = hc_catn(buf, p, holder); p = hc_cat(buf, p, "\n" as *u8)
1771 }
1772 return p
1773}
1774// hc_emit_snapshot: write the mgmt-API health snapshot. SUP 1 = single-supervisor BY CONSTRUCTION (this proc holds
1775// the heartbeat lease; a 2nd supervisor DEFERS, see cmd_supervise) -> mc_is_duel(1)=false, NO false "dueling-
1776// supervisors" (the operator's exact past misdiagnosis). Atomic write to the path nx_mgmt_api reads (HC_MGMT_CMD).
1777func hc_emit_snapshot(rw_sites: i64, rw_wiki: i64, rw_ggw: i64, rw_gserve: i64, rw_reader: i64, rw_redirect: i64, rw_tgw: i64, rw_mgmt: i64, rw_adm: i64, rw_vroom: i64, rw_tapi: i64, rw_mail: i64) -> i64 {
1778 let buf: *u8 = sys_mmap(HC_MAGIC_4096); var o: i64 = 0
1779 o = hc_cat(buf, o, "SUP 1\n" as *u8)
1780 o = hc_snap_svc(buf, o, "sites.elf" as *u8, HC_MAGIC_8443, rw_sites)
1781 o = hc_snap_svc(buf, o, "nx_wiki_gw.elf" as *u8, HC_MAGIC_18791, rw_wiki)
1782 o = hc_snap_svc(buf, o, "nx_gallery_gateway.elf" as *u8, HC_MAGIC_18190, rw_ggw)
1783 o = hc_snap_svc(buf, o, "nx_gallery_serve.elf" as *u8, HC_MAGIC_18090, rw_gserve)
1784 o = hc_snap_svc(buf, o, "nx_media_server_auth.elf" as *u8, HC_MAGIC_8791, rw_reader)
1785 o = hc_snap_svc(buf, o, "redirect.elf" as *u8, HC_MAGIC_8080, rw_redirect)
1786 o = hc_snap_svc(buf, o, "nx_torrent_gw.elf" as *u8, HC_MAGIC_18793, rw_tgw)
1787 o = hc_snap_svc(buf, o, "nx_clock_tickless.elf" as *u8, 0, 0) // rwin=0 BY CONSTRUCTION: tickless respawn is by-design, NOT a crash-loop (no false +/-)
1788 o = hc_snap_svc(buf, o, "nx_mgmt_api.elf" as *u8, HC_MAGIC_18098, rw_mgmt)
1789 o = hc_snap_svc(buf, o, "nx_docportal_admin_daemon.elf" as *u8, HC_MAGIC_18456, rw_adm) // admin.<d>/ (relocated :HC_MAGIC_8456 -> :HC_MAGIC_18456 to dodge PID HC_MAGIC_15274's squat; matches HC_ADMIN_CMD + proxy_routes) -- 8th token = its real :HC_MAGIC_18456 holder
1790 o = hc_snap_svc(buf, o, "nx_email_portal_daemon.elf" as *u8, HC_MAGIC_18465, rw_mail) // mail.<d>/ email portal (matches HC_MAILPORTAL_CMD + proxy_routes)
1791 o = hc_snap_svc(buf, o, "nx_siteedit_daemon.elf" as *u8, HC_MAGIC_18466, 0)
1792 o = hc_snap_svc(buf, o, "nx_inventory_serve.elf" as *u8, HC_MAGIC_18122, 0) // inventory/ownership checker (loopback-only) // admin.<d>/site visuals editor (rw window not tracked yet)
1793 o = hc_snap_svc(buf, o, "nx_vroom_daemon.elf" as *u8, HC_MAGIC_8446, rw_vroom) // video room backend (nginx-fronted :HC_MAGIC_8446) -- ADDITIVE: surfaces the guarded (poll @890) daemon in /api/health so a dead room is VISIBLE, not silent
1794 o = hc_snap_svc(buf, o, "nx_tools_api_serve.elf" as *u8, HC_MAGIC_18096, rw_tapi) // agent-facing tools API (/api/tools + /mcp) -- R0 MCP-compatible + superset; surfaces in /api/services + /health
1795 // THE TOKEN MINTER (:9091), 2026-07-30 -- same ADDITIVE fix the vroom row above records, for the one
1796 // service it matters most on. hc_guard_login has supervised it for a while, but it appeared in NONE of
1797 // /api/health, /api/services or mgmt_snap.json, so overall:"OK" did not cover the surface that mints
1798 // EVERY session: if login died, health still read OK and an operator watching it learned nothing.
1799 // The guard protects AVAILABILITY; this snapshot protects ATTENTION. They must not disagree about which
1800 // services exist. rwin=0 like the siteedit row -- its restart window is not threaded into this emitter yet
1801 // (an honest 0, not a fabricated number).
1802 o = hc_snap_svc(buf, o, "nx_opaque_login.elf" as *u8, HC_MAGIC_9091, 0)
1803 let tmp: *u8 = "/volume1/homes/elderwesto/nishihost/mgmt_snap.json.tmp" as *u8
1804 let dst: *u8 = "/volume1/homes/elderwesto/nishihost/mgmt_snap.json" as *u8
1805 let fd: i64 = sys_openat_wr(tmp, 0x1a4)
1806 if fd >= 0 { sys_write(fd, buf, o); sys_close(fd); sys_renameat(tmp, dst) }
1807 sys_munmap(buf, HC_MAGIC_4096)
1808 return 0
1809}
1810
1811func hc_emit_status_html(now: i64) -> i64 {
1812 let buf: *u8 = sys_mmap(HC_MAGIC_16384); var o: i64=0
1813 o=hc_cat(buf,o,"<!doctype html><html lang=en><head><meta charset=utf-8><meta http-equiv=refresh content=15><meta name=viewport content='width=device-width,initial-scale=1'><title>Nishi Systems Status</title><style>body{margin:0;background:#0b1020;color:#e6ecf5;font:15px/1.6 -apple-system,Segoe UI,Roboto,sans-serif}.wrap{max-width:680px;margin:0 auto;padding:32px 20px}h1{font-size:1.5rem;margin:0 0 2px}.sub{color:#8794ad;font-size:.9rem;margin:0 0 24px}.row{display:flex;justify-content:space-between;align-items:center;padding:13px 16px;margin:7px 0;background:#141b30;border:1px solid #1f2942;border-radius:9px}.svc{font-weight:500}.pill{font-size:.8rem;font-weight:700;padding:3px 11px;border-radius:20px;letter-spacing:.04em}.pill.up{background:#0f3d24;color:#3ad77f}.pill.down{background:#451620;color:#ff6b81}.ts{color:#5f6d88;font-size:.8rem;margin-top:22px;text-align:center}</style></head><body><div class=wrap>" as *u8)
1814 o=hc_cat(buf,o,"<h1>Nishi Systems Status</h1><p class=sub>live · self-refreshing every 15s · emitted by the sovereign nx_hostctl supervisor</p>" as *u8)
1815 o=hc_status_row(buf,o,"sites.elf" as *u8,"Web — nishifamily.com (:8443 TLS)" as *u8)
1816 o=hc_status_row(buf,o,"nx_wiki_gw.elf" as *u8,"Wiki OPAQUE gateway (:18791)" as *u8)
1817 o=hc_status_row(buf,o,"nx_hub_gw.elf" as *u8,"Hub OPAQUE gateway (:18792)" as *u8)
1818 o=hc_status_row(buf,o,"nx_gen_gateway_daemon.elf" as *u8,"Gen OPAQUE gateway (:18794)" as *u8)
1819 o=hc_status_row(buf,o,"nx_gen_orchestrator_daemon.elf" as *u8,"Gen orchestrator (:18795)" as *u8)
1820 o=hc_status_row(buf,o,"nx_opaque_login.elf" as *u8,"Login OPAQUE daemon (:9091)" as *u8)
1821 o=hc_status_row(buf,o,"nx_gallery_gateway.elf" as *u8,"Gallery OPAQUE gateway (:18190)" as *u8)
1822 o=hc_status_row(buf,o,"nx_gallery_serve.elf" as *u8,"Gallery media serve (:18090)" as *u8)
1823 o=hc_status_row(buf,o,"nx_media_server_auth.elf" as *u8,"Library reader (:8791)" as *u8)
1824 o=hc_status_row(buf,o,"redirect.elf" as *u8,"HTTP→HTTPS redirect (:8080)" as *u8)
1825 o=hc_status_row(buf,o,"nx_vroom_daemon.elf" as *u8,"Video room backend (:8446, nginx-fronted)" as *u8)
1826 o=hc_cat(buf,o,"<p class=ts>supervisor poll @ epoch " as *u8); o=hc_catn(buf,o,now); o=hc_cat(buf,o,"s</p></div></body></html>" as *u8)
1827 let tmp: *u8 = "/volume1/homes/elderwesto/nishihost/sites/nishifamily/status.html.tmp" as *u8
1828 let dst: *u8 = "/volume1/homes/elderwesto/nishihost/sites/nishifamily/status.html" as *u8
1829 let fd: i64 = sys_openat_wr(tmp, 0x1a4)
1830 if fd >= 0 { sys_write(fd, buf, o); sys_close(fd); sys_renameat(tmp, dst) }
1831 sys_munmap(buf, HC_MAGIC_16384)
1832 return 0
1833}
1834
1835// POLL supervisor: every 15s, ensure each daemon is alive AND (for plaintext daemons) actually SERVING;
1836// restart any that died or wedged, crash-loop-guarded. ADOPTS already-running daemons (no double-spawn).
1837// Sovereign replacement for nishi_supervisor.sh -- now HUNG-aware, the gap systemd/proc-scan both miss.
1838// assert vm.overcommit_memory=1 (the 2026-07-03 commit-leak outage fix: fork-per-connection daemons with
1839// large anon maps get fork() refused under the mode-0 heuristic once Committed_AS piles up -- the sovereign
1840// spine re-asserts the knob on EVERY supervise start, so a NAS reboot can never silently re-arm the wedge).
1841// RAM-only kernel knob: reversible, never-brick by construction; a write failure logs and continues.
1842func hc_assert_overcommit() -> i64 {
1843 let fd: i64 = sys_openat_wr("/proc/sys/vm/overcommit_memory" as *u8, 0x1a4)
1844 if fd < 0 { hc_puts("[hostctl] WARN: cannot open vm.overcommit_memory (fork-wedge guard NOT asserted)\n" as *u8); return 0 }
1845 sys_write(fd, "1" as *u8, 1)
1846 sys_close(fd)
1847 hc_puts("[hostctl] vm.overcommit_memory=1 asserted (commit-leak fork-wedge guard)\n" as *u8)
1848 return 0
1849}
1850
1851func cmd_supervise() -> i64 {
1852 // FD-LEAK CURE (2026-07-17): drop any INHERITED fd >= 3 before doing anything else. A dirty launch chain
1853 // (a selfswap/boot that still held mgmt's :18098 listen socket) would otherwise propagate that socket to
1854 // EVERY daemon this supervisor forks -- children inherit the supervisor's fd table -- so a redeployed mgmt
1855 // hits EADDRINUSE and cannot rebind :18098 (the ~10min control-plane outage of 2026-07-17). One scrub here
1856 // cleans the supervisor AND, by inheritance, every child it spawns. [[nx_fd_hygiene]]
1857 nx_fd_scrub_inherited()
1858 hc_puts("[hostctl] fd-scrub at supervisor entry (inherited fds dropped -> no listen-socket leak into children)\n" as *u8)
1859 hc_puts("[hostctl] sovereign supervisor: PID-liveness + SERVING health-probe (HUNG-aware) + crash-loop guard\n" as *u8)
1860 hc_assert_overcommit()
1861 // SINGLE-SUPERVISOR by construction: if another supervisor is already heartbeating, DEFER (don't start a
1862 // competing poll loop -- that race was the nishifamily/andelinwest outage). Never zero: the deferring
1863 // instance just exits, the live one keeps running. reconcile/selfswap clear the lease so they always claim.
1864 if hc_sup_fresh() == 1 {
1865 hc_puts("[hostctl] another supervisor is heartbeating (lease fresh <90s) -- DEFERRING, not competing\n" as *u8)
1866 return 0
1867 }
1868 hc_sup_touch() // claim the lease NOW so any later/racing launch sees the fresh heartbeat and defers
1869 let kpid: i64 = sys_fork() // dedicated reader-keeper (blocking-wait pattern); poll loop below handles the rest
1870 if kpid == 0 { cmd_reader_keep(); sys_exit(0); return 0 }
1871 hc_puts("[hostctl] forked reader-keeper pid=" as *u8); hc_putn(kpid); hc_puts("\n" as *u8)
1872 // retire the bash gallery while-loop supervisor (unique: its cmdline has BOTH "while" and the gateway elf;
1873 // the real daemons + the sites supervisor do not) so this becomes the ONE supervisor for the gallery too.
1874 let bk: i64 = proc_kill_by_two("while" as *u8, "nx_gallery_gateway.elf" as *u8, 9)
1875 hc_puts("[hostctl] retired bash gallery supervisor procs=" as *u8); hc_putn(bk); hc_puts("\n" as *u8)
1876 let s_ws: *i64 = sys_mmap(16) as *i64; let s_cnt: *i64 = sys_mmap(16) as *i64 // sites.elf
1877 let r_ws: *i64 = sys_mmap(16) as *i64; let r_cnt: *i64 = sys_mmap(16) as *i64 // redirect.elf
1878 let v_ws: *i64 = sys_mmap(16) as *i64; let v_cnt: *i64 = sys_mmap(16) as *i64 // vroom
1879 let sr_ws: *i64 = sys_mmap(16) as *i64; let sr_cnt: *i64 = sys_mmap(16) as *i64 // sni_router.elf :HC_MAGIC_7443 (sovereign public edge)
1880 let x_ws: *i64 = sys_mmap(16) as *i64; let x_cnt: *i64 = sys_mmap(16) as *i64 // translate
1881 let lib_ws: *i64 = sys_mmap(16) as *i64; let lib_cnt: *i64 = sys_mmap(16) as *i64 // library reader :HC_MAGIC_8791
1882 let dsup_ws: *i64 = sys_mmap(16) as *i64; let dsup_cnt: *i64 = sys_mmap(16) as *i64 // FLEET SUPERVISOR nx_daemon_supervisor (:18095 status; had NO parent until 2026-09-02 -- adopted if running, respawned if dead)
1883 let dsup_st: *i64 = sys_mmap(32) as *i64 // stale-cycle state for hc_guard_dsup: [0]=last /status cycle seen, [1]=polls without an advance (zero-filled by mmap)
1884 let reap_st: *i64 = sys_mmap(16) as *i64 // reaped-child status (alloc ONCE, reused -- no per-poll leak)
1885 let gs_ws: *i64 = sys_mmap(16) as *i64; let gs_cnt: *i64 = sys_mmap(16) as *i64 // gallery serve :HC_MAGIC_18090
1886 let gw_ws: *i64 = sys_mmap(16) as *i64; let gw_cnt: *i64 = sys_mmap(16) as *i64 // gallery gateway :HC_MAGIC_18190
1887 let wgw_ws: *i64 = sys_mmap(16) as *i64; let wgw_cnt: *i64 = sys_mmap(16) as *i64 // wiki gateway :HC_MAGIC_18791
1888 let hgw_ws: *i64 = sys_mmap(16) as *i64; let hgw_cnt: *i64 = sys_mmap(16) as *i64 // hub gateway :HC_MAGIC_18792
1889 let lgn_ws: *i64 = sys_mmap(16) as *i64; let lgn_cnt: *i64 = sys_mmap(16) as *i64 // login daemon :HC_MAGIC_9091
1890 let tor_ws: *i64 = sys_mmap(16) as *i64; let tor_cnt: *i64 = sys_mmap(16) as *i64 // media/torrent daemon :HC_MAGIC_8097
1891 let tgw_ws: *i64 = sys_mmap(16) as *i64; let tgw_cnt: *i64 = sys_mmap(16) as *i64 // torrent OPAQUE gateway :HC_MAGIC_18793
1892 let gor_ws: *i64 = sys_mmap(16) as *i64; let gor_cnt: *i64 = sys_mmap(16) as *i64 // gen orchestrator :HC_MAGIC_18795
1893 let ggw_ws: *i64 = sys_mmap(16) as *i64; let ggw_cnt: *i64 = sys_mmap(16) as *i64 // gen OPAQUE gateway :HC_MAGIC_18794
1894 let syn_ws: *i64 = sys_mmap(16) as *i64; let syn_cnt: *i64 = sys_mmap(16) as *i64 // SYNTH STUDIO daemon :HC_MAGIC_18796 (sites /synth/api -> here; renders motion/creatures on demand)
1895 let devapi_ws: *i64 = sys_mmap(16) as *i64; let devapi_cnt: *i64 = sys_mmap(16) as *i64 // DEV/CI API daemon :HC_MAGIC_18797 (sites /api/dev -> here; build/gate/run organs over HTTP, cap-gated)
1896 let clk_ws: *i64 = sys_mmap(16) as *i64; let clk_cnt: *i64 = sys_mmap(16) as *i64 // nx_clock_tickless: the ONE consolidated clock (runs a bounded tickless window then exits -> respawned = continuous)
1897 let mgmt_ws: *i64 = sys_mmap(16) as *i64; let mgmt_cnt: *i64 = sys_mmap(16) as *i64 // mgmt API :HC_MAGIC_18099 (HTTP /api)
1898 let adm_ws: *i64 = sys_mmap(16) as *i64; let adm_cnt: *i64 = sys_mmap(16) as *i64 // doc-portal admin daemon :HC_MAGIC_8456 (admin.<d>/ owner self-service)
1899 let mail_ws: *i64 = sys_mmap(16) as *i64; let mail_cnt: *i64 = sys_mmap(16) as *i64 // email-portal daemon :HC_MAGIC_18465 (mail.<d>/ webmail)
1900 let inv_ws: *i64 = sys_mmap(16) as *i64; let inv_cnt: *i64 = sys_mmap(16) as *i64 // inventory checker :HC_MAGIC_18122 (loopback-only, proxied at /inventory)
1901 let sed_ws: *i64 = sys_mmap(16) as *i64; let sed_cnt: *i64 = sys_mmap(16) as *i64 // site-visuals editor :HC_MAGIC_18466 (admin.<d>/site)
1902 let tapi_ws: *i64 = sys_mmap(16) as *i64; let tapi_cnt: *i64 = sys_mmap(16) as *i64 // tools API :HC_MAGIC_18096 (HTTP /api/tools + /mcp -- R0 agent-facing API)
1903 let fin_ws: *i64 = sys_mmap(16) as *i64; let fin_cnt: *i64 = sys_mmap(16) as *i64 // finance dashboard :HC_MAGIC_18097 (HTTP /finance)
1904 let dist_ws: *i64 = sys_mmap(16) as *i64; let dist_cnt: *i64 = sys_mmap(16) as *i64 // /dist download server :HC_MAGIC_18120 (HTTP /dist -- content-addressed)
1905 let mp_ws: *i64 = sys_mmap(16) as *i64; let mp_cnt: *i64 = sys_mmap(16) as *i64 // multiplayer game relay :HC_MAGIC_7702 (HTTP /mineworld-mp + /pstate + /roster)
1906 let seed_ws: *i64 = sys_mmap(16) as *i64; let seed_cnt: *i64 = sys_mmap(16) as *i64 // BitTorrent seeder :HC_MAGIC_6881 (inbound peers -- the UPLOAD/SHARE half)
1907 let sann_ws: *i64 = sys_mmap(16) as *i64; let sann_cnt: *i64 = sys_mmap(16) as *i64 // DHT announcer (makes the seeder discoverable via BEP-5)
1908 let he_ws: *i64 = sys_mmap(16) as *i64; let he_cnt: *i64 = sys_mmap(16) as *i64 // continuous M&E evaluator (nx_health_eval loop -- functional/quality health of the whole surface, every 300s)
1909 let sg_ws: *i64 = sys_mmap(16) as *i64; let sg_cnt: *i64 = sys_mmap(16) as *i64 // video signaling/media relay :HC_MAGIC_8445 (task #26: was UNSUPERVISED -- the fire-and-pray near-miss)
1910 let rel_ws: *i64 = sys_mmap(16) as *i64; let rel_cnt: *i64 = sys_mmap(16) as *i64 // Relationship OS daemon :HC_MAGIC_8027 (the /relate app; backs off until relatedeploy'd)
1911 let pjw_ws: *i64 = sys_mmap(16) as *i64; let pjw_cnt: *i64 = sys_mmap(16) as *i64 // /project OPAQUE gateway :HC_MAGIC_8028 (contractor portal; adopts the running daemon)
1912 let cs_ws: *i64 = sys_mmap(16) as *i64; let cs_cnt: *i64 = sys_mmap(16) as *i64 // ethical CLEAN-SERVE daemon :HC_MAGIC_8102 (/clean; backs off until cleanservedeploy'd)
1913 let meshsrv_ws: *i64 = sys_mmap(16) as *i64; let meshsrv_cnt: *i64 = sys_mmap(16) as *i64 // WORKER MESH serve :HC_MAGIC_8029 (console + SSE gen + gated image backend)
1914 let meshgw_ws: *i64 = sys_mmap(16) as *i64; let meshgw_cnt: *i64 = sys_mmap(16) as *i64 // WORKER MESH OPAQUE gateway :HC_MAGIC_8055 (gated /mesh console)
1915 let arc_ws: *i64 = sys_mmap(16) as *i64; let arc_cnt: *i64 = sys_mmap(16) as *i64 // time-machine archive server :18801 (static serve of web_assets/archive)
1916 var run: i64 = 1
1917 while run == 1 {
1918 // seq1318: ONE /proc walk feeds EVERY liveness question below; all guards read the SAME instant.
1919 ps_refresh()
1920 hc_guard_one("sites.elf" as *u8, HC_ELF, 0, s_ws, s_cnt, HC_PID, 1) // TLS:HC_MAGIC_8443 -> PID-only
1921 hc_guard_one("redirect.elf" as *u8, HC_REDIRECT, 0, r_ws, r_cnt, HC_PID, 0) // PID-only: the :HC_MAGIC_8080 serving-probe (hp_probe sends /healthz, reads HC_MAGIC_4096, closes) SIGPIPE'd/HUNG-killed this working daemon every poll -> crash-loop (SAME root cause as the reader, see hostctl:~409). PID-liveness like sites.elf. (verify post-deploy: external probe :80 -> 301 https)
1922 hc_guard_one("nx_vroom_daemon.elf" as *u8, HC_VROOM, HC_MAGIC_8446, v_ws, v_cnt, HC_PID, 0) // plaintext -> probe
1923 // 2026-09-02 RETIRED FROM THIS ROSTER: hc_guard_one("/sni_router.elf", HC_SNIROUTER, 0, sr_ws, sr_cnt, HC_PID, 0).
1924 // daemons.reg retired the :7443 legacy router to `watch` on 2026-08-04 (DSM nginx owns :443; the serving path is
1925 // :443 -> NAT -> :8443 sites.elf, measured 20/20 from a LAN client) -- but THIS hand-coded roster kept guarding
1926 // it. MEASURED in supervisor.log's TAIL today: `[guard] restarted /sni_router.elf (was dead)` then `[reap] sig=9`
1927 // on a loop for hours, the crash-loop breaker engaging every few cycles, on a box at load 22-33 whose fork rate
1928 // read 37/s. A GUARD WHOSE PROBE PORT IS DEAD MANUFACTURES THE CHURN IT REPORTS. sr_ws/sr_cnt stay allocated
1929 // above so no other slot moves; re-add the call only after the router binds a port that is actually its own.
1930 hc_guard_one("nx_translate_daemon.elf" as *u8, HC_XLATE, HC_MAGIC_8447, x_ws, x_cnt, HC_PID, 0) // plaintext -> probe
1931 hc_guard_galx_serve(gs_ws, gs_cnt) // gallery serve :HC_MAGIC_18090 (NSFW gallery backend)
1932 hc_guard_galx_gw(gw_ws, gw_cnt) // gallery OPAQUE gateway :HC_MAGIC_18190 (login + media proxy)
1933 hc_guard_wiki_gw(wgw_ws, wgw_cnt) // wiki OPAQUE gateway :HC_MAGIC_18791 (login + the gated HC_MAGIC_1195-page wiki)
1934 hc_guard_hub_gw(hgw_ws, hgw_cnt) // hub OPAQUE gateway :HC_MAGIC_18792 (leveled /hub via the maturity registry)
1935 hc_guard_login(lgn_ws, lgn_cnt) // login OPAQUE daemon :HC_MAGIC_9091 (the token minter -- was unsupervised)
1936 hc_guard_torrent(tor_ws, tor_cnt) // media/torrent daemon :HC_MAGIC_8097 (the acquirer, migrated dev -> NAS hub; backs off until deployed)
1937 hc_guard_torrent_gw(tgw_ws, tgw_cnt) // torrent OPAQUE gateway :HC_MAGIC_18793 (sites /torrent -> here -> daemon; the live nishifamily front)
1938 hc_guard_gen_orch(gor_ws, gor_cnt) // gen orchestrator :HC_MAGIC_18795 (UI+batch->HC_MAGIC_5080+gallery; backs off until gendeploy'd)
1939 hc_guard_gen_gw(ggw_ws, ggw_cnt) // gen OPAQUE gateway :HC_MAGIC_18794 (sites /gen -> here -> orchestrator; backs off until gendeploy'd)
1940 hc_guard_synth(syn_ws, syn_cnt) // SYNTH STUDIO daemon :HC_MAGIC_18796 (sites /synth/api -> here; adopts the running detached daemon, respawns after crash/reboot)
1941 hc_guard_devapi(devapi_ws, devapi_cnt) // DEV/CI API daemon :HC_MAGIC_18797 (sites /api/dev -> here; adopts running daemon, respawns after crash/reboot)
1942 hc_guard_one("nx_clock_tickless.elf" as *u8, HC_CLOCK, 0, clk_ws, clk_cnt, HC_PID, 0) // the ONE consolidated scheduler: PID-only (alive during its tickless window, dead after -> respawn = continuous, no per-job daemon). ADDITIVE: nothing above changes.
1943 hc_guard_arcsrv(arc_ws, arc_cnt) // time-machine archive :18801. WAS hc_guard_one(..HC_ARCSRV..), which spawns via hc_spawn_path -- MEASURED DEAD: nx_netobs bench gave ok=0 err=1 in 203us (instant REFUSAL, not a timeout) with the elf promoted and the guard entry provably correct, i.e. spawning and dying. hc_spawn_path execs bare and inherits the supervisor's stdout; this daemon WRITES to stdout, so its first write to a dead pipe SIGPIPEs it -- the identical failure recorded twice in this file. hc_spawn_arcsrv adds /dev/null on 0,1,2 + the cwd its web_assets/ and seg_store paths need. Still PID-liveness only, no serving probe. ADDITIVE: nothing above changes.
1944 hc_guard_mgmt(mgmt_ws, mgmt_cnt) // sovereign management API :HC_MAGIC_18099 (HTTP /api -- operate the ecosystem over the wire, not the shell dance)
1945 hc_guard_relate(rel_ws, rel_cnt) // Relationship OS daemon :HC_MAGIC_8027 (/relate; fail-safe backoff until relatedeploy promotes the binary)
1946 hc_guard_project(pjw_ws, pjw_cnt) // /project OPAQUE gateway :HC_MAGIC_8028 (contractor portal; fail-safe backoff until the elf is deployed)
1947 hc_guard_cleanserve(cs_ws, cs_cnt) // ethical CLEAN-SERVE daemon :HC_MAGIC_8102 (/clean; fail-safe backoff until cleanservedeploy promotes the binary)
1948 hc_guard_mesh_serve(meshsrv_ws, meshsrv_cnt) // WORKER MESH serve :HC_MAGIC_8029 (sovereign job console backend; adopts the running setsid daemon, respawns after crash/reboot)
1949 hc_guard_mesh_gw(meshgw_ws, meshgw_cnt) // WORKER MESH OPAQUE gateway :HC_MAGIC_8055 (sites /mesh -> here; gated console, respawns after crash/reboot)
1950 hc_guard_admin(adm_ws, adm_cnt) // doc-portal ADMIN daemon :HC_MAGIC_8456 (admin.<d>/ -- owner self-service: invite-gated self-register + upload)
1951 hc_guard_mailportal(mail_ws, mail_cnt) // EMAIL-PORTAL daemon :HC_MAGIC_18465 (mail.<d>/ -- Modern-Auth webmail: invite register + inbox + local delivery)
1952 hc_guard_siteedit(sed_ws, sed_cnt) // SITE-VISUALS editor :HC_MAGIC_18466 (admin.<d>/site -- blueprint save/preview/publish, same realm as the doc portal)
1953 hc_guard_inventory(inv_ws, inv_cnt) // INVENTORY/ownership checker :HC_MAGIC_18122 (loopback-only; published at /inventory by proxy_routes.conf)
1954 hc_guard_tapi(tapi_ws, tapi_cnt) // agent-facing tools API :HC_MAGIC_18096 (HTTP /api/tools + /mcp -- R0 MCP-compatible + superset)
1955 hc_guard_fin(fin_ws, fin_cnt) // finance dashboard :HC_MAGIC_18097 (HTTP /finance -- gated login surface)
1956 hc_guard_dist(dist_ws, dist_cnt) // /dist content-addressed download server :HC_MAGIC_18120 (durable -- auto-restarts)
1957 hc_guard_seed(seed_ws, seed_cnt) // BitTorrent seeder :HC_MAGIC_6881 (inbound peers; serves seed_index.conf -- the UPLOAD/SHARE half, durable)
1958 hc_guard_seedann(sann_ws, sann_cnt) // DHT announcer: periodically announce_peer every registered info_hash -> discoverable (durable)
1959 hc_guard_mp(mp_ws, mp_cnt) // multiplayer game relay :HC_MAGIC_7702 (/mineworld-mp + /pstate + /roster -- shared-world games)
1960 hc_guard_health(he_ws, he_cnt) // CONTINUOUS M&E: nx_health_eval loop -- functional/quality health of the whole surface every 300s (kills fire-and-pray). ADDITIVE: nothing above changes.
1961 hc_guard_sig2(sg_ws, sg_cnt)
1962 hc_guard_dsup(dsup_ws, dsup_cnt, dsup_st) // FLEET SUPERVISOR nx_daemon_supervisor: the census said nothing launched it; now hostctl does (adopt-if-CYCLING, kill-and-respawn-if-stale, respawn-if-dead). ADDITIVE. // video signaling/media relay :HC_MAGIC_8445 (task #26 closed: supervised + reconcile-cycled). ADDITIVE.
1963 hc_emit_status_html(sys_now_realtime_sec()) // LIVE nishifamily.com/status.html -- refreshed every poll
1964 let snap_now: i64 = sys_now_realtime_ms() // real windowed rwin per service (guard cnt + 60s health-reset)
1965 hc_emit_snapshot(hc_rwin(s_cnt,s_ws,snap_now), hc_rwin(wgw_cnt,wgw_ws,snap_now), hc_rwin(gw_cnt,gw_ws,snap_now), hc_rwin(gs_cnt,gs_ws,snap_now), hc_rwin(lib_cnt,lib_ws,snap_now), hc_rwin(r_cnt,r_ws,snap_now), hc_rwin(tgw_cnt,tgw_ws,snap_now), hc_rwin(mgmt_cnt,mgmt_ws,snap_now), hc_rwin(adm_cnt,adm_ws,snap_now), hc_rwin(v_cnt,v_ws,snap_now), hc_rwin(tapi_cnt,tapi_ws,snap_now), hc_rwin(mail_cnt,mail_ws,snap_now)) // LIVE mgmt_snap.json -> /api/health + /api/services -> nishifamily.com/health dashboard (TRUE state, no false +/-)
1966 // reader handled by the forked cmd_reader_keep() (blocking-wait), NOT polled here -- polling kills it
1967 var rr: i64 = sys_wait4(0-1, reap_st, WNOHANG) // reap dead children so zombies don't pile toward RLIMIT_NPROC
1968 while rr > 0 {
1969 hc_puts(" [reap] pid=" as *u8); hc_putn(rr); hc_puts(" sig=" as *u8); hc_putn(reap_st[0]&0x7f); hc_puts(" code=" as *u8); hc_putn((reap_st[0]>>8)&0xff); hc_puts("\n" as *u8) // INSTRUMENT: why does the supervised reader exit?
1970 rr = sys_wait4(0-1, reap_st, WNOHANG)
1971 }
1972 hc_sup_touch() // heartbeat the single-supervisor lease every poll (a competing launch sees this and defers)
1973 sys_sleep_ms(HC_MAGIC_15000)
1974 }
1975 return 0
1976}
1977
1978func cmd_deploy() -> i64 {
1979 hc_puts("[hostctl] deploy: atomic-publish staged artifacts + restart (pure syscalls, no shell)\n" as *u8)
1980 sys_mkdir(HC_DOCROOT, 0x1ed)
1981 let r1: i64 = sys_renameat(HC_INDEX_NEW, HC_INDEX)
1982 let r2: i64 = sys_renameat(HC_CONF_NEW, HC_CONF)
1983 // seq1097 (2026-07-27 outage): REFUSE the elf swap unless a REAL artifact is staged. The old
1984 // unconditional live->prev rename meant a deploy with nothing staged (e.g. a retry after an
1985 // aborted-response /api/deploy that DID execute server-side) renamed live away and installed
1986 // NOTHING -- guard spins exit-127 on a missing file. stat-gate: exists AND st_size>0 (st_size @
1987 // +48, same struct-stat offsets hc_file_age_s relies on). Fail-safe: refuse loudly, touch nothing.
1988 let stb: *u8 = sys_mmap(160)
1989 var stok: i64 = 0
1990 if sys_fstatat(HC_ELF_NEW, stb) == 0 {
1991 let szp: *i64 = ((stb as i64) + 48) as *i64
1992 if szp[0] > 0 { stok = 1 }
1993 }
1994 if stok == 0 {
1995 hc_puts(" REFUSED elf swap: sites.elf.new absent or 0 bytes -- live binary left untouched\n" as *u8)
1996 return 1
1997 }
1998 sys_renameat(HC_ELF, HC_ELF_PREV) // never-brick: keep the current live binary as .prev for rollback
1999 let r3: i64 = sys_renameat(HC_ELF_NEW, HC_ELF)
2000 nx_chmod(HC_ELF, 0x1ed)
2001 // REAL return codes, NOT (rX & 1). rename returns 0 on success and -errno on failure, and ENOENT is -2
2002 // whose low bit is 0 -- so the masked form printed EVERY EVEN ERRNO AS SUCCESS. That is exactly how a
2003 // promote that installed NOTHING reported `rc=0` in cmd_mgmtdeploy on 2026-07-30, and it was caught only
2004 // by comparing artifact bytes. Print what the kernel actually said.
2005 hc_puts(" rename rc index=" as *u8); hc_putn(r1)
2006 hc_puts(" conf=" as *u8); hc_putn(r2)
2007 hc_puts(" elf=" as *u8); hc_putn(r3)
2008 hc_puts(" (0=ok, negative=-errno, NOT bit-masked)\n" as *u8)
2009 // ROBUST name-kill (matches cmd_wikideploy/galxdeploy): the pidfile is only written when the supervisor
2010 // ITSELF restarts sites.elf (hc_guard_one write_pid=1). An ADOPTED sites.elf (running before the supervisor
2011 // came up) leaves the pidfile stale -> the old pidfile-kill could MISS the restart (new binary never loads)
2012 // or SIGKILL a reused PID. Kill by name so the supervisor's name-guard respawns the NEW binary deterministically.
2013 let pk: i64 = proc_kill_by_name("sites.elf" as *u8, 9)
2014 hc_puts(" killed sites.elf procs=" as *u8); hc_putn(pk); hc_puts(" -> supervisor respawns the NEW binary (name-guarded restart, <=15s)\n" as *u8)
2015 return 0
2016}
2017
2018// mgmtdeploy: promote nx_mgmt_api.elf.new -> live (.prev kept, never-brick) + kill by name -> hc_guard_mgmt
2019// respawns the NEW binary (<=15s). Closes the publish-from-anywhere bootstrap: /api/upload stages the mgmt
2020// binary itself, /api/deploy (conf row `mgmtapi` -> this sub) promotes it -- after which ALL future mgmt
2021// updates AND static-content publishes flow over the authenticated public edge, no SSH/LAN.
2022func cmd_mgmtdeploy() -> i64 {
2023 hc_puts("[hostctl] mgmtdeploy: promote the staged mgmt binary -> live (.prev kept) + kick -> guard respawns\n" as *u8)
2024 // ---- REFUSE BEFORE DESTROY (2026-07-30). THREE COMPOUNDING DEFECTS LIVED IN THESE FIVE LINES:
2025 // (1) the live -> .prev rename ran UNCONDITIONALLY, BEFORE anything checked a staged binary existed. With
2026 // no .new present that MOVES THE LIVE BINARY AWAY and the install rename then fails, leaving NO live
2027 // mgmt at all. Only the never-brick auto-rollback put it back -- MEASURED TODAY: live and .prev both
2028 // ended at 578789 while the real 578865 build sat on disk unused.
2029 // (2) the rc was printed as (rr & 1). rename returns 0 on success and -errno on failure, and ENOENT is
2030 // -2, whose low bit is 0 -- so THE FAILURE PRINTED rc=0, IDENTICAL TO SUCCESS. Every even errno
2031 // displayed as success, so the operator reads a green promote that never happened.
2032 // (3) /api/build stages `<t>.sov.elf.new` but this promoter only ever read `<t>.elf.new` -- the seq1525
2033 // class, staged where the promoter cannot see it. Two names for one artifact is two sources of truth.
2034 // FIX: accept EITHER staged name, and REFUSE WITHOUT TOUCHING LIVE when neither is present.
2035 let mlive: *u8 = "/volume1/homes/elderwesto/nishihost/nx_mgmt_api.elf" as *u8
2036 let mprev: *u8 = "/volume1/homes/elderwesto/nishihost/nx_mgmt_api.elf.prev" as *u8
2037 let mnew1: *u8 = "/volume1/homes/elderwesto/nishihost/nx_mgmt_api.elf.new" as *u8
2038 let mnew2: *u8 = "/volume1/homes/elderwesto/nishihost/nx_mgmt_api.sov.elf.new" as *u8
2039 var stg: *u8 = 0 as *u8
2040 // ★PRECEDENCE BUG FIXED 2026-07-30 -- THIS IS HOW A "SUCCESSFUL" DEPLOY SHIPS A STALE BINARY.
2041 // This preferred mnew1 (.elf.new, the legacy UPLOAD name) whenever it existed, so ONE stale leftover
2042 // PERMANENTLY SHADOWED every fresh /api/build artifact. MEASURED: both names sat on disk; /api/deploy
2043 // answered PROMOTED and hc_promote_to genuinely promoted -- the STALE one -- while nx_mgmt_api.sov.elf.new
2044 // (581942B, built minutes earlier) was left untouched. Nothing lied; the wrong artifact was chosen. The
2045 // leftover persists BY DESIGN because hc_promote_to COPIES rather than renames (EXDEV safety), so nothing
2046 // ever consumed it. Prefer the sanctioned build artifact, and consume BOTH on success (below) so a
2047 // leftover can never shadow a build again. Rollback is unaffected -- it lives in .prev, not in .new.
2048 if hc_exists(mnew2) == 1 { stg = mnew2 }
2049 if stg == (0 as *u8) { if hc_exists(mnew1) == 1 { stg = mnew1 } }
2050 if stg == (0 as *u8) {
2051 hc_puts(" REFUSED: no staged binary -- looked for BOTH nx_mgmt_api.elf.new and nx_mgmt_api.sov.elf.new.\n" as *u8)
2052 hc_puts(" LIVE IS UNTOUCHED. The old code would have moved it to .prev and left the host with nothing.\n" as *u8)
2053 return 1
2054 }
2055 // USE THE SHARED PROMOTER, DO NOT HAND-ROLL ANOTHER ONE. This exact defect has now been found and fixed
2056 // THREE TIMES in three functions -- hc_promote_to first, then cmd_selfswap at seq992 after its own outage,
2057 // then here. hc_promote_to is also STRICTLY SAFER than a local renameat: it COPIES, because sys_renameat
2058 // across btrfs subvolumes returns EXDEV, which once moved a live binary to .prev and installed NOTHING.
2059 // A fourth site that hand-rolls this will rediscover the same outage; call this instead.
2060 let ok: i64 = hc_promote_to(stg, mlive, mprev)
2061 if ok == 0 {
2062 hc_puts(" INSTALL FAILED -- hc_promote_to reported no-op/short-write; live left as it was.\n" as *u8)
2063 return 1
2064 }
2065 hc_puts(" installed via hc_promote_to (EXDEV-safe copy, .prev banked, refuses when nothing is staged)\n" as *u8)
2066 // CONSUME BOTH STAGED NAMES. hc_promote_to COPIES, so without this the source survives and the next
2067 // deploy re-promotes an artifact that has already shipped -- which is exactly the shadowing bug above.
2068 // Safe: these are SPENT staging files, the live binary is installed and .prev holds the rollback copy.
2069 // Unlinking both (not just the one chosen) is the point -- leaving the loser is what created the trap.
2070 sys_unlinkat(mnew2)
2071 sys_unlinkat(mnew1)
2072 hc_puts(" consumed staged artifacts (both names) -- a leftover can no longer shadow the next build\n" as *u8)
2073 // ---- R5 SEQUENCING: LET MGMT FINISH ITS REPLY BEFORE WE KILL IT ------------------------------------
2074 // THE DEFECT THIS REMOVES: this sub is invoked BY the mgmt daemon (POST /api/deploy target=mgmtapi ->
2075 // md_exec_hostctl -> here), so SIGKILLing nx_mgmt_api.elf right now destroys the process that is still
2076 // writing the caller's HTTP response. That is the FETCH-FAIL every /api/deploy has ever returned (~14x in
2077 // one session) -- and we built DOCTRINE around it ("503 = EXPECTED, do NOT retry-hammer") instead of
2078 // fixing it. It is also why the seq1563 deploy lease strands: mgmt dies before reaching its own release,
2079 // so the lane stays closed until the TTL and the NEXT deploy is refused as lease-busy.
2080 // ⚠ THE KILLER IS A DIFFERENT PROCESS: hostctl is forked by mgmt, so mgmt is not "self" from here and the
2081 // md_kill_by_name self-guard cannot fire. The delay has to live at the site that actually kills.
2082 // FIX: detach a child that waits, THEN signals. hostctl returns immediately, mgmt finishes and flushes its
2083 // response, and only then does it go -- guard respawns the already-promoted binary. SIGTERM not SIGKILL so
2084 // a daemon that later grows a drain handler gets to use it; the guard still respawns either way.
2085 let dpid: i64 = sys_fork()
2086 if dpid == 0 {
2087 nx_setsid()
2088 sys_sleep_ms(HC_MAGIC_1500) // hoisted 2026-09-02: the ratchet refused the whole file's build for this one inline literal (const already existed)
2089 proc_kill_by_name("nx_mgmt_api.elf" as *u8, 15)
2090 sys_exit(0)
2091 }
2092 hc_puts(" scheduled SIGTERM of nx_mgmt_api.elf in 1500ms (reply-flush window) -> hc_guard_mgmt respawns the NEW binary (<=15s)\n" as *u8)
2093 return 0
2094}
2095// never-brick mgmt ROLLBACK: restore nx_mgmt_api.elf.prev -> live + kick (reverse a bad mgmtdeploy).
2096func cmd_mgmtrollback() -> i64 {
2097 hc_puts("[hostctl] mgmtrollback: restore nx_mgmt_api.elf.prev -> live + kick\n" as *u8)
2098 let rr: i64 = sys_renameat("/volume1/homes/elderwesto/nishihost/nx_mgmt_api.elf.prev" as *u8, "/volume1/homes/elderwesto/nishihost/nx_mgmt_api.elf" as *u8)
2099 nx_chmod("/volume1/homes/elderwesto/nishihost/nx_mgmt_api.elf" as *u8, 0x1ed)
2100 hc_put_rc(" restore rename rc=" as *u8, rr)
2101 let pk: i64 = proc_kill_by_name("nx_mgmt_api.elf" as *u8, 9)
2102 hc_puts(" killed nx_mgmt_api.elf procs=" as *u8); hc_putn(pk); hc_puts(" -> guard respawns the RESTORED binary\n" as *u8)
2103 return 0
2104}
2105
2106const HC_COPYBUF: i64 = 262144 // chunked-copy buffer for cross-subvolume promote (hc_copy_file)
2107// ---- P1 off-LAN parity: promote/rollback the TORRENT stack (lives in /volume1/ai/torrent/, a DIFFERENT dir
2108// than the nishihost staging area). /api/upload stages <name>.new in nishihost cwd; this cross-dir promotes it
2109// into the torrent dir (SAME volume1 => sys_renameat works). GUARDED per-binary: only promote if the staged
2110// .new exists, so deploying one torrent binary never destroys the other's live copy. .prev kept (never-brick).
2111func hc_exists(p: *u8) -> i64 { let fd: i64 = sys_openat_rd(p); if fd < 0 { return 0 } sys_close(fd); return 1 }
2112// ---- HONEST RETURN CODES (2026-07-30) ------------------------------------------------------------------
2113// THE IDIOM THIS REPLACES, WHICH WAS AT 14 SITES IN THIS FILE: `b[0] = (48 + (rc & 1))` printed only the LOW
2114// BIT of a syscall result. rename/unlink return 0 on success and -errno on failure, and ENOENT is -2 -- low
2115// bit 0 -- so EVERY EVEN ERRNO RENDERED AS `0`, INDISTINGUISHABLE FROM SUCCESS. That is precisely how
2116// cmd_mgmtdeploy reported `install rename rc=0` while installing NOTHING and briefly leaving the host with no
2117// mgmt binary; it was caught only by comparing artifact BYTES, never by the message.
2118// ★★★★★LAW: A SUCCESS MESSAGE DERIVED FROM A MASKED ERROR CODE IS WORSE THAN NO MESSAGE -- it does not
2119// merely fail to inform, it actively asserts the opposite of what happened. One helper, so no site can get
2120// this wrong again (the same discipline as binding SIGPIPE and FD_CLOEXEC to the listen primitive).
2121func hc_put_rc(label: *u8, rc: i64) -> i64 {
2122 hc_puts(label)
2123 hc_putn(rc)
2124 hc_puts(" (0=ok, negative=-errno, NOT bit-masked)\n" as *u8)
2125 return 0
2126}
2127// chunked copy src -> dst (0777); 0 = clean full copy, -1 = short write. REQUIRED for the torrent promote:
2128// /volume1/ai/torrent is a DIFFERENT btrfs subvolume than /volume1/homes (nishihost), so sys_renameat ACROSS
2129// them returns EXDEV. The old hc_promote_to swallowed that (rename live->prev same-dir OK, then rename
2130// new->live cross-subvol EXDEV FAILED) -> it moved the live binary to .prev and installed NOTHING -> the
2131// daemon could not respawn (missing binary) = a self-inflicted outage. Copy is cross-subvolume-safe.
2132func hc_copy_file(src: *u8, dst: *u8) -> i64 {
2133 let sf: i64 = sys_openat_rd(src); if sf < 0 { return 0 - 1 }
2134 let df: i64 = sys_openat_wr(dst, 0x1ff); if df < 0 { sys_close(sf); return 0 - 1 }
2135 let buf: *u8 = sys_mmap(HC_COPYBUF); var bad: i64 = 0; var go: i64 = 1
2136 while go == 1 {
2137 let r: i64 = sys_read(sf, buf, HC_COPYBUF)
2138 if r <= 0 { go = 0 } else { let w: i64 = sys_write(df, buf, r); if w != r { bad = 1; go = 0 } }
2139 }
2140 sys_close(sf); sys_close(df)
2141 return 0 - bad
2142}
2143// Byte length of a path, or -1 if unreadable. Streamed, so an arbitrarily large elf is never held whole.
2144func hc_file_size(p: *u8) -> i64 {
2145 let fd: i64 = sys_openat_rd(p)
2146 if fd < 0 { return 0 - 1 }
2147 let sb: *u8 = sys_mmap(HC_COPYBUF)
2148 var tot: i64 = 0
2149 var go: i64 = 1
2150 while go == 1 {
2151 let r: i64 = sys_read(fd, sb, HC_COPYBUF)
2152 if r <= 0 { go = 0 }
2153 if r > 0 { tot = tot + r }
2154 }
2155 sys_close(fd)
2156 return tot
2157}
2158// ---- EXPECTED-IDENTITY PROMOTE (2026-07-30) -- deploy a DIGEST, not a TAG -------------------------------
2159// THE RACE THIS CLOSES, MEASURED THE SAME DAY: nx_sov_build_run writes _build/<t>.sov.elf and a LATER step
2160// copies that PATH and promotes it. Any sibling rebuilding the same target in between OVERWRITES the file.
2161// I built nx_mgmt_api at 578865, verified it, and by promote time _build held a sibling's 579263 -- WHICH IS
2162// WHAT WENT LIVE. I verified one artifact and shipped another and nothing detected it. mgmt then walked
2163// 578789 -> 578865 -> 579263 -> 580657 inside one hour, so this is the normal condition, not a freak.
2164// A PATH IS A PROMISE ABOUT A LOCATION, NOT ABOUT CONTENT. The `build-<target>` lease does not help: it is
2165// released when the COMPILE ends, so it locks the wrong interval -- the hazard lives AFTER it.
2166// expect_size > 0 makes the caller state WHICH artifact it verified; a mismatch REFUSES with both numbers
2167// instead of silently shipping bytes nobody tested. 0 keeps the old behaviour so every existing caller is
2168// unchanged and this is purely additive.
2169// ⚠SIZE IS A WEAKER CHECK THAN A CONTENT HASH -- a same-size rewrite passes (the seq1477 law). It is used
2170// here because it needs NO new import in a file 52 organs depend on, and it catches the measured failure.
2171// The strong check is `nx_artifact_id verify <path> <size> <fnv>` run by the caller before invoking this.
2172func hc_promote_to_expect(nhnew: *u8, live: *u8, prev: *u8, expect_size: i64) -> i64 {
2173 if hc_exists(nhnew) == 0 { return 0 }
2174 let asz: i64 = hc_file_size(nhnew)
2175 if expect_size > 0 {
2176 if asz != expect_size {
2177 hc_puts(" REFUSED: the staged artifact is NOT the one you built -- expected bytes=" as *u8)
2178 hc_putn(expect_size)
2179 hc_puts(" actual bytes=" as *u8); hc_putn(asz); hc_puts("\n" as *u8)
2180 hc_puts(" A sibling almost certainly rebuilt this target between your build and this promote.\n" as *u8)
2181 hc_puts(" LIVE IS UNTOUCHED. Rebuild, re-read the size, and promote the artifact you verified.\n" as *u8)
2182 return 0
2183 }
2184 }
2185 // DURABLE ROLLBACK CHAIN (2026-08-21). MEASURED THIS SESSION: two deploys of ONE target inside a
2186 // single session left BOTH live and .prev holding the new build -- the pre-change binary was GONE,
2187 // and an older-generation binary CANNOT be rebuilt. This slot holds "the PREVIOUS DEPLOY", never
2188 // "the last known good", so the SECOND deploy is the one that leaves you with no way back. Until now
2189 // the only defence was the operator remembering to copy the artifact aside first, and
2190 // *A SAFETY PROPERTY THAT DEPENDS ON SOMEONE REMEMBERING IS AN ADOPTION GAP WITH EXTRA STEPS.
2191 // One generation deeper is kept here, and the generation that DOES fall off is ANNOUNCED with its
2192 // size -- a bounded chain whose loss is VISIBLE rather than silent (the no-silent-caps law).
2193 // Bounded deliberately: one extra file per target, no directory, and no new import into a file 52
2194 // organs depend on. It does NOT make the chain infinite -- it converts the measured two-deploy loss
2195 // into a kept copy and makes every deeper loss say so out loud.
2196 let bufG: *u8 = sys_mmap(512)
2197 let prev2: *u8 = hc_pathsuf(bufG, prev, "2" as *u8)
2198 if hc_exists(prev) == 1 {
2199 if hc_exists(prev2) == 1 {
2200 hc_puts(" ROLLBACK-CHAIN dropping generation " as *u8); hc_puts(prev2)
2201 hc_puts(" bytes=" as *u8); hc_putn(hc_file_size(prev2))
2202 hc_puts(" -- if that artifact cannot be rebuilt, bank it BEFORE the next deploy\n" as *u8)
2203 }
2204 sys_renameat(prev, prev2) // rotate: the outgoing .prev survives one more deploy
2205 }
2206 sys_renameat(live, prev) // keep current live as .prev (same-dir rename; a running proc keeps its old inode)
2207 let rr: i64 = hc_copy_file(nhnew, live) // promote staged .new -> live via COPY (cross-subvolume EXDEV-safe; sys_renameat here WAS the outage)
2208 nx_chmod(live, 0x1ed)
2209 if rr == 0 {
2210 // A RECEIPT ON EVERY PROMOTE, not only when asked: a deploy verb that cannot name what it deployed
2211 // is not a receipt, and a lost response then reads as a stale binary.
2212 hc_puts(" promoted bytes=" as *u8); hc_putn(asz); hc_puts(" (verify with: nx_artifact_id.elf id <live-path>)\n" as *u8)
2213 return 1
2214 }
2215 return 0
2216}
2217func hc_promote_to(nhnew: *u8, live: *u8, prev: *u8) -> i64 {
2218 return hc_promote_to_expect(nhnew, live, prev, 0)
2219}
2220// ---- GENERIC DEPLOY (R2 of the SOTA rung plan) ---------------------------------------------------
2221// THE DEFECT THIS RETIRES: cmd_deploy() takes NO PARAMETERS. It is hardcoded to the HC_ELF constants
2222// and to proc_kill_by_name("sites.elf") -- a GENERIC NAME on a SINGLE-SERVICE deployer. That is why
2223// every new deployable needed its own function, and the cost was counted 2026-07-31:
2224// 15 cmd_*deploy functions + 12 cmd_*rollback twins = 27 near-duplicate copies of ONE pattern.
2225//
2226// THE REAL COST IS NOT DUPLICATION, IT IS DIVERGENCE. Four hard-won lessons live in cmd_mgmtdeploy --
2227// refuse-before-destroy, print the REAL rc, accept EITHER staged name, consume BOTH on success -- and
2228// cmd_deploy has only the first. Each lesson had to be re-applied 27 times and demonstrably was not.
2229// ★★★★★★ EVERY COPY OF A PATTERN IS A PLACE A FIX CAN FAIL TO ARRIVE.
2230//
2231// With this, adding a deployable is a ROW in deploy_targets.conf naming sub=gdeploy plus the live path
2232// and process name -- a DATA edit, not new code. That is the whole of R2.
2233
2234// Build <live><suffix> into dst. Returns dst for call-site brevity.
2235func hc_pathsuf(dst: *u8, live: *u8, suf: *u8) -> *u8 {
2236 var o: i64 = hc_cat(dst, 0, live)
2237 o = hc_cat(dst, o, suf)
2238 dst[o] = 0 as u8
2239 return dst
2240}
2241
2242// Derive the SECOND staged name: /path/nx_foo.elf -> /path/nx_foo.sov.elf.new
2243// /api/build stages <target>.sov.elf.new while /api/upload stages <artifact>.new. TWO NAMES FOR ONE
2244// ARTIFACT IS TWO SOURCES OF TRUTH, and a promoter that reads only one silently ignores the other --
2245// the seq1525 class, staged where the promoter cannot see it.
2246func hc_sovname(dst: *u8, live: *u8) -> *u8 {
2247 var n: i64 = 0
2248 while live[n] != (0 as u8) { n = n + 1 }
2249 // strip a trailing ".elf" if present, then append ".sov.elf.new"
2250 var cut: i64 = n
2251 if n > 4 {
2252 if live[n-4] == (46 as u8) { if live[n-3] == (101 as u8) { if live[n-2] == (108 as u8) { if live[n-1] == (102 as u8) { cut = n - 4 } } } }
2253 }
2254 var i: i64 = 0
2255 while i < cut { dst[i] = live[i]; i = i + 1 }
2256 var o: i64 = hc_cat(dst, cut, ".sov.elf.new" as *u8)
2257 dst[o] = 0 as u8
2258 return dst
2259}
2260
2261// Promote a staged artifact over <live> and restart <killname>. ALL FOUR LESSONS IN ONE PLACE.
2262func hc_deploy_one(live: *u8, killname: *u8) -> i64 {
2263 let bufA: *u8 = sys_mmap(512)
2264 let bufB: *u8 = sys_mmap(512)
2265 let bufP: *u8 = sys_mmap(512)
2266 let new1: *u8 = hc_pathsuf(bufA, live, ".new" as *u8)
2267 let new2: *u8 = hc_sovname(bufB, live)
2268 let prev: *u8 = hc_pathsuf(bufP, live, ".prev" as *u8)
2269
2270 // LESSON 3 + PRECEDENCE: prefer the SANCTIONED BUILD artifact (.sov.elf.new). Preferring the legacy
2271 // upload name let ONE stale leftover permanently shadow every fresh build -- a promote that reported
2272 // success and shipped the wrong binary. Nothing lied; the wrong artifact was chosen.
2273 var stg: *u8 = 0 as *u8
2274 if hc_exists(new2) == 1 { stg = new2 }
2275 if stg == (0 as *u8) { if hc_exists(new1) == 1 { stg = new1 } }
2276
2277 // LESSON 1 -- REFUSE BEFORE DESTROY. The original unconditional live->prev rename moved the live
2278 // binary away BEFORE checking anything was staged, leaving the host with NOTHING when the install
2279 // then failed. Refuse loudly and touch nothing.
2280 if stg == (0 as *u8) {
2281 hc_puts(" REFUSED: nothing staged for " as *u8); hc_puts(live)
2282 hc_puts(" (looked for BOTH .new and .sov.elf.new) -- LIVE UNTOUCHED\n" as *u8)
2283 return 1
2284 }
2285
2286 // hc_promote_to banks .prev, COPIES (EXDEV-safe across subvolumes), and chmods 0755.
2287 // ⚠⚠ IT RETURNS 1 ON SUCCESS AND 0 ON FAILURE -- the INVERSE of the syscall convention used three
2288 // lines below it. The first version of this function assumed 0=ok and therefore printed
2289 // "PROMOTE FAILED" over a promote that had DEMONSTRABLY SUCCEEDED (live=NEW, .prev=OLD on disk),
2290 // then skipped the consume and the restart. Caught by a sandbox positive-path test, not by review.
2291 // ★★★★★★ A RETURN CONVENTION IS PART OF AN API -- READ IT, NEVER INFER IT FROM THE NEIGHBOURS.
2292 // This file mixes both conventions, which is exactly why the mistake is available to make.
2293 let ok: i64 = hc_promote_to(stg, live, prev)
2294 hc_puts(" promote ok=" as *u8); hc_putn(ok); hc_puts(" (hc_promote_to: 1=SUCCESS, 0=failure)\n" as *u8)
2295 if ok != 1 {
2296 hc_puts(" PROMOTE FAILED -- live left as-is, .prev intact\n" as *u8)
2297 return 1
2298 }
2299
2300 // LESSON 4 -- consume BOTH staged names. hc_promote_to copies rather than renames, so nothing
2301 // consumes the source; a leftover would shadow the next build forever.
2302 sys_unlinkat(new1)
2303 sys_unlinkat(new2)
2304
2305 let pk: i64 = proc_kill_by_name(killname, 9)
2306 hc_puts(" killed " as *u8); hc_puts(killname)
2307 hc_puts(" procs=" as *u8); hc_putn(pk)
2308 hc_puts(" -> guard respawns the NEW binary (name-guarded restart, <=15s)\n" as *u8)
2309 return 0
2310}
2311
2312// Does s start with p? Needed for the gdeploy@<row> form; hc_streq is exact-match only.
2313func hc_prefix(s: *u8, p: *u8) -> i64 {
2314 var i: i64 = 0
2315 while p[i] != (0 as u8) {
2316 if s[i] == (0 as u8) { return 0 }
2317 if s[i] != p[i] { return 0 }
2318 i = i + 1
2319 }
2320 return 1
2321}
2322
2323// Read field `want` (0-based) of the deploy_targets.conf row whose FIRST field == rowname, into out.
2324// Returns 1 if found. ONE SOURCE OF TRUTH ON PURPOSE: the paths live in the SAME row /api/deploy already
2325// reads, not a second file. A second mapping file would be a second thing to forget to update, which is
2326// the declared-vs-real divergence this whole arc is about.
2327func hc_row_field(rowname: *u8, want: i64, out: *u8) -> i64 {
2328 let lp: *i64 = sys_mmap(16) as *i64
2329 lp[0] = 0
2330 let b: *u8 = sys_read_file("deploy_targets.conf" as *u8, lp)
2331 let n: i64 = lp[0]
2332 if n <= 0 { return 0 }
2333 var line: i64 = 0
2334 while line < n {
2335 var eol: i64 = line
2336 var es: i64 = 0
2337 while es == 0 { if eol >= n { es = 1 } else { if b[eol] == (10 as u8) { es = 1 } else { eol = eol + 1 } } }
2338 var skip: i64 = 0
2339 if line < eol { if b[line] == (35 as u8) { skip = 1 } }
2340 if skip == 0 {
2341 // field 0 must equal rowname
2342 var p: i64 = line
2343 var fe: i64 = 0
2344 while fe == 0 { if p < eol { if b[p] == (32 as u8) { fe = 1 } else { p = p + 1 } } else { fe = 1 } }
2345 var hit: i64 = 1
2346 var k: i64 = 0
2347 while rowname[k] != (0 as u8) {
2348 if line + k >= p { hit = 0; k = k + 1 } else {
2349 if b[line + k] != rowname[k] { hit = 0 }
2350 k = k + 1
2351 }
2352 }
2353 if p - line != k { hit = 0 }
2354 if hit == 1 {
2355 var f: i64 = 1
2356 var q: i64 = p
2357 var done: i64 = 0
2358 while done == 0 {
2359 var ws: i64 = 0
2360 while ws == 0 { if q < eol { if b[q] == (32 as u8) { q = q + 1 } else { ws = 1 } } else { ws = 1 } }
2361 if q >= eol { done = 1 } else {
2362 let fs: i64 = q
2363 var f2: i64 = 0
2364 while f2 == 0 { if q < eol { if b[q] == (32 as u8) { f2 = 1 } else { q = q + 1 } } else { f2 = 1 } }
2365 if f == want {
2366 var z: i64 = 0
2367 while fs + z < q { out[z] = b[fs + z]; z = z + 1 }
2368 out[z] = 0 as u8
2369 return 1
2370 }
2371 f = f + 1
2372 }
2373 }
2374 return 0
2375 }
2376 }
2377 line = eol + 1
2378 }
2379 return 0
2380}
2381
2382// gdeploy <live-path> <kill-name> -- the data-driven deploy verb.
2383func cmd_gdeploy(live: *u8, killname: *u8) -> i64 {
2384 hc_puts("[hostctl] gdeploy: generic atomic promote + name-guarded restart\n" as *u8)
2385 hc_puts(" live=" as *u8); hc_puts(live); hc_puts(" kill=" as *u8); hc_puts(killname); hc_puts("\n" as *u8)
2386 return hc_deploy_one(live, killname)
2387}
2388
2389// ---- THE PER-ROW REVERSE GEAR (2026-09-03) -------------------------------------------------------
2390// WHY THIS EXISTS, MEASURED: every gdeploy@ row in deploy_targets.conf named `rollback` in field 5, and
2391// cmd_rollback() TAKES NO TARGET ARGUMENT -- it unconditionally renames sites.elf.prev over sites.elf and
2392// kills sites.elf. So the declared reverse gear of 16 daemons REVERSED THE FRONT DOOR and left the bad
2393// daemon live; and because /api/deploy's health watchdog invokes field 5, that wrong-subject destruction
2394// was AUTOMATIC, not merely a manual footgun. This file already recorded the hazard twice by hand
2395// (docportal corrected 2026-09-02, comparegw dodging it with a deliberately unknown verb, and the words
2396// "every gdeploy row above carries that word") without generalising it.
2397// ★A DEFECT NAMED IN A COMMENT BESIDE THE ROWS THAT STILL HAVE IT IS NOT DOCUMENTED, IT IS ADVERTISED.
2398// Nothing new is needed to do this right: hc_deploy_one already banks <live>.prev per row, and the row
2399// itself carries live-path (field 6) and kill-name (field 7). There was simply never a generic reverse.
2400//
2401// TWO CONJUNCTS cmd_rollback DOES NOT HAVE, both deliberate and both about failing toward the live binary:
2402// 1. REFUSE BEFORE DESTROY (hc_deploy_one lesson 1): with no banked .prev there is nothing to restore and
2403// a rename of an absent file would leave the target with NOTHING. Refuse loudly, touch nothing.
2404// 2. DO NOT KILL AFTER A FAILED RESTORE. cmd_rollback chmods and kills regardless of the rename rc; if the
2405// restore failed, killing the process only respawns THE BAD BINARY while reporting a rollback. A reverse
2406// gear that cannot prove it restored must not also stop the thing it failed to fix.
2407// The rc is PROPAGATED (cmd_gdeploy discards hc_deploy_one's rc and exits 0, so a REFUSED deploy reads as
2408// success -- an asymmetry deliberately NOT copied here, because a refused rollback the caller reads as
2409// success is how a bad binary stays live with everyone believing it was reverted).
2410func cmd_gdeploy_rollback(live: *u8, killname: *u8) -> i64 {
2411 hc_puts("[hostctl] gdeployrb: restore <live>.prev -> live + name-guarded restart (PER-ROW reverse gear)\n" as *u8)
2412 hc_puts(" live=" as *u8); hc_puts(live); hc_puts(" kill=" as *u8); hc_puts(killname); hc_puts("\n" as *u8)
2413 let bufP: *u8 = sys_mmap(512)
2414 let prev: *u8 = hc_pathsuf(bufP, live, ".prev" as *u8)
2415 if hc_exists(prev) != 1 {
2416 hc_puts(" REFUSED: no banked " as *u8); hc_puts(prev)
2417 hc_puts(" -- LIVE UNTOUCHED (there is nothing to roll back to)\n" as *u8)
2418 return 1
2419 }
2420 let rr: i64 = sys_renameat(prev, live)
2421 hc_put_rc(" restore rename rc=" as *u8, rr)
2422 if rr != 0 {
2423 hc_puts(" REFUSED: restore FAILED -- live left as it was and the process NOT killed (a kill here would respawn the bad binary)\n" as *u8)
2424 return 1
2425 }
2426 nx_chmod(live, 0x1ed)
2427 let pk: i64 = proc_kill_by_name(killname, 9)
2428 hc_puts(" killed " as *u8); hc_puts(killname)
2429 hc_puts(" procs=" as *u8); hc_putn(pk)
2430 hc_puts(" -> supervisor respawns the RESTORED binary\n" as *u8)
2431 return 0
2432}
2433
2434// ---- TOOLCHAIN DEPLOY (seq891) -------------------------------------------------------------------
2435// THE GAP THIS CLOSES: the ecosystem could build and deploy every SERVICE over its own API but could
2436// NOT update the COMPILER that builds them. /api/upload gates on a service-basename allowlist and
2437// /api/build stages into nishihost/, with no allowlisted route into buildroot/_offc -- so a PROVEN
2438// compiler fix could not be landed API-first (rule 27) and needed on-LAN/ssh.
2439//
2440// NEVER-BRICK BY CONSTRUCTION: this reuses hc_promote_to, the same primitive the torrent and gallery
2441// cross-dir promotes already use. It no-ops when nothing is staged, banks the current binary as .prev,
2442// COPIES rather than renames (cross-subvolume EXDEV is what caused a real outage here once), and
2443// chmods 0755 so the promoted compiler stays EXECUTABLE -- the detail that makes the tempting
2444// /api/unpack shortcut unsafe (nx_treepack writes 0644 and unlinks; see debt seq903).
2445//
2446// Each binary is INDEPENDENT: a missing stage is a no-op, not a failure, so a partial ship can never
2447// half-install a toolchain. The toolchain is NOT a daemon -- there is nothing to kill or respawn, and
2448// the next /api/build simply picks up the new binary. Verify a landing by BEHAVIOUR (build a probe),
2449// never by the promote returning 1.
2450const HC_TC_CC: *u8 = "/volume1/homes/elderwesto/nishihost/buildroot/_offc/nx_cc_sovereign.elf" as *u8
2451const HC_TC_CC_NEW: *u8 = "/volume1/homes/elderwesto/nishihost/buildroot/runtime/nx_cc_sovereign.elf.new" as *u8
2452const HC_TC_CC_PREV: *u8 = "/volume1/homes/elderwesto/nishihost/buildroot/_offc/nx_cc_sovereign.elf.prev" as *u8
2453const HC_TC_CC_BAD: *u8 = "/volume1/homes/elderwesto/nishihost/buildroot/_offc/nx_cc_sovereign.elf.bad" as *u8
2454const HC_TC_ASM: *u8 = "/volume1/homes/elderwesto/nishihost/buildroot/_offc/nxasm_x86_main.elf" as *u8
2455const HC_TC_ASM_NEW: *u8 = "/volume1/homes/elderwesto/nishihost/buildroot/runtime/nxasm_x86_main.elf.new" as *u8
2456const HC_TC_ASM_PREV: *u8 = "/volume1/homes/elderwesto/nishihost/buildroot/_offc/nxasm_x86_main.elf.prev" as *u8
2457const HC_TC_ASM_BAD: *u8 = "/volume1/homes/elderwesto/nishihost/buildroot/_offc/nxasm_x86_main.elf.bad" as *u8
2458const HC_TC_SBR: *u8 = "/volume1/homes/elderwesto/nishihost/buildroot/_offc/nx_sov_build_run.elf" as *u8
2459const HC_TC_SBR_NEW: *u8 = "/volume1/homes/elderwesto/nishihost/buildroot/runtime/nx_sov_build_run.elf.new" as *u8
2460const HC_TC_SBR_PREV: *u8 = "/volume1/homes/elderwesto/nishihost/buildroot/_offc/nx_sov_build_run.elf.prev" as *u8
2461const HC_TC_SBR_BAD: *u8 = "/volume1/homes/elderwesto/nishihost/buildroot/_offc/nx_sov_build_run.elf.bad" as *u8
2462func cmd_toolchaindeploy() -> i64 {
2463 hc_puts("[hostctl] toolchaindeploy: promote staged toolchain -> buildroot/_offc/ (.prev kept, chmod 0755)\n" as *u8)
2464 let c: i64 = hc_promote_to(HC_TC_CC_NEW, HC_TC_CC, HC_TC_CC_PREV)
2465 let a: i64 = hc_promote_to(HC_TC_ASM_NEW, HC_TC_ASM, HC_TC_ASM_PREV)
2466 let b: i64 = hc_promote_to(HC_TC_SBR_NEW, HC_TC_SBR, HC_TC_SBR_PREV)
2467 hc_puts("[hostctl] toolchaindeploy: cc=" as *u8); hc_putn(c)
2468 hc_puts(" nxasm=" as *u8); hc_putn(a)
2469 hc_puts(" sovbuildrun=" as *u8); hc_putn(b)
2470 hc_puts(" (1=promoted, 0=nothing staged) -- VERIFY BY BUILDING A PROBE, not by these counts\n" as *u8)
2471 return 0
2472}
2473func cmd_toolchainrollback() -> i64 {
2474 hc_puts("[hostctl] toolchainrollback: restore the .prev toolchain binaries\n" as *u8)
2475 let c: i64 = hc_promote_to(HC_TC_CC_PREV, HC_TC_CC, HC_TC_CC_BAD)
2476 let a: i64 = hc_promote_to(HC_TC_ASM_PREV, HC_TC_ASM, HC_TC_ASM_BAD)
2477 let b: i64 = hc_promote_to(HC_TC_SBR_PREV, HC_TC_SBR, HC_TC_SBR_BAD)
2478 hc_puts("[hostctl] toolchainrollback: cc=" as *u8); hc_putn(c)
2479 hc_puts(" nxasm=" as *u8); hc_putn(a)
2480 hc_puts(" sovbuildrun=" as *u8); hc_putn(b)
2481 hc_puts("\n" as *u8)
2482 return 0
2483}
2484func cmd_torrentdeploy() -> i64 {
2485 hc_puts("[hostctl] torrentdeploy: promote staged torrent binaries -> /volume1/ai/torrent/ (.prev kept) + kicktorrent\n" as *u8)
2486 let d: i64 = hc_promote_to("/volume1/homes/elderwesto/nishihost/nx_torrent_daemon.sov.elf.new" as *u8, "/volume1/ai/torrent/nx_torrent_daemon.sov.elf" as *u8, "/volume1/ai/torrent/nx_torrent_daemon.sov.elf.prev" as *u8)
2487 let s: i64 = hc_promote_to("/volume1/homes/elderwesto/nishihost/nx_torrent_seedeval.elf.new" as *u8, "/volume1/ai/torrent/nx_torrent_seedeval.elf" as *u8, "/volume1/ai/torrent/nx_torrent_seedeval.elf.prev" as *u8)
2488 // ★THE SEEDER ITSELF (2026-07-30) -- the one torrent binary in this directory with NO promotion line.
2489 // torrentdeploy promoted daemon, seedeval, worker, mp4faststart, extract and vidindex, but never
2490 // nx_torrent_seed, so a seeder fix could not ship by ANY sanctioned route: /api/promote is refused now
2491 // that it is correctly declared a daemon, and /api/deploy had nothing to call. This ONE LINE is the
2492 // whole adoption gap -- the primitives (hc_promote_to), the guard (restarts it when dead) and the
2493 // restart verb (kickseed) all already existed and were simply unreachable for this artefact.
2494 // ⚠NAME TRAP: the siblings promote to `<name>.sov.elf`, but HC_SEED_CMD execs `./nx_torrent_seed.elf`
2495 // and the guard matches that exact name -- so the LIVE target is `.elf`, NOT `.sov.elf`. Promoting to
2496 // the sibling-style name would place a binary nothing ever runs and read as a successful deploy.
2497 // hc_promote_to is guarded on .new existence, so this is a NO-OP whenever no seeder is staged.
2498 let sd: i64 = hc_promote_to("/volume1/homes/elderwesto/nishihost/nx_torrent_seed.sov.elf.new" as *u8, "/volume1/ai/torrent/nx_torrent_seed.elf" as *u8, "/volume1/ai/torrent/nx_torrent_seed.elf.prev" as *u8)
2499 // WORKER (nx_torrent_get.sov.elf) parity: it lives in /volume1/ai/torrent/ as a daemon SIBLING (d_self_dir
2500 // execs it there) but had NO API deploy path -- so a worker fix (e.g. the "IGNORING: seeders unchoke us,
2501 // have=0" data-timeout fix) could not ship without shell. Built by /api/build -> nishihost/<name>.sov.elf.new,
2502 // cross-dir promoted here (same volume1 => rename), .prev kept (never-brick). Guarded on .new existence, so a
2503 // daemon-only or seedeval-only deploy never touches the live worker. Running workers double-fork (reparent to
2504 // init) so they survive; NEW spawns use the new elf -> pause/resume a stuck torrent to force it onto the fix.
2505 let w: i64 = hc_promote_to("/volume1/homes/elderwesto/nishihost/nx_torrent_get.sov.elf.new" as *u8, "/volume1/ai/torrent/nx_torrent_get.sov.elf" as *u8, "/volume1/ai/torrent/nx_torrent_get.sov.elf.prev" as *u8)
2506 // nx_mp4_faststart: daemon sibling (self-dir) the /stream handler execve's to relocate moov to the front of a
2507 // non-faststart mp4 so a browser <video> can play it. Same cross-subvolume copy-promote as the worker.
2508 let mf: i64 = hc_promote_to("/volume1/homes/elderwesto/nishihost/nx_mp4_faststart.sov.elf.new" as *u8, "/volume1/ai/torrent/nx_mp4_faststart.sov.elf" as *u8, "/volume1/ai/torrent/nx_mp4_faststart.sov.elf.prev" as *u8)
2509 // GALLERY BRIDGE (2026-07-24): EXTRACTOR (download.part -> real .mp4 on complete) + fixed NAS-path INDEXER
2510 // (scans /volume1/ai/torrent -> gallery catalog). Worker-spawned siblings; absent-.new promotes = no-ops (:1759).
2511 let ex: i64 = hc_promote_to("/volume1/homes/elderwesto/nishihost/nx_torrent_extract.sov.elf.new" as *u8, "/volume1/ai/torrent/nx_torrent_extract.sov.elf" as *u8, "/volume1/ai/torrent/nx_torrent_extract.sov.elf.prev" as *u8)
2512 let gv: i64 = hc_promote_to("/volume1/homes/elderwesto/nishihost/nx_galx_vidindex.sov.elf.new" as *u8, "/volume1/ai/torrent/nx_galx_vidindex.sov.elf" as *u8, "/volume1/ai/torrent/nx_galx_vidindex.sov.elf.prev" as *u8)
2513 hc_puts(" promoted daemon=" as *u8); hc_putn(d); hc_puts(" seedeval=" as *u8); hc_putn(s); hc_puts(" SEEDER=" as *u8); hc_putn(sd); hc_puts(" worker=" as *u8); hc_putn(w); hc_puts(" mp4faststart=" as *u8); hc_putn(mf); hc_puts(" extract=" as *u8); hc_putn(ex); hc_puts(" vidindex=" as *u8); hc_putn(gv); hc_puts("\n" as *u8)
2514 // 2026-07-24: daemon auto-kill REMOVED here -- torrentdeploy now only PLACES binaries (incl. the new
2515 // gallery-bridge extractor + indexer siblings); restart the daemon EXPLICITLY via kicktorrent only when
2516 // the daemon binary itself changed, so placing sibling tools never forces a needless daemon restart.
2517 hc_puts(" (daemon not auto-restarted; run kicktorrent explicitly if the daemon binary changed)\n" as *u8)
2518 return 0
2519}
2520func cmd_torrentrollback() -> i64 {
2521 hc_puts("[hostctl] torrentrollback: restore torrent binaries .prev -> live + kicktorrent (reverse a bad torrentdeploy)\n" as *u8)
2522 let d: i64 = hc_promote_to("/volume1/ai/torrent/nx_torrent_daemon.sov.elf.prev" as *u8, "/volume1/ai/torrent/nx_torrent_daemon.sov.elf" as *u8, "/volume1/ai/torrent/nx_torrent_daemon.sov.elf.bad" as *u8)
2523 let s: i64 = hc_promote_to("/volume1/ai/torrent/nx_torrent_seedeval.elf.prev" as *u8, "/volume1/ai/torrent/nx_torrent_seedeval.elf" as *u8, "/volume1/ai/torrent/nx_torrent_seedeval.elf.bad" as *u8)
2524 // ★ROLLBACK MUST COVER EXACTLY WHAT DEPLOY PLACES. A deploy line without a matching rollback line is a
2525 // one-way door: the .prev is banked and unreachable, so a bad seeder could be shipped but not reversed.
2526 let sd: i64 = hc_promote_to("/volume1/ai/torrent/nx_torrent_seed.elf.prev" as *u8, "/volume1/ai/torrent/nx_torrent_seed.elf" as *u8, "/volume1/ai/torrent/nx_torrent_seed.elf.bad" as *u8)
2527 hc_puts(" restored daemon=" as *u8); hc_putn(d); hc_puts(" seedeval=" as *u8); hc_putn(s); hc_puts(" SEEDER=" as *u8); hc_putn(sd); hc_puts("\n" as *u8)
2528 if d == 1 { proc_kill_by_name("nx_torrent_daemon" as *u8, 9) }
2529 // Restart the seeder only if its binary actually changed, mirroring the daemon rule above.
2530 if sd == 1 { proc_kill_by_name("nx_torrent_seed.elf" as *u8, 9) }
2531 return 0
2532}
2533
2534// promote/rollback the Relationship OS daemon (:8027). Same-dir promote in nishihost cwd (hc_promote_to = keep
2535// live as .prev, mv .new -> live, chmod; guarded on .new existence -> deploying without a staged .new is a no-op).
2536func cmd_relatedeploy() -> i64 {
2537 hc_puts("[hostctl] relatedeploy: promote nx_relate_daemon.elf.new -> live (.prev kept) + restart :8027\n" as *u8)
2538 let d: i64 = hc_promote_to(HC_RELATE_NEW, HC_RELATE, HC_RELATE_PREV)
2539 hc_puts(" promoted=" as *u8); hc_putn(d); hc_puts("\n" as *u8)
2540 if d == 1 { let pk: i64 = proc_kill_by_name("nx_relate_daemon.elf" as *u8, 9); hc_puts(" killed relate procs=" as *u8); hc_putn(pk); hc_puts(" -> guard respawns the NEW :8027 daemon\n" as *u8) }
2541 return 0
2542}
2543func cmd_relaterollback() -> i64 {
2544 hc_puts("[hostctl] relaterollback: restore nx_relate_daemon.elf.prev -> live + restart (reverse a bad relatedeploy)\n" as *u8)
2545 let d: i64 = hc_promote_to(HC_RELATE_PREV, HC_RELATE, "/volume1/homes/elderwesto/nishihost/nx_relate_daemon.elf.bad" as *u8)
2546 hc_puts(" restored=" as *u8); hc_putn(d); hc_puts("\n" as *u8)
2547 if d == 1 { proc_kill_by_name("nx_relate_daemon.elf" as *u8, 9) }
2548 return 0
2549}
2550// promote/rollback the SOVEREIGN RU<->EN translate daemon (:8447, /translate). Same-dir promote in nishihost cwd
2551// (mirrors cmd_docportaldeploy). Staged binary is nx_translate_daemon.sov.elf.new (nx_ship/build-over-API output).
2552func cmd_xlatedeploy() -> i64 {
2553 hc_puts("[hostctl] xlatedeploy: promote nx_translate_daemon.sov.elf.new -> live (.prev kept) + restart :8447\n" as *u8)
2554 let d: i64 = hc_promote_to(HC_XLATE_NEW, HC_XLATE, HC_XLATE_PREV)
2555 hc_puts(" promoted=" as *u8); hc_putn(d); hc_puts("\n" as *u8)
2556 if d == 1 { let pk: i64 = proc_kill_by_name("nx_translate_daemon.elf" as *u8, HC_SIGKILL); hc_puts(" killed xlate procs=" as *u8); hc_putn(pk); hc_puts(" -> guard respawns the NEW :8447 daemon\n" as *u8) }
2557 return 0
2558}
2559func cmd_xlaterollback() -> i64 {
2560 hc_puts("[hostctl] xlaterollback: restore nx_translate_daemon.elf.prev -> live + restart (reverse a bad xlatedeploy)\n" as *u8)
2561 let d: i64 = hc_promote_to(HC_XLATE_PREV, HC_XLATE, "/volume1/homes/elderwesto/nishihost/nx_translate_daemon.elf.bad" as *u8)
2562 hc_puts(" restored=" as *u8); hc_putn(d); hc_puts("\n" as *u8)
2563 if d == 1 { proc_kill_by_name("nx_translate_daemon.elf" as *u8, HC_SIGKILL) }
2564 return 0
2565}
2566
2567// promote/rollback the ethical CLEAN-SERVE daemon (:8102). Same-dir promote in nishihost cwd (mirrors cmd_relatedeploy).
2568func cmd_cleanservedeploy() -> i64 {
2569 hc_puts("[hostctl] cleanservedeploy: promote nx_clean_serve_daemon.elf.new -> live (.prev kept) + restart :8102\n" as *u8)
2570 let d: i64 = hc_promote_to(HC_CLEANSERVE_NEW, HC_CLEANSERVE, HC_CLEANSERVE_PREV)
2571 hc_puts(" promoted=" as *u8); hc_putn(d); hc_puts("\n" as *u8)
2572 if d == 1 { let pk: i64 = proc_kill_by_name("nx_clean_serve_daemon.elf" as *u8, 9); hc_puts(" killed cleanserve procs=" as *u8); hc_putn(pk); hc_puts(" -> guard respawns the NEW :8102 daemon\n" as *u8) }
2573 return 0
2574}
2575// promote/rollback the DOCPORTAL admin daemon (:HC_MAGIC_18456, /search + /doc + /api). Same-dir promote in nishihost cwd
2576// (mirrors cmd_cleanservedeploy). The staged binary is <name>.SOV.elf.new (nx_ship/build-over-API output) -> the
2577// deploy sub consumes it directly, so /api/deploy target=docportal needs NO manual .sov rename. .prev = rollback.
2578func cmd_docportaldeploy() -> i64 {
2579 hc_puts("[hostctl] docportaldeploy: promote nx_docportal_admin_daemon.sov.elf.new -> live (.prev kept) + kick :18456\n" as *u8)
2580 let d: i64 = hc_promote_to(HC_DOCPORTAL_NEW, HC_DOCPORTAL, HC_DOCPORTAL_PREV)
2581 hc_puts(" promoted=" as *u8); hc_putn(d); hc_puts("\n" as *u8)
2582 if d == 1 { let pk: i64 = proc_kill_by_name("nx_docportal_admin_daemon.elf" as *u8, 9); hc_puts(" killed docportal procs=" as *u8); hc_putn(pk); hc_puts(" -> guard respawns the NEW :18456 daemon\n" as *u8) }
2583 return 0
2584}
2585func cmd_docportalrollback() -> i64 {
2586 hc_puts("[hostctl] docportalrollback: restore nx_docportal_admin_daemon.elf.prev -> live + kick (reverse a bad docportaldeploy)\n" as *u8)
2587 let d: i64 = hc_promote_to(HC_DOCPORTAL_PREV, HC_DOCPORTAL, "/volume1/homes/elderwesto/nishihost/nx_docportal_admin_daemon.elf.bad" as *u8)
2588 hc_puts(" restored=" as *u8); hc_putn(d); hc_puts("\n" as *u8)
2589 if d == 1 { proc_kill_by_name("nx_docportal_admin_daemon.elf" as *u8, 9) }
2590 return 0
2591}
2592func cmd_cleanserverollback() -> i64 {
2593 hc_puts("[hostctl] cleanserverollback: restore nx_clean_serve_daemon.elf.prev -> live + restart (reverse a bad cleanservedeploy)\n" as *u8)
2594 let d: i64 = hc_promote_to(HC_CLEANSERVE_PREV, HC_CLEANSERVE, "/volume1/homes/elderwesto/nishihost/nx_clean_serve_daemon.elf.bad" as *u8)
2595 hc_puts(" restored=" as *u8); hc_putn(d); hc_puts("\n" as *u8)
2596 if d == 1 { proc_kill_by_name("nx_clean_serve_daemon.elf" as *u8, 9) }
2597 return 0
2598}
2599
2600// never-brick ROLLBACK: restore the previous live sites.elf (saved by cmd_deploy as .prev) + respawn. Reverses a bad deploy.
2601func cmd_rollback() -> i64 {
2602 hc_puts("[hostctl] rollback: restore sites.elf.prev -> live + respawn (reverse a bad deploy)\n" as *u8)
2603 let rr: i64 = sys_renameat(HC_ELF_PREV, HC_ELF)
2604 nx_chmod(HC_ELF, 0x1ed)
2605 hc_put_rc(" restore rename rc=" as *u8, rr)
2606 let pk: i64 = proc_kill_by_name("sites.elf" as *u8, 9)
2607 hc_puts(" killed sites.elf procs=" as *u8); hc_putn(pk); hc_puts(" -> supervisor respawns the RESTORED binary\n" as *u8)
2608 return 0
2609}
2610
2611// CERT-ONLY deploy: backup the live cert+key as .bak, atomically install the staged .new, then kill
2612// sites.elf so the supervisor respawns the LIVE binary (which reloads the cert at startup). NO binary
2613// swap -- safe even with a broken staged sites.elf. never-brick: .bak enables cmd_certrollback.
2614func cmd_certswap() -> i64 {
2615 hc_puts("[hostctl] certswap: backup live cert -> .bak, install .new -> live, restart sites.elf (no binary swap)\n" as *u8)
2616 sys_renameat(HC_CERT_LIVE, HC_CERT_BAK)
2617 sys_renameat(HC_KEY_LIVE, HC_KEY_BAK)
2618 let r1: i64 = sys_renameat(HC_CERT_NEW, HC_CERT_LIVE)
2619 let r2: i64 = sys_renameat(HC_KEY_NEW, HC_KEY_LIVE)
2620 hc_put_rc(" install rc cert=" as *u8, r1)
2621 hc_put_rc(" install rc key=" as *u8, r2)
2622 let pk: i64 = proc_kill_by_name("sites.elf" as *u8, 9)
2623 hc_puts(" killed sites.elf procs=" as *u8); hc_putn(pk); hc_puts(" -> supervisor respawns the LIVE binary (reloads new cert, <=15s)\n" as *u8)
2624 return 0
2625}
2626
2627// never-brick cert ROLLBACK: restore the previous cert+key (.bak) + respawn. Reverses a bad certswap.
2628func cmd_certrollback() -> i64 {
2629 hc_puts("[hostctl] certrollback: restore cert/key .bak -> live + restart sites.elf\n" as *u8)
2630 sys_renameat(HC_CERT_BAK, HC_CERT_LIVE)
2631 sys_renameat(HC_KEY_BAK, HC_KEY_LIVE)
2632 let pk: i64 = proc_kill_by_name("sites.elf" as *u8, 9)
2633 hc_puts(" killed sites.elf procs=" as *u8); hc_putn(pk); hc_puts(" -> supervisor respawns (restored cert)\n" as *u8)
2634 return 0
2635}
2636
2637// spawn the live login daemon detached (mirrors hc_spawn_wiki_gw).
2638func hc_spawn_login() -> i64 {
2639 let pid: i64 = sys_fork()
2640 if pid==0 {
2641 nx_setsid()
2642 let dn: i64 = sys_openat_wr("/dev/null" as *u8, 0x1a4)
2643 if dn >= 0 { sys_dup3(dn,0,0); sys_dup3(dn,1,0); sys_dup3(dn,2,0) }
2644 let argv: *i64 = sys_mmap(32) as *i64
2645 argv[0]=HC_SH as i64; argv[1]=HC_DASHC as i64; argv[2]=HC_LOGIN_CMD as i64; argv[3]=0
2646 let envp: *i64 = sys_mmap(16) as *i64; envp[0]="PATH=/usr/bin:/bin" as *u8 as i64; envp[1]=0
2647 sys_execve_clean(HC_SH, argv, envp)
2648 sys_exit(127)
2649 }
2650 return pid
2651}
2652// PRE-FLIGHT: spawn the staged login .new on throwaway :9099 (NOT :9091); print its startup. OPAQUE-LOGIN-UP =
2653// safe to logindeploy; CTX-INIT-FAIL/BIND-FAIL = bad keys/args, do NOT deploy. Then kill the test (frees :9099).
2654func cmd_logintest() -> i64 {
2655 hc_puts("=== logintest: spawn nx_opaque_login.elf.new on :9099 (live :9091 untouched) ===\n" as *u8)
2656 let pid: i64 = sys_fork()
2657 if pid==0 {
2658 nx_setsid()
2659 let argv: *i64 = sys_mmap(32) as *i64
2660 argv[0]=HC_SH as i64; argv[1]=HC_DASHC as i64; argv[2]=HC_LOGIN_TEST_CMD as i64; argv[3]=0
2661 let envp: *i64 = sys_mmap(16) as *i64; envp[0]="PATH=/usr/bin:/bin" as *u8 as i64; envp[1]=0
2662 sys_execve_clean(HC_SH, argv, envp)
2663 sys_exit(127)
2664 }
2665 sys_sleep_ms(HC_MAGIC_1500)
2666 let lb: *u8 = sys_mmap(HC_MAGIC_8192)
2667 let n: i64 = hc_read_cmdline("/tmp/logintest.out" as *u8, lb, HC_MAGIC_8192)
2668 hc_puts("--- /tmp/logintest.out ---\n" as *u8)
2669 if n > 0 { sys_write(1, lb, n) } else { hc_puts("(empty -- did not start?)\n" as *u8) }
2670 let k: i64 = proc_kill_by_name("nx_opaque_login.elf.new" as *u8, 9)
2671 hc_puts("\n killed test procs=" as *u8); hc_putn(k); hc_puts(" (:9099 freed)\n" as *u8)
2672 return 0
2673}
2674
2675// runmtlsproxy: SHALLOW execve (REPLACE this fresh nx_hostctl image with the proxy) -- reached ONLY via
2676// hc_dfork_exec(HC_RUNMTLSPROXY), which already fork+setsid-detached. The SECOND execve from this NON-forked
2677// main-dispatch context dodges the deep-forked-child codegen edge -- FULLY SOVEREIGN, no /bin/sh (cf. cmd_runsite).
2678// stdout/stderr -> /tmp/mtlsproxy.out so mtlsproxytest can report the cert-load + bind result. main() already chdir'd.
2679func cmd_runmtlsproxy() -> i64 {
2680 let lf: i64 = sys_openat_wr("/tmp/mtlsproxy.out" as *u8, 0x1a4)
2681 if lf >= 0 { sys_dup3(lf,1,0); sys_dup3(lf,2,0) }
2682 let argv: *i64 = sys_mmap(32) as *i64
2683 argv[0]=HC_MTLS_PROXY_BIN as i64; argv[1]=HC_MP_PORT as i64; argv[2]=HC_MP_BACKEND as i64; argv[3]=0
2684 let envp: *i64 = sys_mmap(16) as *i64; envp[0]="PATH=/usr/bin:/bin" as *u8 as i64; envp[1]=0
2685 sys_execve_clean(HC_MTLS_PROXY_BIN, argv, envp)
2686 sys_exit(127)
2687 return 0
2688}
2689// mtlsproxytest: sovereign-launch the mTLS proxy on :9444, print its startup log (cert load + bind), and leave it
2690// RUNNING for a browser test. Touches NOTHING live -- new port, unsupervised, no DSM/:443 change.
2691func cmd_mtlsproxytest() -> i64 {
2692 hc_puts("=== mtlsproxytest: sovereign launch nx_aw_mtls_proxy.elf :9444 -> wiki_gw :18791 (no /bin/sh) ===\n" as *u8)
2693 hc_dfork_exec(HC_RUNMTLSPROXY)
2694 sys_sleep_ms(HC_MAGIC_1500)
2695 let lb: *u8 = sys_mmap(HC_MAGIC_8192)
2696 let n: i64 = hc_read_cmdline("/tmp/mtlsproxy.out" as *u8, lb, HC_MAGIC_8192)
2697 hc_puts("--- /tmp/mtlsproxy.out ---\n" as *u8)
2698 if n > 0 { sys_write(1, lb, n) } else { hc_puts("(empty -- did not start? cert path / bind :9444)\n" as *u8) }
2699 if proc_alive_by_name("nx_aw_mtls_proxy.elf" as *u8) == 1 { hc_puts(" nx_aw_mtls_proxy ALIVE on :9444 (sovereign, unsupervised test)\n" as *u8) } else { hc_puts(" nx_aw_mtls_proxy NOT alive -- see log above\n" as *u8) }
2700 return 0
2701}
2702
2703// SHALLOW execve targets (reached via hc_dfork_exec -> fresh main-dispatch image, dodges the codegen edge, no sh).
2704// NAS-resident Apertus/model mirror: shallow-execve the download organ (absolute /volume1 paths -> CWD-independent),
2705// log to /tmp/apertus_mirror.out. Reached ONLY via hc_dfork_exec(HC_RUNMIRROR) (fork+setsid-detached), so it survives
2706// the SSH channel teardown. Mirrors cmd_runmtlsproxy/cmd_runandelin exactly.
2707func cmd_runmirror() -> i64 {
2708 let lf: i64 = sys_openat_wr("/tmp/apertus_mirror.out" as *u8, 0x1a4)
2709 if lf >= 0 { sys_dup3(lf,1,0); sys_dup3(lf,2,0) }
2710 let argv: *i64 = sys_mmap(32) as *i64
2711 argv[0]=HC_MIRROR_BIN as i64; argv[1]=0
2712 let envp: *i64 = sys_mmap(16) as *i64; envp[0]="PATH=/usr/bin:/bin" as *u8 as i64; envp[1]=0
2713 sys_execve_clean(HC_MIRROR_BIN, argv, envp)
2714 sys_exit(127)
2715 return 0
2716}
2717// mirror: fire-and-forget launch the NAS-resident mirror (detached), then show the first log bytes as confirmation.
2718func cmd_mirror() -> i64 {
2719 hc_puts("=== mirror: sovereign-launch nx_apertus_mirror_nas.elf -> /volume1/ai/apertus (NAS-local, detached) ===\n" as *u8)
2720 hc_dfork_exec(HC_RUNMIRROR)
2721 sys_sleep_ms(HC_MAGIC_1500)
2722 let lb: *u8 = sys_mmap(HC_MAGIC_8192)
2723 let n: i64 = hc_read_cmdline("/tmp/apertus_mirror.out" as *u8, lb, HC_MAGIC_8192)
2724 hc_puts("--- /tmp/apertus_mirror.out (first bytes) ---\n" as *u8)
2725 if n>0 { sys_write(1, lb, n) } else { hc_puts("(empty -- starting)\n" as *u8) }
2726 return 0
2727}
2728// PARALLEL: shallow-execve the concurrent-fork downloader (proves what crashed WSL runs fine on the NAS).
2729func cmd_runmirrorpar() -> i64 {
2730 let lf: i64 = sys_openat_wr("/tmp/apertus_par.out" as *u8, 0x1a4)
2731 if lf >= 0 { sys_dup3(lf,1,0); sys_dup3(lf,2,0) }
2732 let argv: *i64 = sys_mmap(32) as *i64
2733 argv[0]=HC_MIRRORPAR_BIN as i64; argv[1]=0
2734 let envp: *i64 = sys_mmap(16) as *i64; envp[0]="PATH=/usr/bin:/bin" as *u8 as i64; envp[1]=0
2735 sys_execve_clean(HC_MIRRORPAR_BIN, argv, envp)
2736 sys_exit(127)
2737 return 0
2738}
2739func cmd_mirrorpar() -> i64 {
2740 hc_puts("=== mirrorpar: sovereign-launch nx_par_pull_nas.elf (PARALLEL concurrent, NAS-native, detached) ===\n" as *u8)
2741 hc_dfork_exec(HC_RUNMIRRORPAR)
2742 sys_sleep_ms(HC_MAGIC_2500)
2743 let lb: *u8 = sys_mmap(HC_MAGIC_8192)
2744 let n: i64 = hc_read_cmdline("/tmp/apertus_par.out" as *u8, lb, HC_MAGIC_8192)
2745 hc_puts("--- /tmp/apertus_par.out (first bytes) ---\n" as *u8)
2746 if n>0 { sys_write(1, lb, n) } else { hc_puts("(empty -- starting)\n" as *u8) }
2747 return 0
2748}
2749// stop the NAS mirror/parallel pulls -- FULL-cmdline match (hc_kill_by_cmdline), NOT the 15-char-truncated comm.
2750func cmd_mirrorstop() -> i64 {
2751 hc_puts("=== mirrorstop: kill NAS mirror + parallel pulls (full-cmdline match) ===\n" as *u8)
2752 let k1: i64 = hc_kill_by_cmdline("nx_apertus_mirror_nas.elf" as *u8)
2753 let k2: i64 = hc_kill_by_cmdline("nx_par_pull_nas.elf" as *u8)
2754 hc_puts(" killed mirror=" as *u8); hc_putn(k1); hc_puts(" par=" as *u8); hc_putn(k2); hc_puts("\n" as *u8)
2755 return 0
2756}
2757// rundistpub: SHALLOW execve of the publisher -- reached ONLY via hc_dfork_exec, dodging the deep-forked-child
2758// codegen edge (a DIRECT fork+execve here silently no-ops, exactly what the mirror sidesteps). stdout -> the log.
2759func cmd_rundistpub() -> i64 {
2760 let lf: i64 = sys_openat_wr("/tmp/distpub.out" as *u8, 0x1a4)
2761 if lf >= 0 { sys_dup3(lf,1,0); sys_dup3(lf,2,0) }
2762 let argv: *i64 = sys_mmap(32) as *i64; argv[0]=HC_DISTPUB_BIN as i64; argv[1]=0
2763 let envp: *i64 = sys_mmap(16) as *i64; envp[0]="PATH=/usr/bin:/bin" as *u8 as i64; envp[1]=0
2764 sys_execve_clean(HC_DISTPUB_BIN, argv, envp)
2765 sys_exit(127)
2766 return 0
2767}
2768// distpub: launch the publisher detached (survives SSH teardown), give it time to hash, then emit its output.
2769// Idempotent + additive, so re-running is always safe if the first emit is early.
2770func cmd_distpub() -> i64 {
2771 hc_puts("=== distpub: publish a real NAS file to the hub distribution index ===\n" as *u8)
2772 hc_dfork_exec(HC_RUNDISTPUB)
2773 sys_sleep_ms(HC_MAGIC_4000)
2774 let lb: *u8 = sys_mmap(HC_MAGIC_8192); let n: i64 = hc_read_cmdline("/tmp/distpub.out" as *u8, lb, HC_MAGIC_8192)
2775 hc_puts("--- /tmp/distpub.out ---\n" as *u8)
2776 if n>0 { sys_write(1, lb, n) } else { hc_puts("(empty -- still hashing? re-run distpub; it is idempotent)\n" as *u8) }
2777 return 0
2778}
2779// rundistserve: SHALLOW execve of the /dist download server (via hc_dfork_exec). argv = [bin, "serve", "18099"].
2780func cmd_rundistserve() -> i64 {
2781 let lf: i64 = sys_openat_wr("/tmp/distserve.out" as *u8, 0x1a4)
2782 if lf >= 0 { sys_dup3(lf,1,0); sys_dup3(lf,2,0) }
2783 let argv: *i64 = sys_mmap(64) as *i64; argv[0]=HC_DISTSERVE_BIN as i64; argv[1]=HC_A_SERVE as i64; argv[2]=HC_A_PORT as i64; argv[3]=0
2784 let envp: *i64 = sys_mmap(16) as *i64; envp[0]="PATH=/usr/bin:/bin" as *u8 as i64; envp[1]=0
2785 sys_execve_clean(HC_DISTSERVE_BIN, argv, envp)
2786 sys_exit(127)
2787 return 0
2788}
2789// rundistprobe: SHALLOW execve of the loopback probe. argv = [bin, "probe", "18099", "/dist/<cid>/<name>"].
2790func cmd_rundistprobe() -> i64 {
2791 let lf: i64 = sys_openat_wr("/tmp/distprobe.out" as *u8, 0x1a4)
2792 if lf >= 0 { sys_dup3(lf,1,0); sys_dup3(lf,2,0) }
2793 let argv: *i64 = sys_mmap(64) as *i64; argv[0]=HC_DISTSERVE_BIN as i64; argv[1]=HC_A_PROBE as i64; argv[2]=HC_A_PORT as i64; argv[3]=HC_DIST_PROBE_PATH as i64; argv[4]=0
2794 let envp: *i64 = sys_mmap(16) as *i64; envp[0]="PATH=/usr/bin:/bin" as *u8 as i64; envp[1]=0
2795 sys_execve_clean(HC_DISTSERVE_BIN, argv, envp)
2796 sys_exit(127)
2797 return 0
2798}
2799// distserve: launch the /dist download server detached, show its LIVE banner.
2800func cmd_distserve() -> i64 {
2801 hc_puts("=== distserve: start the /dist download server on 127.0.0.1:18099 ===\n" as *u8)
2802 hc_dfork_exec(HC_RUNDISTSERVE)
2803 sys_sleep_ms(HC_MAGIC_1200)
2804 let lb: *u8 = sys_mmap(HC_MAGIC_4096); let n: i64 = hc_read_cmdline("/tmp/distserve.out" as *u8, lb, HC_MAGIC_4096)
2805 if n>0 { sys_write(1, lb, n) } else { hc_puts("(no banner yet)\n" as *u8) }
2806 return 0
2807}
2808// distprobe: loopback GET a published cid -> proves the download transport returns the real bytes.
2809func cmd_distprobe() -> i64 {
2810 hc_puts("=== distprobe: loopback GET a published cid from :18099 ===\n" as *u8)
2811 hc_dfork_exec(HC_RUNDISTPROBE)
2812 sys_sleep_ms(HC_MAGIC_2000)
2813 let lb: *u8 = sys_mmap(HC_MAGIC_8192); let n: i64 = hc_read_cmdline("/tmp/distprobe.out" as *u8, lb, HC_MAGIC_8192)
2814 if n>0 { sys_write(1, lb, n) } else { hc_puts("(no probe output -- server not up?)\n" as *u8) }
2815 return 0
2816}
2817func cmd_runandelin() -> i64 {
2818 let lf: i64 = sys_openat_wr("/tmp/andelin.out" as *u8, 0x1a4)
2819 if lf >= 0 { sys_dup3(lf,1,0); sys_dup3(lf,2,0) }
2820 let argv: *i64 = sys_mmap(32) as *i64
2821 argv[0]=HC_ANDELIN_BIN as i64; argv[1]=0
2822 let envp: *i64 = sys_mmap(16) as *i64; envp[0]="PATH=/usr/bin:/bin" as *u8 as i64; envp[1]=0
2823 sys_execve_clean(HC_ANDELIN_BIN, argv, envp)
2824 sys_exit(127)
2825 return 0
2826}
2827func cmd_runsnir() -> i64 {
2828 let lf: i64 = sys_openat_wr("/tmp/snir.out" as *u8, 0x1a4)
2829 if lf >= 0 { sys_dup3(lf,1,0); sys_dup3(lf,2,0) }
2830 let argv: *i64 = sys_mmap(32) as *i64
2831 argv[0]=HC_SNIR_BIN as i64; argv[1]=HC_SNIR_PORT as i64; argv[2]=HC_SNIR_BACKEND as i64; argv[3]=0
2832 let envp: *i64 = sys_mmap(16) as *i64; envp[0]="PATH=/usr/bin:/bin" as *u8 as i64; envp[1]=0
2833 sys_execve_clean(HC_SNIR_BIN, argv, envp)
2834 sys_exit(127)
2835 return 0
2836}
2837// nftread: SOVEREIGN NETFILTER R0 grounding. Direct (non-forked main-dispatch) shallow execve of nx_nft_read ->
2838// READS the kernel nat-table info via getsockopt(IPT_SO_GET_INFO). Runs as root (this nx_hostctl was sudo'd).
2839// READ-ONLY: cannot disturb DSM. stdout (the table info, or the rc telling us legacy-vs-nft) flows back up the SSH channel.
2840func cmd_nftread() -> i64 {
2841 let argv: *i64 = sys_mmap(16) as *i64; argv[0]=HC_NFTREAD_BIN as i64; argv[1]=0
2842 let envp: *i64 = sys_mmap(16) as *i64; envp[0]="PATH=/usr/bin:/bin" as *u8 as i64; envp[1]=0
2843 sys_execve_clean(HC_NFTREAD_BIN, argv, envp)
2844 sys_exit(127)
2845 return 0
2846}
2847// nettap: the sovereign WIRESHARK-in-the-API (operator 2026-07-04 "build that capability into the apis").
2848// Shallow-execve of nx_netscope_capture (AF_PACKET raw socket -> nx_packet_dissect; root here = CAP_NET_RAW OK).
2849// READ-ONLY on the wire + HARD-BOUNDED (dport filter, 60s wall-clock, 200-row cap) -- observes, never disturbs.
2850// Optional argv[2] = dest port (default 443). Output (SYN src -> dst rows) flows back up the SSH channel.
2851func cmd_nettap(port: *u8) -> i64 {
2852 let argv: *i64 = sys_mmap(48) as *i64
2853 argv[0] = HC_NETTAP_BIN as i64
2854 if (port as i64) != 0 { argv[1] = port as i64 } else { argv[1] = "443" as *u8 as i64 }
2855 argv[2] = "60" as *u8 as i64
2856 argv[3] = "200" as *u8 as i64
2857 argv[4] = 0
2858 let envp: *i64 = sys_mmap(16) as *i64; envp[0]="PATH=/usr/bin:/bin" as *u8 as i64; envp[1]=0
2859 sys_execve_clean(HC_NETTAP_BIN, argv, envp)
2860 sys_exit(127)
2861 return 0
2862}
2863// platformtest: launch the andelinwest CLIENT daemon (:8453) + the SNI router (:8444) on INTERNAL ports, print
2864// each startup, leave both RUNNING for verification. Touches NOTHING live (no :443, no DSM).
2865func cmd_platformtest() -> i64 {
2866 hc_puts("=== platformtest: sovereign-launch andelinwest :8453 (LE ECDSA) + SNI router :8444 (no /bin/sh) ===\n" as *u8)
2867 let lb: *u8 = sys_mmap(HC_MAGIC_8192)
2868 hc_dfork_exec(HC_RUNANDELIN)
2869 sys_sleep_ms(HC_MAGIC_1200)
2870 let n1: i64 = hc_read_cmdline("/tmp/andelin.out" as *u8, lb, HC_MAGIC_8192)
2871 hc_puts("--- /tmp/andelin.out ---\n" as *u8); if n1>0 { sys_write(1, lb, n1) } else { hc_puts("(empty)\n" as *u8) }
2872 if proc_alive_by_name("nx_andelinwest_daemon.elf" as *u8) == 1 { hc_puts(" andelinwest ALIVE :8453\n" as *u8) } else { hc_puts(" andelinwest NOT alive\n" as *u8) }
2873 hc_dfork_exec(HC_RUNSNIR)
2874 sys_sleep_ms(HC_MAGIC_1200)
2875 let n2: i64 = hc_read_cmdline("/tmp/snir.out" as *u8, lb, HC_MAGIC_8192)
2876 hc_puts("--- /tmp/snir.out ---\n" as *u8); if n2>0 { sys_write(1, lb, n2) } else { hc_puts("(empty)\n" as *u8) }
2877 if proc_alive_by_name("nx_sni_router.elf" as *u8) == 1 { hc_puts(" sni_router ALIVE :8444\n" as *u8) } else { hc_puts(" sni_router NOT alive\n" as *u8) }
2878 return 0
2879}
2880// DEPLOY the new login daemon: save .prev, atomic-swap .new->live, kill+respawn :9091 (24h sessions). Existing
2881// tokens keep working (stateless); only /login is briefly down during respawn. Reversible: loginrollback.
2882func cmd_logindeploy() -> i64 {
2883 hc_puts("[hostctl] logindeploy: .prev save + atomic-swap nx_opaque_login.elf + restart :9091 (24h sessions)\n" as *u8)
2884 sys_renameat(HC_LOGIN, HC_LOGIN_PREV)
2885 let r: i64 = sys_renameat(HC_LOGIN_NEW, HC_LOGIN)
2886 nx_chmod(HC_LOGIN, 0x1ed)
2887 hc_put_rc(" swap rc=" as *u8, r)
2888 let pk: i64 = proc_kill_by_name("nx_opaque_login.elf" as *u8, 9)
2889 sys_sleep_ms(400)
2890 let np: i64 = hc_spawn_login()
2891 hc_puts(" killed old login procs=" as *u8); hc_putn(pk); hc_puts(" respawned pid=" as *u8); hc_putn(np); hc_puts(" :9091\n" as *u8)
2892 return 0
2893}
2894// ROLLBACK the login daemon: restore .prev -> live + restart :9091. Reverses a bad logindeploy.
2895func cmd_loginrollback() -> i64 {
2896 hc_puts("[hostctl] loginrollback: restore nx_opaque_login.elf.prev -> live + restart :9091\n" as *u8)
2897 let r: i64 = sys_renameat(HC_LOGIN_PREV, HC_LOGIN)
2898 nx_chmod(HC_LOGIN, 0x1ed)
2899 hc_put_rc(" restore rc=" as *u8, r)
2900 proc_kill_by_name("nx_opaque_login.elf" as *u8, 9)
2901 sys_sleep_ms(400)
2902 hc_spawn_login()
2903 hc_puts(" restored + restarted :9091\n" as *u8)
2904 return 0
2905}
2906
2907// HUB deploy prep: create the hub content dirs with pure syscalls (no shell mkdir) + chmod the gateway
2908// binary executable if it has already been recv'd. The supervisor's HC_HUB_GW guard then auto-launches it.
2909// Idempotent (sys_mkdir on an existing dir is harmless; nx_chmod on an absent file is harmless).
2910func cmd_hubdeploy() -> i64 {
2911 hc_puts("[hostctl] hubdeploy: mkdir /volume1/ai/hub{,/pages} + chmod nx_hub_gw.elf +x (sovereign sys_mkdir)\n" as *u8)
2912 sys_mkdir("/volume1/ai/hub" as *u8, 0x1ff) // 0777 so the elderwesto recv can write content here
2913 sys_mkdir("/volume1/ai/hub/pages" as *u8, 0x1ff)
2914 nx_chmod("/volume1/ai/hub/nx_hub_gw.elf" as *u8, 0x1ed) // 0755 if already landed (harmless if absent)
2915 let hk: i64 = proc_kill_by_name("nx_hub_gw.elf" as *u8, 9) // restart so a re-deployed binary takes effect (HC_HUB_GW guard respawns it)
2916 hc_puts(" hub dirs ready + killed nx_hub_gw procs=" as *u8); hc_putn(hk); hc_puts(" -> HC_HUB_GW guard respawns the new :18792 gateway\n" as *u8)
2917 return 0
2918}
2919
2920// GEN deploy prep: create /volume1/ai/gen (0777 so the elderwesto recv can write the elfs + the daemons can
2921// write the gallery store/blob/sidecar) + chmod the gen daemons +x. The HC_GEN_* guards then auto-launch them.
2922// Idempotent (sys_mkdir on an existing dir is harmless; nx_chmod on an absent file is harmless).
2923func cmd_gendeploy() -> i64 {
2924 hc_puts("[hostctl] gendeploy: mkdir /volume1/ai/gen + chmod gen daemons +x -> guards launch :18794/:18795\n" as *u8)
2925 sys_mkdir("/volume1/ai/gen" as *u8, 0x1ff)
2926 nx_chmod("/volume1/ai/gen/nx_gen_gateway_daemon.elf" as *u8, 0x1ed)
2927 nx_chmod("/volume1/ai/gen/nx_gen_orchestrator_daemon.elf" as *u8, 0x1ed)
2928 let g1: i64 = proc_kill_by_name("nx_gen_gateway_daemon.elf" as *u8, 9)
2929 let g2: i64 = proc_kill_by_name("nx_gen_orchestrator_daemon.elf" as *u8, 9)
2930 hc_puts(" gen dir ready + killed gw=" as *u8); hc_putn(g1); hc_puts(" orch=" as *u8); hc_putn(g2); hc_puts(" -> HC_GEN guards respawn :18794/:18795\n" as *u8)
2931 return 0
2932}
2933// genprobe: one-shot LIVE proof. Run nx_gen_live_probe.elf (sh -c exec, like cmd_logintest) -> it registers a temp
2934// owner in the live store, enrolls it OWNER, logs in, and drives the deployed gateway @127.0.0.1:18794 asserting
2935// owner->200 + no-cred->401, then demotes the temp owner. Read its output back and print it (relayed to operator).
2936func cmd_genprobe() -> i64 {
2937 // The live probe now drives a REAL generation (~15s GPU) which outlasts the nx_aw_hostctl relay's read window.
2938 // So: PRINT the previous run's COMPLETE result (from the file), then FIRE a new run DETACHED (stdout->file +
2939 // setsid so it survives the SSH close and finishes the generation). Re-run genprobe in ~25s to read this run.
2940 hc_puts("[hostctl] genprobe: last result below, then firing a fresh live-probe run (detached)\n" as *u8)
2941 let lb: *u8 = sys_mmap(HC_MAGIC_131072)
2942 let n: i64 = hc_read_cmdline("/volume1/ai/gen/genprobe.out" as *u8, lb, HC_MAGIC_131072)
2943 hc_puts("--- last nx_gen_live_probe result ---\n" as *u8)
2944 if n > 0 { sys_write(1, lb, n) } else { hc_puts("(no previous result yet)\n" as *u8) }
2945 nx_chmod("/volume1/ai/gen/nx_gen_live_probe.elf" as *u8, 0x1ed)
2946 let pid: i64 = sys_fork()
2947 if pid==0 {
2948 nx_setsid()
2949 let argv: *i64 = sys_mmap(32) as *i64
2950 argv[0]=HC_SH as i64; argv[1]=HC_DASHC as i64; argv[2]=HC_GENPROBE_CMD as i64; argv[3]=0
2951 let envp: *i64 = sys_mmap(16) as *i64; envp[0]="PATH=/usr/bin:/bin" as *u8 as i64; envp[1]=0
2952 sys_execve_clean(HC_SH, argv, envp)
2953 sys_exit(127)
2954 }
2955 hc_puts("--- fired a new run (detached); re-run `genprobe` in ~25s to read its result ---\n" as *u8)
2956 return 0
2957}
2958// First-swap TAKEOVER: stop the old .sh supervisor + old daemon (sovereign /proc kill), atomic-publish
2959// the staged artifacts, then BECOME the sovereign supervisor (spawn + monitor + respawn the new daemon).
2960// Run detached (setsid) on the NAS -- retires nishi_supervisor.sh.
2961func cmd_takeover() -> i64 {
2962 hc_puts("[hostctl] TAKEOVER: stop old .sh supervisor + daemon, atomic-publish, become sovereign supervisor\n" as *u8)
2963 proc_kill_by_name("nishi_supervisor" as *u8, 9)
2964 proc_kill_by_name("sites.elf" as *u8, 9)
2965 sys_sleep_ms(600)
2966 sys_mkdir(HC_DOCROOT, 0x1ed)
2967 sys_renameat(HC_INDEX_NEW, HC_INDEX)
2968 sys_renameat(HC_CONF_NEW, HC_CONF)
2969 // seq1097 twin: never install a 0-byte staged elf (a failed upload can stage one; it sat for days
2970 // in 2026-07). Absent .new already fails the rename harmlessly; this closes the 0-byte case.
2971 let tkstb: *u8 = sys_mmap(160)
2972 var tkok: i64 = 0
2973 if sys_fstatat(HC_ELF_NEW, tkstb) == 0 {
2974 let tkszp: *i64 = ((tkstb as i64) + 48) as *i64
2975 if tkszp[0] > 0 { tkok = 1 }
2976 }
2977 if tkok == 1 {
2978 sys_renameat(HC_ELF_NEW, HC_ELF)
2979 nx_chmod(HC_ELF, 0x1ed)
2980 } else {
2981 hc_puts("[hostctl] takeover: no real staged sites.elf.new (absent or 0B) -- keeping current live\n" as *u8)
2982 }
2983 hc_puts("[hostctl] artifacts published; daemonizing sovereign supervisor (setsid + detach stdio)\n" as *u8)
2984 let pid: i64 = sys_fork()
2985 if pid == 0 {
2986 nx_setsid() // new session -> survives SSH/parent close
2987 let dn: i64 = sys_openat_wr("/dev/null" as *u8, 0x1a4)
2988 if dn >= 0 { sys_dup3(dn, 1, 0); sys_dup3(dn, 2, 0) } // detach stdout/stderr from the SSH channel
2989 cmd_supervise() // become the detached sovereign supervisor
2990 sys_exit(0)
2991 return 0
2992 }
2993 hc_puts("[hostctl] supervisor daemonized; takeover returns (ssh_exec gets channel EOF)\n" as *u8)
2994 return 0
2995}
2996
2997// LOCAL Engineer gate: prove atomic-rename publish + pidfile + kill + /proc-scan-kill on /tmp (no NAS).
2998func cmd_selftest() -> i64 {
2999 var pass: i64=0; var total: i64=0
3000 // 1. atomic publish
3001 let fda: i64 = sys_openat_wr("/tmp/hc_live" as *u8, 0x1a4); sys_write(fda, "OLD" as *u8, 3); sys_close(fda)
3002 let fdb: i64 = sys_openat_wr("/tmp/hc_live.new" as *u8, 0x1a4); sys_write(fdb, "NEWCONTENT" as *u8, 10); sys_close(fdb)
3003 sys_renameat("/tmp/hc_live.new" as *u8, "/tmp/hc_live" as *u8)
3004 let box: *i64 = sys_mmap(16) as *i64; box[0]=0
3005 let got: *u8 = sys_read_file("/tmp/hc_live" as *u8, box)
3006 total=total+1
3007 if (got as i64)!=0 { if box[0]==10 { hc_puts(" PASS atomic-publish: live flipped to NEWCONTENT\n" as *u8); pass=pass+1 } else { hc_puts(" FAIL publish len\n" as *u8) } } else { hc_puts(" FAIL publish read\n" as *u8) }
3008 // 2. pidfile round-trip + kill
3009 let kid: i64 = sys_fork()
3010 if kid==0 { sys_sleep_ms(HC_MAGIC_4000); sys_exit(0); return 0 }
3011 hc_write_pid("/tmp/hc_test.pid" as *u8, kid)
3012 let rp: i64 = hc_read_pid("/tmp/hc_test.pid" as *u8)
3013 sys_sleep_ms(300)
3014 let kr: i64 = nx_kill(rp, 9)
3015 let st: *i64 = sys_mmap(16) as *i64; st[0]=0
3016 let reaped: i64 = sys_wait4(kid, st, 0)
3017 total=total+1
3018 if rp==kid { if kr==0 { if (st[0]&0x7f)==9 { hc_puts(" PASS pidfile+kill: round-tripped pid, SIGKILLed daemon\n" as *u8); pass=pass+1 } else { hc_puts(" FAIL not signal-killed\n" as *u8) } } else { hc_puts(" FAIL kill rc\n" as *u8) } } else { hc_puts(" FAIL pidfile round-trip\n" as *u8) }
3019 // 3. proc_kill_by_name -- fork a child that execs /bin/sleep with a unique marker, /proc-kill it
3020 let kid2: i64 = sys_fork()
3021 if kid2 == 0 {
3022 let av: *i64 = sys_mmap(32) as *i64
3023 av[0] = "/bin/sleep" as *u8 as i64; av[1] = "31337" as *u8 as i64; av[2] = 0
3024 let ev: *i64 = sys_mmap(16) as *i64; ev[0] = 0
3025 sys_execve_clean("/bin/sleep" as *u8, av, ev)
3026 sys_exit(0)
3027 return 0
3028 }
3029 sys_sleep_ms(400)
3030 let nk: i64 = proc_kill_by_name("31337" as *u8, 9)
3031 let st2: *i64 = sys_mmap(16) as *i64; st2[0]=0
3032 let reaped2: i64 = sys_wait4(kid2, st2, 0)
3033 total=total+1
3034 if nk >= 1 { if reaped2 == kid2 { if (st2[0]&0x7f)==9 { hc_puts(" PASS proc_kill_by_name: found by /proc cmdline + SIGKILLed\n" as *u8); pass=pass+1 } else { hc_puts(" FAIL proc_kill: not signal-killed\n" as *u8) } } else { hc_puts(" FAIL proc_kill: wait4\n" as *u8) } } else { hc_puts(" FAIL proc_kill: found 0\n" as *u8) }
3035
3036 hc_puts("---- hostctl selftest passed " as *u8); let nb: *u8=sys_mmap(4); nb[0]=(48+pass) as u8; sys_write(1,nb,1); hc_puts(" / " as *u8); let tb: *u8=sys_mmap(4); tb[0]=(48+total) as u8; sys_write(1,tb,1); hc_puts(" ----\n" as *u8)
3037 if pass==total { return 0 }
3038 return 1
3039}
3040
3041// SOVEREIGN supervisor self-update (operator: "no sh"). nx_aw_push streams the new binary to nishihost as
3042// nx_hostctl.new, then execs THIS (run as nx_hostctl.new selfswap). We: atomic-rename .new over the live
3043// supervisor path; kill ONLY the old supervisor (matched by its "supervise" cmdline -- this "selfswap"
3044// process and sites.elf/redirect/vroom do NOT contain that token, so they're untouched); then re-exec the
3045// LIVE (now-new) binary as a detached `supervise`. The new supervisor ADOPTS every running daemon (proc_alive,
3046// no double-spawn) and adds the library reader -> the live site is never interrupted, only the supervisor
3047// process is swapped. Re-exec (not a bare cmd_supervise call) gives it the canonical "nx_hostctl supervise"
3048// cmdline so the NEXT selfswap can find it.
3049func cmd_selfswap() -> i64 {
3050 hc_puts("[hostctl] selfswap: atomic-install new supervisor + restart supervisor only (sites.elf untouched)\n" as *u8)
3051 // *** FAIL-SAFE GUARD (seq992, 2026-07-25) -- RESOLVE THE STAGED BINARY BEFORE TOUCHING THE LIVE ONE.
3052 // This function used to rename the live supervisor to .prev and only THEN rename the staged binary
3053 // over it, with NO existence check. If nothing was staged under HC_SELF_NEW, the live supervisor was
3054 // moved away, NOTHING was installed, the running supervisor was SIGKILLed, and the re-exec targeted a
3055 // path that no longer existed => no supervisor, unable to respawn itself. That is the EXACT outage
3056 // hc_promote_to was rewritten to avoid ("it moved the live binary to .prev and installed NOTHING"),
3057 // and hc_promote_to got the hc_exists guard while this path did not.
3058 // It was reachable by the DOCUMENTED sequence: /api/build stages <t>.sov.elf.new, but the deploy row
3059 // names nx_hostctl.new, and no API-reachable rename bridges them (seq983) -- so build-then-deploy ran
3060 // selfswap with HC_SELF_NEW absent. Accepting the .sov.elf.new name here closes the naming trap too.
3061 var srcnew: *u8 = HC_SELF_NEW
3062 if hc_exists(HC_SELF_NEW) == 0 {
3063 if hc_exists(HC_SELF_NEW_SOV) == 1 {
3064 srcnew = HC_SELF_NEW_SOV
3065 hc_puts(" staged binary found under the /api/build name (nx_hostctl.sov.elf.new)\n" as *u8)
3066 } else {
3067 hc_puts("[hostctl] selfswap: REFUSED -- no staged supervisor at nx_hostctl.new or nx_hostctl.sov.elf.new; live binary UNTOUCHED\n" as *u8)
3068 return 1
3069 }
3070 }
3071 sys_renameat(HC_SELF, HC_SELF_PREV) // never-brick (#26): save the OLD supervisor binary for superrollback (selfswap had NO rollback)
3072 let rr: i64 = sys_renameat(srcnew, HC_SELF)
3073 nx_chmod(HC_SELF, 0x1ed)
3074 hc_put_rc(" install rename rc=" as *u8, rr)
3075 let k: i64 = proc_kill_by_two("nx_hostctl" as *u8, "supervise" as *u8, 9)
3076 hc_puts(" killed old supervisor procs=" as *u8); let kb: *u8=sys_mmap(4); kb[0]=(48+(k%10)) as u8; sys_write(1,kb,1); hc_puts(" (matched nx_hostctl+supervise only -- s6-supervise untouched)\n" as *u8)
3077 sys_sleep_ms(400)
3078 hc_sup_clear() // clear the lease so the re-exec'd new supervisor claims (the killed old one's heartbeat is stale)
3079 // ONE launcher (2026-09-02): this used to hand-roll the fork with stdout AND stderr on /dev/null, so every `[guard]`
3080 // verdict of a selfswap'd supervisor -- including each kill+respawn of nx_daemon_supervisor -- was discarded, while
3081 // superrollback's hc_daemonize_supervise logged the same lines to supervisor.log. Measured that day: 13 fleet-supervisor
3082 // LIVE banners with not one guard line behind them. hc_dfork_exec keeps stdin on /dev/null (the SSH-channel lesson) and
3083 // routes stdout/stderr to supervisor.log; selfswap and superrollback now share it, so the two cannot disagree.
3084 hc_daemonize_supervise()
3085 hc_puts(" new supervisor daemonized (re-exec'd live binary as `supervise`, stdout/stderr -> supervisor.log)\n" as *u8)
3086 return 0
3087}
3088
3089// superrollback: restore the PREVIOUS supervisor binary (saved by selfswap as .prev) + reconcile to it. The
3090// never-brick (#26) rollback path selfswap lacked -- if a freshly selfswap'd supervisor misbehaves, this puts the
3091// proven binary back and relaunches it (kill duplicates, clear the lease, daemonize the one). The recovery net.
3092func cmd_superrollback() -> i64 {
3093 hc_puts("[hostctl] superrollback: restore nx_hostctl.prev -> live supervisor binary, then reconcile to it\n" as *u8)
3094 let rr: i64 = sys_renameat(HC_SELF_PREV, HC_SELF)
3095 nx_chmod(HC_SELF, 0x1ed)
3096 hc_puts(" restore rename rc=" as *u8); hc_putn(rr); hc_puts("\n" as *u8)
3097 let k: i64 = proc_kill_by_two("nx_hostctl" as *u8, "supervise" as *u8, 9)
3098 hc_puts(" killed supervisors=" as *u8); hc_putn(k); hc_puts("\n" as *u8)
3099 sys_sleep_ms(800)
3100 hc_sup_clear()
3101 hc_daemonize_supervise()
3102 hc_puts(" restored (prev) supervisor daemonized\n" as *u8)
3103 return 0
3104}
3105
3106// supervisetest: READ-ONLY mechanical proof of the single-supervisor guarantee (#26: prove, don't assert). Reads
3107// the live lease + reports its age and what a 2nd `supervise` launch WOULD do -- WITHOUT starting a competing
3108// loop. fresh(<90s) => a duplicate launch defers (guaranteed one supervisor); stale => the heartbeat stopped.
3109func cmd_supervisetest() -> i64 {
3110 hc_puts("[hostctl] supervisetest: READ-ONLY single-supervisor lease check (no competing loop started)\n" as *u8)
3111 let e: i64 = hc_read_pid(HC_SUP_LOCK)
3112 let now: i64 = sys_now_realtime_sec()
3113 hc_puts(" lease_epoch=" as *u8); hc_putn(e); hc_puts(" now=" as *u8); hc_putn(now); hc_puts(" age_s=" as *u8); hc_putn(now - e); hc_puts("\n" as *u8)
3114 let fresh: i64 = hc_sup_fresh()
3115 hc_puts(" hc_sup_fresh=" as *u8); hc_putn(fresh)
3116 if fresh == 1 { hc_puts(" -> a 2nd `supervise` launch WOULD DEFER = single-supervisor GUARANTEED (mechanically proven)\n" as *u8) }
3117 if fresh == 0 { hc_puts(" -> lease NOT fresh (no live heartbeat) -> a launch would CLAIM (no live supervisor to defer to)\n" as *u8) }
3118 return 0
3119}
3120
3121// DIAGNOSTIC: spawn the reader exactly as the supervisor does (fork + sh -c exec, direct child), then BLOCK in
3122// wait4 on it and report lifetime + sig/code. Run standalone (nx_hostctl spawntest) -> isolates the spawn from
3123// the poll loop. If it never returns, the reader stays up when nx_hostctl spawns it (so the loop/probe is the
3124// real culprit); if it returns, we finally see WHY the reader dies (signal vs exit code, and how long it lived).
3125func cmd_spawntest() -> i64 {
3126 hc_puts("[spawntest] fork+exec reader (direct child), blocking wait4 for its fate\n" as *u8)
3127 let t0: i64 = sys_now_realtime_sec()
3128 let pid: i64 = hc_spawn_reader()
3129 hc_puts(" spawned pid=" as *u8); hc_putn(pid); hc_puts("\n" as *u8)
3130 let st: *i64 = sys_mmap(16) as *i64; st[0]=0
3131 let reaped: i64 = sys_wait4(pid, st, 0)
3132 let t1: i64 = sys_now_realtime_sec()
3133 hc_puts(" REAPED=" as *u8); hc_putn(reaped); hc_puts(" lived_s=" as *u8); hc_putn(t1-t0)
3134 hc_puts(" sig=" as *u8); hc_putn(st[0]&0x7f); hc_puts(" code=" as *u8); hc_putn((st[0]>>8)&0xff); hc_puts("\n" as *u8)
3135 return 0
3136}
3137
3138// hc_dfork_exec: the SOVEREIGN daemonizer -- pure .nx, NO OS setsid/sh. SINGLE fork -> the CHILD does nx_setsid
3139// (the setsid SYSCALL -> SESSION LEADER, no controlling terminal) -> execve's a fresh `nx_hostctl <arg>` image,
3140// which runs forever and reparents to init when this (parent) process exits. The parent does NOT wait4 (the
3141// child never returns). This is EXACTLY the structure of `setsid nx_hostctl supervise &` (live PID 16331, which
3142// SURVIVES) and the durable `setsid ./sites.elf` -- both SESSION LEADERS. The earlier DOUBLE fork made the
3143// daemon a non-leader grandchild, which cmd_supervise did NOT survive (the trivial sleeper did) -- session-
3144// leadership is the property that matters. stdio -> supervisor.log + /dev/null. arg = "supervise"|"sleeper".
3145func hc_dfork_exec(arg: *u8) -> i64 {
3146 let pid: i64 = sys_fork()
3147 if pid == 0 {
3148 nx_setsid()
3149 let lf: i64 = sys_openat_append("/volume1/homes/elderwesto/nishihost/supervisor.log" as *u8, 420)
3150 let dn: i64 = sys_openat_wr("/dev/null" as *u8, 0x1a4)
3151 if dn >= 0 { sys_dup3(dn, 0, 0) }
3152 if lf >= 0 { sys_dup3(lf, 1, 0); sys_dup3(lf, 2, 0) }
3153 let argv: *i64 = sys_mmap(32) as *i64
3154 argv[0]=HC_SELF as i64; argv[1]=arg as i64; argv[2]=0
3155 let envp: *i64 = sys_mmap(16) as *i64; envp[0]="PATH=/usr/bin:/bin" as *u8 as i64; envp[1]=0
3156 sys_execve_clean(HC_SELF, argv, envp) // child (session leader) becomes nx_hostctl <arg>, runs forever
3157 sys_exit(127)
3158 return 0
3159 }
3160 return 0 // parent returns immediately; child reparents to init on exit
3161}
3162
3163func hc_daemonize_supervise() -> i64 { return hc_dfork_exec(HC_SUPERVISE) }
3164
3165// A sovereign idle daemon (NO OS /bin/sleep) -- the daemontest payload only: loops sleeping forever so I can
3166// daemonize it and confirm it survived the channel teardown without restarting the real supervisor.
3167func cmd_sleeper() -> i64 {
3168 var run: i64 = 1
3169 while run == 1 { sys_sleep_ms(HC_MAGIC_3600000) }
3170 return 0
3171}
3172
3173// SAFE proof that the SOVEREIGN hc_dfork_exec survives the teardown, WITHOUT restarting the real supervisor:
3174// daemonize `nx_hostctl sleeper` (pure .nx, no OS tools), then check it is still running after the channel closed.
3175func cmd_daemontest() -> i64 {
3176 hc_puts("[daemontest] SOVEREIGN hc_dfork_exec -> nx_hostctl sleeper (no OS tools); check it survives\n" as *u8)
3177 hc_dfork_exec(HC_SLEEPER)
3178 return 0
3179}
3180
3181// S-CLASS OPS RECONCILE (operator: "fix this bullshit rooted owned stuff -- s-class exceed at ops/mgmt").
3182// THE ROOT-CAUSE of the recurring pain: a SPLIT ownership model -- the boot rc.d launches nx_hostctl as ROOT
3183// (so sites.elf/vroom/translate/redirect are root), while ad-hoc SSH-launched supervisors + the reader ran as
3184// elderwesto. Neither could manage the other's daemons (EPERM), deploys couldn't restart root daemons, and
3185// duplicate supervisors competed. FIX = ONE supervisor, run as root (consistent with the boot context),
3186// owning EVERYTHING. Run via `sudo nx_hostctl reconcile` (nx_aw_sudo): kill every supervisor/keeper (matched
3187// nx_hostctl+supervise, NOT this "reconcile" proc), the reader, and sites.elf (so the freshly-deployed binary
3188// loads); then fork+setsid+detach and BECOME the one root supervisor (cmd_supervise forks the keeper -> reader
3189// and adopts/respawns the rest). Direct cmd_supervise() call (NOT execve) -- the keeper-proven survival path.
3190func cmd_reconcile() -> i64 {
3191 hc_puts("[hostctl] reconcile: ONE sovereign session-leader supervisor; ADOPT running sites.elf (zero website downtime)\n" as *u8)
3192 let k1: i64 = proc_kill_by_two("nx_hostctl" as *u8, "supervise" as *u8, 9)
3193 let k2: i64 = proc_kill_by_name("nx_media_server_auth.elf" as *u8, 9)
3194 let k3: i64 = proc_kill_by_name("nx_health_eval.elf" as *u8, 9) // cycle the M&E loop so the fresh supervisor respawns the latest ELF (no long-lived orphan on an update)
3195 let k4: i64 = proc_kill_by_name("nx_signaling_v2" as *u8, 9) // cycle the signaling relay onto the latest ELF (clients auto-reconnect lanes ~1.2s + re-hello presence)
3196 hc_puts(" killed supervisors+keepers=" as *u8); hc_putn(k1); hc_puts(" readers=" as *u8); hc_putn(k2); hc_puts(" health=" as *u8); hc_putn(k3); hc_puts(" sig2=" as *u8); hc_putn(k4); hc_puts(" (sites.elf KEPT -> adopted)\n" as *u8)
3197 sys_sleep_ms(800)
3198 hc_sup_clear() // clear the lease so the fresh supervisor claims (the killed old one's heartbeat is stale-by-fiat)
3199 hc_daemonize_supervise()
3200 hc_puts(" ONE sovereign supervisor daemonized (single-fork session leader) -> keeper(reader) + adopts sites.elf\n" as *u8)
3201 return 0
3202}
3203
3204// kickreader: SURGICAL one-shot wedge-clear. Kill ONLY the library reader (:8791) by name; the long-running
3205// supervisor's blocking-wait keeper (cmd_reader_keep) detects the death and respawns a FRESH reader. Does NOT
3206// touch the supervisor/keeper/sites.elf/gallery/wiki -> minimal blast radius (the reader blips ~1s, website
3207// untouched). This is the surgical primitive a wedge needs: a wedge = alive-but-slow, which the keeper can't
3208// see (it only respawns on DEATH). Never-brick #26: the kill is reversible BY the keeper (proven UP at runtime).
3209// The one-shot's own cmdline is "nx_hostctl kickreader" (never contains the reader needle) -> no self-match.
3210func cmd_kickreader() -> i64 {
3211 hc_puts("[hostctl] kickreader: SIGKILL the library reader (:8791) -> the keeper respawns a fresh one\n" as *u8)
3212 let k: i64 = proc_kill_by_name("nx_media_server_auth.elf" as *u8, 9)
3213 hc_puts(" killed reader procs=" as *u8); hc_putn(k); hc_puts(" (keeper blocking-wait4 respawns a FRESH reader)\n" as *u8)
3214 if k == 0 { hc_puts(" NOTE: no reader matched -- nothing to kick (reader not running here?)\n" as *u8) }
3215 return 0
3216}
3217
3218// kicktorrent: SURGICAL one-shot for the media/torrent daemon (:8097). Kill ONLY the daemon by name; the
3219// supervise-loop guard (hc_guard_torrent, proc_alive "nx_torrent_daemon") detects the death and respawns it
3220// via the hub profile (nx_media_env hub) -> the NEW binary. The one-shot's cmdline is "nx_hostctl kicktorrent"
3221// (never contains "nx_torrent_daemon"; "nx_torrent_gw" is a different name) -> no self/gateway match. Use after
3222// staging a new daemon binary. Never-brick #26: reversible BY the guard (proven UP at runtime).
3223func cmd_kicktorrent() -> i64 {
3224 hc_puts("[hostctl] kicktorrent: SIGKILL the media/torrent daemon (:8097) -> the guard respawns the NEW binary\n" as *u8)
3225 let k: i64 = proc_kill_by_name("nx_torrent_daemon" as *u8, 9)
3226 hc_puts(" killed daemon procs=" as *u8); hc_putn(k); hc_puts(" (supervisor guard respawns via the hub profile)\n" as *u8)
3227 if k == 0 { hc_puts(" NOTE: no daemon matched -- nothing to kick (not running here?)\n" as *u8) }
3228 return 0
3229}
3230
3231// kickseed: SURGICAL one-shot for the BitTorrent SEEDER (:6881). Kill it by name; hc_guard_seed respawns the
3232// NEW binary on the next poll. The one-shot cmdline "nx_hostctl kickseed" never contains "nx_torrent_seed.elf"
3233// -> no self-match. Use after staging a new seeder binary or editing seed_index.conf (fresh registry read).
3234func cmd_kickseed() -> i64 {
3235 hc_puts("[hostctl] kickseed: SIGKILL the BitTorrent seeder (:6881) -> hc_guard_seed respawns the NEW binary\n" as *u8)
3236 let k: i64 = proc_kill_by_name("nx_torrent_seed.elf" as *u8, 9)
3237 hc_puts(" killed seeder procs=" as *u8); hc_putn(k); hc_puts(" (supervisor guard respawns from seed_index.conf)\n" as *u8)
3238 if k == 0 { hc_puts(" NOTE: no seeder matched -- guard will start it on the next poll (fail-safe)\n" as *u8) }
3239 return 0
3240}
3241// portmap: auto-open :6881 on the router via NAT-PMP (nx_natpmp) -> WAN-reachable seeder + more peers. Fail-safe.
3242// routerctl: sovereign router dashboard (nx_router_ctl dash over our own SSH -> GL.iNet uci: model/wan-ip/forwards/clients).
3243const HC_ROUTERCTL_CMD: *u8 = "cd /volume1/ai/torrent && chmod +x ./nx_router_ctl.elf 2>/dev/null; : > /tmp/routerctl.out; ./nx_router_ctl.elf dash >> /tmp/routerctl.out 2>&1" as *u8
3244func cmd_routerctl() -> i64 {
3245 let pid: i64 = sys_fork()
3246 if pid == 0 {
3247 let argv: *i64 = sys_mmap(32) as *i64; argv[0]=HC_SH as i64; argv[1]=HC_DASHC as i64; argv[2]=HC_ROUTERCTL_CMD as i64; argv[3]=0
3248 let envp: *i64 = sys_mmap(16) as *i64; envp[0]="PATH=/usr/bin:/bin" as *u8 as i64; envp[1]=0
3249 sys_execve_clean(HC_SH, argv, envp); sys_exit(127)
3250 }
3251 let st: *i64 = sys_mmap(16) as *i64; sys_wait4(pid, st, 0)
3252 hc_puts("=== routerctl: GL.iNet dashboard (sovereign SSH+uci) ===\n" as *u8)
3253 let lb: *u8 = sys_mmap(HC_MAGIC_16384); let n: i64 = hc_read_cmdline("/tmp/routerctl.out" as *u8, lb, HC_MAGIC_16384)
3254 if n > 0 { sys_write(1, lb, n) } else { hc_puts("(no output)\n" as *u8) }
3255 return 0
3256}
3257const HC_PORTMAP_CMD: *u8 = "cd /volume1/ai/torrent && chmod +x ./nx_natpmp.elf ./nx_upnp_igd.elf 2>/dev/null; : > /tmp/portmap.out; echo === NAT-PMP === >> /tmp/portmap.out; ./nx_natpmp.elf 6881 >> /tmp/portmap.out 2>&1; echo === UPnP-IGD === >> /tmp/portmap.out; ./nx_upnp_igd.elf 6881 >> /tmp/portmap.out 2>&1" as *u8
3258func cmd_portmap() -> i64 {
3259 // The SSDP->desc->SOAP flow can exceed the control-plane relay timeout, so run it DETACHED and show the
3260 // PREVIOUS run's result. Each call: print /tmp/portmap.out (last result) + launch a fresh background run.
3261 hc_puts("=== portmap: last NAT-PMP + UPnP result (/tmp/portmap.out) ===\n" as *u8)
3262 let lb: *u8 = sys_mmap(HC_MAGIC_16384); let n: i64 = hc_read_cmdline("/tmp/portmap.out" as *u8, lb, HC_MAGIC_16384)
3263 if n > 0 { sys_write(1, lb, n) } else { hc_puts("(no prior result yet -- fresh run launching now)\n" as *u8) }
3264 let pid: i64 = sys_fork() // detached (double-fork) so it survives the relay close
3265 if pid == 0 {
3266 let pid2: i64 = sys_fork()
3267 if pid2 == 0 {
3268 let argv: *i64 = sys_mmap(32) as *i64; argv[0]=HC_SH as i64; argv[1]=HC_DASHC as i64; argv[2]=HC_PORTMAP_CMD as i64; argv[3]=0
3269 let envp: *i64 = sys_mmap(16) as *i64; envp[0]="PATH=/usr/bin:/bin" as *u8 as i64; envp[1]=0
3270 sys_execve_clean(HC_SH, argv, envp); sys_exit(127)
3271 }
3272 sys_exit(0)
3273 }
3274 let st: *i64 = sys_mmap(16) as *i64; sys_wait4(pid, st, 0)
3275 hc_puts(" (fresh portmap launched in background; call `portmap` again in ~15s to read the result)\n" as *u8)
3276 return 0
3277}
3278// trackerrefresh: GROW the tracker list from live public sources (nx_tracker_refresh over sovereign TLS,
3279// merged+deduped into trackers.txt). "grow, not static" -- schedule daily; workers read trackers.txt on spawn.
3280const HC_TRACKERREFRESH_CMD: *u8 = "cd /volume1/ai/torrent && mkdir -p data && chmod +x ./nx_tracker_refresh.elf 2>/dev/null; : > /tmp/trackerrefresh.out; ./nx_tracker_refresh.elf /volume1/ai/torrent/trackers.txt >> /tmp/trackerrefresh.out 2>&1" as *u8
3281func cmd_trackerrefresh() -> i64 {
3282 let pid: i64 = sys_fork()
3283 if pid == 0 {
3284 let argv: *i64 = sys_mmap(32) as *i64; argv[0]=HC_SH as i64; argv[1]=HC_DASHC as i64; argv[2]=HC_TRACKERREFRESH_CMD as i64; argv[3]=0
3285 let envp: *i64 = sys_mmap(16) as *i64; envp[0]="PATH=/usr/bin:/bin" as *u8 as i64; envp[1]=0
3286 sys_execve_clean(HC_SH, argv, envp); sys_exit(127)
3287 }
3288 let st: *i64 = sys_mmap(16) as *i64; sys_wait4(pid, st, 0)
3289 hc_puts("=== trackerrefresh: grow trackers.txt from live public lists ===\n" as *u8)
3290 let lb: *u8 = sys_mmap(HC_MAGIC_65536); let n: i64 = hc_read_cmdline("/tmp/trackerrefresh.out" as *u8, lb, HC_MAGIC_65536)
3291 if n > 0 { sys_write(1, lb, n) } else { hc_puts("(no output)\n" as *u8) }
3292 return 0
3293}
3294// reseed: register EVERY completed download (both areas) into the seed registry so we SHARE our whole
3295// library back (nx_torrent_reseed computes info_hash=SHA1(meta), plen, total=.part-size; idempotent).
3296const HC_RESEED_CMD: *u8 = "cd /volume1/ai/torrent && chmod +x ./nx_torrent_reseed.elf 2>/dev/null; : > /tmp/reseed.out; ./nx_torrent_reseed.elf /volume1/ai/torrent/media /volume1/ai/torrent/seed_index.conf >> /tmp/reseed.out 2>&1; ./nx_torrent_reseed.elf /volume1/ai/torrent/gallery /volume1/ai/torrent/seed_index.conf >> /tmp/reseed.out 2>&1" as *u8
3297func cmd_reseed() -> i64 {
3298 let pid: i64 = sys_fork()
3299 if pid == 0 {
3300 let argv: *i64 = sys_mmap(32) as *i64; argv[0]=HC_SH as i64; argv[1]=HC_DASHC as i64; argv[2]=HC_RESEED_CMD as i64; argv[3]=0
3301 let envp: *i64 = sys_mmap(16) as *i64; envp[0]="PATH=/usr/bin:/bin" as *u8 as i64; envp[1]=0
3302 sys_execve_clean(HC_SH, argv, envp); sys_exit(127)
3303 }
3304 let st: *i64 = sys_mmap(16) as *i64; sys_wait4(pid, st, 0)
3305 hc_puts("=== reseed: register all completed downloads for sharing ===\n" as *u8)
3306 let lb: *u8 = sys_mmap(HC_MAGIC_65536); let n: i64 = hc_read_cmdline("/tmp/reseed.out" as *u8, lb, HC_MAGIC_65536)
3307 if n > 0 { sys_write(1, lb, n) } else { hc_puts("(no output)\n" as *u8) }
3308 return 0
3309}
3310// kickworkers: SIGKILL every torrent download WORKER (nx_torrent_get.sov.elf). kicktorrent only kills the
3311// daemon; workers are double-forked (reparented to init) and survive -> a stale/buggy worker keeps flailing
3312// on a download. After a worker-binary fix, kill the old workers then kicktorrent so autoresume respawns the
3313// NEW binary. NEVER-BRICK: SIGKILL only; the donefile persists progress so the resumed worker continues.
3314func cmd_kickworkers() -> i64 {
3315 hc_puts("[hostctl] kickworkers: SIGKILL all torrent download workers (nx_torrent_get.sov.elf)\n" as *u8)
3316 let k: i64 = proc_kill_by_name("nx_torrent_get.sov.elf" as *u8, 9)
3317 hc_puts(" killed worker procs=" as *u8); hc_putn(k); hc_puts(" (kicktorrent next -> autoresume respawns the NEW worker binary; donefile keeps progress)\n" as *u8)
3318 return 0
3319}
3320// torstat: run nx_torrent_seedeval on every active download -> per-torrent SCARCE/IGNORING/COMPLETE verdict.
3321// Reads root-owned media/<btih>/download.* (hostctl is root), so it works where SFTP-as-elderwesto can't.
3322func cmd_torstat() -> i64 {
3323 let pid: i64 = sys_fork()
3324 if pid == 0 {
3325 let argv: *i64 = sys_mmap(32) as *i64; argv[0]=HC_SH as i64; argv[1]=HC_DASHC as i64; argv[2]=HC_TORSTAT_CMD as i64; argv[3]=0
3326 let envp: *i64 = sys_mmap(16) as *i64; envp[0]="PATH=/usr/bin:/bin" as *u8 as i64; envp[1]=0
3327 sys_execve_clean(HC_SH, argv, envp); sys_exit(127)
3328 }
3329 let st: *i64 = sys_mmap(16) as *i64; sys_wait4(pid, st, 0)
3330 hc_puts("=== torstat: seedeval per active download (media/<btih>) ===\n" as *u8)
3331 let lb: *u8 = sys_mmap(HC_MAGIC_262144); let n: i64 = hc_read_cmdline("/tmp/torstat.out" as *u8, lb, HC_MAGIC_262144)
3332 if n > 0 { sys_write(1, lb, n) } else { hc_puts("(no output -- media/torrents.idx empty or missing?)\n" as *u8) }
3333 return 0
3334}
3335// kickseedann: SIGKILL the DHT announcer -> hc_guard_seedann respawns it (fresh registry read + immediate announce sweep).
3336func cmd_kickseedann() -> i64 {
3337 hc_puts("[hostctl] kickseedann: SIGKILL the DHT announcer -> hc_guard_seedann respawns it (immediate re-announce)\n" as *u8)
3338 let k: i64 = proc_kill_by_name("nx_seed_announce_all.elf" as *u8, 9)
3339 hc_puts(" killed announcer procs=" as *u8); hc_putn(k); hc_puts(" (guard respawns; a sweep announces every registered info_hash)\n" as *u8)
3340 if k == 0 { hc_puts(" NOTE: no announcer matched -- guard will start it on the next poll (fail-safe)\n" as *u8) }
3341 return 0
3342}
3343
3344// kicktorrentgw: SURGICAL one-shot for the torrent OPAQUE gateway (:18793). Kill it by name; the guard
3345// (hc_guard_torrent_gw) respawns the NEW binary. The one-shot cmdline "nx_hostctl kicktorrentgw" never
3346// contains "nx_torrent_gw.elf" -> no self-match. Use after staging a new gateway binary (.new + mv).
3347func cmd_kicktorrentgw() -> i64 {
3348 hc_puts("[hostctl] kicktorrentgw: SIGKILL the torrent OPAQUE gateway (:18793) -> the guard respawns the NEW binary\n" as *u8)
3349 let k: i64 = proc_kill_by_name("nx_torrent_gw.elf" as *u8, 9)
3350 hc_puts(" killed gateway procs=" as *u8); hc_putn(k); hc_puts(" (supervisor guard respawns nx_torrent_gw)\n" as *u8)
3351 if k == 0 { hc_puts(" NOTE: no gateway matched -- nothing to kick (not running here?)\n" as *u8) }
3352 return 0
3353}
3354
3355// One-shot gallery gateway deploy: atomic-publish the staged .new gateway binary, then kill the running gateway
3356// -> the supervisor (the bash loop, OR this nx_hostctl once it supervises the gallery) respawns the NEW binary.
3357// killdurindex: SIGKILL the duration-index batch (+ its ts_dur child). A boot-spawn (now removed) forked the
3358// durindex WITHOUT close-on-exec, so it inherited the gallery's :18090 LISTENING socket and kept it open after
3359// the gallery was killed -> every new gallery serve hit EADDRINUSE on bind -> exit -> crash-loop. Killing it
3360// frees :18090; the supervisor guard then brings nx_gallery_serve back. Surgical one-shot (mirrors kicktorrent).
3361func cmd_killdurindex() -> i64 {
3362 hc_puts("[hostctl] killdurindex: SIGKILL nx_galx_durindex + nx_ts_dur (frees the :18090 socket fd they inherited)\n" as *u8)
3363 let k1: i64 = proc_kill_by_name("nx_galx_durindex.elf" as *u8, 9)
3364 let k2: i64 = proc_kill_by_name("nx_ts_dur.elf" as *u8, 9)
3365 hc_puts(" killed durindex=" as *u8); hc_putn(k1); hc_puts(" ts_dur=" as *u8); hc_putn(k2); hc_puts(" -> :18090 freed; the guard respawns the gallery serve\n" as *u8)
3366 return 0
3367}
3368// Launch the duration-index batch the PROPER ecosystem way: a detached control-plane one-shot, NOT a serve
3369// boot-spawn. setsid (survives the ssh session) + CLOSE every inherited fd 3..255 (the ssh channel and any
3370// sockets -> the long-lived batch holds NOTHING; this is exactly the hygiene the boot-spawn lacked) + flock
3371// single-instance (in the durindex itself) + resumable. cwd /volume1/ai/galx; chmod the elfs +x (recv lands 0644).
3372func hc_spawn_durindex_job() -> i64 {
3373 let pid: i64 = sys_fork()
3374 if pid == 0 {
3375 nx_setsid()
3376 sys_chdir("/volume1/ai/galx" as *u8)
3377 var f: i64 = 3; while f < 256 { sys_close(f); f = f + 1 }
3378 let dn: i64 = sys_openat_wr("/dev/null" as *u8, 0x1a4)
3379 let lg: i64 = sys_openat_append("galx_durindex.log" as *u8, 0x1a4)
3380 if dn >= 0 { sys_dup3(dn, 0, 0); sys_close(dn) }
3381 if lg >= 0 { sys_dup3(lg, 1, 0); sys_dup3(lg, 2, 0); sys_close(lg) }
3382 nx_chmod("./nx_galx_durindex.elf" as *u8, 0x1ed)
3383 nx_chmod("./nx_ts_dur.elf" as *u8, 0x1ed)
3384 let av: *i64 = sys_mmap(64) as *i64
3385 av[0] = "./nx_galx_durindex.elf" as *u8 as i64
3386 av[1] = "knowledge/status/galx_vid_paths.tsv" as *u8 as i64
3387 av[2] = "./nx_ts_dur.elf" as *u8 as i64
3388 av[3] = "knowledge/status/galx_dur.raw" as *u8 as i64
3389 av[4] = 0
3390 let envp: *i64 = sys_mmap(16) as *i64; envp[0] = "PATH=/usr/bin:/bin" as *u8 as i64; envp[1] = 0
3391 sys_execve_clean("./nx_galx_durindex.elf" as *u8, av, envp)
3392 sys_exit(127)
3393 }
3394 return pid
3395}
3396// galxpipeline: detached analysis-on-INGEST pass (operator 2026-07-14, API/MCP-native media derivation).
3397// Runs nx_media_ingest_pipeline (thumbnail prewarm + NXVI duration/keyframe/markers) from /volume1/ai/galx so
3398// newly-found media gets its thumbnail + duration without a manual step. Mirrors hc_spawn_durindex_job exactly.
3399func hc_spawn_pipeline_job() -> i64 {
3400 let pid: i64 = sys_fork()
3401 if pid == 0 {
3402 nx_setsid()
3403 sys_chdir("/volume1/ai/galx" as *u8)
3404 var f: i64 = 3; while f < 256 { sys_close(f); f = f + 1 }
3405 let dn: i64 = sys_openat_wr("/dev/null" as *u8, 0x1a4)
3406 let lg: i64 = sys_openat_append("galx_pipeline.log" as *u8, 0x1a4)
3407 if dn >= 0 { sys_dup3(dn, 0, 0); sys_close(dn) }
3408 if lg >= 0 { sys_dup3(lg, 1, 0); sys_dup3(lg, 2, 0); sys_close(lg) }
3409 nx_chmod("./nx_media_ingest_pipeline.elf" as *u8, 0x1ed)
3410 let av: *i64 = sys_mmap(64) as *i64
3411 av[0] = "./nx_media_ingest_pipeline.elf" as *u8 as i64
3412 av[1] = 0
3413 let envp: *i64 = sys_mmap(16) as *i64; envp[0] = "PATH=/usr/bin:/bin" as *u8 as i64; envp[1] = 0
3414 sys_execve_clean("./nx_media_ingest_pipeline.elf" as *u8, av, envp)
3415 sys_exit(127)
3416 }
3417 return pid
3418}
3419// galxidxrun (MV-2; the SEEK half of "seek is broken"): detached NXVI keyframe-index BACKFILL over every
3420// recording lacking one. The index was built LAZILY on first play, so ~98% of recordings had no scrub on
3421// first open -- measured 8,821 of 76,018 indexed while the durindex batch precedent sits at 62,100. Mirrors
3422// hc_spawn_pipeline_job exactly (setsid + fds closed + own log). NEWEST-FIRST by the organ's own design;
3423// sequential fork+wait = bounded IO; idempotent (NXVI v2 skipped) = re-run CONTINUES, never restarts.
3424// DECLARED LIMIT: nx_ts_index parses H.264 only -- HEVC recordings stay unindexed until the MV-4 arc.
3425func hc_spawn_idxbackfill_job() -> i64 {
3426 let pid: i64 = sys_fork()
3427 if pid == 0 {
3428 nx_setsid()
3429 sys_chdir("/volume1/ai/galx" as *u8)
3430 var f: i64 = 3; while f < 256 { sys_close(f); f = f + 1 }
3431 let dn: i64 = sys_openat_wr("/dev/null" as *u8, 0x1a4)
3432 let lg: i64 = sys_openat_append("galx_idxbackfill.log" as *u8, 0x1a4)
3433 if dn >= 0 { sys_dup3(dn, 0, 0); sys_close(dn) }
3434 if lg >= 0 { sys_dup3(lg, 1, 0); sys_dup3(lg, 2, 0); sys_close(lg) }
3435 nx_chmod("./nx_galx_idx_backfill.elf" as *u8, 0x1ed)
3436 nx_chmod("./nx_ts_index.elf" as *u8, 0x1ed)
3437 let av: *i64 = sys_mmap(64) as *i64
3438 av[0] = "./nx_galx_idx_backfill.elf" as *u8 as i64
3439 av[1] = 0
3440 let envp: *i64 = sys_mmap(16) as *i64; envp[0] = "PATH=/usr/bin:/bin" as *u8 as i64; envp[1] = 0
3441 sys_execve_clean("./nx_galx_idx_backfill.elf" as *u8, av, envp)
3442 sys_exit(127)
3443 }
3444 return pid
3445}
3446// galxidxkick (seq1065): recover a WEDGED backfill. SIGKILL on a D-state process does NOT land until its
3447// I/O completes (measured on the mvault walker, seq955), so the kick VERIFIES death before doing anything
3448// else -- a blind kill+respawn would put TWO writers on the same galxidx_<id>.idx files. Decision tree:
3449// still alive after kill -> WEDGED-UNKILLABLE: report + do nothing (retry later; nothing else is safe)
3450// dead, pipeline alive -> the pipeline's wait4 just returned; IT resumes iteration (no respawn here,
3451// avoids the dual-writer race between standalone + pipeline-forked backfill)
3452// dead, pipeline dead too -> respawn the standalone backfill via hc_spawn_idxbackfill_job
3453func cmd_galxidxkick() -> i64 {
3454 hc_puts("[hostctl] galxidxkick: kill the (possibly wedged) NXVI backfill, verify death, resume safely\n" as *u8)
3455 let k: i64 = proc_kill_by_name("nx_galx_idx_backfill.elf" as *u8, 9)
3456 hc_puts(" SIGKILL sent to procs=" as *u8); hc_putn(k); hc_puts("\n" as *u8)
3457 sys_sleep_ms(800)
3458 if proc_alive_by_name("nx_galx_idx_backfill.elf" as *u8) == 1 {
3459 hc_puts(" VERDICT=WEDGED-UNKILLABLE: still alive after SIGKILL (D-state; the signal lands when its I/O completes). NOT respawning -- retry galxidxkick later.\n" as *u8)
3460 return 1
3461 }
3462 if proc_alive_by_name("nx_media_ingest_pipeline.elf" as *u8) == 1 {
3463 hc_puts(" VERDICT=KILLED; pipeline is alive and its wait4 just returned -> pipeline resumes iteration itself (no standalone respawn, avoids dual writers)\n" as *u8)
3464 return 0
3465 }
3466 hc_spawn_idxbackfill_job()
3467 hc_puts(" VERDICT=KILLED+RESPAWNED standalone (pipeline not running) -> galx_idxbackfill.log\n" as *u8)
3468 return 0
3469}
3470// galxpipelinekick (seq1065): recover a wedged ANALYSIS PIPELINE (thumbs + NXVI). Kills the pipeline AND its
3471// forked backfill child (killing only the parent would orphan a wedged child that keeps the guard matching),
3472// verifies BOTH deaths, then respawns the pipeline fresh. Same D-state honesty as galxidxkick.
3473func cmd_galxpipelinekick() -> i64 {
3474 hc_puts("[hostctl] galxpipelinekick: kill pipeline + backfill child, verify death, respawn pipeline\n" as *u8)
3475 let kp: i64 = proc_kill_by_name("nx_media_ingest_pipeline.elf" as *u8, 9)
3476 let kb: i64 = proc_kill_by_name("nx_galx_idx_backfill.elf" as *u8, 9)
3477 hc_puts(" SIGKILL sent: pipeline=" as *u8); hc_putn(kp); hc_puts(" backfill=" as *u8); hc_putn(kb); hc_puts("\n" as *u8)
3478 sys_sleep_ms(800)
3479 var still: i64 = 0
3480 if proc_alive_by_name("nx_media_ingest_pipeline.elf" as *u8) == 1 { still = 1 }
3481 if proc_alive_by_name("nx_galx_idx_backfill.elf" as *u8) == 1 { still = 1 }
3482 if still == 1 {
3483 hc_puts(" VERDICT=WEDGED-UNKILLABLE: a member is still alive after SIGKILL (D-state). NOT respawning -- retry later.\n" as *u8)
3484 return 1
3485 }
3486 hc_spawn_pipeline_job()
3487 hc_puts(" VERDICT=KILLED+RESPAWNED pipeline (thumb prewarm + NXVI resume from scratch pass; idempotent per item) -> galx_pipeline.log\n" as *u8)
3488 return 0
3489}
3490func cmd_galxidxrun() -> i64 {
3491 hc_puts("[hostctl] galxidxrun: detached NXVI keyframe-seek backfill (newest-first, idempotent, resumable) -> /volume1/ai/galx/galx_idxbackfill.log\n" as *u8)
3492 if proc_alive_by_name("nx_galx_idx_backfill.elf" as *u8) == 1 { hc_puts(" already running -> no-op (idempotent)\n" as *u8); return 0 }
3493 hc_spawn_idxbackfill_job()
3494 hc_puts(" spawned detached\n" as *u8)
3495 return 0
3496}
3497func cmd_galxpipeline() -> i64 {
3498 hc_puts("[hostctl] galxpipeline: detached analysis-on-ingest pass (thumbnail prewarm + NXVI duration/markers) from /volume1/ai/galx -- idempotent, resumable\n" as *u8)
3499 if proc_alive_by_name("nx_media_ingest_pipeline.elf" as *u8) == 1 { hc_puts(" already running -> no-op (idempotent)\n" as *u8); return 0 }
3500 hc_spawn_pipeline_job()
3501 hc_puts(" spawned -> progress in /volume1/ai/galx/galx_pipeline.log; re-run to resume\n" as *u8)
3502 return 0
3503}
3504// SEARCH PIPELINE ON THE NAS (2026-07-23, operator: "i want the NAS doing these things not the laptop where
3505// we dev"). Detached one-shot run of a search-index pipeline organ against the LIVE web shard at
3506// nishihost/knowledge/store/dp-web-pub-. Mirrors hc_spawn_pipeline_job EXACTLY (the proven setsid pattern;
3507// the deep-fork codegen edge only bites re-forking daemons like sites.elf, not one-shot organs). The organs
3508// are mmap-open (measured pagerank ~4.2GB RSS) so they fit the NAS. Safe-by-construction: pagerank APPENDS
3509// pr: segments (rule-13), compact VERIFIES byte-identical before its atomic manifest swap + keeps superseded
3510// files. a2=0 for a 2-arg organ (compact), else the 3rd argv. Log -> knowledge/status/searchpipe.log.
3511// Address-space ceiling for detached search-pipeline jobs. 16 GiB = ~4x the largest MEASURED legitimate
3512// footprint (pagerank ~4.2GB) and well under the 36GB box, so a normal job never notices and a runaway dies
3513// long before the host is endangered. DATA, not taste: raise it here if a real job ever needs more, and
3514// prefer moving it to config if a second consumer appears.
3515// ⚠RAISED TO 48GiB AND THEN REVERTED, SAME SESSION 2026-08-06 -- BANKED BECAUSE THE RETRACTION IS
3516// THE LESSON. I raised it believing this cap silently killed every searchpipe job at startup: two
3517// `sub=searchcompact` spawns appeared to write NOTHING to searchpipe.log. That absence was
3518// MANUFACTURED BY MY OWN INSTRUMENT -- nx_shelltool had truncated the scan and reported 11 header
3519// matches; the same grep at `per_file_coverage=complete` returned 198, showing compaction running
3520// continuously the whole time (segments 4 -> 10 -> 200 -> 600 -> 896). ***A TRUNCATED SCAN REPORTS
3521// AN ABSENCE, AND AN ABSENCE IS INDISTINGUISHABLE FROM A THING THAT NEVER RAN*** -- so I built a
3522// root cause on top of a measurement artifact and weakened a real OOM protection to fix a defect
3523// that did not exist. 16GiB stands: it is ~4x the largest MEASURED legitimate footprint and it was
3524// added after three organs drove this host to the OOM edge in one session. The REAL defect is that
3525// compaction is LOSING A RACE with the crawler, not that it is dead -- fold budget, not this cap.
3526const HC_JOB_AS_CAP: i64 = 17179869184
3527func hc_spawn_searchpipe_job(organ: *u8, a1: *u8, a2: *u8) -> i64 {
3528 let pid: i64 = sys_fork()
3529 if pid == 0 {
3530 nx_setsid()
3531 sys_chdir("/volume1/homes/elderwesto/nishihost" as *u8)
3532 var f: i64 = 3; while f < 256 { sys_close(f); f = f + 1 }
3533 let dn: i64 = sys_openat_wr("/dev/null" as *u8, 0x1a4)
3534 let lg: i64 = sys_openat_append("knowledge/status/searchpipe.log" as *u8, 0x1a4)
3535 if dn >= 0 { sys_dup3(dn, 0, 0); sys_close(dn) }
3536 if lg >= 0 { sys_dup3(lg, 1, 0); sys_dup3(lg, 2, 0); sys_close(lg) }
3537 nx_chmod(organ, 0x1ed)
3538 let av: *i64 = sys_mmap(64) as *i64
3539 av[0] = organ as i64
3540 av[1] = a1 as i64
3541 av[2] = a2 as i64
3542 av[3] = 0
3543 let envp: *i64 = sys_mmap(16) as *i64; envp[0] = "PATH=/usr/bin:/bin" as *u8 as i64; envp[1] = 0
3544 // MEMORY ENVELOPE (2026-07-30). THREE organs drove this host to the OOM edge in ONE session --
3545 // nx_ssdf ~28GB, nx_mvault ~7.3GB, nx_web_shard_compact ~21GB and still climbing at +88MB/12s with
3546 // 536MB free -- and every time the COLLATERAL was the control plane: mgmt and the tools daemon
3547 // stopped answering, /api/build refused itself, and once sshd could not even complete a handshake.
3548 // The comment above sized these jobs by hope ("~4.2GB RSS so they fit the NAS"); hope is not a limit.
3549 // Cap the CHILD's address space before exec so a runaway JOB dies instead of the HOST.
3550 // ADOPTION, NOT INVENTION: nx_prlimit + RLIMIT_AS already existed in nx_syscalls, and
3551 // nx_supervised_dispatch already proves this exact fork -> cap-self -> exec shape in its gate. It was
3552 // simply never wired at the spawner where production jobs actually run -- this session's recurring
3553 // meta-defect. Applied at the CHOKEPOINT so every searchpipe job inherits it, not per leaf organ.
3554 // Set on SELF (pid 0) after fork, before execve: the limit survives exec and a non-root process
3555 // cannot raise a lowered hard limit back, so the exec'd image cannot opt out.
3556 // LOUD-BY-CONSTRUCTION (2026-08-06). fd 1 is the searchpipe log by now, so this line lands in
3557 // the log BEFORE the address-space cap and the exec. It converts the two silent failure modes
3558 // into readable ones: this marker with NO organ output after it == the child died at startup
3559 // (RLIMIT_AS refusal or a failed exec); no marker at all == the fork/redirect never happened.
3560 // Written because compaction and pagerank were BOTH dead for a week and the only evidence was
3561 // an absence -- and an absence is exactly what a job that was never scheduled also looks like.
3562 hc_puts("[searchpipe] exec " as *u8); hc_puts(organ)
3563 hc_puts(" (if NO organ output follows this line, the child died at STARTUP -- raise HC_JOB_AS_CAP or check the elf, do not assume the job simply had nothing to do)\n" as *u8)
3564 let rlim: *i64 = sys_mmap(16) as *i64
3565 rlim[0] = HC_JOB_AS_CAP
3566 rlim[1] = HC_JOB_AS_CAP
3567 nx_prlimit(0, RLIMIT_AS, rlim as *u8, 0 as *u8)
3568 sys_execve_clean(organ, av, envp)
3569 hc_puts("[searchpipe] EXEC FAILED (127) -- elf missing or not executable: " as *u8); hc_puts(organ); hc_puts("\n" as *u8)
3570 sys_exit(127)
3571 }
3572 return pid
3573}
3574func cmd_searchpagerank() -> i64 {
3575 hc_puts("[hostctl] searchpagerank: detached PageRank build on the NAS live web shard -> pr: priors (mmap-open, ~4.2GB)\n" as *u8)
3576 if proc_alive_by_name("nx_pagerank_build.elf" as *u8) == 1 { hc_puts(" already running -> no-op (idempotent)\n" as *u8); return 0 }
3577 if proc_alive_by_name("nx_web_shard_compact.elf" as *u8) == 1 { hc_puts(" a compaction is running -> defer (no-op)\n" as *u8); return 0 }
3578 hc_spawn_searchpipe_job("./_offc/nx_pagerank_build.elf" as *u8, "web" as *u8, "60" as *u8)
3579 hc_puts(" spawned -> progress in knowledge/status/searchpipe.log\n" as *u8)
3580 return 0
3581}
3582func cmd_searchcompact() -> i64 {
3583 hc_puts("[hostctl] searchcompact: detached web-shard compaction on the NAS -> fold segments (verifies before swap)\n" as *u8)
3584 if proc_alive_by_name("nx_web_shard_compact.elf" as *u8) == 1 { hc_puts(" already running -> no-op (idempotent)\n" as *u8); return 0 }
3585 if proc_alive_by_name("nx_pagerank_build.elf" as *u8) == 1 { hc_puts(" a pagerank build is running -> defer (no-op)\n" as *u8); return 0 }
3586 hc_spawn_searchpipe_job("./_offc/nx_web_shard_compact.elf" as *u8, "web" as *u8, 0 as *u8)
3587 hc_puts(" spawned -> progress in knowledge/status/searchpipe.log\n" as *u8)
3588 return 0
3589}
3590// searchcrawl (2026-07-25, seq912): the COVERAGE half of the search pipeline, alongside searchpagerank
3591// (authority) and searchcompact (storage). Runs the EXISTING nx_web_crawl_step -- a frontier-persisted,
3592// resumable crawler whose frontier lives in the shard itself -- detached via the SAME spawner, so a batch
3593// survives the edge's ~15s backend-read timeout that silently defeats synchronous tools/call ingest.
3594// arg1 = max_pages this run; arg2 = optional seed url to bootstrap/inject into the frontier.
3595// Deliberately NOT a new ingest organ: the crawler, its pacing, dedup and outlink filtering already exist.
3596// FIXED-ARG by design: hostctl subs ignore caller argv (the allowlist pins them), so max_pages and the
3597// bootstrap seed are compiled in rather than passed -- no hostile-arg surface. The seed is idempotent:
3598// an existing fr: row just flips last-wins, so re-running only ever CONTINUES the crawl.
3599// seconds since a file was last written, or -1 if it does not exist. Uses the SAME sys_fstatat + struct
3600// stat offsets the docportal shard-cache signature already relies on (st_mtime sec @ +88 on x86_64) --
3601// existing primitive, no new mechanism. Absent file => -1 => callers must treat it as 'cannot judge'.
3602func hc_file_age_s(path: *u8) -> i64 {
3603 let stb: *u8 = sys_mmap(160)
3604 if sys_fstatat(path, stb) != 0 { return 0 - 1 }
3605 let mtp: *i64 = ((stb as i64) + 88) as *i64
3606 let now: i64 = sys_now_realtime_sec()
3607 let age: i64 = now - mtp[0]
3608 if age < 0 { return 0 }
3609 return age
3610}
3611func cmd_searchcrawl() -> i64 {
3612 let maxp: *u8 = "400" as *u8
3613 // AIMED 2026-07-26: was a single Wikipedia hub, which filled the frontier with encyclopedia-adjacent
3614 // pages -- 113 of them landed and the judged ruler did not move BY ONE POINT, because the queries ask
3615 // for canonical sites (health agency, tax authority, kernel archive) that hub never links to. Now a
3616 // 44-domain CURATED list, selected by a documented rule that never mentions the benchmark. Re-seeding
3617 // is idempotent (a known frontier url is skipped), so every run just continues the crawl.
3618 let seed: *u8 = "knowledge/status/canonical_seeds.txt" as *u8
3619 hc_puts("[hostctl] searchcrawl: detached resumable web crawl on the NAS (frontier lives in the shard; re-run to continue)\n" as *u8)
3620 // STALENESS ESCAPE (seq961, a defect in my own first cut): a bare proc_alive guard turns ONE hang into
3621 // PERMANENT unavailability -- a stalled crawler holds the lock forever and the leg is wedged with no way
3622 // out over the API. Liveness is judged by PROGRESS (searchpipe.log mtime), not by the process existing:
3623 // alive AND log older than HC_CRAWL_STALE_S => reap it (the same hc_kill_by_cmdline every kick sub uses)
3624 // and fall through to a fresh spawn. Alive AND progressing => genuine no-op, still idempotent.
3625 if proc_alive_by_name("nx_web_crawl_step.elf" as *u8) == 1 {
3626 let age: i64 = hc_file_age_s("knowledge/status/searchpipe.log" as *u8)
3627 if age >= 0 { if age < HC_CRAWL_STALE_S {
3628 hc_puts(" already running and progressing (log age " as *u8); hc_putn(age); hc_puts("s) -> no-op (idempotent)\n" as *u8)
3629 return 0
3630 } }
3631 hc_puts(" STALLED: alive but no log progress for " as *u8); hc_putn(age); hc_puts("s -> reaping and respawning\n" as *u8)
3632 let kk: i64 = hc_kill_by_cmdline("nx_web_crawl_step.elf" as *u8)
3633 hc_puts(" reaped procs=" as *u8); hc_putn(kk); hc_puts("\n" as *u8)
3634 }
3635 if proc_alive_by_name("nx_web_shard_compact.elf" as *u8) == 1 { hc_puts(" a compaction is running -> defer (no-op)\n" as *u8); return 0 }
3636 if proc_alive_by_name("nx_pagerank_build.elf" as *u8) == 1 { hc_puts(" a pagerank build is running -> defer (no-op)\n" as *u8); return 0 }
3637 hc_spawn_searchpipe_job("./nx_web_crawl_step.elf" as *u8, maxp, seed)
3638 hc_puts(" spawned -> progress in knowledge/status/searchpipe.log\n" as *u8)
3639 return 0
3640}
3641func cmd_durindexrun() -> i64 {
3642 hc_puts("[hostctl] durindexrun: detached duration-index batch (setsid + ALL fds closed + flock single-instance) from /volume1/ai/galx -- the proper one-shot, NOT a serve boot-spawn\n" as *u8)
3643 if proc_alive_by_name("nx_galx_durindex.elf" as *u8) == 1 { hc_puts(" already running -> no-op (resumable+idempotent)\n" as *u8); return 0 }
3644 hc_spawn_durindex_job()
3645 hc_puts(" spawned -> appends knowledge/status/galx_dur.raw; progress in /volume1/ai/galx/galx_durindex.log; re-run to resume\n" as *u8)
3646 return 0
3647}
3648func hc_count_lines(path: *u8) -> i64 {
3649 let szp: *i64 = sys_mmap(16) as *i64
3650 let b: *u8 = sys_read_file(path, szp)
3651 if (b as i64) == 0 { return 0 - 1 }
3652 let sz: i64 = szp[0]
3653 var n: i64 = 0; var i: i64 = 0
3654 while i < sz { if b[i] == (10 as u8) { n = n + 1 } i = i + 1 }
3655 return n
3656}
3657func hc_tail(path: *u8, nb: i64) -> i64 {
3658 let szp: *i64 = sys_mmap(16) as *i64
3659 let b: *u8 = sys_read_file(path, szp)
3660 if (b as i64) == 0 { hc_puts(" (log absent)\n" as *u8); return 0 }
3661 let sz: i64 = szp[0]
3662 var start: i64 = sz - nb; if start < 0 { start = 0 }
3663 sys_write(1, ((b as i64) + start) as *u8, sz - start); hc_puts("\n" as *u8)
3664 return 0
3665}
3666// durindexstat: report runtime-sort data readiness = galx_dur.raw durations done vs vid_paths total.
3667func cmd_durindexstat() -> i64 {
3668 let dn: i64 = hc_count_lines("/volume1/ai/galx/knowledge/status/galx_dur.raw" as *u8)
3669 let pn: i64 = hc_count_lines("/volume1/ai/galx/knowledge/status/galx_vid_paths.tsv" as *u8)
3670 hc_puts("[hostctl] durindexstat: galx_dur.raw durations=" as *u8); hc_putn(dn); hc_puts(" / vid_paths total=" as *u8); hc_putn(pn); hc_puts("\n" as *u8)
3671 if dn < 0 { hc_puts(" galx_dur.raw ABSENT -> runtime-sort shows building (run durindexrun)\n" as *u8) }
3672 else { if dn >= pn { hc_puts(" -> COMPLETE: runtime-sort fully populated\n" as *u8) } else { hc_puts(" -> PARTIAL: runtime-sort works on the indexed subset; durindexrun to continue\n" as *u8) } }
3673 hc_puts(" --- galx_durindex.log tail ---\n" as *u8)
3674 hc_tail("/volume1/ai/galx/galx_durindex.log" as *u8, 700)
3675 return 0
3676}
3677// copy the n-th (0-indexed) line of buf into out (null-terminated, CR stripped); returns len or -1.
3678func hc_nth_line(buf: *u8, sz: i64, n: i64, out: *u8) -> i64 {
3679 var line: i64 = 0; var i: i64 = 0; var ls: i64 = 0
3680 while i <= sz {
3681 var nl: i64 = 0; if i == sz { nl = 1 } else { if buf[i] == (10 as u8) { nl = 1 } }
3682 if nl == 1 {
3683 if line == n { var ce: i64 = i; if ce > ls { if buf[ce-1] == (13 as u8) { ce = ce - 1 } } var o: i64 = 0; var k: i64 = ls; while k < ce { out[o] = buf[k]; o = o + 1; k = k + 1 } out[o] = 0 as u8; return o }
3684 line = line + 1; ls = i + 1
3685 }
3686 i = i + 1
3687 }
3688 return 0 - 1
3689}
3690// tsdurtest: run nx_ts_dur on the video at vid_paths line 40302 (first non-done) + show its raw output -- to
3691// diagnose why the batch produced no durations for the non-.ts tail.
3692func cmd_tsdurtest() -> i64 {
3693 let szp: *i64 = sys_mmap(16) as *i64
3694 let b: *u8 = sys_read_file("/volume1/ai/galx/knowledge/status/galx_vid_paths.tsv" as *u8, szp)
3695 if (b as i64) == 0 { hc_puts("no vid_paths\n" as *u8); return 0 }
3696 let path: *u8 = sys_mmap(HC_MAGIC_2048)
3697 if hc_nth_line(b, szp[0], HC_MAGIC_40302, path) < 0 { hc_puts("line 40302 not found\n" as *u8); return 0 }
3698 hc_puts("[tsdurtest] line 40302 path=" as *u8); hc_puts(path); hc_puts("\n" as *u8)
3699 let pid: i64 = sys_fork()
3700 if pid == 0 {
3701 sys_chdir("/volume1/ai/galx" as *u8)
3702 let of: i64 = sys_openat_wr("/tmp/tsdurtest.out" as *u8, 0x1a4)
3703 if of >= 0 { sys_dup3(of, 1, 0); sys_dup3(of, 2, 0) }
3704 nx_chmod("./nx_ts_dur.elf" as *u8, 0x1ed)
3705 let av: *i64 = sys_mmap(32) as *i64; av[0] = "./nx_ts_dur.elf" as *u8 as i64; av[1] = path as i64; av[2] = 0
3706 let envp: *i64 = sys_mmap(16) as *i64; envp[0] = "PATH=/usr/bin:/bin" as *u8 as i64; envp[1] = 0
3707 sys_execve_clean("./nx_ts_dur.elf" as *u8, av, envp); sys_exit(127)
3708 }
3709 let st: *i64 = sys_mmap(16) as *i64; sys_wait4(pid, st, 0)
3710 hc_puts(" --- nx_ts_dur output ---\n" as *u8)
3711 hc_tail("/tmp/tsdurtest.out" as *u8, 400)
3712 return 0
3713}
3714// durbinbuild: compact galx_dur.raw -> galx_dur.bin so the gallery's /vid/<id>/dur seekbar lookup is an
3715// O(1) 8-byte read instead of a 16MB first+last-PCR re-scan. Run after the durindex appends new durations;
3716// the gallery reads the fresh .bin with NO restart (mirrors galx_vid_off.bin). Short-lived: wait + show.
3717func cmd_durbinbuild() -> i64 {
3718 hc_puts("[hostctl] durbinbuild: compacting galx_dur.raw -> galx_dur.bin (O(1) /dur seekbar lookup)\n" as *u8)
3719 let bf: i64 = sys_openat_rd("/volume1/ai/galx/nx_galx_durbin.elf" as *u8)
3720 if bf < 0 { hc_puts(" ERROR nx_galx_durbin.elf MISSING -> re-send it\n" as *u8); return 0 }
3721 let bsz: i64 = sys_lseek(bf, 0, 2); sys_close(bf)
3722 hc_puts(" binary present, size=" as *u8); hc_putn(bsz); hc_puts("\n" as *u8)
3723 let pid: i64 = sys_fork()
3724 if pid == 0 {
3725 sys_chdir("/volume1/ai/galx" as *u8)
3726 let of: i64 = sys_openat_wr("/tmp/durbin.out" as *u8, 0x1a4)
3727 if of >= 0 { sys_dup3(of, 1, 0); sys_dup3(of, 2, 0) }
3728 nx_chmod("./nx_galx_durbin.elf" as *u8, 0x1ed)
3729 let av: *i64 = sys_mmap(32) as *i64; av[0] = "./nx_galx_durbin.elf" as *u8 as i64; av[1] = 0
3730 let envp: *i64 = sys_mmap(16) as *i64; envp[0] = "PATH=/usr/bin:/bin" as *u8 as i64; envp[1] = 0
3731 sys_execve_clean("./nx_galx_durbin.elf" as *u8, av, envp); sys_exit(127)
3732 }
3733 let st: *i64 = sys_mmap(16) as *i64; sys_wait4(pid, st, 0)
3734 let raw: i64 = st[0]
3735 hc_puts(" child status raw=" as *u8); hc_putn(raw); hc_puts(" exit=" as *u8); hc_putn((raw>>8)&0xff); hc_puts(" sig=" as *u8); hc_putn(raw&0x7f); hc_puts("\n" as *u8)
3736 hc_tail("/tmp/durbin.out" as *u8, 400)
3737 let cf: i64 = sys_openat_rd("/volume1/ai/galx/knowledge/status/galx_dur.bin" as *u8)
3738 if cf < 0 { hc_puts(" galx_dur.bin NOT created\n" as *u8) } else { let csz: i64 = sys_lseek(cf, 0, 2); sys_close(cf); hc_puts(" galx_dur.bin size=" as *u8); hc_putn(csz); hc_puts(" bytes (= 16 + 8*n)\n" as *u8) }
3739 return 0
3740}
3741// streaming copy src->dst (0755). Returns 0 ok, <0 fail. (staging the freshly-built elf for /api/deploy)
3742func hc_copyfile(src: *u8, dst: *u8) -> i64 {
3743 let sfd: i64 = sys_openat_rd(src); if sfd < 0 { return 0 - 1 }
3744 let dfd: i64 = sys_openat_wr(dst, 0x1ed); if dfd < 0 { sys_close(sfd); return 0 - 2 }
3745 let buf: *u8 = sys_mmap(HC_MAGIC_1048576); var go: i64 = 1
3746 while go == 1 { let nr: i64 = sys_read(sfd, buf, HC_MAGIC_1048576); if nr <= 0 { go = 0 } else { sys_write(dfd, buf, nr) } }
3747 sys_close(sfd); sys_close(dfd); return 0
3748}
3749// buildrun <name>: COMPILE a target ON THE NAS. cd buildroot (has _offc/ toolchain + runtime/ synced source),
3750// run _offc/nx_sov_build_run.elf <name> --build-only -> buildroot/_build/<name>.sov.elf (or, for
3751// pre-flock builder versions, /tmp/