code wiki / (root) / nx_mesh_hostagent.nx

nx_mesh_hostagent.nx source

↩ module page · 203 lines · 9362 B

1// nx_mesh_hostagent.nx -- WORKER MESH: the AUTONOMOUS host-agent that makes autoscale HANDS-OFF. It runs on the 2// worker host, and each tick it: reads DEMAND, PROBES the worker for warmth (bounded, ~1s), DECIDES via the autoscale 3// policy (SPAWN/SERVE/HOLD/REAP), and ACTUATES -- fork+execve the worker on SPAWN, nx_kill+wait4 on REAP. No human in 4// the loop: the organ physically starts and stops the worker process as demand comes and goes. On NishiOS this forks 5// the container natively; the exact same fork/kill lifecycle is exercised here against a real child process. 6// 7// CLI: (no args) -> self-test GATE (the decision policy) 8// demo <workerpath> <port> -> run the autonomous cold->SPAWN->SERVE->(idle)->REAP->cold cycle, forking and 9// killing a REAL worker child on a built-in demand schedule (proves the loop) 10// Actions: 0 HOLD 1 SPAWN 2 SERVE 3 REAP. license_tier: ORIGINAL 11import "nx_syscalls.nx" 12import "nx_connect.nx" // bounded connect: a raw sys_connect hangs ~127s on a black-holed host 13import "nx_runtime.nx" 14import "nx_http_client.nx" // nx_http_client_sockaddr_ipv4 + nx_http_client_build_request (probe) 15const HA_MAGIC_2048: i64 = 2048 16const HA_MAGIC_2000: i64 = 2000 17const HA_MAGIC_4096: i64 = 4096 18const HA_MAGIC_4095: i64 = 4095 19 20const HA_HOLD: i64 = 0 21const HA_SPAWN: i64 = 1 22const HA_SERVE: i64 = 2 23const HA_REAP: i64 = 3 24 25func ha_p(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } sys_write(1, s, n); return 0 } 26func ha_pn(v: i64) -> i64 { 27 let bb: *u8 = sys_mmap(28) 28 var m: i64 = v 29 if m < 0 { sys_write(1, "-" as *u8, 1); m = 0 - m } 30 let tt: *u8 = sys_mmap(28) 31 var k: i64 = 0 32 if m == 0 { tt[0] = 48 as u8; k = 1 } 33 while m > 0 { tt[k] = (48 + (m - (m/10)*10)) as u8; m = m / 10; k = k + 1 } 34 var i: i64 = 0 35 while i < k { bb[i] = tt[k-1-i]; i = i + 1 } 36 sys_write(1, bb, k) 37 return 0 38} 39func ha_atoi(s: *u8) -> i64 { var v: i64 = 0; var i: i64 = 0; while s[i] != (0 as u8) { let c: i64 = s[i] as i64; if c >= 48 { if c <= 57 { v = v * 10 + (c - 48) } } i = i + 1 } return v } 40func ha_streq(a: *u8, b: *u8) -> i64 { var i: i64 = 0; while b[i] != (0 as u8) { if a[i] != b[i] { return 0 } i = i + 1 } if a[i] != (0 as u8) { return 0 } return 1 } 41func ha_action_name(a: i64) -> *u8 { 42 if a == HA_HOLD { return "HOLD" as *u8 } 43 if a == HA_SPAWN { return "SPAWN" as *u8 } 44 if a == HA_SERVE { return "SERVE" as *u8 } 45 return "REAP" as *u8 46} 47 48// ---- the policy (identical to nx_mesh_autoscale am_decide) ---- 49func ha_decide(warm: i64, demand: i64, idle: i64, ttl: i64) -> i64 { 50 if demand == 1 { if warm == 0 { return HA_SPAWN } return HA_SERVE } 51 if warm == 1 { if idle >= ttl { return HA_REAP } return HA_HOLD } 52 return HA_HOLD 53} 54 55// ---- bounded warmth probe (non-blocking connect + poll) on 127.0.0.1:port ---- 56func ha_pollfd(pfd: *u8, fd: i64, events: i64) -> i64 { 57 pfd[0]=(fd&0xff) as u8; pfd[1]=((fd>>8)&0xff) as u8; pfd[2]=((fd>>16)&0xff) as u8; pfd[3]=((fd>>24)&0xff) as u8 58 pfd[4]=(events&0xff) as u8; pfd[5]=((events>>8)&0xff) as u8; pfd[6]=0 as u8; pfd[7]=0 as u8 59 return 0 60} 61func ha_resp_2xx(buf: *u8, n: i64) -> i64 { 62 var i: i64 = 0 63 while i + 3 < n { 64 if buf[i]==(50 as u8) { if buf[i+1]==(48 as u8) { if buf[i+2]==(48 as u8) { return 1 } } } 65 if buf[i]==(10 as u8) { i = n } 66 i = i + 1 67 } 68 return 0 69} 70func ha_probe(port: i64) -> i64 { 71 let sa: *u8 = sys_mmap(16) 72 nx_http_client_sockaddr_ipv4(sa, 127, 0, 0, 1, port) 73 let fd: i64 = sys_socket(AF_INET, SOCK_STREAM | HA_MAGIC_2048, 0) 74 if fd < 0 { return 0 } 75 nx_connect_bounded(fd, sa, 16, NX_CONN_DEFAULT_MS) 76 let pfd: *u8 = sys_mmap(8) 77 ha_pollfd(pfd, fd, 4) 78 let pn: i64 = sys_poll(pfd, 1, 1000) 79 if pn <= 0 { sys_close(fd); return 0 } 80 let rev: i64 = (pfd[6] as i64) | ((pfd[7] as i64) << 8) 81 if (rev & 8) != 0 { sys_close(fd); return 0 } 82 if (rev & 16) != 0 { sys_close(fd); return 0 } 83 // DERIVED FROM THE BUILDER'S OWN BOUND (2026-08-27). This read sys_mmap(256); the request 84 // nx_http_client_build_request emits today is ~357 bytes (request line + Host + the Chrome 85 // identity block + the derived codec-caps Accept pair + Connection: close), so every call 86 // overran this arena into the next cell. Found by the crash guard on the browser's own 87 // page-demo row (ARENA-OVERRUN prev_alloc_size=256); nx_http_client owns the bound. 88 let req: *u8 = sys_mmap(nx_http_client_request_cap(10, 6, 0, 0)) 89 let rl: i64 = nx_http_client_build_request("/v1/models" as *u8, 10, "worker" as *u8, 6, req) 90 sys_write(fd, req, rl) 91 ha_pollfd(pfd, fd, 1) 92 let pn2: i64 = sys_poll(pfd, 1, HA_MAGIC_2000) 93 if pn2 <= 0 { sys_close(fd); return 0 } 94 let out: *u8 = sys_mmap(HA_MAGIC_4096) 95 let got: i64 = sys_read(fd, out, HA_MAGIC_4095) 96 sys_close(fd) 97 if got <= 0 { return 0 } 98 return ha_resp_2xx(out, got) 99} 100 101func ha_sleep_ms(ms: i64) -> i64 { sys_poll(0 as *u8, 0, ms); return 0 } 102 103// ---- ACTUATION: fork+execve the worker; nx_kill+wait4 to reap ---- 104func ha_spawn(path: *u8, portstr: *u8) -> i64 { 105 let pid: i64 = sys_fork() 106 if pid == 0 { 107 let av: *i64 = sys_mmap(64) as *i64 108 av[0] = path as i64; av[1] = portstr as i64; av[2] = 0 109 sys_execve(path, av, 0 as *i64) 110 sys_exit(127) // only if execve failed 111 } 112 return pid 113} 114func ha_reap(pid: i64) -> i64 { 115 nx_kill(pid, 9) // SIGKILL -- guaranteed release of VRAM/port 116 let st: *i64 = sys_mmap(8) as *i64 117 sys_wait4(pid, st, 0) // reap the zombie 118 return 0 119} 120 121func ha_gate() -> i64 { 122 ha_p("=== nx_mesh_hostagent: autonomous autoscale host-agent (fork worker on demand, reap on idle) ===\n" as *u8) 123 var t1: i64 = 0 124 if ha_decide(0,1,0,2) == HA_SPAWN { t1 = 1 } 125 var t2: i64 = 0 126 if ha_decide(1,1,0,2) == HA_SERVE { t2 = 1 } 127 var t3: i64 = 0 128 if ha_decide(1,0,3,2) == HA_REAP { t3 = 1 } 129 var t4: i64 = 0 130 if ha_decide(1,0,1,2) == HA_HOLD { t4 = 1 } 131 var t5: i64 = 0 132 if ha_decide(0,0,9,2) == HA_HOLD { t5 = 1 } 133 ha_p(" T1 cold+demand->SPAWN: " as *u8); ha_pn(t1) 134 ha_p(" | T2 warm+demand->SERVE: " as *u8); ha_pn(t2) 135 ha_p(" | T3 warm+idle->REAP: " as *u8); ha_pn(t3) 136 ha_p(" | T4 warm+fresh->HOLD: " as *u8); ha_pn(t4) 137 ha_p(" | T5 cold+nodemand->HOLD: " as *u8); ha_pn(t5); ha_p("\n" as *u8) 138 var pass: i64 = 0 139 if t1==1 { if t2==1 { if t3==1 { if t4==1 { if t5==1 { pass = 1 } } } } } 140 if pass == 1 { ha_p("MESHHOSTAGENTGATE verdict=GREEN (policy correct)\n" as *u8); return 0 } 141 ha_p("MESHHOSTAGENTGATE verdict=RED\n" as *u8) 142 return 1 143} 144 145// autonomous demo: demand high for the first 4 ticks then gone; the agent forks + reaps a REAL worker child. 146func ha_demo(path: *u8, portstr: *u8) -> i64 { 147 let port: i64 = ha_atoi(portstr) 148 ha_p("=== autonomous host-agent loop (worker=" as *u8); ha_p(path); ha_p(" :" as *u8); ha_pn(port); ha_p(") ===\n" as *u8) 149 var worker_pid: i64 = 0 150 var idle: i64 = 0 151 let ttl: i64 = 2 152 var tick: i64 = 0 153 var spawned_pid: i64 = 0 154 var killed_pid: i64 = 0 155 while tick < 10 { 156 var demand: i64 = 0 157 if tick < 4 { demand = 1 } 158 var warm: i64 = 0 159 if worker_pid != 0 { warm = ha_probe(port) } 160 let act: i64 = ha_decide(warm, demand, idle, ttl) 161 ha_p(" tick " as *u8); ha_pn(tick); ha_p(": demand=" as *u8); ha_pn(demand); ha_p(" warm=" as *u8); ha_pn(warm); ha_p(" pid=" as *u8); ha_pn(worker_pid); ha_p(" idle=" as *u8); ha_pn(idle); ha_p(" -> " as *u8); ha_p(ha_action_name(act)) 162 if act == HA_SPAWN { 163 worker_pid = ha_spawn(path, portstr) 164 spawned_pid = worker_pid 165 idle = 0 166 ha_p(" (forked worker pid=" as *u8); ha_pn(worker_pid); ha_p(")" as *u8) 167 ha_sleep_ms(600) // let it bind before the next probe 168 } 169 if act == HA_SERVE { idle = 0 } 170 if act == HA_HOLD { if demand == 0 { if warm == 1 { idle = idle + 1 } } } 171 if act == HA_REAP { 172 killed_pid = worker_pid 173 ha_reap(worker_pid) 174 ha_p(" (killed worker pid=" as *u8); ha_pn(worker_pid); ha_p(")" as *u8) 175 worker_pid = 0 176 idle = 0 177 } 178 ha_p("\n" as *u8) 179 ha_sleep_ms(500) 180 tick = tick + 1 181 } 182 // safety: reap if still running 183 if worker_pid != 0 { ha_reap(worker_pid); killed_pid = worker_pid } 184 ha_p("SUMMARY: autonomously SPAWNED pid=" as *u8); ha_pn(spawned_pid); ha_p(" then REAPED pid=" as *u8); ha_pn(killed_pid) 185 var ok: i64 = 0 186 if spawned_pid > 0 { if killed_pid == spawned_pid { ok = 1 } } 187 if ok == 1 { ha_p(" -- HANDS-OFF CYCLE PROVEN (probe went 0->1->0 as the agent started+stopped the worker)\n" as *u8); return 0 } 188 ha_p(" -- INCOMPLETE\n" as *u8) 189 return 1 190} 191 192func main(argc: i64, argv: *i64) -> i64 { 193 if argc >= 2 { 194 let cmd: *u8 = argv[1] as *u8 195 if ha_streq(cmd, "demo" as *u8) == 1 { 196 if argc < 4 { ha_p("usage: nx_mesh_hostagent demo <workerpath> <port>\n" as *u8); return 2 } 197 return ha_demo(argv[2] as *u8, argv[3] as *u8) 198 } 199 ha_p("usage: nx_mesh_hostagent demo <workerpath> <port> (no args = gate)\n" as *u8) 200 return 2 201 } 202 return ha_gate() 203}