code wiki / (root) / nx_tools_api_serve.nx

nx_tools_api_serve.nx source

↩ module page · 162 lines · 11717 B

1// nx_tools_api_serve.nx -- standalone loopback HTTP server for the R0 agent-facing API (nx_tools_api). 2// Composes nx_http_server (bind/listen/accept, loopback-default) + nx_tools_api (ta_handle). ADDITIVE + ISOLATED: 3// a NEW service on a caller-chosen port that touches NOTHING existing -> never-brick by construction. 4// nx_tools_api_serve serve [port] -- bootstrap-register a few real tools (idempotent), then accept-loop 5// nx_tools_api_serve probe <port> <p> -- sovereign plain-HTTP GET client (self-test the live round-trip) 6// license_tier: ORIGINAL 7import "nx_http_server.nx" 8import "nx_connect.nx" // bounded connect: a raw sys_connect hangs ~127s on a black-holed host 9import "nx_api_edge.nx" // s-class edge: CORS + security-headers + rate-limit + problem+json; transitively nx_tools_api (ta_handle + ta_cat/ta_catn/ta_slen + tool_register + tr_atoi) 10const TSV_MAGIC_2048: i64 = 2048 11 12const TSV_PORT_DEFAULT: i64 = 8799 13const TSV_REQ_CAP: i64 = 65536 14const TSV_RESP_CAP: i64 = 1048576 15 16func tsv_puts(s: *u8) -> i64 { sys_write(1, s, ta_slen(s)); return 0 } 17func tsv_atoi_cstr(s: *u8) -> i64 { return tr_atoi(s, 0, ta_slen(s)) } 18 19// bootstrap the production registry with a few REAL, honestly-statused tools so /api/tools is non-empty on first 20// run (idempotent -- reg_put dedups by name; real services register themselves at their own startup). 21func tsv_seed() -> i64 { 22 tool_register("nx_tools_api" as *u8, "sovereign agent-facing tools API: registry over HTTP" as *u8, "GET /api/tools | POST /mcp (JSON-RPC 2.0)" as *u8, "gate-5/5" as *u8) 23 tool_register("nx_mgmt_client" as *u8, "drive the sovereign control-plane over TLS-1.3" as *u8, "nx_mgmt_client <url> login|call ..." as *u8, "live-proven-off-lan" as *u8) 24 tool_register("nx_https_get" as *u8, "sovereign HTTPS GET (TLS-1.3, own trust store)" as *u8, "nx_https_get(url, entropy, key, store, now, out, cap)" as *u8, "shipped" as *u8) 25 tool_register("nx_aw_hostctl" as *u8, "run one allowlisted nx_hostctl sub on the NAS over sovereign SSH" as *u8, "nx_aw_hostctl <sub>" as *u8, "shipped" as *u8) 26 // SOTA-CRITIC surface (2026-07-04): expose the ecosystem's own grader via MCP so ANY engaging LLM 27 // (Claude/Mythos/...) is HELD to the measured-not-asserted rubric, not trusted to be SOTA. The critic 28 // grades depth x breadth toward S-class from the sovereign seg_store, triangulated (2+ independent sources). 29 tool_register("nx_ecosystem_maturity_rollup" as *u8, "THE Nishi SOTA critic: measured (not asserted) ecosystem maturity toward S-class, per-domain current->bar + next rung, triangulated + liar-killed" as *u8, "nx_ecosystem_maturity_rollup [store] [autonomy_log] [out_log] -> overall permil + per-domain grades + GREEN/RED" as *u8, "gate-GREEN" as *u8) 30 // OPS-VIA-MCP (2026-07-08): READ-ONLY control surfaces, executed by fork-pinning nx_hostctl to a FIXED sub 31 // (tool_allowlist.conf 4th field) so a cap for nx_status runs `nx_hostctl status` and NEVER a destructive sub. 32 tool_register("nx_status" as *u8, "sovereign supervisor status: live services + guard state on the NAS (read-only)" as *u8, "nx_status -> supervisor snapshot (pinned nx_hostctl status)" as *u8, "live-2026-07-08" as *u8) 33 tool_register("nx_torstat" as *u8, "torrent stack status: peers, pieces, seeds (read-only)" as *u8, "nx_torstat -> torrent snapshot (pinned nx_hostctl torstat)" as *u8, "live-2026-07-08" as *u8) 34 // MGMT CONTROL PLANE over MCP (2026-07-08): nx_mgmt_call mints a fresh admin session (nx_session_mint_lib, from 35 // the NAS key bundle) per call and drives the never-brick mgmt API (:18098). Reads are pinned (fixed method+path); 36 // nx_mgmt is the general driver -- ADMIN cap only. Retires SSH for deploy/reconcile/restart. 37 tool_register("nx_services" as *u8, "mgmt API: live service inventory + per-service state (read-only)" as *u8, "nx_services -> /api/services JSON" as *u8, "live-2026-07-08" as *u8) 38 tool_register("nx_health" as *u8, "mgmt API: overall health rollup -- degraded/down services (read-only)" as *u8, "nx_health -> /api/health JSON" as *u8, "live-2026-07-08" as *u8) 39 tool_register("nx_mgmt" as *u8, "mgmt control-plane driver: deploy/reconcile/restart/... over the never-brick mgmt API (ADMIN cap required; mints a fresh admin session per call)" as *u8, "nx_mgmt <METHOD> <path> [json_body] -> mgmt API response" as *u8, "live-2026-07-08" as *u8) 40 // VERIFICATION SURFACE (2026-07-15): rule-11 magic gate + capability triage + SOTA racing lap, read-only. 41 // Graded 10/10 vs ESLint no-magic-numbers (external oracle -- NOT self-certified). tools/call proven live. 42 tool_register("nx_verify" as *u8, "Sovereign verification. VERBS: magic = rule-11 magic-number gate (allowlists casts/hex/mmap+syscall/radix-10/const; exempts data tables; graded 10/10 vs ESLint no-magic-numbers external oracle); triage = capability gap analysis; lap = racing-crew where-was/is/to-go vs SOTA. Read-only." as *u8, "over /mcp tools/call name=nx_verify arguments={argv:[VERB,...]}. e.g. {argv:[\"magic\",\"/path/file.nx\"]} -> VERIFY-MAGIC .. PASS|FAIL|EXEMPT" as *u8, "GREEN (10/10 vs ESLint; ratchet live in pre-commit; lap AT-SOTA; tools/call live over /mcp)" as *u8) 43 return 0 44} 45 46// SOTA concurrency: FORK-PER-REQUEST. The parent only accept()s + fork()s; each request is served in 47// its OWN child process, so a long-running tool (e.g. a bulk ingest) holds exactly ONE child while the 48// parent keeps serving everything else -- no more single-call starvation of the plane. Process isolation 49// means a crashing tool cannot take the daemon down. Bounded worker cap (no fork-bomb) + non-blocking 50// reaping (no zombies) + inline backpressure at cap (never drop a request). 51// v1 TRADEOFF (documented, intentional): nx_api_edge's per-client rate-limit + idempotency tables are 52// per-PROCESS static; after fork each child gets a private COW copy, so those reset per request. Flood 53// protection is instead the bounded TSV_MAXKIDS concurrency + backpressure. SOTA-v2 = relocate those 54// tables to sha_mmap_shared (MAP_SHARED survives fork) to restore true cross-request state. 55const TSV_MAXKIDS: i64 = 16 56const TSV_WNOHANG: i64 = 1 57 58// serve exactly one accepted connection to completion (read -> edge_handle -> send+close). 59func tsv_serve_one(cfd: i64, req: *u8, out: *u8) -> i64 { 60 let n: i64 = sys_read(cfd, req, TSV_REQ_CAP) 61 if n > 0 { 62 let rn: i64 = nx_api_edge_handle(req, n, out) // hardened edge wraps ta_handle 63 nx_http_server_send_response(cfd, out, rn) // sends + closes cfd 64 } else { sys_close(cfd) } 65 return 0 66} 67 68func tsv_serve(port: i64) -> i64 { 69 // Survive a client that walks away mid-response. Without this the kernel 70 // TERMINATES this daemon on the first write to a peer that closed early -- 71 // and a marathon tools/call whose caller (or the edge, at its read timeout) 72 // gives up is exactly that write. The daemon then dies holding a healthy 73 // listening socket, so the guard reports a crash-loop with no cause while 74 // the work itself completed (the seq1261/seq1126 outage class; proven both 75 // ways by nx_sigpipe_gate). Writers see -EPIPE and handle it as any other 76 // failed write; nothing else changes. 77 sys_ignore_sigpipe() 78 tsv_seed() 79 let addr: *u8 = sys_mmap(16) 80 nx_http_server_addr_loopback(addr, port) 81 let v: *i64 = sys_mmap(16) as *i64 82 // R5 ADOPTION: hot listener (SO_REUSEPORT). This daemon serves EVERY sovereign MCP tool, so restarting it 83 // darkens all tooling for every seat -- and it is the one service with no sovereign recovery path (seq1373), 84 // because nx_mgmt itself is served through here. Letting a new instance bind :18096 while the old still 85 // answers is what turns that restart from a blackout into a handoff. 86 // ⚠ BOTH sides need the option: the first restart after this ships still cannot hand off. Gate: nx_hotlisten_gate 3/3. 87 let lfd: i64 = nx_http_server_listen_hot(addr, 16, v) 88 if lfd < 0 { tsv_puts("LISTEN-FAIL verdict="); let mb: *u8 = sys_mmap(32); let mo: i64 = ta_catn(mb, 0, v[0]); sys_write(1, mb, mo); tsv_puts("\n" as *u8); sys_exit(1); return 1 } 89 let bnr: *u8 = sys_mmap(96); var bo: i64 = ta_cat(bnr, 0, "nx_tools_api_serve LIVE (fork-per-request cap=" as *u8); bo = ta_catn(bnr, bo, TSV_MAXKIDS); bo = ta_cat(bnr, bo, ") on 127.0.0.1:" as *u8); bo = ta_catn(bnr, bo, port); bnr[bo] = 10 as u8; sys_write(1, bnr, bo + 1) 90 let req: *u8 = sys_mmap(TSV_REQ_CAP) 91 let out: *u8 = sys_mmap(TSV_RESP_CAP) 92 let st: *i64 = sys_mmap(16) as *i64 93 var active: i64 = 0 94 var run: i64 = 1 95 while run == 1 { 96 // non-blocking reap of any finished children so they never become zombies + free worker slots 97 var rp: i64 = sys_wait4(0 - 1, st, TSV_WNOHANG) 98 while rp > 0 { if active > 0 { active = active - 1 } rp = sys_wait4(0 - 1, st, TSV_WNOHANG) } 99 let cfd: i64 = nx_http_server_accept_one(lfd, v) 100 if cfd >= 0 { 101 if active < TSV_MAXKIDS { 102 let pid: i64 = sys_fork() 103 if pid == 0 { 104 // CHILD: serve this one request in its own process, then exit the whole process 105 tsv_serve_one(cfd, req, out) 106 sys_exit_group(0) 107 } else { 108 // PARENT: child owns cfd -> close our copy + keep accepting. fork<0 -> serve inline (never drop). 109 if pid > 0 { sys_close(cfd); active = active + 1 } else { tsv_serve_one(cfd, req, out) } 110 } 111 } else { 112 // BACKPRESSURE: at worker cap -> serve inline (serialize) rather than drop the request 113 tsv_serve_one(cfd, req, out) 114 } 115 } 116 } 117 return 0 118} 119 120// sovereign plain-HTTP GET client -> connect 127.0.0.1:port, GET path, print the raw response. Proves the LIVE 121// socket round-trip against our own server (no curl, no TLS). 122func tsv_probe(port: i64, path: *u8) -> i64 { 123 let addr: *u8 = sys_mmap(16) 124 nx_http_server_addr_loopback(addr, port) 125 let fd: i64 = sys_socket(2, 1, 0) // AF_INET, SOCK_STREAM 126 if fd < 0 { tsv_puts("PROBE socket-fail\n" as *u8); sys_exit(1); return 1 } 127 if nx_connect_bounded(fd, addr, 16, NX_CONN_DEFAULT_MS) < 0 { tsv_puts("PROBE connect-fail\n" as *u8); sys_close(fd); sys_exit(1); return 1 } 128 let req: *u8 = sys_mmap(TSV_MAGIC_2048) 129 var o: i64 = ta_cat(req, 0, "GET " as *u8) 130 o = ta_cat(req, o, path) 131 o = ta_cat(req, o, " HTTP/1.1\r\nHost: 127.0.0.1\r\nConnection: close\r\n\r\n" as *u8) 132 sys_write(fd, req, o) 133 let buf: *u8 = sys_mmap(TSV_RESP_CAP) 134 var total: i64 = 0 135 var run: i64 = 1 136 while run == 1 { 137 let r: i64 = sys_read(fd, ((buf as i64) + total) as *u8, TSV_RESP_CAP - total) 138 if r <= 0 { run = 0 } else { total = total + r } 139 } 140 sys_close(fd) 141 sys_write(1, buf, total) 142 tsv_puts("\n" as *u8) 143 return 0 144} 145 146func main(argc: i64, argv: *i64) -> i64 { 147 if argc < 2 { tsv_puts("usage: nx_tools_api_serve serve [port] | probe <port> <path>\n" as *u8); sys_exit(2); return 2 } 148 let mode: *u8 = argv[1] as *u8 149 if ta_streq_n(mode, ta_slen(mode), "serve" as *u8) == 1 { 150 var port: i64 = TSV_PORT_DEFAULT 151 if argc >= 3 { port = tsv_atoi_cstr(argv[2] as *u8) } 152 return tsv_serve(port) 153 } 154 if ta_streq_n(mode, ta_slen(mode), "probe" as *u8) == 1 { 155 if argc < 4 { tsv_puts("usage: nx_tools_api_serve probe <port> <path>\n" as *u8); sys_exit(2); return 2 } 156 let port: i64 = tsv_atoi_cstr(argv[2] as *u8) 157 return tsv_probe(port, argv[3] as *u8) 158 } 159 tsv_puts("unknown mode (serve|probe)\n" as *u8) 160 sys_exit(2) 161 return 2 162}