code wiki / _hdl_build / nx_docportal_admin_daemon.nx

nx_docportal_admin_daemon.nx source

↩ module page · 1099 lines · 72720 B

1// nx_docportal_admin_daemon.nx -- the admin.<domain> DOCUMENT-PORTAL daemon, on the CANONICAL ecosystem auth 2// (the SAME Modern Auth nishifamily.com/status uses: OPAQUE-3DH + Argon2id + NO-COOKIE Ed25519 session). Operator 3// 2026-06-28: "match it to what we have in the nishi ecosystem and team." So this does NOT invent a token scheme -- 4// it COMPOSES nx_status_daemon's proven auth (sd_* request parsing + nx_modern_auth_login + nx_sa_validate) and 5// wraps the proven nx_docportal_admin_lib router da_handle: 6// GET /admin -> the no-cookie login + upload SPA shell (public) 7// POST /admin/login -> handle+passphrase -> nx_modern_auth_login -> 200 {"token":...} | 401 8// * /admin/* (token) -> X-Nishi-Session validates (nx_sa_validate) ? da_handle at STAFF level : 401 9// A loopback HTTP daemon the sites daemon reverse-proxies to (behind the SNI router admin.<d> row); the public 10// TLS + cert are the operator-gated deploy step. Pure router dad_handle = bytes-in/bytes-out (the gate drives it 11// in-process, no socket). license_tier: ORIGINAL 12import "nx_docportal_admin_lib.nx" 13import "nx_status_daemon.nx" 14import "hub/nx_modern_auth_flow.nx" 15import "nx_syscalls.nx" 16import "nx_invite_token.nx" // invite-token store: inv_issue / inv_check / inv_consume 17import "nx_opaque_login.nx" // olg_register (OPAQUE one-shot over nx_modern_auth_register) 18import "nx_proxy_route.nx" // L2: pr_lookup_tmo, the per-read window the edge gives this host's /search row, so the heartbeat cadence is derived from the route table and never guessed 19import "nx_docportal_search_serve.nx" // R2 dss_serve: PUBLIC sovereign seg_store-native /search (no tsv, no derived .idx) 20import "nx_tool_registry.nx" // API-FIRST: the service self-registers nishi_search/nishi_doc at startup 21import "nx_multipart.nx" // RFC 7578 multipart/form-data parser (real <input type=file> uploads) 22import "nx_sysload.nx" // host sensors (sl_ncpu / sl_loadavg_milli): the concurrency ceiling is DERIVED from the live box, never guessed 23 24// Rule 11: the accept-failure backoff is a named constant, not a number buried in the loop. 25// 50ms is short enough that a transient accept error costs nothing perceptible and long enough that 26// a PERSISTENT one cannot spin a core -- 20 retries/sec instead of millions. 27const DAD_ACCEPT_BACKOFF_MS: i64 = 50 28// Rule 11: how stale the web-shard handle may get, in seconds. The refresh reopens a 1.59GB shard 29// on any manifest change, so it must NOT run per request. 10s bounds index staleness while keeping 30// the reopen off the hot path entirely when the crawler is active. 31// RAISED 10 -> 300 (2026-08-08) after measuring the PUBLIC cost of this gate. dss_web_cache_refresh 32// closes and reopens the whole web shard (94 segments, 1.59GB) whenever the manifest signature moved, 33// and that reopen was measured at 3-8s. This daemon is no longer the loopback admin daemon its 34// comments describe: proxy_routes.conf routes PUBLIC nishifamily.com /search and /doc here, so a 35// 10s gate put a multi-second reopen in front of essentially every human-paced click -- measured 36// from a browser vantage as 0.5s to 40s on /search and /doc while the crawler was committing. 37// 300s bounds index staleness at 5 minutes (fine for a doc/search index) and cuts a browsing user's 38// exposure ~30x. HONEST LIMIT: this is a MITIGATION, not the architectural fix. The reopen still 39// lands on the request path, it just lands 30x less often. The real fix is to refresh on a 40// background beat and swap the handle in when it is ready; the rate-limit state cannot simply move 41// into the forked child because the child exits and last_refresh would never advance, making EVERY 42// request refresh -- strictly worse than today. 43const DAD_REFRESH_MIN_SEC: i64 = 300 44// CEILING ON DEFERRAL (2026-08-14). Derived from DAD_REFRESH_MIN_SEC, not guessed: three refresh 45// intervals. It bounds worst-case index staleness at 15 minutes on a daemon that never goes idle, 46// while leaving ample room for the common case (any gap with zero children in flight refreshes at the 47// normal 300s). Named for exactly ONE purpose -- the deferral ceiling -- so it can never drift into 48// doubling as anything else. 49const DAD_REFRESH_MAX_SEC: i64 = 3 * DAD_REFRESH_MIN_SEC 50const DAD_REQCAP: i64 = 65536 51const DAD_OUTCAP: i64 = 524288 52 53// ---- BOUNDED CONCURRENCY (2026-08-14) ------------------------------------------------------- 54// Rule 11: the ceiling is DERIVED from the live host (ncpu - reserve - load) via the incumbent 55// sensor layer nx_sysload, not guessed. Only two policy numbers remain, each named for ONE thing. 56// DAD_CPU_RESERVE: cores deliberately left to the rest of the estate (sites.elf, gallery, crawler) 57// so serving /search can never starve the box -- the same polite-worker-budget shape nx_sysload 58// was written to feed (nx_resource_governor: "ncpu - reserve - load"). 59const DAD_CPU_RESERVE: i64 = 2 60// DAD_MIN_WORKERS: the floor. 1 reproduces exactly today's behaviour, so this change can only ever 61// ADD concurrency and never remove it -- the fail-safe direction is "behave as before". 62const DAD_MIN_WORKERS: i64 = 1 63 64// Reap every child that has ALREADY exited, without blocking. Returns how many were reaped. 65// Composes the proven idiom rather than inventing a second reaper: nx_initlive_probe verifies 66// fork + wait4(WNOHANG) works on this host (verdict=GREEN) and nx_init_live supervises with it. 67func dad_reap_done(wst: *i64) -> i64 { 68 var n: i64 = 0 69 var go: i64 = 1 70 while go == 1 { 71 let r: i64 = sys_wait4(0 - 1, wst, WNOHANG) 72 if r > 0 { n = n + 1 } else { go = 0 } 73 } 74 return n 75} 76 77// The concurrency ceiling, sensed from the REAL host through nx_sysload's reader. 78// DELIBERATELY NOT "ncpu - reserve - load". That is nx_resource_governor's POLITE BATCH budget, and 79// it is correct for background work that must yield to interactive serving. This daemon IS the 80// interactive serving path, so subtracting instantaneous load is wrong BY CONSTRUCTION: the load it 81// samples INCLUDES the traffic it exists to serve, so it throttles itself hardest exactly when 82// demand is highest. MEASURED 2026-08-14 on this box (AMD Ryzen Embedded V1500B, 4c/8t): ncpu=8, 83// loadavg~6 gave 8 - 2 - 6 = 0 -> clamped to 1 -> the ceiling silently reproduced the very serial 84// behaviour this change exists to remove, and 12 concurrent queries still completed strictly in 85// sequence (1.3s..14.1s). 86// ★A CEILING THAT SUBTRACTS THE DEMAND IT MUST ABSORB IS A SELF-DEFEATING BOUND. 87// CAPACITY is the ceiling; OVERLOAD is handled by the backpressure wait below, which is dynamic and 88// cannot deadlock. sl_ncpu() returns 1 as its safe default on read failure, so ncpu is PRINTED at 89// startup beside the cap -- an unsensed 1 must be visible as such, never mistaken for a measurement. 90func dad_worker_cap() -> i64 { 91 let ncpu: i64 = sl_ncpu() 92 var capw: i64 = ncpu - DAD_CPU_RESERVE 93 if capw < DAD_MIN_WORKERS { capw = DAD_MIN_WORKERS } 94 return capw 95} 96 97// the no-cookie admin SPA: log in -> token in sessionStorage -> upload form posts to /admin/upload with the 98// X-Nishi-Session header (NEVER a cookie). Minimal Web-API binding only (fetch/FileReader are JS-only). (public UI) 99func dad_shell(out: *u8) -> i64 { 100 // Build the HTML body FIRST into a temp buffer so the header can carry Content-Length. sites.elf's BUFFERED 101 // reverse proxy delimits the upstream body by Content-Length; a close-delimited response (no length) makes the 102 // proxy hop fail (-4) even though the daemon serves a direct client fine. Mirrors the JSON paths + the mgmt API. 103 let body: *u8 = sys_mmap(DAD_OUTCAP) 104 var b: i64 = 0 105 b = sd_cat(body, b, "<!DOCTYPE html><meta charset=utf-8><meta name=viewport content=\"width=device-width,initial-scale=1\"><title>Nishi document portal</title>" as *u8) 106 b = sd_cat(body, b, "<style>body{font-family:-apple-system,Segoe UI,sans-serif;max-width:720px;margin:6vh auto;padding:0 20px;color:#1c1c1e}input,select{width:100%;padding:9px;margin:.4rem 0;box-sizing:border-box;border:1px solid #ccc;border-radius:7px}button{padding:10px 18px;border:0;border-radius:7px;background:#0a6;color:#fff;font-size:1rem}.row{display:flex;gap:14px}.row label{font-size:.9rem}.e{color:#b00;min-height:1.2em}</style>" as *u8) 107 // NISHI-FIRST (2026-07-05 doctrine): the login is a REAL <form> -- native POST works with ZERO JS 108 // (nishi browser / any no-JS client); the JS below upgrades it to the SPA flow for third-party 109 // browsers (the last-mile shim). Hidden ui=1 rides ONLY the native submit -> server answers HTML. 110 b = sd_cat(body, b, "<div id=login><h2>&#128274; Nishi document portal</h2><form id=lf method=post action=/admin/login><input type=hidden name=ui value=1><input id=h name=handle placeholder=\"handle\" autocomplete=username autofocus><input id=p name=passphrase type=password placeholder=\"passphrase\" autocomplete=current-password><button type=submit id=b>Sign in</button></form><p id=e class=e></p></div>" as *u8) 111 b = sd_cat(body, b, "<div id=up hidden><h2>Upload a document</h2><input id=dom placeholder=\"domain (e.g. andelinwest.com)\"><input id=f type=file>" as *u8) 112 b = sd_cat(body, b, "<div class=row><label><input type=radio name=vis value=public checked> Public (visitor-facing)</label><label><input type=radio name=vis value=private> Private (client vault)</label></div>" as *u8) 113 b = sd_cat(body, b, "<div class=row><label><input type=checkbox id=ps checked> List in onsite search</label><label><input type=checkbox id=ab> Allow AI to publish blog posts</label></div>" as *u8) 114 b = sd_cat(body, b, "<button id=u>Upload</button><p id=r class=e></p></div>" as *u8) 115 b = sd_cat(body, b, "<script>var L=document.getElementById('login'),U=document.getElementById('up'),E=document.getElementById('e');" as *u8) 116 b = sd_cat(body, b, "document.getElementById('lf').onsubmit=function(){E.textContent='';var b='handle='+encodeURIComponent(h.value)+'&passphrase='+encodeURIComponent(p.value);fetch('/admin/login',{method:'POST',headers:{'Content-Type':'application/x-www-form-urlencoded'},body:b}).then(function(r){if(r.ok){return r.json()}throw 0}).then(function(j){sessionStorage.nx_sess=j.token;L.hidden=true;U.hidden=false}).catch(function(){E.textContent='Wrong handle or passphrase.'});return false};" as *u8) 117 b = sd_cat(body, b, "document.getElementById('u').onclick=function(){var R=document.getElementById('r');R.textContent='';var fr=new FileReader();fr.onload=function(){var vis=document.querySelector('input[name=vis]:checked').value;var q='/admin/upload?domain='+encodeURIComponent(dom.value)+'&visibility='+vis+'&pub_search='+(document.getElementById('ps').checked?1:0)+'&ai_blog='+(document.getElementById('ab').checked?1:0);fetch(q,{method:'POST',headers:{'X-Nishi-Session':sessionStorage.nx_sess||''},body:fr.result}).then(function(r){return r.text()}).then(function(t){R.style.color='#0a6';R.textContent=t}).catch(function(){R.textContent='Upload failed.'})};fr.readAsText(document.getElementById('f').files[0])};</script>" as *u8) 118 var o: i64 = 0 119 o = sd_cat(out, o, "HTTP/1.1 200 OK\r\nContent-Type: text/html; charset=utf-8\r\nConnection: close\r\nContent-Length: " as *u8) 120 o = sd_catn(out, o, b) 121 o = sd_cat(out, o, "\r\n\r\n" as *u8) 122 var i: i64 = 0 123 while i < b { out[o] = body[i]; o = o + 1; i = i + 1 } 124 return o 125} 126 127// Per-domain invite-token store path = "<storefile>.invites" (storefile = argv[3], carried on 128// ctx.account_store). Each realm/domain has its OWN storefile, so its invite tokens are isolated 129// by construction (per-domain isolation). DERIVED (not a new argv slot) => the daemon argv contract 130// <port> <keysfile> <storefile> <realm> <budget> stays unchanged (backward-compatible). 131func dad_invite_path(ctx: *NxAuthContext, out: *u8) -> i64 { 132 let sp: *u8 = ctx.account_store as *u8 133 var i: i64 = 0 134 while sp[i] != (0 as u8) { out[i] = sp[i]; i = i + 1 } 135 let suf: *u8 = ".invites" as *u8 136 var j: i64 = 0 137 while suf[j] != (0 as u8) { out[i] = suf[j]; i = i + 1; j = j + 1 } 138 out[i] = 0 as u8 139 return i 140} 141 142// ==== NISHI-FIRST no-JS session plumbing (2026-07-05 doctrine: nishi os/browser first; JS = the 143// third-party last-mile shim). The no-cookie C1 cardinal is PRESERVED: no Set-Cookie ever -- the no-JS 144// path carries the Ed25519 session token in the ?s= query of same-portal links (short-TTL, realm-scoped, 145// SAME validator). The query-session helpers now live in the SHARED nx_site_auth (nx_sa_validate_qs / 146// nx_sa_qs_raw / nx_sa_tok_urlenc) so mail/siteedit/every surface inherit them -- DRY, one auth home. ==== 147 148// the no-JS signed-in LANDING page (HTML answer to a form login): links carry the session in ?s=. 149func dad_landing(out: *u8, b64: *u8, b64n: i64) -> i64 { 150 let body: *u8 = sys_mmap(DAD_OUTCAP) 151 var b: i64 = 0 152 b = sd_cat(body, b, "<!DOCTYPE html><meta charset=utf-8><title>Signed in</title><body style=\"font-family:sans-serif;max-width:720px;margin:6vh auto\"><h2>Signed in</h2><p>No-JS session active (nishi-first). Continue to:</p><p><a href=\"/admin/ui?s=" as *u8) 153 b = nx_sa_tok_urlenc(b64, b64n, body, b) 154 b = sd_cat(body, b, "\">the document portal</a></p>" as *u8) 155 var o: i64 = 0 156 o = sd_cat(out, o, "HTTP/1.1 200 OK\r\nContent-Type: text/html; charset=utf-8\r\nConnection: close\r\nContent-Length: " as *u8) 157 o = sd_catn(out, o, b) 158 o = sd_cat(out, o, "\r\n\r\n" as *u8) 159 var i: i64 = 0 160 while i < b { out[o] = body[i]; o = o + 1; i = i + 1 } 161 return o 162} 163 164// the no-JS admin UI: shows the authenticated handle + a paste-text upload FORM (multipart file 165// pickers are the next rung; textarea covers the nishi browser + any no-JS client TODAY). 166// ---- session-uid -> handle map (the no-cookie session carries the 32-byte uid HASH, not the plaintext 167// handle; without this the authed page shows binary hash bytes in "Signed in as"). Mirrors the mail portal's 168// .mailmap: login/register append "MAP <64hex-uid> <handle>\n" to "<storefile>.uidmap" (append-only, rule 13), 169// /admin/ui resolves hash->handle. Same OPAQUE realm -> the docportal now shows the handle like the mail portal. 170func dad_hex32(src: *u8, out: *u8) -> i64 { 171 let hx: *u8 = "0123456789abcdef" as *u8 172 var i: i64 = 0 173 while i < 32 { out[i * 2] = hx[((src[i] as i64) >> 4) & 15]; out[i * 2 + 1] = hx[(src[i] as i64) & 15]; i = i + 1 } 174 out[64] = 0 as u8 175 return 64 176} 177func dad_uidmap_path(ctx: *NxAuthContext, out: *u8) -> i64 { 178 let sp: *u8 = ctx.account_store as *u8 179 var i: i64 = 0 180 while sp[i] != (0 as u8) { out[i] = sp[i]; i = i + 1 } 181 let suf: *u8 = ".uidmap" as *u8 182 var j: i64 = 0 183 while suf[j] != (0 as u8) { out[i] = suf[j]; i = i + 1; j = j + 1 } 184 out[i] = 0 as u8 185 return i 186} 187func dad_map_put(path: *u8, hexuid: *u8, h: *u8, hn: i64) -> i64 { 188 let row: *u8 = sys_mmap(256) 189 var o: i64 = sd_cat(row, 0, "MAP " as *u8) 190 var i: i64 = 0 191 while i < 64 { row[o] = hexuid[i]; o = o + 1; i = i + 1 } 192 row[o] = 32 as u8; o = o + 1 193 i = 0 194 while i < hn { row[o] = h[i]; o = o + 1; i = i + 1 } 195 row[o] = 10 as u8; o = o + 1 196 let fd: i64 = sys_openat_append(path, 0x1a4) 197 if fd < 0 { return 0 - 1 } 198 sys_write(fd, row, o) 199 sys_close(fd) 200 return 0 201} 202func dad_map_get(path: *u8, hexuid: *u8, out: *u8, cap: i64) -> i64 { 203 let szp: *i64 = sys_mmap(16) as *i64 204 szp[0] = 0 205 let b: *u8 = sys_read_file(path, szp) 206 if (b as i64) == 0 { sys_munmap(szp as *u8, 16); return 0 } 207 let n: i64 = szp[0] 208 var best: i64 = 0 209 var cur: i64 = 0 210 while cur < n { 211 var le: i64 = cur 212 while le < n && (b[le] as i64) != 10 { le = le + 1 } 213 if le - cur > 69 { 214 if (b[cur] as i64) == 77 { 215 var m: i64 = 1 216 var k: i64 = 0 217 while k < 64 { if b[cur + 4 + k] != hexuid[k] { m = 0; k = 64 } else { k = k + 1 } } 218 if m == 1 { 219 var w: i64 = 0 220 var s: i64 = cur + 69 221 while s < le { if w < cap - 1 { out[w] = b[s]; w = w + 1 } s = s + 1 } 222 out[w] = 0 as u8 223 best = w 224 } 225 } 226 } 227 cur = le + 1 228 } 229 // FREE the buffer sys_read_file mmap'd (cap 4 GiB + 16) -- it is NEVER freed by sys_read_file (the caller owns 230 // it), so this per-request map lookup was leaking the whole (append-only, growing) map file resident every call 231 // = the measured 27 GB docportal RSS (the F-class sys_read_file pattern). munmap bounds it to zero residual. 232 sys_munmap(b, 4294967312) 233 sys_munmap(szp as *u8, 16) 234 return best 235} 236 237func dad_ui_page(out: *u8, handle: *u8, hn: i64, sraw: *u8, sn: i64) -> i64 { 238 let body: *u8 = sys_mmap(DAD_OUTCAP) 239 var b: i64 = 0 240 b = sd_cat(body, b, "<!DOCTYPE html><meta charset=utf-8><title>Nishi document portal</title><body style=\"font-family:sans-serif;max-width:720px;margin:6vh auto\"><h2>Document portal</h2><p>Signed in as <b>" as *u8) 241 var i: i64 = 0 242 while i < hn { body[b] = handle[i]; b = b + 1; i = i + 1 } 243 b = sd_cat(body, b, "</b> (no-JS mode)</p><form method=post action=\"/admin/uploadtext?s=" as *u8) 244 i = 0 245 while i < sn { body[b] = sraw[i]; b = b + 1; i = i + 1 } 246 b = sd_cat(body, b, "\"><p><input name=domain value=\"andelinwest.com\" style=\"width:100%;padding:8px\"></p><p><select name=visibility><option value=public>Public (visitor-facing)</option><option value=private>Private (client vault)</option></select> <label><input type=checkbox name=pub_search value=1 checked> List in onsite search</label> <label><input type=checkbox name=ai_blog value=1> Allow AI blog</label></p><p><textarea name=text rows=12 style=\"width:100%\" placeholder=\"paste the document text here\"></textarea></p><button type=submit>Upload text</button></form>" as *u8) 247 // REAL file upload (multipart/form-data): a standard <input type=file>. Any file, binary-safe. 248 b = sd_cat(body, b, "<hr><h3>Or upload a file</h3><form enctype=multipart/form-data method=post action=\"/admin/uploadfile?s=" as *u8) 249 i = 0 250 while i < sn { body[b] = sraw[i]; b = b + 1; i = i + 1 } 251 b = sd_cat(body, b, "\"><p><input name=domain value=\"andelinwest.com\" style=\"width:100%;padding:8px\"></p><p><select name=visibility><option value=public>Public (visitor-facing)</option><option value=private>Private (client vault)</option></select> <label><input type=checkbox name=pub_search value=1 checked> List in onsite search</label></p><p><input type=file name=file></p><button type=submit>Upload file</button></form>" as *u8) 252 var o: i64 = 0 253 o = sd_cat(out, o, "HTTP/1.1 200 OK\r\nContent-Type: text/html; charset=utf-8\r\nConnection: close\r\nContent-Length: " as *u8) 254 o = sd_catn(out, o, b) 255 o = sd_cat(out, o, "\r\n\r\n" as *u8) 256 i = 0 257 while i < b { out[o] = body[i]; o = o + 1; i = i + 1 } 258 return o 259} 260 261// no-JS upload shim: form-urlencoded fields (domain/visibility/pub_search/ai_blog/text) -> the 262// CANONICAL /admin/upload request (query params on the request line + raw text body) -> da_handle. 263// One storage path, two front doors (rule 15/19: same engine, no contract fork). 264func dad_uploadtext(ctx: *NxAuthContext, req: *u8, req_n: i64, subject: *u8, out: *u8) -> i64 { 265 let body_off: i64 = sd_body_off(req, req_n) 266 let body: *u8 = ((req as i64) + body_off) as *u8 267 let body_n: i64 = req_n - body_off 268 let f_off: *i64 = sys_mmap(8) as *i64 269 let f_len: *i64 = sys_mmap(8) as *i64 270 // domain 271 let domb: *u8 = sys_mmap(256) 272 var dom_n: i64 = 0 273 if sd_form_field(body, body_n, "domain" as *u8, 6, f_off, f_len) == 1 { 274 dom_n = sd_urldecode(((body as i64) + f_off[0]) as *u8, f_len[0], domb, 255) 275 } 276 if dom_n < 1 { return sd_cat(out, 0, "HTTP/1.1 400 Bad Request\r\nContent-Type: text/plain\r\nConnection: close\r\nContent-Length: 14\r\n\r\nmissing domain" as *u8) } 277 // visibility (default public) 278 let visb: *u8 = sys_mmap(64) 279 var vis_n: i64 = 0 280 if sd_form_field(body, body_n, "visibility" as *u8, 10, f_off, f_len) == 1 { 281 vis_n = sd_urldecode(((body as i64) + f_off[0]) as *u8, f_len[0], visb, 63) 282 } 283 if vis_n < 1 { visb[0] = 112 as u8; visb[1] = 117 as u8; visb[2] = 98 as u8; visb[3] = 108 as u8; visb[4] = 105 as u8; visb[5] = 99 as u8; vis_n = 6 } 284 // checkboxes: present -> 1, absent -> 0 285 var ps: i64 = 0 286 if sd_form_field(body, body_n, "pub_search" as *u8, 10, f_off, f_len) == 1 { ps = 1 } 287 var ab: i64 = 0 288 if sd_form_field(body, body_n, "ai_blog" as *u8, 7, f_off, f_len) == 1 { ab = 1 } 289 // the document text 290 if sd_form_field(body, body_n, "text" as *u8, 4, f_off, f_len) != 1 { return sd_cat(out, 0, "HTTP/1.1 400 Bad Request\r\nContent-Type: text/plain\r\nConnection: close\r\nContent-Length: 12\r\n\r\nmissing text" as *u8) } 291 let txt: *u8 = sys_mmap(DAD_REQCAP) 292 let txt_n: i64 = sd_urldecode(((body as i64) + f_off[0]) as *u8, f_len[0], txt, DAD_REQCAP - 1) 293 if txt_n < 1 { return sd_cat(out, 0, "HTTP/1.1 400 Bad Request\r\nContent-Type: text/plain\r\nConnection: close\r\nContent-Length: 10\r\n\r\nempty text" as *u8) } 294 // synthesize the canonical upload request 295 let syn: *u8 = sys_mmap(DAD_REQCAP + 4096) 296 var s: i64 = 0 297 s = sd_cat(syn, s, "POST /admin/upload?domain=" as *u8) 298 var i: i64 = 0 299 while i < dom_n { syn[s] = domb[i]; s = s + 1; i = i + 1 } 300 s = sd_cat(syn, s, "&visibility=" as *u8) 301 i = 0 302 while i < vis_n { syn[s] = visb[i]; s = s + 1; i = i + 1 } 303 s = sd_cat(syn, s, "&pub_search=" as *u8) 304 if ps == 1 { syn[s] = 49 as u8 } else { syn[s] = 48 as u8 } 305 s = s + 1 306 s = sd_cat(syn, s, "&ai_blog=" as *u8) 307 if ab == 1 { syn[s] = 49 as u8 } else { syn[s] = 48 as u8 } 308 s = s + 1 309 s = sd_cat(syn, s, " HTTP/1.1\r\n\r\n" as *u8) 310 i = 0 311 while i < txt_n { syn[s] = txt[i]; s = s + 1; i = i + 1 } 312 let dctx: *DaCtx = sys_mmap(16) as *DaCtx 313 dctx.user_level = 2 314 dctx.subject = subject 315 return da_handle(dctx, syn, s, out) 316} 317 318// ===== REAL multipart/form-data FILE upload (standards-correct: what an <input type=file> submits; binary- 319// safe, any file type). Composes the shipped nx_multipart parser + feeds the extracted file bytes into the 320// SAME da_handle /admin/upload store path the paste-text shim uses (one storage engine, three front doors). ===== 321 322// extract the boundary token from the request's Content-Type header. returns length (0 if none). 323func dad_ct_boundary(req: *u8, req_n: i64, out: *u8) -> i64 { 324 let off: *i64 = sys_mmap(8) as *i64 325 let ln: *i64 = sys_mmap(8) as *i64 326 if nx_http_header_find(req, req_n, "Content-Type" as *u8, 12, off, ln) != NXHF_FOUND { return 0 } 327 let v: *u8 = ((req as i64) + off[0]) as *u8 328 let vn: i64 = ln[0] 329 let key: *u8 = "boundary=" as *u8 330 var bstart: i64 = 0 - 1 331 var i: i64 = 0 332 while i + 9 <= vn { 333 var m: i64 = 1 334 var j: i64 = 0 335 while j < 9 { if (v[i+j] as i64) != (key[j] as i64) { m = 0; j = 9 } else { j = j + 1 } } 336 if m == 1 { bstart = i + 9; i = vn } else { i = i + 1 } 337 } 338 if bstart < 0 { return 0 } 339 var w: i64 = 0 340 var k: i64 = bstart 341 while k < vn { let c: i64 = v[k] as i64; if c == 59 { k = vn } else { if c != 34 { out[w] = c as u8; w = w + 1 } k = k + 1 } } 342 out[w] = 0 as u8 343 return w 344} 345 346// extract a `key` value (e.g. name=" or filename=") from a part's header block body[hoff..hoff+hlen). 347// returns value length (0 if absent). key includes the trailing quote char it opens on. 348func dad_cd_extract(body: *u8, hoff: i64, hlen: i64, key: *u8, out: *u8) -> i64 { 349 var kl: i64 = 0 350 while key[kl] != (0 as u8) { kl = kl + 1 } 351 let end: i64 = hoff + hlen 352 var start: i64 = 0 - 1 353 var i: i64 = hoff 354 while i + kl <= end { 355 var m: i64 = 1 356 var j: i64 = 0 357 while j < kl { if (body[i+j] as i64) != (key[j] as i64) { m = 0; j = kl } else { j = j + 1 } } 358 if m == 1 { start = i + kl; i = end } else { i = i + 1 } 359 } 360 if start < 0 { return 0 } 361 var w: i64 = 0 362 var k: i64 = start 363 while k < end { if (body[k] as i64) == 34 { k = end } else { out[w] = body[k]; w = w + 1; k = k + 1 } } 364 out[w] = 0 as u8 365 return w 366} 367 368const DAD_MAXPARTS: i64 = 16 369 370// parse the multipart body -> pull the `file` part bytes + the domain/visibility/pub_search/ai_blog text 371// parts -> synthesize the canonical /admin/upload request -> da_handle (STAFF). Returns response length. 372func dad_uploadfile(ctx: *NxAuthContext, req: *u8, req_n: i64, subject: *u8, out: *u8) -> i64 { 373 let boundary: *u8 = sys_mmap(256) 374 let blen: i64 = dad_ct_boundary(req, req_n, boundary) 375 if blen <= 0 { return sd_cat(out, 0, "HTTP/1.1 400 Bad Request\r\nContent-Type: text/plain\r\nConnection: close\r\nContent-Length: 21\r\n\r\nno multipart boundary" as *u8) } 376 let body_off: i64 = sd_body_off(req, req_n) 377 let body: *u8 = ((req as i64) + body_off) as *u8 378 let body_n: i64 = req_n - body_off 379 let parts: *MultipartPart = sys_mmap(32 * DAD_MAXPARTS) as *MultipartPart 380 let np: i64 = multipart_parse(body, body_n, boundary, blen, parts, DAD_MAXPARTS) 381 if np <= 0 { return sd_cat(out, 0, "HTTP/1.1 400 Bad Request\r\nContent-Type: text/plain\r\nConnection: close\r\nContent-Length: 19\r\n\r\nmalformed multipart" as *u8) } 382 let domb: *u8 = sys_mmap(256); var dom_n: i64 = 0 383 let visb: *u8 = sys_mmap(64); var vis_n: i64 = 0 384 var ps: i64 = 0 385 var ab: i64 = 0 386 var file_off: i64 = 0 - 1 387 var file_len: i64 = 0 388 let nmb: *u8 = sys_mmap(128) 389 var i: i64 = 0 390 while i < np { 391 let p: *MultipartPart = ((parts as i64) + i * 32) as *MultipartPart 392 let nm_n: i64 = dad_cd_extract(body, p.headers_off, p.headers_len, "name=\"" as *u8, nmb) 393 if nm_n == 4 { if sd_starts(nmb, 4, "file" as *u8) == 1 { file_off = p.body_off; file_len = p.body_len } } 394 if nm_n == 6 { if sd_starts(nmb, 6, "domain" as *u8) == 1 { var w: i64 = 0; while w < p.body_len { domb[w] = body[p.body_off + w]; w = w + 1 } domb[p.body_len] = 0 as u8; dom_n = p.body_len } } 395 if nm_n == 10 { if sd_starts(nmb, 10, "visibility" as *u8) == 1 { var w2: i64 = 0; while w2 < p.body_len { visb[w2] = body[p.body_off + w2]; w2 = w2 + 1 } visb[p.body_len] = 0 as u8; vis_n = p.body_len } } 396 if nm_n == 10 { if sd_starts(nmb, 10, "pub_search" as *u8) == 1 { ps = 1 } } 397 if nm_n == 7 { if sd_starts(nmb, 7, "ai_blog" as *u8) == 1 { ab = 1 } } 398 i = i + 1 399 } 400 if file_len <= 0 { return sd_cat(out, 0, "HTTP/1.1 400 Bad Request\r\nContent-Type: text/plain\r\nConnection: close\r\nContent-Length: 18\r\n\r\nno file part found" as *u8) } 401 if dom_n <= 0 { return sd_cat(out, 0, "HTTP/1.1 400 Bad Request\r\nContent-Type: text/plain\r\nConnection: close\r\nContent-Length: 14\r\n\r\nmissing domain" as *u8) } 402 if vis_n <= 0 { visb[0] = 112 as u8; visb[1] = 117 as u8; visb[2] = 98 as u8; visb[3] = 108 as u8; visb[4] = 105 as u8; visb[5] = 99 as u8; vis_n = 6 } 403 // synthesize the canonical /admin/upload request (query metadata + raw file body) -> the SAME store path 404 let syn: *u8 = sys_mmap(body_n + 4096) 405 var s: i64 = sd_cat(syn, 0, "POST /admin/upload?domain=" as *u8) 406 var q: i64 = 0 407 while q < dom_n { syn[s] = domb[q]; s = s + 1; q = q + 1 } 408 s = sd_cat(syn, s, "&visibility=" as *u8) 409 q = 0 410 while q < vis_n { syn[s] = visb[q]; s = s + 1; q = q + 1 } 411 s = sd_cat(syn, s, "&pub_search=" as *u8) 412 if ps == 1 { syn[s] = 49 as u8 } else { syn[s] = 48 as u8 } 413 s = s + 1 414 s = sd_cat(syn, s, "&ai_blog=" as *u8) 415 if ab == 1 { syn[s] = 49 as u8 } else { syn[s] = 48 as u8 } 416 s = s + 1 417 s = sd_cat(syn, s, " HTTP/1.1\r\n\r\n" as *u8) 418 var f: i64 = 0 419 while f < file_len { syn[s] = body[file_off + f]; s = s + 1; f = f + 1 } 420 let dctx: *DaCtx = sys_mmap(16) as *DaCtx 421 dctx.user_level = 2 422 dctx.subject = subject 423 return da_handle(dctx, syn, s, out) 424} 425 426// ---- L2 EARLY BYTES (search rung L2, 2026-09-14). The SERP's status line, headers and page shell go out BEFORE the 427// search runs, framed chunked because the length is unknown at that moment, and the socket's owner keeps the edge's 428// per-read window alive with heartbeat chunks while a GRANDCHILD computes the rest of the page into a per-request file. 429// ONE writer per socket by construction (this child); the search process never touches the wire. The heartbeat cadence 430// is DERIVED from proxy_routes.conf's timeout= for this host's /search row (a third of it, so two beats may be lost 431// before the edge gives up); a route with no token gets the edge's default window. A slow query is a slow page, never 432// a 503. dss_serve, the Content-Length page the 49-tooth gate drives, is untouched. 433const DAD_EDGE_READ_TMO_S: i64 = 15 // sites.elf NX_SD2_BACKEND_TIMEOUT_S: the per-read window a route gets when proxy_routes.conf carries no timeout= token 434const DAD_HB_DIV: i64 = 3 // heartbeats at a third of the window 435const DAD_HB_POLL_MS: i64 = 200 // how often the writer asks whether the search process has finished 436const DAD_WNOHANG: i64 = 1 // wait4 flag: poll, never block -- the writer must keep breathing 437const DAD_MS_PER_S: i64 = 1000 438const DAD_BODY_MODE: i64 = 420 // 0644: the grandchild's per-request body file 439static dad_routes_g: *u8 440static dad_routes_n: i64 441func dad_slen(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n } 442// is this request the HTML SERP (the only route that streams)? 443func dad_is_search(req: *u8, req_n: i64) -> i64 { 444 let poff: *i64 = sys_mmap(8) as *i64 445 let plen: *i64 = sys_mmap(8) as *i64 446 poff[0] = 0 447 plen[0] = 0 448 sd_find_path(req, req_n, poff, plen) 449 let path: *u8 = ((req as i64) + poff[0]) as *u8 450 return sd_starts(path, plen[0], "/search" as *u8) 451} 452// heartbeat cadence in ms for this host's /search route: the route's per-read window over DAD_HB_DIV 453func dad_hb_ms(host: *u8) -> i64 { 454 if (dad_routes_g as i64) == 0 { 455 let nb: *i64 = sys_mmap(16) as *i64 456 dad_routes_g = sys_read_file("proxy_routes.conf" as *u8, nb) 457 if (dad_routes_g as i64) == 0 { dad_routes_n = 0 } else { dad_routes_n = nb[0] } 458 } 459 var tmo: i64 = 0 460 if dad_routes_n > 0 { 461 let port: *i64 = sys_mmap(8) as *i64 462 let mode: *i64 = sys_mmap(8) as *i64 463 let t: *i64 = sys_mmap(8) as *i64 464 t[0] = 0 465 pr_lookup_tmo(dad_routes_g, dad_routes_n, host, dad_slen(host), "/search" as *u8, 7, port, mode, t) 466 tmo = t[0] 467 } 468 if tmo <= 0 { tmo = DAD_EDGE_READ_TMO_S } 469 return tmo * DAD_MS_PER_S / DAD_HB_DIV 470} 471// L2b GUARD (2026-09-15): early bytes reach a client ONLY through a route the front door STREAMS. The buffered 472// branch of sites.elf reads the backend to EOF before it answers, so a chunked heartbeat stream behind a 473// `buffered` row is a stall for the whole per-read window -- measured: every hourly search journey FAIL at 474// ~15.5 s from epoch 1789418137, the first beat after the E4 rebuild re-shipped the streaming dispatch that L2 475// had rolled back by binary only. The route table is the ONE authority on how the front door forwards, so this 476// reads the SAME row dad_hb_ms reads and streams iff it says `stream`; no row, no table, or any other mode 477// answers whole (the proven Content-Length path). Data-driven: flipping the row to `stream` (hot-reloaded by 478// sites.elf) turns streaming on with no rebuild -- once L2b lands there. The pure form takes the table so the 479// gate can drive both directions without a proxy_routes.conf in its CWD. 480func dad_early_ok_tab(routes: *u8, rn: i64, host: *u8) -> i64 { 481 if rn <= 0 { return 0 } 482 if (routes as i64) == 0 { return 0 } 483 let sp: *u8 = "/search" as *u8 484 let port: *i64 = sys_mmap(8) as *i64 485 let mode: *i64 = sys_mmap(8) as *i64 486 let t: *i64 = sys_mmap(8) as *i64 487 port[0] = 0 488 mode[0] = PR_MODE_BUFFERED 489 t[0] = 0 490 pr_lookup_tmo(routes, rn, host, dad_slen(host), sp, dad_slen(sp), port, mode, t) 491 if mode[0] == PR_MODE_STREAM { return 1 } 492 return 0 493} 494func dad_early_ok(req: *u8, req_n: i64) -> i64 { 495 let host: *u8 = sys_mmap(256) 496 dsv_host(req, req_n, host, 255) 497 if (dad_routes_g as i64) == 0 { 498 let nb: *i64 = sys_mmap(16) as *i64 499 dad_routes_g = sys_read_file("proxy_routes.conf" as *u8, nb) 500 if (dad_routes_g as i64) == 0 { dad_routes_n = 0 } else { dad_routes_n = nb[0] } 501 } 502 return dad_early_ok_tab(dad_routes_g, dad_routes_n, host) 503} 504func dad_serve_early(cfd: i64, req: *u8, req_n: i64, out: *u8) -> i64 { 505 let hostbuf: *u8 = sys_mmap(256) 506 dsv_host(req, req_n, hostbuf, 255) 507 let t0: i64 = dsv_now_us() 508 let q: *u8 = sys_mmap(DSV_MAGIC_1024) 509 let effdom: *u8 = sys_mmap(256) 510 let box: *i64 = sys_mmap(32) as *i64 511 let qn: i64 = dsv_serp_parse(hostbuf, req, req_n, q, effdom, box) 512 let body: *u8 = sys_mmap(DSV_BODYCAP) 513 let b1: i64 = dsv_serp_prelude(body, q, qn, box[1]) 514 let o1: i64 = dsv_respond_early(out, body, b1) 515 sys_write(cfd, out, o1) // THE EARLY BYTES: status line, headers and the page shell, before the search runs 516 let slow: i64 = dss_serve_slow_ms(req, req_n, "knowledge/search_probe_slow.conf" as *u8) 517 // the rest of the page is computed by a grandchild into a per-request file; this process keeps the wire alive 518 let path: *u8 = sys_mmap(128) 519 var po: i64 = dsv_cat(path, 0, "/tmp/nx_serp_" as *u8) 520 po = dsv_catn(path, po, t0) 521 po = dsv_cat(path, po, ".body" as *u8) 522 let tmp: *u8 = sys_mmap(128) 523 var to: i64 = dsv_cat(tmp, 0, path) 524 to = dsv_cat(tmp, to, ".tmp" as *u8) 525 let kid: i64 = sys_fork() 526 if kid == 0 { 527 if slow > 0 { sys_sleep_ms(slow) } 528 let b2: i64 = dsv_serp_rest(effdom, q, qn, box[1], box[2], body, b1, t0) 529 let fd: i64 = sys_openat_wr(tmp, DAD_BODY_MODE) 530 if fd >= 0 { sys_write(fd, (body as i64 + b1) as *u8, b2 - b1); sys_close(fd); sys_renameat(tmp, path) } 531 sys_exit(0) 532 } 533 let hb: i64 = dad_hb_ms(hostbuf) 534 let hbbuf: *u8 = sys_mmap(64) 535 let hbn: i64 = dsv_chunk(hbbuf, 0, "<!-- -->" as *u8, 0, 8) 536 let wst: *i64 = sys_mmap(16) as *i64 537 var waited: i64 = 0 538 var done: i64 = 0 539 if kid < 0 { done = 1 } 540 while done == 0 { 541 let r: i64 = sys_wait4(kid, wst, DAD_WNOHANG) 542 if r == kid { done = 1 } else { if r < 0 { done = 1 } else { 543 sys_sleep_ms(DAD_HB_POLL_MS) 544 waited = waited + DAD_HB_POLL_MS 545 if waited >= hb { sys_write(cfd, hbbuf, hbn); waited = 0 } 546 } } 547 } 548 let nb2: *i64 = sys_mmap(16) as *i64 549 let rest: *u8 = sys_read_file(path, nb2) 550 var o2: i64 = 0 551 if (rest as i64) != 0 { o2 = dsv_chunk(out, 0, rest, 0, nb2[0]); sys_unlinkat(path) } 552 else { let fail: *u8 = "<p class=meta>search failed to answer; try again</p></main></body></html>" as *u8; o2 = dsv_chunk(out, 0, fail, 0, dad_slen(fail)) } 553 o2 = dsv_chunk_end(out, o2) 554 sys_write(cfd, out, o2) 555 return 0 556} 557 558// ---- THE ROUTER: request bytes -> response bytes (no socket). The gate drives this directly. ---- 559func dad_handle(ctx: *NxAuthContext, req: *u8, req_n: i64, out: *u8) -> i64 { 560 let poff: *i64 = sys_mmap(8) as *i64; let plen: *i64 = sys_mmap(8) as *i64 561 poff[0] = 0; plen[0] = 0 562 sd_find_path(req, req_n, poff, plen) 563 let path: *u8 = ((req as i64) + poff[0]) as *u8 564 let pn: i64 = plen[0] 565 let is_post: i64 = (req[0] == 80 as u8) as i64 566 var o: i64 = 0 567 // PUBLIC sovereign onsite /search (no auth, seg_store-native, NO tsv) -- matched FIRST, before the /admin chain. 568 // Domain from the Host header -> dss_serve queries dp-<Host>-pub- (this daemon fronts andelinwest.com). 569 if sd_starts(path, pn, "/search" as *u8) == 1 { 570 let hostbuf: *u8 = sys_mmap(256) 571 dsv_host(req, req_n, hostbuf, 255) 572 return dss_serve(hostbuf, req, req_n, out) 573 } 574 // PUBLIC /doc?cid=<cid> document view (the search loop's click-through; -pub- shard only). Boundary-guarded: 575 // exactly "/doc" or "/doc?..." -- a raw prefix would also swallow /doctor-style paths (path includes the query). 576 if sd_starts(path, pn, "/doc" as *u8) == 1 { 577 var docb: i64 = 0 578 if pn == 4 { docb = 1 } 579 if pn > 4 { if path[4] == (63 as u8) { docb = 1 } } 580 if docb == 1 { 581 let hostbuf2: *u8 = sys_mmap(256) 582 dsv_host(req, req_n, hostbuf2, 255) 583 return dsv_doc_serve(hostbuf2, req, req_n, out) 584 } 585 } 586 // API-FIRST surface: versioned public JSON (CORS, structured errors). Same engine, machine contract -- 587 // the HTML SERP above is just one client of it. Boundary-guarded like /doc. 588 if sd_starts(path, pn, "/api/search" as *u8) == 1 { 589 var apib: i64 = 0 590 if pn == 11 { apib = 1 } 591 if pn > 11 { if path[11] == (63 as u8) { apib = 1 } } 592 if apib == 1 { 593 let hostbuf3: *u8 = sys_mmap(256) 594 dsv_host(req, req_n, hostbuf3, 255) 595 return dss_api_search(hostbuf3, req, req_n, out) 596 } 597 } 598 if sd_starts(path, pn, "/api/doc" as *u8) == 1 { 599 var apid: i64 = 0 600 if pn == 8 { apid = 1 } 601 if pn > 8 { if path[8] == (63 as u8) { apid = 1 } } 602 if apid == 1 { 603 let hostbuf4: *u8 = sys_mmap(256) 604 dsv_host(req, req_n, hostbuf4, 255) 605 return dss_api_doc(hostbuf4, req, req_n, out) 606 } 607 } 608 if sd_starts(path, pn, "/api/suggest" as *u8) == 1 { 609 var apis: i64 = 0 610 if pn == 12 { apis = 1 } 611 if pn > 12 { if path[12] == (63 as u8) { apis = 1 } } 612 if apis == 1 { 613 let hostbuf5: *u8 = sys_mmap(256) 614 dsv_host(req, req_n, hostbuf5, 255) 615 return dss_api_suggest(hostbuf5, req, req_n, out) 616 } 617 } 618 // machine-readable OpenAPI 3.1 contract (enterprise: client codegen / Swagger / contract testing). 619 // Exact "/api/openapi.json" or with a query string. 620 if sd_starts(path, pn, "/api/openapi.json" as *u8) == 1 { 621 var apio: i64 = 0 622 if pn == 17 { apio = 1 } 623 if pn > 17 { if path[17] == (63 as u8) { apio = 1 } } 624 if apio == 1 { 625 let hostbuf6: *u8 = sys_mmap(256) 626 dsv_host(req, req_n, hostbuf6, 255) 627 return dss_api_openapi(hostbuf6, out) 628 } 629 } 630 if sd_starts(path, pn, "/admin/register" as *u8) == 1 { 631 // INVITE-GATED OPAQUE self-registration: a remote firm presents a SECRET single-use, expiring 632 // invite token (minted out-of-band by inv_issue) instead of a guessable handle. Matched BEFORE 633 // the "/admin/" session gate (which is a prefix of this path) and as a sibling of /admin/login. 634 // Gate shape mirrors nx_lan_signup_routes.lsd_route POST /register -- swapping its LAN-IP gate 635 // for the inv_check token gate. On success: olg_register (OPAQUE) -> inv_consume -> 200 mnemonic. 636 if is_post == 1 { 637 let body_off: i64 = sd_body_off(req, req_n) 638 let body: *u8 = ((req as i64) + body_off) as *u8 639 let body_n: i64 = req_n - body_off 640 let hoff: *i64 = sys_mmap(8) as *i64; let hn: *i64 = sys_mmap(8) as *i64 641 let poff2: *i64 = sys_mmap(8) as *i64; let pnn: *i64 = sys_mmap(8) as *i64 642 let ioff: *i64 = sys_mmap(8) as *i64; let inn: *i64 = sys_mmap(8) as *i64 643 var got: i64 = 0 644 if sd_form_field(body, body_n, "handle" as *u8, 6, hoff, hn) == 1 { 645 if sd_form_field(body, body_n, "pw" as *u8, 2, poff2, pnn) == 1 { 646 if sd_form_field(body, body_n, "invite" as *u8, 6, ioff, inn) == 1 { got = 1 } 647 } 648 } 649 var done: i64 = 0 650 if got == 1 { 651 let hbuf: *u8 = sys_mmap(256); let pbuf: *u8 = sys_mmap(512); let ibuf: *u8 = sys_mmap(128) 652 let h_dec: i64 = sd_urldecode(((body as i64) + hoff[0]) as *u8, hn[0], hbuf, 255) 653 let p_dec: i64 = sd_urldecode(((body as i64) + poff2[0]) as *u8, pnn[0], pbuf, 511) 654 let i_dec: i64 = sd_urldecode(((body as i64) + ioff[0]) as *u8, inn[0], ibuf, 127) 655 if h_dec > 0 { if p_dec > 0 { if i_dec > 0 { 656 let invpath: *u8 = sys_mmap(512) 657 dad_invite_path(ctx, invpath) 658 let now_s: i64 = sys_now_realtime_sec() 659 // THE GATE: token must be a live, realm-scoped, unconsumed invite (level > 0). 660 let lvl: i64 = inv_check(invpath, ibuf, i_dec, ctx.realm_id, ctx.realm_id_n, now_s) 661 if lvl <= 0 { 662 o = sd_cat(out, 0, "HTTP/1.1 403 Forbidden\r\nContent-Type: application/json\r\nConnection: close\r\nContent-Length: 37\r\n\r\n{\"error\":\"invalid or expired invite\"}" as *u8) 663 done = 1 664 } else { 665 let mn: *u8 = sys_mmap(512); let mnn: *i64 = sys_mmap(16) as *i64 666 if olg_register(ctx, hbuf, h_dec, pbuf, p_dec, mn, 512, mnn) == NX_MAUTH_OK { 667 // uidmap: record uid-hash -> handle at register so /admin/ui greets by name 668 let uidh2: *u8 = sys_mmap(32) 669 if nx_ncs_derive_user_id_hash(ctx.realm_id, ctx.realm_id_n, hbuf, h_dec, uidh2) == NX_NCS_OK { 670 let uhex2: *u8 = sys_mmap(72); dad_hex32(uidh2, uhex2) 671 let ump2: *u8 = sys_mmap(512); dad_uidmap_path(ctx, ump2) 672 dad_map_put(ump2, uhex2, hbuf, h_dec) 673 } 674 inv_consume(invpath, ibuf, i_dec, now_s) // single-use: burn the invite 675 o = sd_cat(out, 0, "HTTP/1.1 200 OK\r\nContent-Type: application/json\r\nConnection: close\r\nContent-Length: " as *u8) 676 o = sd_catn(out, o, 15 + mnn[0]) 677 o = sd_cat(out, o, "\r\n\r\n{\"mnemonic\":\"" as *u8) 678 var z: i64 = 0; while z < mnn[0] { out[o] = mn[z]; o = o + 1; z = z + 1 } 679 o = sd_cat(out, o, "\"}" as *u8) 680 done = 1 681 } else { 682 o = sd_cat(out, 0, "HTTP/1.1 400 Bad Request\r\nContent-Type: application/json\r\nConnection: close\r\nContent-Length: 27\r\n\r\n{\"error\":\"register failed\"}" as *u8) 683 done = 1 684 } 685 } 686 } } } 687 } 688 if done == 0 { o = sd_cat(out, 0, "HTTP/1.1 400 Bad Request\r\nContent-Type: application/json\r\nConnection: close\r\nContent-Length: 27\r\n\r\n{\"error\":\"register failed\"}" as *u8) } 689 } else { o = dad_shell(out) } 690 } else { if sd_starts(path, pn, "/admin/login" as *u8) == 1 { 691 if is_post == 1 { 692 let body_off: i64 = sd_body_off(req, req_n) 693 let body: *u8 = ((req as i64) + body_off) as *u8 694 let body_n: i64 = req_n - body_off 695 let hoff: *i64 = sys_mmap(8) as *i64; let hn: *i64 = sys_mmap(8) as *i64 696 let poff2: *i64 = sys_mmap(8) as *i64; let pnn: *i64 = sys_mmap(8) as *i64 697 var got: i64 = 0 698 if sd_form_field(body, body_n, "handle" as *u8, 6, hoff, hn) == 1 { 699 if sd_form_field(body, body_n, "passphrase" as *u8, 10, poff2, pnn) == 1 { got = 1 } 700 } 701 // ui=1 rides ONLY the native <form> submit (nishi-first no-JS path) -> answer HTML, not JSON. 702 var uiflag: i64 = 0 703 let uoff: *i64 = sys_mmap(8) as *i64 704 let un: *i64 = sys_mmap(8) as *i64 705 if sd_form_field(body, body_n, "ui" as *u8, 2, uoff, un) == 1 { uiflag = 1 } 706 var ok: i64 = 0 707 if got == 1 { 708 let hbuf: *u8 = sys_mmap(256); let pbuf: *u8 = sys_mmap(512) 709 let h_dec: i64 = sd_urldecode(((body as i64) + hoff[0]) as *u8, hn[0], hbuf, 255) 710 let p_dec: i64 = sd_urldecode(((body as i64) + poff2[0]) as *u8, pnn[0], pbuf, 511) 711 if h_dec > 0 { if p_dec > 0 { 712 let tok: *u8 = sys_mmap(NX_MAUTH_SESSION_TOKEN_BYTES) 713 let tok_n: *i64 = sys_mmap(8) as *i64; tok_n[0] = 0 714 if nx_modern_auth_login(ctx, hbuf, h_dec, pbuf, p_dec, tok, NX_MAUTH_SESSION_TOKEN_BYTES, tok_n) == NX_MAUTH_OK { 715 // uidmap: the session token carries the uid HASH -> record hash->handle so /admin/ui greets by name 716 let uidh: *u8 = sys_mmap(32) 717 if nx_ncs_derive_user_id_hash(ctx.realm_id, ctx.realm_id_n, hbuf, h_dec, uidh) == NX_NCS_OK { 718 let uhex: *u8 = sys_mmap(72); dad_hex32(uidh, uhex) 719 let ump: *u8 = sys_mmap(512); dad_uidmap_path(ctx, ump) 720 dad_map_put(ump, uhex, hbuf, h_dec) 721 } 722 let b64: *u8 = sys_mmap(256); let b64_n: i64 = b64_encode(tok, NX_MAUTH_SESSION_TOKEN_BYTES, b64) 723 if uiflag == 1 { o = dad_landing(out, b64, b64_n) } 724 else { 725 o = sd_cat(out, o, "HTTP/1.1 200 OK\r\nContent-Type: application/json\r\nConnection: close\r\nContent-Length: " as *u8) 726 o = sd_catn(out, o, 12 + b64_n) 727 o = sd_cat(out, o, "\r\n\r\n{\"token\":\"" as *u8) 728 var z: i64 = 0; while z < b64_n { out[o] = b64[z]; o = o + 1; z = z + 1 } 729 o = sd_cat(out, o, "\"}" as *u8) 730 } 731 ok = 1 732 } 733 } } 734 } 735 if ok == 0 { 736 if uiflag == 1 { o = sd_cat(out, 0, "HTTP/1.1 401 Unauthorized\r\nContent-Type: text/html; charset=utf-8\r\nConnection: close\r\nContent-Length: 106\r\n\r\n<!DOCTYPE html><meta charset=utf-8><p>Wrong handle or passphrase.</p><p><a href=\"/admin\">Try again</a></p>" as *u8) } 737 else { o = sd_emit_401_json(out) } 738 } 739 } else { o = dad_shell(out) } 740 } else { if sd_starts(path, pn, "/admin/ui" as *u8) == 1 { 741 // NISHI-FIRST no-JS admin page: session from the ?s= query (same Ed25519 validator) -> the 742 // handle-greeting + paste-upload form. Renders + navigates in the nishi browser TODAY. 743 let hb: *u8 = sys_mmap(256) 744 let hbn: *i64 = sys_mmap(8) as *i64 745 let now_ui: i64 = sys_now_realtime_sec() 746 if nx_sa_validate_qs(ctx, path, pn, now_ui, hb, 255, hbn) == NX_MAUTH_OK { 747 let voff: *i64 = sys_mmap(8) as *i64 748 let vlen: i64 = nx_sa_qs_raw(path, pn, voff) 749 let sp: *u8 = ((path as i64) + voff[0]) as *u8 750 // resolve the session uid HASH -> plaintext handle (else "Signed in as" shows raw hash bytes) 751 var disp_h: *u8 = hb 752 var disp_n: i64 = hbn[0] 753 if hbn[0] == 32 { 754 let uhex: *u8 = sys_mmap(72); dad_hex32(hb, uhex) 755 let ump: *u8 = sys_mmap(512); dad_uidmap_path(ctx, ump) 756 let rhb: *u8 = sys_mmap(128) 757 let rhn: i64 = dad_map_get(ump, uhex, rhb, 127) 758 if rhn > 0 { disp_h = rhb; disp_n = rhn } 759 } 760 o = dad_ui_page(out, disp_h, disp_n, sp, vlen) 761 } else { o = sd_emit_401_json(out) } 762 } else { if sd_starts(path, pn, "/admin/uploadtext" as *u8) == 1 { 763 // NISHI-FIRST no-JS upload: auth via ?s= OR the header, then the form->canonical-request shim. 764 let now_ut: i64 = sys_now_realtime_sec() 765 let hb2: *u8 = sys_mmap(256) 766 let hn2: *i64 = sys_mmap(8) as *i64 767 hn2[0] = 0 768 var authed: i64 = 0 769 if nx_sa_validate_qs(ctx, path, pn, now_ut, hb2, 255, hn2) == NX_MAUTH_OK { authed = 1 } 770 if authed == 0 { if nx_sa_validate_handle(ctx, req, req_n, now_ut, hb2, 255, hn2) == NX_MAUTH_OK { authed = 1 } } 771 if authed == 1 { 772 let subhex2: *u8 = sys_mmap(72); subhex2[0] = 0 as u8 773 if hn2[0] == 32 { dad_hex32(hb2, subhex2) } 774 if is_post == 1 { o = dad_uploadtext(ctx, req, req_n, subhex2, out) } 775 else { o = sd_emit_401_json(out) } 776 } else { o = sd_emit_401_json(out) } 777 } else { if sd_starts(path, pn, "/admin/uploadfile" as *u8) == 1 { 778 // REAL multipart/form-data file upload (what an <input type=file> submits): auth via ?s= OR header, 779 // then dad_uploadfile parses the parts + feeds the file bytes into the SAME /admin/upload store path. 780 let now_uf: i64 = sys_now_realtime_sec() 781 let hb3: *u8 = sys_mmap(256) 782 let hn3: *i64 = sys_mmap(8) as *i64 783 hn3[0] = 0 784 var authed_f: i64 = 0 785 if nx_sa_validate_qs(ctx, path, pn, now_uf, hb3, 255, hn3) == NX_MAUTH_OK { authed_f = 1 } 786 if authed_f == 0 { if nx_sa_validate_handle(ctx, req, req_n, now_uf, hb3, 255, hn3) == NX_MAUTH_OK { authed_f = 1 } } 787 if authed_f == 1 { 788 let subhex3: *u8 = sys_mmap(72); subhex3[0] = 0 as u8 789 if hn3[0] == 32 { dad_hex32(hb3, subhex3) } 790 if is_post == 1 { o = dad_uploadfile(ctx, req, req_n, subhex3, out) } 791 else { o = sd_emit_401_json(out) } 792 } else { o = sd_emit_401_json(out) } 793 } else { if sd_starts(path, pn, "/admin/" as *u8) == 1 { 794 // session-gated: the /admin/<action> paths (upload/policy/whoami) validate the no-cookie token, then route 795 // to da_handle at STAFF level (admin.<d> = the management capability). Unauthenticated -> 401 BEFORE 796 // da_handle ever runs (deny-by-default, two layers). Bare /admin falls through to the public login shell. 797 let now_s: i64 = sys_now_realtime_sec() 798 // P2: emit the session SUBJECT via nx_sa_validate_handle (verified to accept EXACTLY the same sessions as 799 // nx_sa_validate -- same sig/MAC + TTL + realm check, computed before + independent of the subject copy). 800 // The non-null hb/hbn + hb-cap>=32 are REQUIRED (else deny / null-deref). Same ?s= buffer pattern used above. 801 let hb: *u8 = sys_mmap(256) 802 let hbn: *i64 = sys_mmap(8) as *i64 803 hbn[0] = 0 804 if nx_sa_validate_handle(ctx, req, req_n, now_s, hb, 255, hbn) == NX_MAUTH_OK { 805 let dctx: *DaCtx = sys_mmap(16) as *DaCtx 806 dctx.user_level = 2 807 let subhex: *u8 = sys_mmap(72); subhex[0] = 0 as u8 808 if hbn[0] == 32 { dad_hex32(hb, subhex) } 809 dctx.subject = subhex 810 o = da_handle(dctx, req, req_n, out) 811 } else { o = sd_emit_401_json(out) } 812 } else { o = dad_shell(out) } } } } } } 813 return o 814} 815 816func main(argc: i64, argv: *i64) -> i64 { 817 if argc < 6 { sys_write(2, "usage: nx_docportal_admin_daemon <port> <keysfile> <storefile> <realm> <budget>\n" as *u8, 79); return 1 } 818 let port: i64 = sd_atoi(argv[1] as *u8) 819 let keysfile: *u8 = argv[2] as *u8 820 let storefile: *u8 = argv[3] as *u8 821 let realm: *u8 = argv[4] as *u8 822 let budget: i64 = sd_atoi(argv[5] as *u8) 823 let realm_n: i64 = sd_len(realm) 824 825 // fail-fast: arm the realm context at startup (Rule 20), exactly like nx_status_daemon 826 let oprf_seed: *u8 = sys_mmap(32); let akp: *u8 = sys_mmap(32); let akb: *u8 = sys_mmap(33) 827 let edp: *u8 = sys_mmap(32); let edb: *u8 = sys_mmap(32) 828 sys_write(1, "DBG start: args parsed\n" as *u8, 23) 829 if nx_uas_server_keys_load_or_init(keysfile, oprf_seed, akp, akb, edp, edb) != NX_UAS_OK { sys_write(2, "FATAL: server-key bundle\n" as *u8, 24); return 2 } 830 sys_write(1, "DBG: server-keys OK\n" as *u8, 20) 831 let ctx: *NxAuthContext = sys_mmap(256) as *NxAuthContext 832 if nx_auth_context_init(ctx, realm, realm_n, realm, realm_n, storefile as i64, oprf_seed, edp, edb, 900, 8192, 1, 1, 5, 1) != NX_MAUTH_OK { sys_write(2, "FATAL: context init\n" as *u8, 20); return 3 } 833 sys_write(1, "DBG: context init OK\n" as *u8, 21) 834 835 // API-FIRST: announce the search API in the ecosystem tool registry (idempotent check-first; the NAS 836 // CWD is nishihost/, so this writes the LIVE knowledge/toolreg- shard -> /api/tools + MCP tools/list 837 // discover nishi_search with zero adapter -- the "services register at their own startup" pattern). 838 let trp: *i64 = sys_mmap(16) as *i64 839 let trl: *i64 = sys_mmap(16) as *i64 840 if tool_get("nishi_search" as *u8, trp, trl) != 1 { 841 tool_register("nishi_search" as *u8, "Sovereign nishi search: a domain's docs + site pages, the nishi library (Host nishifamily.com), and the crawled open web (scope=web). Versioned JSON, CORS, structured errors." as *u8, "GET /api/search?q=<terms>[&scope=web] (per-domain via Host)" as *u8, "GREEN" as *u8) 842 } 843 if tool_get("nishi_doc" as *u8, trp, trl) != 1 { 844 tool_register("nishi_doc" as *u8, "Fetch a public document by content id from the nishi search corpus (JSON; text bounded + truncation-flagged)." as *u8, "GET /api/doc?cid=<cid>[&scope=web]" as *u8, "GREEN" as *u8) 845 } 846 847 let addr: *u8 = sys_mmap(16) 848 if nx_http_server_addr_loopback(addr, port) != 16 { sys_write(2, "FATAL: addr_loopback != 16\n" as *u8, 27); return 4 } 849 sys_write(1, "DBG: addr_loopback OK\n" as *u8, 22) 850 // ⚠LISTEN FIRST IS DELIBERATE -- I TRIED THE OPPOSITE AND MEASURED IT WORSE. DO NOT "FIX" THIS. 851 // The cold-start story, fully measured 2026-08-15: this parent spends ~8-12 s pre-warming a 1.59GB 852 // web shard. With listen() FIRST that cost is ABSORBED BY THE ACCEPT QUEUE -- connections wait in the 853 // 64-deep backlog and the first request completes in ~8.1 s, with NO failures. Moving the pre-warm 854 // above listen() closes the port for the whole warm-up instead, and the edge turns ECONNREFUSED into 855 // a user-visible 503: MEASURED 503 for 12.09 s, then 200 in 1.11 s. That trades one slow success for 856 // twelve seconds of hard failure, which is strictly worse for a visitor and is the exact symptom this 857 // daemon was reported for. Reverted. 858 // ★★★★★★A FAST FAILURE IS NOT AUTOMATICALLY BETTER THAN A SLOW SUCCESS -- THAT DEPENDS ENTIRELY ON 859 // WHETHER THE CALLER CAN DO ANYTHING WITH THE FAILURE. Here it cannot: the visitor sees 503. 860 // WHAT WAS GENUINELY WRONG WAS THE MEASUREMENT, NOT THE ORDER. Queue time is invisible to EVERY 861 // timer this daemon has -- the parent's starts at accept(), the child's after fork() -- so the daemon 862 // honestly reported <=1405 ms per request while curl measured 8144 ms end to end, and I attributed 863 // that gap in turn to the search engine, the did-you-mean walk, and the edge proxy before finding it 864 // here. ★★★★★A LATENCY NOBODY'S CLOCK STARTS FOR IS BLAMED ON WHOEVER IS MEASURED LAST. 865 // The remedy is therefore to make the cost VISIBLE (the warm_ms line below) and eventually CHEAPER -- 866 // never to hide it behind a closed port. 867 // ★ORDER DECIDED BY MATCHED MEASUREMENT, NOT BY ARGUMENT (2026-08-15). Both orders were built, 868 // deployed and probed from t=0 with the IDENTICAL protocol (300ms poll, count non-200s, record the 869 // first 200 and its duration): 870 // pre-warm BEFORE listen -> first 200 at t=12.09s, that request 1.11s 871 // listen BEFORE pre-warm -> first 200 at t=20.4s, that request 10.70s 872 // Pre-warm-first wins on BOTH axes, so it is what ships. I briefly reverted it after calling it 873 // "worse", which was WRONG: I had compared its t=0 probe against a listen-first number taken after a 874 // 30s sleep, i.e. against an already-warm daemon. ★★★★★★A COMPARISON BETWEEN TWO CONFIGURATIONS IS 875 // ONLY A COMPARISON IF BOTH WERE MEASURED IN THE SAME STATE -- otherwise you are timing the sleep. 876 // WHY listen-first is worse despite producing no ECONNREFUSED: the port opens instantly but the 877 // parent is then busy warming for ~9.8s, so arriving connections sit in the 64-deep backlog and are 878 // served LATE -- one measured at 10.70s, which burns most of the edge's 15s NX_SD2_BACKEND_TIMEOUT_S. 879 // Refusing fast during startup is the honest signal: the daemon is not ready, the caller learns in 880 // microseconds, and readiness arrives sooner overall. 881 // THE REAL FIX IS NEITHER ORDER -- IT IS THE 9.8s ITSELF. STARTUP warm_ms=9796 and, on the refresh 882 // path, REQ done parent_us=9783316: the same ~9.8s ss_open2 of the 1.59GB web shard, once at startup 883 // and again on whichever accept triggers a refresh (blocking the single-threaded parent, which is why 884 // it presents as a RUN of slow requests rather than one). Until that open is incremental, this order 885 // is the best available placement of an unavoidable cost, not a solution to it. 886 // SERVE-SCALE: pre-warm the web-shard handle in the PARENT so every forked child inherits it COW -- 887 // per-request ss_open on the bulk-CC shard measured ~0.7s/query without this. Refreshed per accept 888 // below (stat-signature check, ~free; reopen only when new segments actually ship). 889 let t_warm: i64 = dsv_now_us() 890 if dss_web_cache_refresh() == 1 { sys_write(1, "web shard handle pre-warmed\n" as *u8, 28) } 891 // Arm the shared query memo HERE -- in the parent, before any fork. sys_mmap_shared's own contract 892 // says "allocate in the PARENT before fork", and this daemon forks per request, so a memo armed 893 // anywhere else would be COW-private to one child and invisible to every other request. 894 if dsq_init() == 1 { sys_write(1, "query memo armed (shared, fixed-capacity)\n" as *u8, 42) } 895 // ANNOUNCE THE COLD-START COST. Every request queued behind this warm-up pays it, and no per-request 896 // timer can see that, so without this line the number is unobtainable from the daemon's own log -- 897 // which is precisely how it stayed unexplained. Print it once, at the only place that knows it. 898 let wb: *u8 = sys_mmap(96) 899 var wn: i64 = dsv_cat(wb, 0, "STARTUP warm_ms=" as *u8) 900 wn = dsv_catn(wb, wn, (dsv_now_us() - t_warm) / 1000) 901 wn = dsv_cat(wb, wn, " -- the port is opened AFTER this, so nothing queued behind it\n" as *u8) 902 sys_write(1, wb, wn) 903 904 // ONLY NOW open the port: every resource a request needs is resident and shared, so the backlog can 905 // no longer hide a cold-start cost, and the first accepted connection is served at warm speed. 906 let lv: *i64 = sys_mmap(8) as *i64 907 let lfd: i64 = nx_http_server_listen(addr, 64, lv) 908 if lfd < 0 { sys_write(2, "FATAL: listen failed (port busy or denied)\n" as *u8, 43); return 4 } 909 sys_write(1, "nx_docportal_admin_daemon listening loopback (READY: warm before listen)\n" as *u8, 73) 910 911 let req: *u8 = sys_mmap(DAD_REQCAP) 912 let out: *u8 = sys_mmap(DAD_OUTCAP) 913 let av: *i64 = sys_mmap(8) as *i64 // HOISTED out of the loop -- reused each accept (was leaking a page/iter) 914 let wst: *i64 = sys_mmap(16) as *i64 // HOISTED -- child reap status, reused 915 // Seeded from the pre-warm above, not from zero: the shard was JUST opened, so the first 916 // request must not immediately reopen it. Without this seed the gate would let exactly one 917 // full 1.59GB reopen through on the very first query after every restart -- the slowest 918 // possible moment, right when the daemon is already cold. 919 var last_refresh: i64 = sys_now_realtime_sec() 920 var served: i64 = 0 921 // Sensed ONCE, in the parent, then held. Re-sensing per accept would read a load average this 922 // daemon is itself creating and ratchet its own ceiling down toward 1 under exactly the load it 923 // exists to absorb. PRINT THE VALUE: a ceiling nobody can see is a ceiling nobody can debug. 924 let dad_cap: i64 = dad_worker_cap() 925 var dad_live: i64 = 0 926 let capbuf: *u8 = sys_mmap(96) 927 var cbn: i64 = 0 928 cbn = dsv_cat(capbuf, cbn, "worker cap=" as *u8) 929 cbn = dsv_catn(capbuf, cbn, dad_cap) 930 cbn = dsv_cat(capbuf, cbn, " ncpu=" as *u8) 931 cbn = dsv_catn(capbuf, cbn, sl_ncpu()) 932 cbn = dsv_cat(capbuf, cbn, " reserve=" as *u8) 933 cbn = dsv_catn(capbuf, cbn, DAD_CPU_RESERVE) 934 cbn = dsv_cat(capbuf, cbn, " (capacity bound; load deliberately NOT subtracted)\n" as *u8) 935 sys_write(1, capbuf, cbn) 936 // HOISTED per-request diagnostic buffer -- reused every iteration, never mmap'd inside the loop 937 // (the per-call-allocation law this file has already had to learn twice). 938 let logbuf: *u8 = sys_mmap(128) 939 while served < budget { 940 let cfd: i64 = nx_http_server_accept_one(lfd, av) 941 if cfd < 0 { 942 // ACCEPT BACKOFF (2026-08-01). This branch retried INSTANTLY, so any persistent accept 943 // error became a 100pct-CPU busy loop while the socket stayed LISTENING -- which every 944 // port-probe health check reads as a healthy daemon. 50ms costs nothing on the happy 945 // path (this branch is not taken when accepts succeed) and turns a spin into a 946 // survivable retry. It also stops a failing daemon from eating its 20M `served` budget 947 // in minutes. 948 sys_sleep_ms(DAD_ACCEPT_BACKOFF_MS) 949 served = served + 1 950 } 951 if cfd >= 0 { 952 // PER-REQUEST TRACE (2026-08-01). This daemon emitted NOTHING after `pre-warmed`, so when 953 // it wedged there was no way to tell which stage died: accept, refresh, fork, or handle. 954 // I spent an hour narrowing it from the outside with CPU counters and fd counts and still 955 // could not say. Three cheap writes make the next occurrence self-diagnosing. 956 // ★★★★★A DAEMON THAT LOGS ONLY ITS STARTUP CAN ONLY EVER TELL YOU IT STARTED. 957 sys_write(1, "REQ accepted\n" as *u8, 13) 958 // ROOT-CAUSE FIX (2026-08-01), found by the trace two lines above. 959 // The wedge was HERE: the log read accepted=52, refresh-ok=51, done=51 -- the daemon 960 // accepted a request and never returned from dss_web_cache_refresh(). That call compares 961 // a manifest signature and, on ANY change, does ss_close + ss_open2 over the whole web 962 // shard: 94 segments, 1.59GB. It ran ON EVERY ACCEPTED REQUEST. 963 // WHY IT ONLY BIT NOW: the manifest used to be frozen because the crawler was committing 964 // nothing (the segments=0 poisoned-segid bug I root-fixed earlier tonight). With the 965 // crawler working the shard grows again -- 87 segments at session start, 94 now -- so the 966 // cached handle is invalidated constantly and a full reopen lands on the request path. 967 // ★★★★★A CORRECT FIX IN ONE ORGAN CAN EXPOSE A LATENT O(N) COST IN ANOTHER. 968 // THE GATE: at most one refresh per DAD_REFRESH_MIN_SEC. Freshness is bounded by that 969 // interval instead of by request arrival, so a growing shard can no longer put a 970 // 1.59GB reopen in front of every query. Serving a few seconds of slightly stale index 971 // is strictly better than not serving at all. 972 // Reap FIRST so the in-flight count below is current, not left over from a child that has 973 // already exited. WNOHANG, so this costs nothing on the happy path. 974 // WHY THESE TWO NUMBERS ARE LOGGED (2026-08-15): the refresh gate below fires only on 975 // `dad_live == 0`, and the log proved that predicate routinely unreachable -- ~30 consecutive 976 // refresh-defer lines before one refresh-ok, exactly spanning a window where every web request 977 // measured 9.39-9.80 s while site scope stayed at 0.05-0.08 s. Correlation alone cannot say 978 // whether staleness makes requests slow (so they overlap, so dad_live never reaches 0) or the 979 // defers are a symptom of slowness caused elsewhere. Those have OPPOSITE remedies, the window 980 // cannot be reproduced on demand (it needs the crawler shipping segments), and guessing it is 981 // how three attributions went wrong today. Logging dad_live beside each refresh decision and 982 // the per-request duration beside each completion makes the NEXT occurrence self-diagnosing 983 // instead of requiring the condition to be caught live. 984 let t_acc: i64 = dsv_now_us() 985 dad_live = dad_live - dad_reap_done(wst) 986 let now_s: i64 = sys_now_realtime_sec() 987 if now_s - last_refresh >= DAD_REFRESH_MIN_SEC { 988 // DEFER THE REOPEN WHILE REQUESTS ARE IN FLIGHT (2026-08-14). 989 // dss_refresh_and_invalidate closes and reopens the whole web shard -- 94 segments, 990 // 1.59GB -- measured at 3-8s, and worse under swap pressure. On the accept path that 991 // makes ONE unlucky visitor per refresh window wear the entire cost. 992 // MEASURED TODAY, end to end: a /search?q=test request took 15.038s and the edge 993 // returned 503, while the very next request for the SAME query served in 0.25s. That 994 // single spike is the last surviving cause of the 503 this daemon was reported for. 995 // Deferring until no child is in flight means the reopen can never be charged to a 996 // request that is already running; new connections wait in the listen backlog (64) 997 // instead of one of them timing out. This is only possible because the accept loop now 998 // tracks dad_live -- before the concurrency fix there was no such thing as "idle". 999 // HARD CEILING, so bounded staleness never becomes unbounded: if deferral has pushed us 1000 // past DAD_REFRESH_MAX_SEC we refresh regardless. Without it a permanently busy daemon 1001 // would never refresh at all, trading a latency spike for an index that silently stops 1002 // updating -- strictly worse, and invisible. 1003 if dad_live == 0 { 1004 dss_refresh_and_invalidate() 1005 last_refresh = now_s 1006 sys_write(1, "REQ refresh-ok\n" as *u8, 15) 1007 } else { 1008 if now_s - last_refresh >= DAD_REFRESH_MAX_SEC { 1009 dss_refresh_and_invalidate() 1010 last_refresh = now_s 1011 sys_write(1, "REQ refresh-forced\n" as *u8, 19) 1012 } else { 1013 var lbd: i64 = dsv_cat(logbuf, 0, "REQ refresh-defer live=" as *u8) 1014 lbd = dsv_catn(logbuf, lbd, dad_live) 1015 lbd = dsv_cat(logbuf, lbd, "\n" as *u8) 1016 sys_write(1, logbuf, lbd) 1017 } 1018 } 1019 } else { 1020 sys_write(1, "REQ refresh-skip\n" as *u8, 17) 1021 } 1022 // FORK-PER-REQUEST (the durable leak fix): dad_handle mmaps DAD_OUTCAP (512 KB) + boxes INTERNALLY on 1023 // every request and frees NONE -- the measured ~50 MB/s -> 27 GB RSS leak (budget=20M means it never 1024 // self-recycles). A child that handles then sys_exit(0) reclaims EVERY page BY CONSTRUCTION; the parent 1025 // reaps it with a blocking wait4 (no zombies -- the nx_mp_serve leak class avoided). Functionally safe: 1026 // sessions are file-validated (no in-mem state), upload writes hit shared fds so they persist, and the 1027 // parent's ctx/req/out stay pristine (the child mutates only COW copies). Leak fixed -> process stays 1028 // small -> fork stays cheap. Requests serialize, which is fine for a loopback admin daemon. 1029 let kid: i64 = sys_fork() 1030 if kid == 0 { 1031 // TIME THE REQUEST WHERE THE REQUEST ACTUALLY HAPPENS (2026-08-15). The first version of 1032 // this instrument timed accept->"REQ done" IN THE PARENT and printed ms=0 on every line, 1033 // because the parent forks and immediately loops -- the child does all the work. That is 1034 // the estate's own first question about any instrument (does its SUBJECT match the thing 1035 // it claims to measure?) and I got it wrong on the first cut. A PARENT CANNOT TIME WORK IT 1036 // HANDED TO A CHILD; the number it produces is real, it is just about a different event. 1037 let t_kid: i64 = dsv_now_us() 1038 let om: *i64 = sys_mmap(8) as *i64; let opo: *i64 = sys_mmap(8) as *i64; let opl: *i64 = sys_mmap(8) as *i64 1039 let ocl: *i64 = sys_mmap(8) as *i64; let obo: *i64 = sys_mmap(8) as *i64; let orn: *i64 = sys_mmap(8) as *i64 1040 let rrc: i64 = nx_http_server_read_request(cfd, req, DAD_REQCAP, om, opo, opl, ocl, obo, orn) 1041 if rrc == NXS_OK { 1042 // L2: the HTML SERP streams (early bytes + heartbeats) ONLY behind a `stream` route row (L2b guard, 1043 // dad_early_ok); a buffered row and every other route answer whole as before 1044 var early: i64 = 0 1045 if dad_is_search(req, orn[0]) == 1 { early = dad_early_ok(req, orn[0]) } 1046 if early == 1 { dad_serve_early(cfd, req, orn[0], out) } else { 1047 let oN: i64 = dad_handle(ctx, req, orn[0], out) 1048 nx_http_server_send_response_nokeep_close(cfd, out, oN) 1049 } 1050 } 1051 // Written by the CHILD on its own inherited fd 1, after the response is on the wire, so 1052 // it covers read+handle+send -- the duration a visitor actually experiences. 1053 let kb: *u8 = sys_mmap(64) 1054 var kn: i64 = dsv_cat(kb, 0, "REQ child ms=" as *u8) 1055 kn = dsv_catn(kb, kn, (dsv_now_us() - t_kid) / 1000) 1056 kn = dsv_cat(kb, kn, "\n" as *u8) 1057 sys_write(1, kb, kn) 1058 sys_close(cfd) 1059 sys_exit(0) 1060 } 1061 sys_close(cfd) 1062 if kid > 0 { dad_live = dad_live + 1 } 1063 // NON-BLOCKING REAP + BACKPRESSURE (2026-08-14). What stood here was 1064 // if kid > 0 { sys_wait4(kid, wst, 0) } 1065 // a BLOCKING wait before the next accept -- concurrency EXACTLY 1. The comment above 1066 // justified that as "fine for a loopback admin daemon", and it WAS true when written. 1067 // It stopped being true when proxy_routes.conf routed PUBLIC nishifamily.com /search 1068 // and /doc to this daemon: one 10.5s web query then blocked every other visitor for 1069 // its whole duration, the buffered proxy queue backed up, and /search served 503. 1070 // MEASURED 2026-08-14 before this fix: 6 concurrent queries completed at 1071 // 1.8/3.2/4.6/5.9/6.3/7.2s -- a perfect serialization staircase -- while 6 concurrent 1072 // STATIC requests stayed flat at 0.035s, proving the edge was never the limit. This box 1073 // has 20 cores and /search was using exactly one of them at a time. 1074 // A COMMENT'S ASSUMPTION OUTLIVED THE ARCHITECTURE CHANGE THAT INVALIDATED IT. 1075 dad_live = dad_live - dad_reap_done(wst) 1076 // Block ONLY at the ceiling, and only until one slot frees: backpressure, not 1077 // serialization. It bounds fork depth on a shared box instead of admitting unbounded 1078 // children. The else-branch resets to 0 because wait4 <= 0 while children are believed 1079 // live means there is nothing left to reap -- the COUNT was wrong, not the kernel. 1080 while dad_live >= dad_cap { 1081 if sys_wait4(0 - 1, wst, 0) > 0 { dad_live = dad_live - 1 } else { dad_live = 0 } 1082 } 1083 // NAMED FOR WHAT IT MEASURES, NOT FOR WHAT A READER WANTS IT TO MEAN: this is the PARENT's 1084 // accept->fork->reap cost in MICROseconds, not the request duration (the child reports that 1085 // as `REQ child ms=`). Labelled `ms` it printed 0 on every line and read as "every request is 1086 // instant" -- a fabricated-looking constant in exactly the place someone debugging latency 1087 // would look first. A COUNTER NAMED FOR AN EVENT IT DOES NOT COVER IS WORSE THAN NO COUNTER. 1088 var lbz: i64 = dsv_cat(logbuf, 0, "REQ done parent_us=" as *u8) 1089 lbz = dsv_catn(logbuf, lbz, dsv_now_us() - t_acc) 1090 lbz = dsv_cat(logbuf, lbz, " live=" as *u8) 1091 lbz = dsv_catn(logbuf, lbz, dad_live) 1092 lbz = dsv_cat(logbuf, lbz, "\n" as *u8) 1093 sys_write(1, logbuf, lbz) 1094 served = served + 1 1095 } 1096 } 1097 sys_close(lfd) 1098 return 0 1099}