nx_orphan_reap.nx
buildroot/runtime/nx_orphan_reap.nx
about
nx_orphan_reap.nx -- reap ORPHANED GATE DAEMONS that survive a killed gate, by cmdline needle.
WHY THIS EXISTS (measured 2026-08-01): nx_cms_tls_gate forks an admin AND a TLS front, then kills
them in its own teardown. When /api/gate_run hit its 12s deadline the gate's PARENT was killed
before teardown ran, so both daemons survived holding ports 8086/8447. Every later run then logged
BIND-FAIL and the gate reported 1/5 -- four TLS rows red -- for a reason that had nothing to do
with TLS. ★A GATE KILLED BY A DEADLINE SKIPS ITS TEARDOWN, AND ITS ORPHANED DAEMONS POISON EVERY
LATER RUN. Nothing existed to clean them up: proc_kill_by_name was a LIBRARY with no CLI.
⛔NEVER-BRICK GUARDS (rule 26; this verb is destructive BY DESIGN so the guards are structural):
G1 the needle must be >= NR_MIN_NEEDLE chars -- a short substring matches half the process table.
★THE SUBSTRING PROCESS-MATCH TRAP HAS BITTEN THIS ECOSYSTEM BEFORE (a substring process COUNT
counted its own watchdogs); the same blade cuts deeper when it kills instead of counts.
G2 a DENYLIST of load-bearing names is refused outright, even if the caller asks: killing the
supervisor, mgmt api, tools daemon or edge would take the host down and is never what reaping
a test daemon means.
G3 it REFUSES to match itself -- otherwise the reaper is its own first victim (the self-count trap,
4 prior instances, now in kill form).
G4 default signal is TERM (15), not KILL: a daemon that can close its listener should be allowed to.
Usage: nx_orphan_reap <cmdline-needle> [signal] Exit 0 reaped-or-none, 2 REFUSED.
license_tier: ORIGINAL expect_exit:0
dependencies 2 imports · 0 importers
imports: nx_syscalls.nxnx_proc_ctl.nx
imported by: nobody (leaf or entry point)
call flow from main pre-order; caps 40 nodes / depth 6 declared; ↻ = already shown
structs
| none |
consts
| 25 | const NR_MIN_NEEDLE: i64 = 10 |
| 26 | const NR_SIG_TERM: i64 = 15 |
| 27 | const NR_SELF: *u8 = "nx_orphan_reap" |
| 28 | const NR_DENY_CAP: i64 = 8192 |
| 29 | const NR_PROT_CONF: *u8 = "knowledge/status/protected_procs.conf" |
functions
| 34 | func nr_floor(d: *u8) -> i64 called by 1: main |
| 41 | func nr_w(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } sys_write(1, s, n); return 0 } |
| 42 | func nr_n(v: i64) -> i64 |
| 54 | func nr_len(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n } |
| 57 | func nr_denied(needle: *u8) -> i64 |
| 70 | func main(argc: i64, argv: *i64) -> i64 |