code wiki / _hdl_build / nx_mgmt_deploy_candidate_t185.nx

nx_mgmt_deploy_candidate_t185.nx source

↩ module page · 4046 lines · 262144 B

1// nx_mgmt_api.nx -- THE IO / TRANSPORT ring of the sovereign ecosystem control-plane API (the primary adapter). 2// THIN by design (clean three-tier / hexagonal -- see knowledge/library/arch_*): it owns ONLY transport -- 3// the socket loop, HTTP request parse, routing, JSON serialization, and auth gating. ALL business rules live in 4// the LOGIC core (nx_mgmt_core, mc_*); ALL outside-world access lives in the DATA adapters (nx_mgmt_data, md_*). 5// Dependency direction: api -> {core, data}, data -> core-free, core -> nothing (dependency inversion). The 6// router is a PURE FUNCTION ma_handle(ctx, req, req_n, snapfile, out) -> out_n (bytes in, bytes out, NO socket); 7// the gate drives it IN-PROCESS (no curl/shell). Reuses nx_status_daemon's HTTP-parse + Modern-Auth helpers. 8// 9// TRUE MONITORING (no false +/-): /api/health + /api/services read a live SNAPSHOT (md_read_file) and surface 10// dueling-supervisors / duplicate-instances / crash-loops via the core rules; missing snapshot -> UNKNOWN, 11// never OK. Health/services + all write actions are AUTH-gated; write actions are confirm-gated + fail-closed. 12// 13// Routes (auth = X-Nishi-Session Ed25519 session header, canonical Modern Auth, NO cookies): 14// GET /api -> 200 route index (public) 15// POST /api/login -> 200 {"token":...} | 401 16// GET /api/health -> (auth) 200 {overall,degraded,reasons[...]} | 401 17// GET /api/services -> (auth) 200 {services:[...]} | 401 18// POST /api/upload?target=&seq=&final=[&sha256=] -> (auth) chunked artifact publish; append raw body chunk -> 19// <target>.upload, on final rename -> <target>.new (staged for /api/deploy; NEVER promotes) | 400 | 401 20// POST /api/deploy -> (auth) allowlist+validate->promote->http-health->auto-rollback | 400 | 401 21// POST /api/rollback -> (auth, confirm=yes) | 400 | 401 22// POST /api/reconcile -> (auth, confirm=yes) single-supervisor | 400 | 401 23// POST /api/restart -> (auth, confirm=yes, service=) surgical kick | 400 | 401 24// POST /api/migrate|update -> (auth) 501 reserved (R3b: URL->.site ingest) | 401 25// (any other) -> 404 26// Snapshot line format (the monitor writes; md_* reads): "SUP <n>" / "SVC <name> <port> <state> <procs> <rwin> <rtot>" 27// argv: [1]=port [2]=keysfile [3]=storefile [4]=realm [5]=snapfile [6]=budget. license_tier: ORIGINAL 28import "nx_resource_arbiter.nx" // shared representable-size bound for checked request allocation 29import "nx_status_daemon.nx" 30import "nx_mgmt_deploy_data_candidate_t185.nx" 31import "nx_builddeploy_lib.nx" 32import "nx_organkind.nx" // seq1492: ROLE beats NAME for promote/deploy eligibility 33import "nx_mgmt_core.nx" 34import "nx_access_lib.nx" // ag_uid_to_level -- the SHARED access-granting path (session uid -> handle -> level) 35import "nx_os_introspect.nx" // pon_pid_cmdline -- name the port-holder PID the snapshot carries (the os-axis rung) 36import "nx_shard_view.nx" // sv_build_shards_json -- the cross-shard fleet view for /api/shards (CAP-SHARD-VIEW) 37import "nx_srcfresh.nx" // sf_src_stale/sf_lag_sec -- is the gate ELF built from its own source? 38import "nx_fio.nx" // fio_unlink -- canonical sovereign unlinkat (shred a bad/aborted staging file), DRY 39import "nx_sha256.nx" // sha256_digest -- optional integrity check of the reassembled artifact on final chunk 40import "nx_buildecho.nx" // be_after_hex -- lift `closure_sha=` out of nx_closurehash's output. ADDITIVE ONLY (2026-08-08): the inline ma_compiled_name below is deliberately left in place, so this edit cannot change the cross-target guard's behaviour; it only adds a receipt. Bite-proven 9/9 by nx_buildecho_gate. 41import "nx_routeguard_lib.nx" // rg_extract/rg_missing -- the DEPLOY CONTRACT guard: refuse a candidate that DROPS live /api routes (5th regression, id=1785447778). Fail-open by construction. 42import "nx_mgmt_upload.nx" // mu_stage_chunk -- the SHIPPED ordered-chunk write primitive (seq0=truncate, seq>0=append); compose it, don't re-open inline (DRY / retire the orphan) 43import "nx_tool_exec_allow.nx" // tea_sync_promote_ms_from + TEA_WINDOW_CONF/TEA_SRC_CONF -- THE ONE OWNER of the edge deadline pair (knowledge/edge_window.conf). /api/gate_run promotes a still-running gate at (window - reply reserve), the instant the tools-API sync lane already does; DERIVED from the conf, never retyped (2026-08-23, lane J) 44const MA_MAGIC_4096: i64 = 4096 // NX-UNNAMED: mechanical, collision-free placeholder -- this name RESTATES the value and so carries no meaning. Replace it with a domain term that says WHY, or move the number to a config row. 45const MA_MAGIC_16384: i64 = 16384 // NX-UNNAMED: mechanical, collision-free placeholder -- this name RESTATES the value and so carries no meaning. Replace it with a domain term that says WHY, or move the number to a config row. 46const MA_MAGIC_8192: i64 = 8192 // NX-UNNAMED: mechanical, collision-free placeholder -- this name RESTATES the value and so carries no meaning. Replace it with a domain term that says WHY, or move the number to a config row. 47const MA_MAGIC_262144: i64 = 262144 // NX-UNNAMED: mechanical, collision-free placeholder -- this name RESTATES the value and so carries no meaning. Replace it with a domain term that says WHY, or move the number to a config row. 48const MA_MAGIC_1024: i64 = 1024 // NX-UNNAMED: mechanical, collision-free placeholder -- this name RESTATES the value and so carries no meaning. Replace it with a domain term that says WHY, or move the number to a config row. 49const MA_MAGIC_2048: i64 = 2048 // NX-UNNAMED: mechanical, collision-free placeholder -- this name RESTATES the value and so carries no meaning. Replace it with a domain term that says WHY, or move the number to a config row. 50const MA_MAGIC_2046: i64 = 2046 // NX-UNNAMED: mechanical, collision-free placeholder -- this name RESTATES the value and so carries no meaning. Replace it with a domain term that says WHY, or move the number to a config row. 51const MA_MAGIC_8190: i64 = 8190 // NX-UNNAMED: mechanical, collision-free placeholder -- this name RESTATES the value and so carries no meaning. Replace it with a domain term that says WHY, or move the number to a config row. 52const MA_MAGIC_65536: i64 = 65536 // NX-UNNAMED: mechanical, collision-free placeholder -- this name RESTATES the value and so carries no meaning. Replace it with a domain term that says WHY, or move the number to a config row. 53const MA_MAGIC_16380: i64 = 16380 // NX-UNNAMED: mechanical, collision-free placeholder -- this name RESTATES the value and so carries no meaning. Replace it with a domain term that says WHY, or move the number to a config row. 54const MA_MAGIC_262140: i64 = 262140 // NX-UNNAMED: mechanical, collision-free placeholder -- this name RESTATES the value and so carries no meaning. Replace it with a domain term that says WHY, or move the number to a config row. 55const MA_MAGIC_60000: i64 = 60000 // NX-UNNAMED: mechanical, collision-free placeholder -- this name RESTATES the value and so carries no meaning. Replace it with a domain term that says WHY, or move the number to a config row. 56const MA_MAGIC_32768: i64 = 32768 // NX-UNNAMED: mechanical, collision-free placeholder -- this name RESTATES the value and so carries no meaning. Replace it with a domain term that says WHY, or move the number to a config row. 57const MA_MAGIC_1400: i64 = 1400 // NX-UNNAMED: mechanical, collision-free placeholder -- this name RESTATES the value and so carries no meaning. Replace it with a domain term that says WHY, or move the number to a config row. 58const MA_MAGIC_2040: i64 = 2040 // NX-UNNAMED: mechanical, collision-free placeholder -- this name RESTATES the value and so carries no meaning. Replace it with a domain term that says WHY, or move the number to a config row. 59const MA_MAGIC_65500: i64 = 65500 // NX-UNNAMED: mechanical, collision-free placeholder -- this name RESTATES the value and so carries no meaning. Replace it with a domain term that says WHY, or move the number to a config row. 60const MA_MAGIC_8000: i64 = 8000 // NX-UNNAMED: mechanical, collision-free placeholder -- this name RESTATES the value and so carries no meaning. Replace it with a domain term that says WHY, or move the number to a config row. 61const MA_MAGIC_16000: i64 = 16000 // NX-UNNAMED: mechanical, collision-free placeholder -- this name RESTATES the value and so carries no meaning. Replace it with a domain term that says WHY, or move the number to a config row. 62const MA_MAGIC_12000: i64 = 12000 // NX-UNNAMED: mechanical, collision-free placeholder -- this name RESTATES the value and so carries no meaning. Replace it with a domain term that says WHY, or move the number to a config row. 63const MA_MAGIC_300000: i64 = 300000 // NX-UNNAMED: mechanical, collision-free placeholder -- this name RESTATES the value and so carries no meaning. Replace it with a domain term that says WHY, or move the number to a config row. 64const MA_MAGIC_4000: i64 = 4000 // NX-UNNAMED: mechanical, collision-free placeholder -- this name RESTATES the value and so carries no meaning. Replace it with a domain term that says WHY, or move the number to a config row. 65const MA_MAGIC_8180: i64 = 8180 // NX-UNNAMED: mechanical, collision-free placeholder -- this name RESTATES the value and so carries no meaning. Replace it with a domain term that says WHY, or move the number to a config row. 66const MA_MAGIC_10000: i64 = 10000 // NX-UNNAMED: mechanical, collision-free placeholder -- this name RESTATES the value and so carries no meaning. Replace it with a domain term that says WHY, or move the number to a config row. 67const MA_MAGIC_2000000: i64 = 2000000 // NX-UNNAMED: mechanical, collision-free placeholder -- this name RESTATES the value and so carries no meaning. Replace it with a domain term that says WHY, or move the number to a config row. 68const MA_MAGIC_1600: i64 = 1600 // NX-UNNAMED: mechanical, collision-free placeholder -- this name RESTATES the value and so carries no meaning. Replace it with a domain term that says WHY, or move the number to a config row. 69const MA_MAGIC_20480: i64 = 20480 // NX-UNNAMED: mechanical, collision-free placeholder -- this name RESTATES the value and so carries no meaning. Replace it with a domain term that says WHY, or move the number to a config row. 70const MA_MAGIC_86400: i64 = 86400 // NX-UNNAMED: mechanical, collision-free placeholder -- this name RESTATES the value and so carries no meaning. Replace it with a domain term that says WHY, or move the number to a config row. 71const MA_MAGIC_19456: i64 = 19456 // NX-UNNAMED: mechanical, collision-free placeholder -- this name RESTATES the value and so carries no meaning. Replace it with a domain term that says WHY, or move the number to a config row. 72 73// ---- ONE NAMED SOURCE FOR THE PROMOTE LEASE TTL (2026-08-20, debt 1787254670) ---------------- 74// It was TWO independent literals: the acquire below passed "300" and the lease-busy refusal advertised 75// retry_after_s:30. An honest caller obeying the advertised backoff re-hit a lock that could not 76// possibly be free for another 270 seconds -- roughly ten wasted round trips per holder, and a retry 77// storm invited by the error message itself. Rule 11: a bound and the advice about that bound must come 78// from the same place, or they drift; this pair had already drifted by 10x and nothing could see it, 79// because neither number was wrong ON ITS OWN. The acquire renders this const to text (nx_lease takes 80// its TTL as argv) and the refusal prints the same const, so they can no longer disagree. 81const MA_PROMOTE_LEASE_TTL_S: i64 = 300 82// THE SAME PAIR, FOUR MORE TIMES, AND THREE OF THEM WORSE. A full-population census of this file 83// (corpus_complete=1) found the build, async-build, deploy and restart lease-busy refusals ALL 84// advertising retry_after_s:30 against TTLs of 600, 600, 600 and 300 -- so the build lanes were 85// TWENTY times short, telling an honest caller to come back nineteen times before the lock can 86// possibly be free. A FIX THAT LIVES IN ONE LANE AND NOT ITS SIBLINGS IS HALF A FIX, AND THE HALF 87// LEFT UNDONE IS INVISIBLE UNTIL SOMEONE IS RETRYING AGAINST IT. 88const MA_BUILD_LEASE_TTL_S: i64 = 600 89const MA_DEPLOY_LEASE_TTL_S: i64 = 600 90const MA_RESTART_LEASE_TTL_S: i64 = 300 91// TS9 ts_retry_after_derived (trafficsafety, 2026-08-30): the wait ADVICE on a lease-busy refusal. 92// The derived-constant half landed earlier (ma_lease_ttl_txt: acquire and refusal read ONE const). 93// Two halves the scalar alone did not give, per the banked Aug-2026 research (RFC 9110 puts no 94// accuracy obligation on Retry-After, so a bare scalar synchronises the herd -- measured on this 95// file's own promote lease; the field-grade mechanism is a DIFFERENT ERROR CLASS, overloaded-do-not- 96// retry, not a better number): 97// (1) at or above TS_NONRETRY_TTL_S the refusal advertises LEASE-HELD-DO-NOT-RETRY and NO wait 98// hint at all -- a lock held for minutes is not a retry situation; the caller queues the work 99// (a deployq row fires via nx_orchestrate on the first pass with headroom) instead of polling 100// a lock that cannot be free sooner. 300 is not tuned: it is the SMALLEST TTL in this file's 101// lease set, so every exclusive lease lands in the do-not-retry class BY CONSTRUCTION; the 102// jitter branch serves any future sub-300s lease honestly rather than being dead code. 103// (2) below the bar the scalar is JITTERED by up to TTL/TS_JITTER_DIV seconds (time-derived -- 104// this estate has no RNG by design), fanning synchronized refusals over a quarter-TTL window. 105const TS_NONRETRY_TTL_S: i64 = 300 106const TS_JITTER_DIV: i64 = 4 107 108const MA_BODYCAP: i64 = 131072 109// UPLOAD PERFORMANCE (scoped full-body read for /api/upload ONLY): the shared nx_http_server_read_request does a 110// SINGLE sys_read, so a chunk body larger than one read (or split across the wire into >1 read) would be TRUNCATED. 111// That capped the client at ~48KB chunks => ~54 handshakes for a 2.6MB artifact (each handshake ~300-400ms off-LAN). 112// This dedicated 2 MiB reassembly buffer lets the /api/upload path carry a MUCH bigger chunk (collapsing ~54 113// handshakes to ~3), WITHOUT touching the shared reader (blast radius = every daemon) and WITHOUT a hang risk: 114// the continue-read is bounded STRICTLY by Content-Length and this cap, and EOF (sys_read<=0) terminates it. A body 115// whose declared Content-Length exceeds this cap is REFUSED (413) -- never a partial-append-then-success. Rule 11: 116// the cap is a named const, not a magic number; Rule 26: still staging-only (ma_do_upload never touches the live artifact). 117const MA_UPLOAD_REQCAP: i64 = 2097152 // 2 MiB -- the scoped upload-request buffer (headers + one big chunk body) 118const MA_UPLOAD_TOOBIG: i64 = 0 - 1 // sentinel: declared Content-Length would overflow MA_UPLOAD_REQCAP -> 413 refuse 119const MA_SHARDS_CONF: *u8 = "/volume1/homes/elderwesto/nishihost/shards.conf" as *u8 // the shard-registry SSOT the control plane reads 120// ACCESS-GRANTING (lined up with the ecosystem, NOT a private mgmt island): the roles registry + uid->handle index 121// are the SAME files the hub gateway reads, so ONE login + ONE roles row (elderwesto=3) grants access everywhere. 122const MA_ROLES: *u8 = "/volume1/ai/hub/roles.tsv" as *u8 123const MA_IDX: *u8 = "/volume1/homes/elderwesto/nishihost/nishi_uid_handle.tsv" as *u8 124const MA_LVL_READ: i64 = 2 // member+ may READ /api/health + /api/services 125const MA_LVL_ACT: i64 = 3 // OPERATOR required for the write actions (deploy/rollback/reconcile/restart) 126// /api/cap/mint tunables (rule-11: every threshold named -- charset/buffer literals stay inline to match the 127// ma_sanitize_* idiom, but the cap lifetime bounds + allow-length cap are real knobs). 128const CM_DAYS_DEFAULT: i64 = 30 // default cap lifetime when `days` is omitted 129const CM_DAYS_MAX: i64 = 730 // 2 years -- upper bound so a mint can't grant a near-eternal cap 130const CM_SECS_PER_DAY: i64 = 86400 // exp = now + days * this 131const CM_ALLOW_MAX: i64 = 480 // max bytes of the allow= csv (bounds the mint scratch buffers) 132const CM_NAME_MAX: i64 = 120 // max bytes of one tool name inside the csv 133 134// ---- response assembly (transport serialization) ---------------------------------------------------- 135 136func ma_emit_json(out: *u8, prefix: *u8, body: *u8, body_n: i64) -> i64 { 137 var o: i64 = sd_cat(out, 0, prefix) 138 o = sd_catn(out, o, body_n) 139 // api-versioning: every response carries the API-Version header (explicit version negotiation, not just a body 140 // field); Vary: Accept declares content-negotiation. Single point so ALL endpoints are covered uniformly. 141 o = sd_cat(out, o, "\r\nAPI-Version: 2\r\nVary: Accept\r\n\r\n" as *u8) 142 var i: i64 = 0 143 while i < body_n { out[o] = body[i]; o = o + 1; i = i + 1 } 144 return o 145} 146 147// content-negotiation: does the request's Accept header ask for text/plain? (index is header-only, so a match can 148// only come from Accept). Server then serves the text representation instead of JSON -> real Accept-driven negotiation. 149func ma_wants_text(req: *u8, req_n: i64) -> i64 { 150 let t: *u8 = "text/plain" as *u8 151 var i: i64 = 0 152 while i + 10 <= req_n { 153 if req[i] == (116 as u8) { 154 var k: i64 = 0 155 while k < 10 { if req[i + k] != t[k] { k = 100 } else { k = k + 1 } } 156 if k == 10 { return 1 } 157 } 158 i = i + 1 159 } 160 return 0 161} 162// ---- THE ONE ROUTE LIST (2026-08-21) -------------------------------------------------------------- 163// MEASURED: this daemon carried TWO hand-maintained route lists -- the plain-text one below and the 164// JSON array clients actually parse (ma_index) -- and they had diverged IN BOTH DIRECTIONS at once: 165// the JSON array was missing /api/promote_toolchain, so a WORKING route (it answers 400, while a real 166// absence answers 404) read as MISSING and cost a full false investigation; and the plain-text list 167// was missing /api/gate_run and /api/proc_kill, which the JSON array had. 168// *TWO HAND-MAINTAINED LISTS OF THE SAME THING WILL DIVERGE, AND NEITHER ONE TELLS YOU WHICH IS STALE. 169// Both emitters now render from THIS literal. Space-separated so the plain-text form IS the literal and 170// the JSON form is one walk of it -- adding a route is ONE edit, and the two can no longer disagree. 171const MA_ROUTES: *u8 = "/api/login /api/health /api/release_identity /api/services /api/upload /api/deploy /api/deploy_status /api/unpack /api/build /api/gate_run /api/proc_kill /api/promote /api/promote_toolchain /api/tools/register /api/cap/mint /api/hostctl /api/promote_content /api/rollback /api/reconcile /api/restart /api/openapi.json /api/migrate /api/update /api/compare/registry /api/compare/upsert /api/compare/regen /api/compare/publish" 172const MA_RT_SP: i64 = 32 // ' ' -- the separator in MA_ROUTES 173const MA_RT_QUOTE: i64 = 34 // '"' -- JSON string delimiter 174const MA_RT_COMMA: i64 = 44 // ',' -- JSON element separator 175const MA_RT_BUF: i64 = 4096 // one index body; MA_ROUTES is ~420 B and the JSON wrapper ~250 B 176// Render MA_ROUTES as JSON array ELEMENTS ("a","b","c") -- the caller supplies the brackets. 177func ma_routes_json(b: *u8, off: i64) -> i64 { 178 var o: i64 = off 179 var i: i64 = 0 180 var first: i64 = 1 181 while MA_ROUTES[i] != (0 as u8) { 182 if MA_ROUTES[i] == (MA_RT_SP as u8) { 183 i = i + 1 184 } else { 185 if first == 0 { b[o] = MA_RT_COMMA as u8; o = o + 1 } 186 first = 0 187 b[o] = MA_RT_QUOTE as u8; o = o + 1 188 var run: i64 = 1 189 while run == 1 { 190 if MA_ROUTES[i] == (0 as u8) { run = 0 } else { 191 if MA_ROUTES[i] == (MA_RT_SP as u8) { run = 0 } else { 192 b[o] = MA_ROUTES[i]; o = o + 1; i = i + 1 193 } 194 } 195 } 196 b[o] = MA_RT_QUOTE as u8; o = o + 1 197 } 198 } 199 return o 200} 201func ma_index_text(out: *u8) -> i64 { 202 let body: *u8 = sys_mmap(MA_RT_BUF) 203 var o: i64 = sd_cat(body, 0, "nishi-mgmt API v2\nspec: /api/openapi.json\nroutes: " as *u8) 204 o = sd_cat(body, o, MA_ROUTES) 205 o = sd_cat(body, o, "\n" as *u8) 206 body[o] = 0 as u8 207 return ma_emit_json(out, "HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\nConnection: close\r\nContent-Length: " as *u8, body, o) 208} 209// NISHI-NATIVE API CONSOLE (NOT swagger/openapi-ui): a fully-sovereign, self-contained console (no CDN, no third-party 210// UI lib) rendered from OUR OWN /api index, surfacing every ecosystem rung -- mgmt API + MCP agent surface (tools/ 211// resources/prompts) + search + the live SOTA critic + SSE + binary RPC. OpenAPI kept only as an interop LINK, not the 212// UI. (nx_cc trap: no '#' or '!' in the literal -> color names, no doctype.) 213func ma_docs(out: *u8) -> i64 { 214 let body: *u8 = "<html><head><meta charset=utf-8><title>Nishi Sovereign API Console</title><style>body{font-family:system-ui;max-width:64em;margin:0 auto;padding:1.5em;background:snow;color:midnightblue}h1{color:seagreen;margin-bottom:.1em}h2{color:seagreen;border-bottom:2px solid mediumseagreen;padding-bottom:.2em;margin-top:1.4em}.sub{color:slategray;margin-top:0}.card{background:white;border:1px solid gainsboro;border-left:4px solid seagreen;border-radius:6px;padding:.6em 1em;margin:.5em 0}code{background:honeydew;color:darkgreen;padding:2px 6px;border-radius:3px}a{color:seagreen}.tag{font-size:.75em;background:mediumseagreen;color:white;padding:1px 7px;border-radius:10px;margin-left:.4em}</style></head><body><h1>Nishi Sovereign API Console</h1><p class=sub>Own TLS 1.3, own auth (OPAQUE + object-capability), never-brick deploys. Zero third-party framework or UI library.</p><h2>Management control plane</h2><div id=routes>loading...</div><h2>Agent surface (MCP)</h2><div class=card><code>POST /mcp</code> <span class=tag>JSON-RPC 2.0</span><br>tools + resources + prompts. Auth: X-Nishi-Cap / Authorization: Bearer / params._cap.</div><div class=card><code>nishi_search</code> / <code>nishi_doc</code><br>sovereign corpus search + document fetch.</div><div class=card><code>nx_ecosystem_maturity_rollup</code> <span class=tag>live</span><br>measured, liar-killed per-domain SOTA grade.</div><div class=card><code>nx_mgmt</code> <span class=tag>admin</span><br>build / deploy / reconcile / restart over the never-brick control plane.</div><h2>Streaming + RPC</h2><div class=card><code>GET /api/events</code> <span class=tag>SSE</span><br>text/event-stream status events (reconnecting).</div><div class=card><code>POST /api/rpc</code> <span class=tag>binary</span><br>sovereign contract-first binary RPC (contract: <a href=/api/rpc.contract>/api/rpc.contract</a>).</div><h2>Machine-readable</h2><div class=card><a href=/api/openapi.json>/api/openapi.json</a> OpenAPI 3.1 for interop &middot; <a href=/api/inventory>/api/inventory</a> versioned artifacts</div><script>fetch('/api').then(function(r){return r.json()}).then(function(s){var h='<p class=sub>version '+s.version+'</p>';var rs=s.routes;for(var i=0;i<rs.length;i++){h+='<div class=card><code>'+rs[i]+'</code></div>'}document.getElementById('routes').innerHTML=h})</script></body></html>" as *u8 215 return ma_emit_json(out, "HTTP/1.1 200 OK\r\nContent-Type: text/html; charset=utf-8\r\nConnection: close\r\nContent-Length: " as *u8, body, sd_len(body)) 216} 217// webhooks/SSE: GET /api/events -> text/event-stream. Emits status events then closes; EventSource clients auto- 218// reconnect per the retry hint (fits our single-accept server -- no long-lived hold). Real event-driven delivery. 219func ma_events(out: *u8) -> i64 { 220 var o: i64 = sd_cat(out, 0, "HTTP/1.1 200 OK\r\nContent-Type: text/event-stream\r\nCache-Control: no-cache\r\nConnection: close\r\nAPI-Version: 2\r\n\r\n" as *u8) 221 o = sd_cat(out, o, "retry: 5000\nevent: hello\ndata: {\"api\":\"nishi-mgmt\",\"stream\":\"status\"}\n\n" as *u8) 222 o = sd_cat(out, o, "event: tick\ndata: {\"ts\":" as *u8) 223 o = sd_catn(out, o, sys_now_realtime_sec()) 224 o = sd_cat(out, o, ",\"health\":\"/api/health\",\"deploy_status\":\"/api/deploy_status\",\"inventory\":\"/api/inventory\"}\n\n" as *u8) 225 return o 226} 227// binary emitter (payload may contain NUL -> explicit length, not sd_len). 228func ma_emit_binary(out: *u8, body: *u8, body_n: i64) -> i64 { 229 var o: i64 = sd_cat(out, 0, "HTTP/1.1 200 OK\r\nContent-Type: application/octet-stream\r\nConnection: close\r\nAPI-Version: 2\r\nContent-Length: " as *u8) 230 o = sd_catn(out, o, body_n) 231 o = sd_cat(out, o, "\r\n\r\n" as *u8) 232 var i: i64 = 0 233 while i < body_n { out[o] = body[i]; o = o + 1; i = i + 1 } 234 return o 235} 236// grpc-contract-first: SOVEREIGN binary contract-first RPC. POST /api/rpc body = [u32be method_id][args]; response = 237// [u32be status][payload]. Own framing (not gRPC/HTTP2/protobuf -- deliberate, same sovereignty stance as our TLS). 238func ma_rpc(req: *u8, req_n: i64, out: *u8) -> i64 { 239 let boff: i64 = sd_body_off(req, req_n) 240 let body: *u8 = ((req as i64) + boff) as *u8 241 let body_n: i64 = req_n - boff 242 var method: i64 = 0 243 if body_n >= 4 { method = ((body[0] as i64) << 24) | ((body[1] as i64) << 16) | ((body[2] as i64) << 8) | (body[3] as i64) } 244 let resp: *u8 = sys_mmap(MA_MAGIC_4096) 245 resp[0] = 0 as u8; resp[1] = 0 as u8; resp[2] = 0 as u8; resp[3] = 0 as u8 246 var rn: i64 = 4 247 if method == 1 { 248 let p: *u8 = "PONG" as *u8; var k: i64 = 0; while k < 4 { resp[rn] = p[k]; rn = rn + 1; k = k + 1 } 249 } else { if method == 2 { 250 let p: *u8 = "nishi-mgmt v2" as *u8; var k: i64 = 0; while p[k] != (0 as u8) { resp[rn] = p[k]; rn = rn + 1; k = k + 1 } 251 } else { 252 resp[3] = 1 as u8 253 let p: *u8 = "unknown-method" as *u8; var k: i64 = 0; while p[k] != (0 as u8) { resp[rn] = p[k]; rn = rn + 1; k = k + 1 } 254 } } 255 return ma_emit_binary(out, resp, rn) 256} 257func ma_rpc_contract(out: *u8) -> i64 { 258 let body: *u8 = "{\"rpc\":\"nishi-sovereign-binary-rpc\",\"transport\":\"POST /api/rpc over TLS 1.3\",\"framing\":{\"request\":\"[u32be method_id][args]\",\"response\":\"[u32be status][payload]\"},\"note\":\"sovereign binary contract-first RPC -- own framing, not gRPC/HTTP2/protobuf (same sovereignty stance as our own TLS stack)\",\"methods\":[{\"id\":1,\"name\":\"ping\",\"returns\":\"PONG\"},{\"id\":2,\"name\":\"version\",\"returns\":\"version string\"}]}" as *u8 259 return ma_emit_200(out, body) 260} 261// inventory-mgmt-api9: a versioned inventory of the managed deployable artifacts. Each is never-brick-managed (a 262// staged .new + a rollback .prev), built via /api/build and promoted via /api/deploy; GET /api/deploy_status gives 263// the live version verdict. Public discovery (artifact NAMES only, no secrets). 264// ★★★★★★ DERIVED, NOT DECLARED (R0, 2026-07-31). This list was HAND-AUTHORED and had drifted: it named 265// nx_hub_gw.elf and nx_torrent_gw.elf as "managed deployable artifacts" while deploy_targets.conf -- 266// the allowlist /api/deploy ACTUALLY READS -- contained NEITHER. A caller who trusted this route was 267// told a fix could be landed that could not. Declared coverage overstated real coverage, and only the 268// smaller number was ever true. 269// A DERIVED ARTIFACT MUST NOT BE AUTHORABLE: the moment a summary can be written by hand it can disagree 270// with the thing it summarises. This now reads the SAME FILE the deploy path reads, so the two cannot 271// diverge -- if a row is absent the route says so, which is the honest answer. 272// AN INVENTORY THAT OVERSTATES COVERAGE IS WORSE THAN NO INVENTORY: it converts a known gap into a 273// false assurance. 274func ma_inventory(out: *u8) -> i64 { 275 let b: *u8 = sys_mmap(MA_MAGIC_16384) 276 var o: i64 = 0 277 o = sd_cat(b, o, "{\"inventory\":\"managed deployable artifacts -- DERIVED from deploy_targets.conf, the same allowlist /api/deploy reads (never hand-authored: a declared list drifts from the real one and only the smaller is true)\",\"source\":\"deploy_targets.conf\",\"targets\":[" as *u8) 278 279 let lp: *i64 = sys_mmap(16) as *i64 280 lp[0] = 0 281 let f: *u8 = sys_read_file("deploy_targets.conf" as *u8, lp) 282 let n: i64 = lp[0] 283 var count: i64 = 0 284 if n > 0 { 285 var line: i64 = 0 286 while line < n { 287 var eol: i64 = line 288 var es: i64 = 0 289 while es == 0 { if eol >= n { es = 1 } else { if f[eol] == (10 as u8) { es = 1 } else { eol = eol + 1 } } } 290 var skip: i64 = 0 291 if line >= eol { skip = 1 } 292 if skip == 0 { if f[line] == (35 as u8) { skip = 1 } } 293 if skip == 0 { 294 var p: i64 = line 295 var fe: i64 = 0 296 while fe == 0 { if p < eol { if f[p] == (32 as u8) { fe = 1 } else { p = p + 1 } } else { fe = 1 } } 297 if p > line { 298 if count > 0 { o = sd_cat(b, o, "," as *u8) } 299 o = sd_cat(b, o, "\"" as *u8) 300 var z: i64 = line 301 while z < p { b[o] = f[z]; o = o + 1; z = z + 1 } 302 o = sd_cat(b, o, "\"" as *u8) 303 count = count + 1 304 } 305 } 306 line = eol + 1 307 } 308 } 309 o = sd_cat(b, o, "],\"count\":" as *u8) 310 // Inline decimal append -- there is no sd_catn in this file, and REFERENCING A HELPER THAT DOES NOT 311 // EXIST is how a build breaks for a reason unrelated to the change being made. 312 if count <= 0 { b[o] = 48 as u8; o = o + 1 } else { 313 let tmp: *u8 = sys_mmap(32) 314 var m: i64 = count 315 var k: i64 = 0 316 while m > 0 { tmp[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 } 317 var j: i64 = k - 1 318 while j >= 0 { b[o] = tmp[j]; o = o + 1; j = j - 1 } 319 } 320 // NON-VACUITY: if the conf could not be read the list is EMPTY, and an empty inventory must be 321 // legible as "I could not read the source", never as "nothing is deployable". 322 if count <= 0 { 323 o = sd_cat(b, o, ",\"warning\":\"ZERO targets parsed -- deploy_targets.conf unreadable or empty. This is a READ FAILURE, not an empty fleet.\"" as *u8) 324 } 325 o = sd_cat(b, o, ",\"lifecycle\":{\"build\":\"POST /api/build\",\"stage\":\"POST /api/upload\",\"promote\":\"POST /api/deploy\",\"version_verdict\":\"GET /api/deploy_status\",\"rollback\":\"POST /api/rollback\"}}" as *u8) 326 b[o] = 0 as u8 327 return ma_emit_200(out, b) 328} 329func ma_index(out: *u8) -> i64 { 330 // RENDERED FROM MA_ROUTES -- the same literal ma_index_text prints. The hand-maintained twin that 331 // stood here had already drifted from it in BOTH directions; there is now nothing left to keep in sync. 332 let body: *u8 = sys_mmap(MA_RT_BUF) 333 var o: i64 = sd_cat(body, 0, "{\"api\":\"nishi-mgmt\",\"version\":2,\"spec\":\"/api/openapi.json\",\"routes\":[" as *u8) 334 o = ma_routes_json(body, o) 335 o = sd_cat(body, o, "],\"_links\":{\"self\":{\"href\":\"/api\"},\"spec\":{\"href\":\"/api/openapi.json\"},\"health\":{\"href\":\"/api/health\"},\"services\":{\"href\":\"/api/services\"},\"deploy_status\":{\"href\":\"/api/deploy_status\"}}}" as *u8) 336 body[o] = 0 as u8 337 return ma_emit_json(out, "HTTP/1.1 200 OK\r\nContent-Type: application/json\r\nConnection: close\r\nContent-Length: " as *u8, body, o) 338} 339 340// ---- /api/openapi.json (SOTA machine-readable API description == Swagger; enables API-only agent use) -------- 341// GENERATED from the route table (data->JSON), not hand-authored. Public (specs are discovery). Declares the 342// OPAQUE session security scheme + the RFC9457 Problem schema so errors are machine-typed. 343func op_path(out: *u8, o: i64, path: *u8, method: *u8, summary: *u8, authed: i64) -> i64 { 344 o = sd_cat(out, o, "\"" as *u8); o = sd_cat(out, o, path); o = sd_cat(out, o, "\":{\"" as *u8); o = sd_cat(out, o, method) 345 o = sd_cat(out, o, "\":{\"summary\":\"" as *u8); o = sd_cat(out, o, summary); o = sd_cat(out, o, "\",\"security\":" as *u8) 346 if authed == 1 { o = sd_cat(out, o, "[{\"nishiSession\":[]}]" as *u8) } else { o = sd_cat(out, o, "[]" as *u8) } 347 // json-schema-params: POST endpoints declare a typed requestBody; every op declares typed 200 + Problem-typed errors. 348 if (method[0] as i64) == 112 { // 'p' -> post 349 o = sd_cat(out, o, ",\"requestBody\":{\"content\":{\"application/x-www-form-urlencoded\":{\"schema\":{\"type\":\"object\",\"additionalProperties\":{\"type\":\"string\"}}}}}" as *u8) 350 } 351 o = sd_cat(out, o, ",\"responses\":{\"200\":{\"description\":\"ok\",\"content\":{\"application/json\":{\"schema\":{\"type\":\"object\"}}}},\"400\":{\"description\":\"bad request\",\"content\":{\"application/problem+json\":{\"schema\":{\"$ref\":\"#/components/schemas/Problem\"}}}},\"401\":{\"description\":\"unauthorized\"},\"403\":{\"description\":\"insufficient level\"}}}}" as *u8) 352 return o 353} 354func ma_openapi(out: *u8) -> i64 { 355 let b: *u8 = sys_mmap(MA_MAGIC_16384); var o: i64 = 0 356 o = sd_cat(b, o, "{\"openapi\":\"3.1.0\",\"info\":{\"title\":\"Nishi Sovereign Management API\",\"version\":\"2\",\"description\":\"Sovereign control plane: deploy any binary + run any control action off-LAN. OPAQUE-PAKE auth, never-brick staged deploys (health+auto-rollback), own TLS 1.3.\"},\"servers\":[{\"url\":\"https://nishifamily.com\"}]," as *u8) 357 o = sd_cat(b, o, "\"components\":{\"securitySchemes\":{\"nishiSession\":{\"type\":\"apiKey\",\"in\":\"header\",\"name\":\"X-Nishi-Session\",\"description\":\"OPAQUE-PAKE session token from POST /api/login\"}},\"schemas\":{\"Problem\":{\"type\":\"object\",\"description\":\"RFC9457 problem detail\",\"properties\":{\"type\":{\"type\":\"string\"},\"title\":{\"type\":\"string\"},\"status\":{\"type\":\"integer\"},\"detail\":{\"type\":\"string\"},\"instance\":{\"type\":\"string\"}}}}}," as *u8) 358 o = sd_cat(b, o, "\"paths\":{" as *u8) 359 o = op_path(b, o, "/api/login" as *u8, "post" as *u8, "OPAQUE-PAKE login -> session token" as *u8, 0) 360 o = sd_cat(b, o, "," as *u8); o = op_path(b, o, "/api/health" as *u8, "get" as *u8, "control-plane health snapshot" as *u8, 1) 361 o = sd_cat(b, o, "," as *u8); o = op_path(b, o, "/api/release_identity", "get", "SHA-256 of the executable answering this request; authenticated process identity, not a health or hardware attestation", 1) 362 o = sd_cat(b, o, "," as *u8); o = op_path(b, o, "/api/services" as *u8, "get" as *u8, "per-service status" as *u8, 1) 363 o = sd_cat(b, o, "," as *u8); o = op_path(b, o, "/api/upload" as *u8, "post" as *u8, "stage a binary (.new; sha256; never promotes)" as *u8, 1) 364 o = sd_cat(b, o, "," as *u8); o = op_path(b, o, "/api/deploy" as *u8, "post" as *u8, "promote a registry target (validate->promote->async health+auto-rollback watchdog)" as *u8, 1) 365 o = sd_cat(b, o, "," as *u8); o = op_path(b, o, "/api/deploy_status" as *u8, "get" as *u8, "last deploy watchdog verdict (RUNNING|DEPLOYED-GREEN|ROLLED-BACK)" as *u8, 1) 366 o = sd_cat(b, o, "," as *u8); o = op_path(b, o, "/api/unpack" as *u8, "post" as *u8, "unpack a staged source-tree .pack blob into an allowlisted NAS dir (build-over-API tree-sync). REQUIRES sha256=<hex of the pack YOU uploaded>: the staging slot is shared across sessions, so the unpack is pinned to your exact bytes and REFUSES on mismatch rather than applying a tree you never reviewed (seq1807)" as *u8, 1) 367 o = sd_cat(b, o, "," as *u8); o = op_path(b, o, "/api/ship" as *u8, "post" as *u8, "BUILD then PROMOTE-or-DEPLOY then VERIFY in ONE call: {target,confirm=yes,[allow_capability_loss=yes],[deploy_target=<deploy_targets.conf row>]}. Without deploy_target it promotes a one-shot organ; WITH it the artefact takes the DAEMON path (/api/deploy: validate->promote->http health->auto-rollback) and the reply names route=deploy plus the armed watchdog. The deploy ROW NAME differs from the build target (build nx_mgmt_api, deploy row mgmtapi) so it is taken explicitly and never guessed. No nx_stage_alias step is needed or performed -- /api/deploy already falls back from <t>.elf.new to <t>.sov.elf.new, so that step in the old shell recipe was redundant (measured 2026-08-07). Delegates verbatim to /api/build and /api/promote, so build admission, the D001 ratchet, tree-canon, provenance and the staging-hygiene guard all apply unchanged -- it is a composition, not a second deploy path. Hashes the staged bytes itself and passes them as expect_sha256, closing the stale-artefact window the three-call loop leaves open, then RE-READS the live file and returns staged_sha256, live_sha256 and verified. A failed build is passed through unchanged. NOTE: it holds the connection for the whole compile, so a slow target can exceed the edge window and return 503 while the ship COMPLETES -- the artefact, not the response, is authoritative" as *u8, 1) 368 o = sd_cat(b, o, "," as *u8); o = op_path(b, o, "/api/build" as *u8, "post" as *u8, "compile a target on the NAS (build-over-API) -> stage <target>.sov.elf.new for /api/deploy; on failure returns BUILD-FAILED with a diag tail of the nx_cc/nxasm output plus diag_errors, a window anchored at the first nx_parse: line (multi-error recovery leaves error lines mid-log) (fail-loud)" as *u8, 1) 369 o = sd_cat(b, o, "," as *u8); o = op_path(b, o, "/api/promote" as *u8, "post" as *u8, "promote a built one-shot organ ELF (<target>.sov.elf.new -> <target>.elf); STRUCTURAL policy: daemon/oracle names always refused -> /api/deploy, any owner-staged one-shot promotable; confirm=yes; never-brick .prev backup" as *u8, 1) 370 o = sd_cat(b, o, "," as *u8); o = op_path(b, o, "/api/tools/register" as *u8, "post" as *u8, "expose an organ as an MCP tool (append GREEN tool_allowlist.conf row + optional tool_schemas.conf row); {name,elf,confirm=yes,[args],[title],[update=yes]}; fail-closed + idempotent; update=yes atomically REPLACES an existing row (repoint elf/args; can never create); callable via the tools daemon's hot-read, discoverable after nx_toolreg_reconcile" as *u8, 1) 371 o = sd_cat(b, o, "," as *u8); o = op_path(b, o, "/api/cap/mint" as *u8, "post" as *u8, "mint a root tools-capability token via the on-NAS oracle; {allow=<csv of registered tools>,confirm=yes,[days],[nonce]}; least-authority (* refused, every name must be registered), audited in cap_consent.log" as *u8, 1) 372 o = sd_cat(b, o, "," as *u8); o = op_path(b, o, "/api/hostctl" as *u8, "post" as *u8, "run one allowlisted control action (status/torstat/routerctl/kick*/trackerrefresh)" as *u8, 1) 373 o = sd_cat(b, o, "," as *u8); o = op_path(b, o, "/api/restart" as *u8, "post" as *u8, "restart a supervised service" as *u8, 1) 374 o = sd_cat(b, o, "," as *u8); o = op_path(b, o, "/api/rollback" as *u8, "post" as *u8, "roll back a deploy" as *u8, 1) 375 o = sd_cat(b, o, "," as *u8); o = op_path(b, o, "/api/promote_content" as *u8, "post" as *u8, "promote a staged static file" as *u8, 1) 376 o = sd_cat(b, o, "," as *u8); o = op_path(b, o, "/api/promote_toolchain" as *u8, "post" as *u8, "promote a staged BUILD TOOLCHAIN binary into buildroot/_offc -- ELF-validated, .prev-banked, canary-compiled+run, auto-rollback on failure" as *u8, 1) 377 o = sd_cat(b, o, "," as *u8); o = op_path(b, o, "/api/compare/registry" as *u8, "get" as *u8, "the Nishi Compare registry SSOT (text/plain, save-as-is)" as *u8, 1) 378 o = sd_cat(b, o, "," as *u8); o = op_path(b, o, "/api/compare/upsert" as *u8, "post" as *u8, "merge ONE registry line by /compare/<domain> key (commutative across domains; replaced line kept in .hist) then regen the hub" as *u8, 1) 379 o = sd_cat(b, o, "," as *u8); o = op_path(b, o, "/api/compare/regen" as *u8, "post" as *u8, "regenerate /compare hub index.html + api.json from the SSOT (idempotent)" as *u8, 1) 380 o = sd_cat(b, o, "," as *u8); o = op_path(b, o, "/api/compare/publish" as *u8, "post" as *u8, "promote the staged compare.page bytes as /compare/<domain> page|frontier|bench|api (sha256-pinned, confirm=yes)" as *u8, 1) 381 o = sd_cat(b, o, "," as *u8); o = op_path(b, o, "/api/openapi.json" as *u8, "get" as *u8, "this OpenAPI 3.1 spec (machine-readable)" as *u8, 0) 382 o = sd_cat(b, o, "}}" as *u8) 383 return ma_emit_json(out, "HTTP/1.1 200 OK\r\nContent-Type: application/json\r\nConnection: close\r\nContent-Length: " as *u8, b, o) 384} 385 386// RFC 9457 Problem Details: all error responses are application/problem+json with type/title/status members. 387func ma_emit_404(out: *u8) -> i64 { 388 let body: *u8 = "{\"type\":\"about:blank\",\"title\":\"Not Found\",\"status\":404,\"detail\":\"no such route\"}" as *u8 389 return ma_emit_json(out, "HTTP/1.1 404 Not Found\r\nContent-Type: application/problem+json\r\nConnection: close\r\nContent-Length: " as *u8, body, sd_len(body)) 390} 391 392func ma_emit_403(out: *u8) -> i64 { 393 let body: *u8 = "{\"type\":\"about:blank\",\"title\":\"Forbidden\",\"status\":403,\"detail\":\"your access level is insufficient for this action\"}" as *u8 394 return ma_emit_json(out, "HTTP/1.1 403 Forbidden\r\nContent-Type: application/problem+json\r\nConnection: close\r\nContent-Length: " as *u8, body, sd_len(body)) 395} 396 397func ma_emit_501(out: *u8) -> i64 { 398 let body: *u8 = "{\"type\":\"about:blank\",\"title\":\"Not Implemented\",\"status\":501,\"detail\":\"route exists; action wired in a later rung\"}" as *u8 399 return ma_emit_json(out, "HTTP/1.1 501 Not Implemented\r\nContent-Type: application/problem+json\r\nConnection: close\r\nContent-Length: " as *u8, body, sd_len(body)) 400} 401 402// merge the caller's {"error":"..."} body into an RFC9457 problem+json object (type/title/status standard 403// members + the caller's "error" as an extension member) -> every /api 400 is machine-typed, zero caller churn. 404// Extract the target the BUILDER said it compiled, from its own echo: 405// [hostctl] buildrun: compile 'nx_seg_store_gate' on the NAS (nx_cc -> nxasm) 406// Returns 1 and fills `out` when the marker is found, 0 otherwise. Scans the WHOLE capture -- the echo is 407// not at offset 0, and a capture that merges stdout and stderr puts it somewhere different again. 408// ABSENCE IS NOT A MISMATCH: an older builder that does not print this line yields 0, and the caller then 409// proceeds exactly as before. A guard that cannot see its evidence must abstain, never accuse -- turning 410// "I could not look" into "it is wrong" would break every build the moment the echo format changed. 411func ma_compiled_name(buf: *u8, n: i64, out: *u8) -> i64 { 412 let k: *u8 = "compile '" as *u8 413 var i: i64 = 0 414 while i + 9 <= n { 415 var m: i64 = 0 416 var hit: i64 = 1 417 while m < 9 { if buf[i+m] != k[m] { hit = 0; m = 9 } else { m = m + 1 } } 418 if hit == 1 { 419 var s: i64 = i + 9 420 var o: i64 = 0 421 while s < n { 422 let c: i64 = buf[s] as i64 423 if c == 39 { s = n } else { 424 if o < 250 { out[o] = buf[s]; o = o + 1 } 425 s = s + 1 426 } 427 } 428 out[o] = 0 as u8 429 if o == 0 { return 0 } 430 return 1 431 } 432 i = i + 1 433 } 434 return 0 435} 436 437func ma_emit_400(out: *u8, body: *u8) -> i64 { 438 let b2: *u8 = sys_mmap(MA_MAGIC_4096); var o: i64 = 0 439 o = sd_cat(b2, o, "{\"type\":\"about:blank\",\"title\":\"Bad Request\",\"status\":400," as *u8) 440 var i: i64 = 0; if body[0] == (123 as u8) { i = 1 } // skip the caller body's leading '{' 441 while body[i] != (0 as u8) { b2[o] = body[i]; o = o + 1; i = i + 1 } 442 b2[o] = 0 as u8 443 return ma_emit_json(out, "HTTP/1.1 400 Bad Request\r\nContent-Type: application/problem+json\r\nConnection: close\r\nContent-Length: " as *u8, b2, o) 444} 445 446func ma_emit_200(out: *u8, body: *u8) -> i64 { 447 return ma_emit_json(out, "HTTP/1.1 200 OK\r\nContent-Type: application/json\r\nConnection: close\r\nContent-Length: " as *u8, body, sd_len(body)) 448} 449 450// 503 + Retry-After for BUILD ADMISSION (seq708/768/1390). RFC9457 problem+json like the other emitters, 451// so callers stay machine-typed. Retry-After:30 makes the refusal ACTIONABLE -- a client that gets this 452// knows the host is memory-wedged and when to come back, instead of the current failure mode where the 453// build is accepted, the host OOMs, the supervisor reaps nx_mgmt_api, and the caller sees the deploy 454// path vanish with no explanation at all. A stated refusal beats a silent reap. 455func ma_emit_503(out: *u8, body: *u8) -> i64 { 456 let b2: *u8 = sys_mmap(MA_MAGIC_4096); var o: i64 = 0 457 o = sd_cat(b2, o, "{\"type\":\"about:blank\",\"title\":\"Service Unavailable\",\"status\":503," as *u8) 458 var i: i64 = 0; if body[0] == (123 as u8) { i = 1 } 459 while body[i] != (0 as u8) { b2[o] = body[i]; o = o + 1; i = i + 1 } 460 b2[o] = 0 as u8 461 return ma_emit_json(out, "HTTP/1.1 503 Service Unavailable\r\nContent-Type: application/problem+json\r\nRetry-After: 30\r\nConnection: close\r\nContent-Length: " as *u8, b2, o) 462} 463 464// 413 for an upload chunk whose declared Content-Length would overflow the scoped MA_UPLOAD_REQCAP buffer. 465// Fail-closed: emitted BEFORE any body is read/appended, so nothing is staged (the client must use a smaller chunk). 466func ma_emit_413(out: *u8) -> i64 { 467 let body: *u8 = "{\"error\":\"chunk too large; exceeds MA_UPLOAD_REQCAP (use a smaller chunk)\"}" as *u8 468 return ma_emit_json(out, "HTTP/1.1 413 Payload Too Large\r\nContent-Type: application/json\r\nConnection: close\r\nContent-Length: " as *u8, body, sd_len(body)) 469} 470 471func ma_comma(body: *u8, b: i64, first: *i64) -> i64 { 472 if first[0] == 1 { first[0] = 0; return b } 473 return sd_cat(body, b, "," as *u8) 474} 475 476// ---- /api/services (transport: read via DATA, classify via CORE, serialize here) -------------------- 477 478func ma_emit_services(snap: *u8, snap_n: i64, out: *u8) -> i64 { 479 let offs: *i64 = sys_mmap(64) as *i64 480 let lens: *i64 = sys_mmap(64) as *i64 481 let body: *u8 = sys_mmap(MA_BODYCAP) 482 var b: i64 = sd_cat(body, 0, "{\"services\":[" as *u8) 483 var first: i64 = 1 484 var cur: i64 = 0 485 while cur < snap_n { 486 let le: i64 = md_eol(snap, snap_n, cur) 487 let nf: i64 = md_split(snap, cur, le, offs, lens, 8) 488 if nf >= 6 { 489 if md_tok_eq(snap, offs[0], lens[0], "SVC" as *u8) == 1 { 490 if first == 0 { b = sd_cat(body, b, "," as *u8) } 491 first = 0 492 let procs: i64 = md_slice_atoi(snap, offs[4], lens[4]) 493 let rwin: i64 = md_slice_atoi(snap, offs[5], lens[5]) 494 let dup: i64 = mc_is_dup(procs) 495 let lp: i64 = mc_is_loop(rwin) 496 b = sd_cat(body, b, "{\"name\":\"" as *u8) 497 b = md_cat_slice(body, b, snap, offs[1], lens[1]) 498 b = sd_cat(body, b, "\",\"port\":" as *u8) 499 b = sd_catn(body, b, md_slice_atoi(snap, offs[2], lens[2])) 500 b = sd_cat(body, b, ",\"state\":\"" as *u8) 501 b = md_cat_slice(body, b, snap, offs[3], lens[3]) 502 b = sd_cat(body, b, "\",\"procs\":" as *u8) 503 b = sd_catn(body, b, procs) 504 b = sd_cat(body, b, ",\"dup\":" as *u8) 505 b = sd_catn(body, b, dup) 506 b = sd_cat(body, b, ",\"loop\":" as *u8) 507 b = sd_catn(body, b, lp) 508 if nf >= 8 { 509 let holder: i64 = md_slice_atoi(snap, offs[7], lens[7]) // the 8th snapshot token = who REALLY holds the port 510 b = sd_cat(body, b, ",\"holder_pid\":" as *u8); b = sd_catn(body, b, holder) 511 if holder > 0 { 512 var mism: i64 = 0; if md_tok_eq(snap, offs[3], lens[3], "DOWN" as *u8) == 1 { mism = 1 } // DOWN + a foreign holder = a squatter 513 b = sd_cat(body, b, ",\"port_mismatch\":" as *u8); b = sd_catn(body, b, mism) 514 b = sd_cat(body, b, ",\"holder_cmd\":\"" as *u8) 515 let hc: *u8 = sys_mmap(512); let hcn: i64 = pon_pid_cmdline(holder, hc, 512) 516 var z: i64 = 0 517 while z < hcn { let c: i64 = hc[z] & 0xff; if c == 34 { body[b] = 39 as u8; b = b + 1 } else { if c == 92 { body[b] = 47 as u8; b = b + 1 } else { body[b] = c as u8; b = b + 1 } } z = z + 1 } // JSON-safe: " -> ' , \ -> / 518 b = sd_cat(body, b, "\"" as *u8) 519 } 520 } 521 b = sd_cat(body, b, "}" as *u8) 522 } 523 } 524 cur = le + 1 525 } 526 b = sd_cat(body, b, "]}" as *u8) 527 return ma_emit_200(out, body) 528} 529 530func ma_emit_shards(out: *u8) -> i64 { 531 let body: *u8 = sys_mmap(MA_BODYCAP) 532 sv_build_shards_json(MA_SHARDS_CONF, body, MA_BODYCAP) 533 return ma_emit_200(out, body) 534} 535 536func ma_emit_services_file(snapfile: *u8, out: *u8) -> i64 { 537 let sbox: *i64 = sys_mmap(16) as *i64 538 let page: *u8 = md_read_file(snapfile, sbox) 539 if (page as i64) == 0 { 540 let empty: *u8 = sys_mmap(1) 541 return ma_emit_services(empty, 0, out) 542 } 543 return ma_emit_services(page, sbox[0], out) 544} 545 546// ---- /api/nodes (swarm MONITOR pillar: read THIS node's LIVE /proc directly -- the mgmt daemon runs on the NAS) -- 547// BOUNDED /proc reads (openat+read+close); NEVER sys_read_file (mmaps 4 GiB/call unfreed = the supervisor ENOMEM 548// F-class root, nx_hostctl.nx:311). Instantaneous only -- no CPU%-sample sleep -> never stalls the serve loop; 549// loadavg-per-core IS the scheduler-grade pressure signal (runqueue depth). SPOT verdict folded in. 550func mnp_readproc(path: *u8, buf: *u8, cap: i64) -> i64 { 551 if cap <= 0 { return 0 - 1 } 552 buf[0] = 0 as u8 553 let fd: i64 = sys_openat_rd(path) 554 if fd < 0 { return 0 - 1 } 555 var used: i64 = 0 556 // procfs can return a short non-EOF read even with a large destination. 557 while used < cap - 1 { 558 let r: i64 = sys_read(fd, buf + used, cap - 1 - used) 559 if r < 0 { sys_close(fd); buf[0] = 0 as u8; return 0 - 1 } 560 if r == 0 { sys_close(fd); buf[used] = 0 as u8; return used } 561 used = used + r 562 } 563 // Reserve the terminator byte for an EOF probe; never report a prefix as complete. 564 let probe: i64 = sys_read(fd, buf + used, 1) 565 sys_close(fd) 566 buf[used] = 0 as u8 567 if probe < 0 { buf[0] = 0 as u8; return 0 - 1 } 568 if probe > 0 { buf[0] = 0 as u8; return 0 - 2 } 569 return used 570} 571func mnp_skip_sp(buf: *u8, n: i64, p: i64) -> i64 { 572 var i: i64 = p 573 var go: i64 = 1 574 while go == 1 { 575 if i >= n { go = 0 } else { if (buf[i] as i64) == 32 { i = i + 1 } else { go = 0 } } 576 } 577 return i 578} 579func mnp_pdec(buf: *u8, n: i64, p: i64, pend: *i64) -> i64 { 580 var i: i64 = p 581 var v: i64 = 0 582 var go: i64 = 1 583 while go == 1 { 584 if i >= n { go = 0 } else { 585 let c: i64 = buf[i] as i64 586 if c >= 48 { if c <= 57 { v = v * 10 + (c - 48); i = i + 1 } else { go = 0 } } else { go = 0 } 587 } 588 } 589 pend[0] = i 590 return v 591} 592func mnp_count_sub(buf: *u8, n: i64, needle: *u8, nl: i64) -> i64 { 593 var c: i64 = 0 594 var i: i64 = 0 595 while i <= n - nl { 596 var j: i64 = 0 597 var ok: i64 = 1 598 while j < nl { if buf[i + j] != needle[j] { ok = 0; j = nl } else { j = j + 1 } } 599 if ok == 1 { c = c + 1; i = i + nl } else { i = i + 1 } 600 } 601 return c 602} 603func mnp_find_after(buf: *u8, n: i64, key: *u8, klen: i64) -> i64 { 604 var i: i64 = 0 605 let last: i64 = n - klen 606 while i <= last { 607 var j: i64 = 0 608 var ok: i64 = 1 609 while j < klen { if buf[i + j] != key[j] { ok = 0; j = klen } else { j = j + 1 } } 610 if ok == 1 { return i + klen } 611 i = i + 1 612 } 613 return 0 - 1 614} 615func mnp_loadavg_milli(buf: *u8) -> i64 { 616 let r: i64 = mnp_readproc("/proc/loadavg" as *u8, buf, 256) 617 if r <= 0 { return 0 } 618 let pend: *i64 = sys_mmap(16) as *i64 619 let ip: i64 = mnp_pdec(buf, r, 0, pend) 620 var frac: i64 = 0 621 var p: i64 = pend[0] 622 if p < r { 623 if (buf[p] as i64) == 46 { 624 p = p + 1 625 var dd: i64 = 0 626 var go: i64 = 1 627 while go == 1 { 628 if dd >= 2 { go = 0 } else { 629 if p >= r { go = 0 } else { 630 let c: i64 = buf[p] as i64 631 if c >= 48 { if c <= 57 { frac = frac * 10 + (c - 48); p = p + 1; dd = dd + 1 } else { go = 0 } } else { go = 0 } 632 } 633 } 634 } 635 while dd < 2 { frac = frac * 10; dd = dd + 1 } 636 } 637 } 638 return ip * 1000 + frac * 10 639} 640func mnp_ncpu(buf: *u8, cap: i64) -> i64 { 641 let r: i64 = mnp_readproc("/proc/cpuinfo" as *u8, buf, cap) 642 if r <= 0 { return 1 } 643 let c: i64 = mnp_count_sub(buf, r, "processor" as *u8, 9) 644 if c < 1 { return 1 } 645 return c 646} 647func mnp_meminfo_kb(buf: *u8, n: i64, key: *u8, klen: i64) -> i64 { 648 let at: i64 = mnp_find_after(buf, n, key, klen) 649 if at < 0 { return 0 - 1 } 650 let s: i64 = mnp_skip_sp(buf, n, at) 651 let pend: *i64 = sys_mmap(16) as *i64 652 return mnp_pdec(buf, n, s, pend) 653} 654func ma_emit_nodes(out: *u8) -> i64 { 655 let small: *u8 = sys_mmap(MA_MAGIC_8192) 656 let big: *u8 = sys_mmap(MA_MAGIC_262144) 657 let load_milli: i64 = mnp_loadavg_milli(small) 658 let ncpu: i64 = mnp_ncpu(big, MA_MAGIC_262144) 659 var lpc: i64 = load_milli 660 if ncpu > 0 { lpc = load_milli / ncpu } 661 let rmem: i64 = mnp_readproc("/proc/meminfo" as *u8, small, MA_MAGIC_8192) 662 var mtot: i64 = mnp_meminfo_kb(small, rmem, "MemTotal:" as *u8, 9) 663 var mav: i64 = mnp_meminfo_kb(small, rmem, "MemAvailable:" as *u8, 13) 664 if mtot < 1 { mtot = 1 } 665 if mav < 0 { mav = 0 } 666 let mused_pct: i64 = (mtot - mav) * 100 / mtot 667 let rtcp: i64 = mnp_readproc("/proc/net/tcp" as *u8, big, MA_MAGIC_262144) 668 var conns: i64 = 0 669 if rtcp > 0 { let cc: i64 = mnp_count_sub(big, rtcp, ":20FB" as *u8, 5); if cc > 1 { conns = cc - 1 } } 670 var verdict: *u8 = "OK" as *u8 671 if lpc >= 700 { verdict = "BUSY" as *u8 } 672 if lpc >= 1000 { verdict = "OVERLOADED" as *u8 } 673 let body: *u8 = sys_mmap(MA_BODYCAP) 674 var b: i64 = sd_cat(body, 0, "{\"nodes\":[{\"name\":\"nas\",\"role\":\"orchestrator\",\"addr\":\"192.168.8.227\",\"load_milli\":" as *u8) 675 b = sd_catn(body, b, load_milli) 676 b = sd_cat(body, b, ",\"ncpu\":" as *u8); b = sd_catn(body, b, ncpu) 677 b = sd_cat(body, b, ",\"load_per_core_milli\":" as *u8); b = sd_catn(body, b, lpc) 678 b = sd_cat(body, b, ",\"mem_used_pct\":" as *u8); b = sd_catn(body, b, mused_pct) 679 b = sd_cat(body, b, ",\"mem_avail_mb\":" as *u8); b = sd_catn(body, b, mav / MA_MAGIC_1024) 680 b = sd_cat(body, b, ",\"mem_total_mb\":" as *u8); b = sd_catn(body, b, mtot / MA_MAGIC_1024) 681 b = sd_cat(body, b, ",\"conns8443\":" as *u8); b = sd_catn(body, b, conns) 682 b = sd_cat(body, b, ",\"verdict\":\"" as *u8); b = sd_cat(body, b, verdict) 683 b = sd_cat(body, b, "\",\"ts\":" as *u8); b = sd_catn(body, b, sys_now_realtime_sec()) 684 b = sd_cat(body, b, "}],\"workers\":[{\"name\":\"laptop-5080\",\"addr\":\"192.168.8.193:7861\",\"role\":\"gpu-image\",\"state\":\"probe-via-mesh\"},{\"name\":\"west-3090\",\"addr\":\"10.0.4.13:7861\",\"role\":\"gpu-video\",\"state\":\"probe-via-mesh\"}]," as *u8) 685 b = sd_cat(body, b, "\"thresholds\":{\"busy_per_core_milli\":700,\"overload_per_core_milli\":1000}}" as *u8) 686 body[b] = 0 as u8 687 return ma_emit_200(out, body) 688} 689 690// ---- /api/health (transport orchestration: DATA parse + CORE verdict + serialize) ------------------- 691 692func ma_health_count(snap: *u8, snap_n: i64, supb: *i64, nsvcb: *i64, ndownb: *i64) -> i64 { 693 let offs: *i64 = sys_mmap(64) as *i64 694 let lens: *i64 = sys_mmap(64) as *i64 695 var sup: i64 = 0 696 var nsvc: i64 = 0 697 var ndown: i64 = 0 698 var reasons: i64 = 0 699 var cur: i64 = 0 700 while cur < snap_n { 701 let le: i64 = md_eol(snap, snap_n, cur) 702 let nf: i64 = md_split(snap, cur, le, offs, lens, 8) 703 if nf >= 2 { 704 if md_tok_eq(snap, offs[0], lens[0], "SUP" as *u8) == 1 { sup = md_slice_atoi(snap, offs[1], lens[1]) } 705 } 706 if nf >= 6 { 707 if md_tok_eq(snap, offs[0], lens[0], "SVC" as *u8) == 1 { 708 nsvc = nsvc + 1 709 let procs: i64 = md_slice_atoi(snap, offs[4], lens[4]) 710 let rwin: i64 = md_slice_atoi(snap, offs[5], lens[5]) 711 if mc_is_dup(procs) == 1 { reasons = reasons + 1 } 712 if mc_is_loop(rwin) == 1 { reasons = reasons + 1 } 713 if md_tok_eq(snap, offs[3], lens[3], "DOWN" as *u8) == 1 { reasons = reasons + 1; ndown = ndown + 1 } 714 } 715 } 716 cur = le + 1 717 } 718 if mc_is_duel(sup) == 1 { reasons = reasons + 1 } 719 supb[0] = sup 720 nsvcb[0] = nsvc 721 ndownb[0] = ndown 722 return reasons 723} 724 725func ma_health_reasons(snap: *u8, snap_n: i64, sup: i64, body: *u8, b0: i64) -> i64 { 726 let offs: *i64 = sys_mmap(64) as *i64 727 let lens: *i64 = sys_mmap(64) as *i64 728 var b: i64 = b0 729 let firstbox: *i64 = sys_mmap(8) as *i64 730 firstbox[0] = 1 731 if mc_is_duel(sup) == 1 { 732 b = ma_comma(body, b, firstbox) 733 b = sd_cat(body, b, "\"dueling-supervisors\"" as *u8) 734 } 735 var cur: i64 = 0 736 while cur < snap_n { 737 let le: i64 = md_eol(snap, snap_n, cur) 738 let nf: i64 = md_split(snap, cur, le, offs, lens, 8) 739 if nf >= 6 { 740 if md_tok_eq(snap, offs[0], lens[0], "SVC" as *u8) == 1 { 741 let procs: i64 = md_slice_atoi(snap, offs[4], lens[4]) 742 let rwin: i64 = md_slice_atoi(snap, offs[5], lens[5]) 743 if mc_is_dup(procs) == 1 { 744 b = ma_comma(body, b, firstbox) 745 b = sd_cat(body, b, "\"duplicate-instance:" as *u8) 746 b = md_cat_slice(body, b, snap, offs[1], lens[1]) 747 b = sd_cat(body, b, "\"" as *u8) 748 } 749 if mc_is_loop(rwin) == 1 { 750 b = ma_comma(body, b, firstbox) 751 b = sd_cat(body, b, "\"crash-loop:" as *u8) 752 b = md_cat_slice(body, b, snap, offs[1], lens[1]) 753 b = sd_cat(body, b, "\"" as *u8) 754 } 755 if md_tok_eq(snap, offs[3], lens[3], "DOWN" as *u8) == 1 { 756 b = ma_comma(body, b, firstbox) 757 b = sd_cat(body, b, "\"down:" as *u8) 758 b = md_cat_slice(body, b, snap, offs[1], lens[1]) 759 b = sd_cat(body, b, "\"" as *u8) 760 } 761 } 762 } 763 cur = le + 1 764 } 765 return b 766} 767 768// ---- HOST MEMORY-PRESSURE AXIS (sev-9 1785048333: /api/health said OK while swap sat 99.995% exhausted 769// and MemAvailable=146 permil -- the rollup had NO resource signal at all). MemAvailable, not SwapFree, is 770// the near-term OOM guard (incident law), so it is the primary threshold; swap saturation is the secondary. 771// Thresholds are DATA: knowledge/health_mem.conf rows `mem_avail_min_permil<TAB>N` / `swap_used_max_permil<TAB>N`, 772// compiled defaults when absent. /proc/meminfo unreadable -> permils stay -1 and the axis NEVER fires 773// (fail-safe: a blind instrument must say nothing, not false-DEGRADE). Buffers are lazy static pointers 774// (BSS-array class crashes the handler module; per-call sys_mmap is the debt-883 leak class). 775const MA_MEM_AVAIL_MIN_PERMIL: i64 = 150 776const MA_SWAP_USED_MAX_PERMIL: i64 = 950 777static ma_mi_buf: *u8 778static ma_mc_buf: *u8 779static ma_mem_scr: *i64 780// key -> integer after it (skips spaces/tabs); -1 = key absent / no digits. Serves BOTH /proc/meminfo 781// (`MemTotal: 36182312 kB`) and the conf (`mem_avail_min_permil<TAB>150`). 782func ma_key_int(buf: *u8, n: i64, key: *u8) -> i64 { 783 var kl: i64 = 0 784 while key[kl] != (0 as u8) { kl = kl + 1 } 785 var i: i64 = 0 786 while i + kl < n { 787 var m: i64 = 1 788 var j: i64 = 0 789 while j < kl { if buf[i+j] != key[j] { m = 0; j = kl } else { j = j + 1 } } 790 if m == 1 { 791 var p: i64 = i + kl 792 var sk: i64 = 1 793 while sk == 1 { 794 if p >= n { sk = 0 } else { 795 if buf[p] == (32 as u8) { p = p + 1 } else { if buf[p] == (9 as u8) { p = p + 1 } else { sk = 0 } } 796 } 797 } 798 var v: i64 = 0 799 var any: i64 = 0 800 var go: i64 = 1 801 while go == 1 { 802 if p >= n { go = 0 } else { 803 let c: i64 = buf[p] as i64 804 if c < 48 { go = 0 } else { if c > 57 { go = 0 } else { v = v*10 + (c - 48); any = 1; p = p + 1 } } 805 } 806 } 807 if any == 1 { return v } 808 return 0 - 1 809 } 810 while i < n { if buf[i] == (10 as u8) { break } i = i + 1 } 811 i = i + 1 812 } 813 return 0 - 1 814} 815func ma_read_small(path: *u8, buf: *u8, cap: i64) -> i64 { 816 let fd: i64 = sys_openat_rd(path) 817 if fd < 0 { return 0 - 1 } 818 let n: i64 = sys_read(fd, buf, cap) 819 sys_close(fd) 820 return n 821} 822func ma_mem_conf(key: *u8, defv: i64) -> i64 { 823 if (ma_mc_buf as i64) == 0 { ma_mc_buf = sys_mmap(MA_MAGIC_2048) } 824 let n: i64 = ma_read_small("knowledge/health_mem.conf" as *u8, ma_mc_buf, MA_MAGIC_2046) 825 if n <= 0 { return defv } 826 let v: i64 = ma_key_int(ma_mc_buf, n, key) 827 if v < 0 { return defv } 828 return v 829} 830// Measure + judge. ma_mem_scr[0]=mem_avail_permil, [1]=swap_used_permil (-1 = unmeasured). Returns 1 on breach. 831func ma_mem_pressure() -> i64 { 832 if (ma_mem_scr as i64) == 0 { ma_mem_scr = sys_mmap(16) as *i64 } 833 ma_mem_scr[0] = 0 - 1 834 ma_mem_scr[1] = 0 - 1 835 if (ma_mi_buf as i64) == 0 { ma_mi_buf = sys_mmap(MA_MAGIC_8192) } 836 let n: i64 = ma_read_small("/proc/meminfo" as *u8, ma_mi_buf, MA_MAGIC_8190) 837 if n <= 0 { return 0 } 838 let mt: i64 = ma_key_int(ma_mi_buf, n, "MemTotal:" as *u8) 839 let mav: i64 = ma_key_int(ma_mi_buf, n, "MemAvailable:" as *u8) 840 let st: i64 = ma_key_int(ma_mi_buf, n, "SwapTotal:" as *u8) 841 let sf: i64 = ma_key_int(ma_mi_buf, n, "SwapFree:" as *u8) 842 if mt > 0 { if mav >= 0 { ma_mem_scr[0] = mav * 1000 / mt } } 843 if st > 0 { if sf >= 0 { ma_mem_scr[1] = (st - sf) * 1000 / st } } 844 var breach: i64 = 0 845 if ma_mem_scr[0] >= 0 { if ma_mem_scr[0] < ma_mem_conf("mem_avail_min_permil" as *u8, MA_MEM_AVAIL_MIN_PERMIL) { breach = 1 } } 846 if ma_mem_scr[1] >= 0 { if ma_mem_scr[1] > ma_mem_conf("swap_used_max_permil" as *u8, MA_SWAP_USED_MAX_PERMIL) { breach = 1 } } 847 return breach 848} 849 850func ma_emit_health(snap: *u8, snap_n: i64, out: *u8) -> i64 { 851 let supb: *i64 = sys_mmap(8) as *i64 852 let nsvcb: *i64 = sys_mmap(8) as *i64 853 let ndownb: *i64 = sys_mmap(8) as *i64 854 let reasons: i64 = ma_health_count(snap, snap_n, supb, nsvcb, ndownb) 855 let sup: i64 = supb[0] 856 let nsvc: i64 = nsvcb[0] 857 let ndown: i64 = ndownb[0] 858 var noData: i64 = 0 859 if nsvc == 0 { noData = 1 } 860 let memb: i64 = ma_mem_pressure() 861 let verdict: i64 = mc_verdict(noData, reasons + memb) 862 let body: *u8 = sys_mmap(MA_BODYCAP) 863 var b: i64 = sd_cat(body, 0, "{\"overall\":\"" as *u8) 864 if verdict == 0 { b = sd_cat(body, b, "UNKNOWN" as *u8) } 865 if verdict == 1 { b = sd_cat(body, b, "OK" as *u8) } 866 if verdict == 2 { b = sd_cat(body, b, "DEGRADED" as *u8) } 867 b = sd_cat(body, b, "\",\"degraded\":" as *u8) 868 var degcount: i64 = reasons + memb 869 if noData == 1 { degcount = 1 + memb } 870 b = sd_catn(body, b, degcount) 871 b = sd_cat(body, b, ",\"down\":" as *u8) 872 b = sd_catn(body, b, ndown) 873 b = sd_cat(body, b, ",\"supervisors\":" as *u8) 874 b = sd_catn(body, b, sup) 875 b = sd_cat(body, b, ",\"services\":" as *u8) 876 b = sd_catn(body, b, nsvc) 877 if ma_mem_scr[0] >= 0 { 878 b = sd_cat(body, b, ",\"mem_avail_permil\":" as *u8) 879 b = sd_catn(body, b, ma_mem_scr[0]) 880 } 881 if ma_mem_scr[1] >= 0 { 882 b = sd_cat(body, b, ",\"swap_used_permil\":" as *u8) 883 b = sd_catn(body, b, ma_mem_scr[1]) 884 } 885 b = sd_cat(body, b, ",\"reasons\":[" as *u8) 886 if noData == 1 { 887 b = sd_cat(body, b, "\"no-snapshot\"" as *u8) 888 } else { 889 b = ma_health_reasons(snap, snap_n, sup, body, b) 890 } 891 if memb == 1 { 892 if noData == 1 { b = sd_cat(body, b, "," as *u8) } else { if reasons > 0 { b = sd_cat(body, b, "," as *u8) } } 893 b = sd_cat(body, b, "\"mem-pressure:avail_permil=" as *u8) 894 if ma_mem_scr[0] >= 0 { b = sd_catn(body, b, ma_mem_scr[0]) } else { b = sd_cat(body, b, "na" as *u8) } 895 b = sd_cat(body, b, "-swap_used_permil=" as *u8) 896 if ma_mem_scr[1] >= 0 { b = sd_catn(body, b, ma_mem_scr[1]) } else { b = sd_cat(body, b, "na" as *u8) } 897 b = sd_cat(body, b, "\"" as *u8) 898 } 899 b = sd_cat(body, b, "]}" as *u8) 900 return ma_emit_200(out, body) 901} 902 903func ma_emit_health_file(snapfile: *u8, out: *u8) -> i64 { 904 let sbox: *i64 = sys_mmap(16) as *i64 905 let page: *u8 = md_read_file(snapfile, sbox) 906 if (page as i64) == 0 { 907 let empty: *u8 = sys_mmap(1) 908 return ma_emit_health(empty, 0, out) 909 } 910 return ma_emit_health(page, sbox[0], out) 911} 912 913// ---- auth + login (transport) ----------------------------------------------------------------------- 914 915func ma_authed(ctx: *NxAuthContext, req: *u8, req_n: i64) -> i64 { 916 let now_s: i64 = sys_now_realtime_sec() 917 if nx_sa_validate(ctx, req, req_n, now_s) == NX_MAUTH_OK { return 1 } 918 return 0 919} 920 921// ma_level_of: the caller's ACCESS LEVEL for this request. -1 = no/invalid session (=> 401); else 0..3 from the 922// SHARED access-granting path (session uid -> nishi_uid_handle.tsv -> roles.tsv). Composes nx_sa_validate_handle 923// (the SAME realm-bound session validation) + ag_uid_to_level (nx_access_lib) -- so /health + /api gate EXACTLY 924// like the hub gateway. This is what "lines the OPAQUE up with the access-granting system" for the mgmt plane. 925static ma_auth_index_path:*u8 926static ma_auth_roles_path:*u8 927func ma_auth_index()->*u8 { if (ma_auth_index_path as i64)!=0 { return ma_auth_index_path };return MA_IDX } 928func ma_auth_roles()->*u8 { if (ma_auth_roles_path as i64)!=0 { return ma_auth_roles_path };return MA_ROLES } 929func ma_level_of(ctx: *NxAuthContext, req: *u8, req_n: i64) -> i64 { 930 let now_s: i64 = sys_now_realtime_sec() 931 let uid: *u8 = sys_mmap(64); let uidn: *i64 = sys_mmap(8) as *i64 932 if nx_sa_validate_handle(ctx, req, req_n, now_s, uid, 64, uidn) != NX_MAUTH_OK { return 0 - 1 } 933 return ag_uid_to_level(uid, uidn[0], ma_auth_index(), ma_auth_roles()) 934} 935 936func ma_confirmed(req: *u8, req_n: i64) -> i64 { 937 let body_off: i64 = sd_body_off(req, req_n) 938 let body: *u8 = ((req as i64) + body_off) as *u8 939 let body_n: i64 = req_n - body_off 940 let coff: *i64 = sys_mmap(8) as *i64 941 let cn: *i64 = sys_mmap(8) as *i64 942 if sd_form_field(body, body_n, "confirm" as *u8, 7, coff, cn) == 1 { 943 if md_slice_eq(body, coff[0], cn[0], "yes" as *u8, 0, 3) == 1 { return 1 } 944 } 945 return 0 946} 947 948func ma_login(ctx: *NxAuthContext, req: *u8, req_n: i64, out: *u8) -> i64 { 949 let body_off: i64 = sd_body_off(req, req_n) 950 let body: *u8 = ((req as i64) + body_off) as *u8 951 let body_n: i64 = req_n - body_off 952 let hoff: *i64 = sys_mmap(8) as *i64 953 let hn: *i64 = sys_mmap(8) as *i64 954 let poff2: *i64 = sys_mmap(8) as *i64 955 let pnn: *i64 = sys_mmap(8) as *i64 956 var got: i64 = 0 957 if sd_form_field(body, body_n, "handle" as *u8, 6, hoff, hn) == 1 { 958 if sd_form_field(body, body_n, "passphrase" as *u8, 10, poff2, pnn) == 1 { got = 1 } 959 } 960 var o: i64 = 0 961 var ok: i64 = 0 962 if got == 1 { 963 let hbuf: *u8 = sys_mmap(256) 964 let pbuf: *u8 = sys_mmap(512) 965 let h_dec: i64 = sd_urldecode(((body as i64) + hoff[0]) as *u8, hn[0], hbuf, 255) 966 let p_dec: i64 = sd_urldecode(((body as i64) + poff2[0]) as *u8, pnn[0], pbuf, 511) 967 if h_dec > 0 { if p_dec > 0 { 968 let tok: *u8 = sys_mmap(NX_MAUTH_SESSION_TOKEN_BYTES) 969 let tok_n: *i64 = sys_mmap(8) as *i64 970 tok_n[0] = 0 971 if nx_modern_auth_login(ctx, hbuf, h_dec, pbuf, p_dec, tok, NX_MAUTH_SESSION_TOKEN_BYTES, tok_n) == NX_MAUTH_OK { 972 let b64: *u8 = sys_mmap(256) 973 let b64_n: i64 = b64_encode(tok, NX_MAUTH_SESSION_TOKEN_BYTES, b64) 974 o = sd_cat(out, o, "HTTP/1.1 200 OK\r\nContent-Type: application/json\r\nConnection: close\r\nContent-Length: " as *u8) 975 o = sd_catn(out, o, 12 + b64_n) 976 o = sd_cat(out, o, "\r\n\r\n{\"token\":\"" as *u8) 977 var z: i64 = 0 978 while z < b64_n { out[o] = b64[z]; o = o + 1; z = z + 1 } 979 o = sd_cat(out, o, "\"}" as *u8) 980 ok = 1 981 } 982 } } 983 } 984 if ok == 0 { o = sd_emit_401_json(out) } 985 return o 986} 987 988// ---- /api/upload (transport: parse query, allowlist via DATA, reassemble chunk -> stage <name>.new) -------- 989// THE keystone that lets an operator PUBLISH an artifact over the authenticated HTTPS API from ANYWHERE (the gap 990// nx_aw_send left: it needs the LAN). Chunked because ONE request (headers+body) must be <= SD_REQCAP (64KB) and 991// artifacts are megabytes: the client POSTs the raw bytes in <=48KB slices; here we APPEND them into <name>.upload 992// and, on the final chunk, atomically rename to <name>.new. ADDITIVE + NEVER-BRICK (#26): this ONLY writes the 993// staging files <name>.upload / <name>.new; it NEVER promotes/activates/touches the live <name>. Promotion + 994// health-check + auto-rollback stays entirely in /api/deploy. Fail-closed everywhere (unknown target/seq gap -> 995// 400 + nothing appended). The mgmt daemon is single-threaded (one request at a time, main's serve loop), so the 996// per-target expected-seq persisted in the <name>.upload.seq sidecar is race-free by construction. 997 998// ---- query-string helpers (the params ride in the request TARGET, since the body is the raw binary chunk) ----- 999 1000// Locate the '?' in the request target slice path[0..pn); returns the index of the first byte AFTER '?', or -1. 1001func mau_query_off(path: *u8, pn: i64) -> i64 { 1002 var i: i64 = 0 1003 while i < pn { if (path[i] as i64) == 63 { return i + 1 } i = i + 1 } // 63 = '?' 1004 return 0 - 1 1005} 1006 1007// Extract query param `name` from the query string path[qoff..pn) into a null-terminated slice descriptor: 1008// on hit sets voff[0]/vlen[0] to the raw value slice (still %-encoded, terminated by '&' or end) and returns 1; 1009// 0 if absent. name matched as "name=" at a param boundary (start-of-query or just after '&'). Fail-closed: no 1010// url-decode here -- our params are ASCII names/ints/hex, and a stray '%' just stays literal (rejected downstream). 1011func mau_qparam(path: *u8, pn: i64, qoff: i64, name: *u8, name_n: i64, voff: *i64, vlen: *i64) -> i64 { 1012 if qoff < 0 { return 0 } 1013 var pos: i64 = qoff 1014 while pos < pn { 1015 var m: i64 = 1 1016 if pos + name_n + 1 > pn { m = 0 } 1017 if m == 1 { 1018 var i: i64 = 0 1019 while i < name_n { if (path[pos + i] as i64) != (name[i] as i64) { m = 0; i = name_n } else { i = i + 1 } } 1020 } 1021 if m == 1 { if (path[pos + name_n] as i64) != 61 { m = 0 } } // 61 = '=' 1022 // find end of this param's value (next '&' or end-of-query) 1023 var vend: i64 = pos 1024 var scan: i64 = 1 1025 while scan == 1 { 1026 if vend >= pn { scan = 0 } 1027 if scan == 1 { if (path[vend] as i64) == 38 { scan = 0 } } // 38 = '&' 1028 if scan == 1 { vend = vend + 1 } 1029 } 1030 if m == 1 { voff[0] = pos + name_n + 1; vlen[0] = vend - (pos + name_n + 1); return 1 } 1031 pos = vend + 1 1032 } 1033 return 0 1034} 1035 1036// parse a non-negative decimal from path[off..off+len). Returns the value, or -1 if empty / any non-digit byte 1037// (fail-closed: a malformed seq must NOT silently coerce to 0 and get treated as the truncating first chunk). 1038func mau_qint(path: *u8, off: i64, len: i64) -> i64 { 1039 if len <= 0 { return 0 - 1 } 1040 var v: i64 = 0 1041 var i: i64 = 0 1042 while i < len { 1043 let c: i64 = path[off + i] as i64 1044 if c < 48 { return 0 - 1 } 1045 if c > 57 { return 0 - 1 } 1046 v = v * 10 + (c - 48) 1047 i = i + 1 1048 } 1049 return v 1050} 1051 1052// build "<name>.upload" / "<name>.upload.seq" / "<name>.new" from the target slice path[toff..toff+tlen) into buf 1053// (null-terminated). suffix is a NUL-terminated cstr. Returns the length written. 1054func mau_build_path(path: *u8, toff: i64, tlen: i64, suffix: *u8, buf: *u8) -> i64 { 1055 var o: i64 = 0 1056 var i: i64 = 0 1057 while i < tlen { buf[o] = path[toff + i]; o = o + 1; i = i + 1 } 1058 var j: i64 = 0 1059 while suffix[j] != (0 as u8) { buf[o] = suffix[j]; o = o + 1; j = j + 1 } 1060 buf[o] = 0 as u8 1061 return o 1062} 1063 1064// read the expected-next seq from the sidecar file (ASCII int). Returns the int, or -1 if the sidecar is absent 1065// or unparseable (=> only seq 0 is valid, which (re)creates it -- a resumed/garbled sidecar can't inject a gap). 1066func mau_read_seq(sidecar: *u8) -> i64 { 1067 let szp: *i64 = sys_mmap(16) as *i64 1068 let buf: *u8 = sys_read_file(sidecar, szp) 1069 if (buf as i64) == 0 { return 0 - 1 } 1070 let n: i64 = szp[0] 1071 if n <= 0 { return 0 - 1 } 1072 return mau_qint(buf, 0, n) // reuse the strict digit parser; trailing '\n' -> -1, so keep it clean (no newline) 1073} 1074 1075// write the next-expected seq (ASCII, NO trailing newline) into the sidecar (O_CREAT|O_TRUNC 0644). Returns 0/-1. 1076func mau_write_seq(sidecar: *u8, val: i64) -> i64 { 1077 let fd: i64 = sys_openat_wr(sidecar, 0x1a4) // 0644 1078 if fd < 0 { return 0 - 1 } 1079 let t: *u8 = sys_mmap(24) 1080 var m: i64 = val 1081 var k: i64 = 0 1082 if m == 0 { t[0] = 48 as u8; k = 1 } 1083 while m > 0 { t[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 } 1084 let ob: *u8 = sys_mmap(24) 1085 var i: i64 = 0 1086 while i < k { ob[i] = t[k - 1 - i]; i = i + 1 } 1087 sys_write(fd, ob, k) 1088 sys_close(fd) 1089 return 0 1090} 1091 1092// lowercase-hex of a 32-byte digest into out[0..64) (NUL-terminated). 1093func mau_hex32(dig: *u8, out: *u8) -> i64 { 1094 let hx: *u8 = "0123456789abcdef" as *u8 1095 var i: i64 = 0 1096 while i < 32 { 1097 let b: i64 = dig[i] & 0xff 1098 out[i * 2] = hx[(b >> 4) & 0xf] 1099 out[i * 2 + 1] = hx[b & 0xf] 1100 i = i + 1 1101 } 1102 out[64] = 0 as u8 1103 return 64 1104} 1105 1106// case-insensitive compare of the provided sha256 hex slice path[hoff..hoff+hlen) against the computed 64-char hex. 1107// 1 = match, 0 = mismatch (or a non-64-length provided value -> refuse, fail-closed). 1108func mau_hex_eq(path: *u8, hoff: i64, hlen: i64, want: *u8) -> i64 { 1109 if hlen != 64 { return 0 } 1110 var i: i64 = 0 1111 while i < 64 { 1112 var a: i64 = path[hoff + i] as i64 1113 var b: i64 = want[i] as i64 1114 if a >= 65 { if a <= 90 { a = a + 32 } } // ASCII upper -> lower 1115 if b >= 65 { if b <= 90 { b = b + 32 } } 1116 if a != b { return 0 } 1117 i = i + 1 1118 } 1119 return 1 1120} 1121 1122// create every parent directory of `path` (idempotent; EEXIST is fine). Only ever called on paths that 1123// already passed the fail-closed target allowlists, so the walk stays inside the pinned namespace. 1124func mau_mkdirs(path: *u8) -> i64 { 1125 let tmp: *u8 = sys_mmap(320) 1126 var i: i64 = 0 1127 while path[i] != (0 as u8) { 1128 if (path[i] as i64) == 47 { if i > 0 { 1129 var k: i64 = 0 1130 while k < i { tmp[k] = path[k]; k = k + 1 } 1131 tmp[i] = 0 as u8 1132 sys_mkdir(tmp, 0x1ed) 1133 } } 1134 i = i + 1 1135 } 1136 return 0 1137} 1138 1139// THE handler: parse ?target&seq&final[&sha256] from the request target, allowlist-check the target, then APPEND 1140// the raw body chunk into <target>.upload with strict monotonic-seq enforcement; on final=1 (optionally verifying 1141// sha256) atomically rename to <target>.new. Returns response bytes. Never touches the live artifact. 1142func ma_do_upload(req: *u8, req_n: i64, out: *u8) -> i64 { 1143 // -- locate the request target (path + query) and the body slice -- 1144 let poff: *i64 = sys_mmap(8) as *i64 1145 let plen: *i64 = sys_mmap(8) as *i64 1146 poff[0] = 0; plen[0] = 0 1147 sd_find_path(req, req_n, poff, plen) 1148 let path: *u8 = ((req as i64) + poff[0]) as *u8 1149 let pn: i64 = plen[0] 1150 let qoff: i64 = mau_query_off(path, pn) 1151 if qoff < 0 { return ma_emit_400(out, "{\"error\":\"missing query params (target/seq/final)\"}" as *u8) } 1152 1153 let toff: *i64 = sys_mmap(8) as *i64 1154 let tlen: *i64 = sys_mmap(8) as *i64 1155 let soff: *i64 = sys_mmap(8) as *i64 1156 let slen: *i64 = sys_mmap(8) as *i64 1157 let foff: *i64 = sys_mmap(8) as *i64 1158 let flen: *i64 = sys_mmap(8) as *i64 1159 if mau_qparam(path, pn, qoff, "target" as *u8, 6, toff, tlen) != 1 { return ma_emit_400(out, "{\"error\":\"missing target\"}" as *u8) } 1160 if mau_qparam(path, pn, qoff, "seq" as *u8, 3, soff, slen) != 1 { return ma_emit_400(out, "{\"error\":\"missing seq\"}" as *u8) } 1161 if mau_qparam(path, pn, qoff, "final" as *u8, 5, foff, flen) != 1 { return ma_emit_400(out, "{\"error\":\"missing final\"}" as *u8) } 1162 1163 // -- fail-closed allowlist (DATA ring): service binary OR static-content namespace. unknown -> nothing written. -- 1164 var tok_ok: i64 = md_upload_target_ok(path, toff[0], tlen[0]) 1165 if tok_ok != 1 { tok_ok = md_content_target_ok(path, toff[0], tlen[0]) } 1166 if tok_ok != 1 { return ma_emit_400(out, "{\"error\":\"target not allowlisted\"}" as *u8) } 1167 1168 let seq: i64 = mau_qint(path, soff[0], slen[0]) 1169 let fin: i64 = mau_qint(path, foff[0], flen[0]) 1170 if seq < 0 { return ma_emit_400(out, "{\"error\":\"bad seq (non-numeric)\"}" as *u8) } 1171 if fin < 0 { return ma_emit_400(out, "{\"error\":\"bad final (non-numeric)\"}" as *u8) } 1172 1173 // -- build the staging + sidecar + promote paths from the (allowlisted) target basename -- 1174 let stage: *u8 = sys_mmap(256) 1175 let sidecar: *u8 = sys_mmap(256) 1176 let newp: *u8 = sys_mmap(256) 1177 mau_build_path(path, toff[0], tlen[0], ".upload" as *u8, stage) 1178 mau_build_path(path, toff[0], tlen[0], ".upload.seq" as *u8, sidecar) 1179 mau_build_path(path, toff[0], tlen[0], ".new" as *u8, newp) 1180 1181 // -- strict monotonic-seq gate (single-threaded daemon => race-free sidecar) -- 1182 if seq == 0 { 1183 // first chunk: (re)start the transfer -- TRUNCATE stage, reset sidecar. Any prior partial is discarded. 1184 // Multi-page content targets may live in subdirs (wholesale sites): create parents inside the 1185 // pinned, allowlist-validated namespace so the stage write cannot fail on a missing directory. 1186 mau_mkdirs(stage) 1187 } else { 1188 let expected: i64 = mau_read_seq(sidecar) 1189 if expected != seq { 1190 // IDEMPOTENT REPLAY-ACK (safe-to-run-twice): the edge relay LOSES responses AND re-delivers STALE 1191 // earlier chunks under rapid chunk storms; the client then re-sees a chunk the daemon ALREADY 1192 // appended, and a plain bad-seq reject desyncs+aborts the whole transfer (observed: 650KB/80-chunk 1193 // uploads dying at ~12-14). (a) non-final replay: seq < expected -> those bytes are ALREADY in the 1194 // stage; ack WITHOUT appending (a second append would corrupt the artifact; the final sha256 1195 // still end-to-end verifies the reassembled bytes). BROADENED from seq==expected-1 to seq<expected 1196 // (2026-07-24) so a stale duplicate of ANY earlier chunk is a no-op, not a fatal bad-seq. 1197 if expected >= 1 { if seq < expected { if fin != 1 { 1198 let ab2: *u8 = sys_mmap(256) 1199 var a2: i64 = sd_cat(ab2, 0, "{\"action\":\"UPLOAD\",\"target\":\"" as *u8) 1200 a2 = md_cat_slice(ab2, a2, path, toff[0], tlen[0]) 1201 a2 = sd_cat(ab2, a2, "\",\"seq\":" as *u8) 1202 a2 = sd_catn(ab2, a2, seq) 1203 a2 = sd_cat(ab2, a2, ",\"final\":0,\"replay\":1}" as *u8) 1204 return ma_emit_200(out, ab2) 1205 } } } 1206 // (b) final-chunk replay AFTER a completed transfer: sidecar already dropped (expected=-1) and 1207 // <target>.new exists. Fail-closed: ack ONLY when the client's sha256 param matches the 1208 // staged .new bytes (the client always sends sha on final) -- then this replay IS the same 1209 // completed upload; re-emit the STAGED response instead of desyncing the client. 1210 if expected < 0 { if fin == 1 { 1211 let rhoff: *i64 = sys_mmap(8) as *i64 1212 let rhlen: *i64 = sys_mmap(8) as *i64 1213 if mau_qparam(path, pn, qoff, "sha256" as *u8, 6, rhoff, rhlen) == 1 { 1214 let rszp: *i64 = sys_mmap(16) as *i64 1215 let rfull: *u8 = sys_read_file(newp, rszp) 1216 if (rfull as i64) != 0 { 1217 let rdig: *u8 = sys_mmap(32) 1218 sha256_digest(rfull, rszp[0], rdig) 1219 let rhex: *u8 = sys_mmap(72) 1220 mau_hex32(rdig, rhex) 1221 if mau_hex_eq(path, rhoff[0], rhlen[0], rhex) == 1 { 1222 let rb2: *u8 = sys_mmap(320) 1223 var b3: i64 = sd_cat(rb2, 0, "{\"action\":\"UPLOAD\",\"target\":\"" as *u8) 1224 b3 = md_cat_slice(rb2, b3, path, toff[0], tlen[0]) 1225 b3 = sd_cat(rb2, b3, "\",\"bytes\":" as *u8) 1226 b3 = sd_catn(rb2, b3, rszp[0]) 1227 b3 = sd_cat(rb2, b3, ",\"final\":1,\"replay\":1,\"staged\":\"" as *u8) 1228 b3 = md_cat_slice(rb2, b3, path, toff[0], tlen[0]) 1229 b3 = sd_cat(rb2, b3, ".new\"}" as *u8) 1230 return ma_emit_200(out, rb2) 1231 } 1232 } 1233 } 1234 } } 1235 return ma_emit_400(out, "{\"error\":\"bad seq\"}" as *u8) // gap / out-of-order / no prior seq=0 -> reject, append NOTHING 1236 } 1237 } 1238 1239 // -- body slice: everything past the CRLFCRLF header terminator (raw chunk bytes) -- 1240 let body_off: i64 = sd_body_off(req, req_n) 1241 let body: *u8 = ((req as i64) + body_off) as *u8 1242 let body_n: i64 = req_n - body_off 1243 1244 // -- write the chunk via the SHIPPED primitive (seq0 truncates+creates, seq>0 appends) -- compose, don't re-open -- 1245 if mu_stage_chunk(stage, seq, body, body_n) < 0 { return ma_emit_400(out, "{\"error\":\"cannot open staging file\"}" as *u8) } 1246 // advance the expected-seq sidecar to the next chunk number 1247 mau_write_seq(sidecar, seq + 1) 1248 1249 // -- non-final chunk: ack and wait for the next -- 1250 if fin != 1 { 1251 let ab: *u8 = sys_mmap(256) 1252 var a: i64 = sd_cat(ab, 0, "{\"action\":\"UPLOAD\",\"target\":\"" as *u8) 1253 a = md_cat_slice(ab, a, path, toff[0], tlen[0]) 1254 a = sd_cat(ab, a, "\",\"seq\":" as *u8) 1255 a = sd_catn(ab, a, seq) 1256 a = sd_cat(ab, a, ",\"final\":0}" as *u8) 1257 return ma_emit_200(out, ab) 1258 } 1259 1260 // -- FINAL chunk: read back the assembled staging file (for size + optional integrity) -- 1261 let szp: *i64 = sys_mmap(16) as *i64 1262 let full: *u8 = sys_read_file(stage, szp) 1263 let total: i64 = szp[0] 1264 if (full as i64) == 0 { return ma_emit_400(out, "{\"error\":\"staging file vanished before finalize\"}" as *u8) } 1265 1266 // -- optional sha256 verification of the WHOLE assembled artifact -- 1267 let hoff: *i64 = sys_mmap(8) as *i64 1268 let hlen: *i64 = sys_mmap(8) as *i64 1269 if mau_qparam(path, pn, qoff, "sha256" as *u8, 6, hoff, hlen) == 1 { 1270 let dig: *u8 = sys_mmap(32) 1271 sha256_digest(full, total, dig) 1272 let hexbuf: *u8 = sys_mmap(72) 1273 mau_hex32(dig, hexbuf) 1274 if mau_hex_eq(path, hoff[0], hlen[0], hexbuf) != 1 { 1275 fio_unlink(stage) // shred the corrupt upload (never leave a bad .upload around) 1276 fio_unlink(sidecar) 1277 return ma_emit_400(out, "{\"error\":\"sha256 mismatch; staging deleted\"}" as *u8) 1278 } 1279 } 1280 1281 // -- atomically stage for /api/deploy: <target>.upload -> <target>.new (never the live <target>) -- 1282 let rr: i64 = sys_renameat(stage, newp) 1283 fio_unlink(sidecar) // transfer done; drop the seq sidecar 1284 if rr != 0 { return ma_emit_400(out, "{\"error\":\"stage rename failed\"}" as *u8) } 1285 1286 let rb: *u8 = sys_mmap(320) 1287 var b: i64 = sd_cat(rb, 0, "{\"action\":\"UPLOAD\",\"target\":\"" as *u8) 1288 b = md_cat_slice(rb, b, path, toff[0], tlen[0]) 1289 b = sd_cat(rb, b, "\",\"bytes\":" as *u8) 1290 b = sd_catn(rb, b, total) 1291 b = sd_cat(rb, b, ",\"final\":1,\"staged\":\"" as *u8) 1292 b = md_cat_slice(rb, b, path, toff[0], tlen[0]) 1293 b = sd_cat(rb, b, ".new\"}" as *u8) 1294 return ma_emit_200(out, rb) 1295} 1296 1297// ---- write actions (transport orchestration: parse here, allowlist/exec/probe via DATA, decide via CORE) -- 1298// Each is a thin pipeline: parse request -> (data) resolve/validate/exec/probe -> (core) decide -> serialize. 1299 1300const MA_DEPLOY_STATUS: *u8 = "/tmp/nx_ma_deploy_status" as *u8 1301func ma_write_status(s: *u8) -> i64 { 1302 let fd: i64 = sys_openat_wr(MA_DEPLOY_STATUS, 0x1a4) 1303 if fd >= 0 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(fd, s, n); sys_close(fd) } 1304 return 0 1305} 1306// GET /api/deploy_status -> the last deploy's async watchdog verdict (RUNNING|DEPLOYED-GREEN|ROLLED-BACK|PROMOTE-FAILED|none). 1307// ---- GET /api/adnet/invoice (debt 1785513943): make the billing pipeline REACHABLE --------------- 1308// nx_adnet_bill held correct CPM/CPC math that NOTHING called -- zero production callers, only its gate. 1309// A green gate on an uncallable library is still the baseline, so the capability ships as a ROUTE: a 1310// mgmt route is instantly callable, whereas a new MCP tool needs every seat to reconnect. 1311// THIN BY CONSTRUCTION: file access is md_adnet_invoice_report (data ring), money math is nx_adnet_bill, 1312// the rate/event join is nx_adnet_invoice. This function owns transport and nothing else. 1313// 503 rather than 200-with-nothing: an empty invoice and an unreadable one must never look alike. 1314// ---- POST /api/adnet/creative (debt 1785512202): advertiser creative upload ----------------------- 1315// CLOSES THE CHICKEN-AND-EGG: nx_adnet_selfserve requires the img field to be a FIRST-PARTY url, and 1316// nothing in the ecosystem ever let an advertiser produce one -- so no client could onboard at all. 1317// The raw request body IS the png. THIN BY CONSTRUCTION: validation and content-addressed naming are 1318// nx_adnet_creative (gated 13/13), the write is md_adnet_creative_store (data ring); this owns transport. 1319// EVERY REFUSAL NAMES A REMEDIABLE REASON. An advertiser who cannot tell WHY their upload bounced will 1320// mail the operator a png instead, and the self-serve path quietly dies of support load. 1321func ma_do_adnet_creative(req: *u8, req_n: i64, out: *u8) -> i64 { 1322 let body_off: i64 = sd_body_off(req, req_n) 1323 let body: *u8 = ((req as i64) + body_off) as *u8 1324 let body_n: i64 = req_n - body_off 1325 if body_n <= 0 { 1326 return ma_emit_400(out, "{\"error\":\"empty body: POST the png bytes as the raw request body\",\"spec\":\"png, exactly 728x90, at most 65536 bytes\"}" as *u8) 1327 } 1328 let url: *u8 = sys_mmap(256) 1329 let v: i64 = md_adnet_creative_store(body, body_n, url, 256) 1330 if v == ACR_OK { 1331 let rb: *u8 = sys_mmap(MA_MAGIC_1024) 1332 var b: i64 = sd_cat(rb, 0, "{\"action\":\"CREATIVE-ACCEPTED\",\"url\":\"" as *u8) 1333 b = sd_cat(rb, b, url) 1334 b = sd_cat(rb, b, "\",\"note\":\"content-addressed. Put this url in the img field of your inventory row. Re-uploading identical bytes is idempotent; changed artwork mints a NEW url, so the creative can be cached without ever going stale.\"}" as *u8) 1335 rb[b] = 0 as u8 1336 return ma_emit_200(out, rb) 1337 } 1338 if v < 0 { 1339 return ma_emit_503(out, "{\"error\":\"creative validated but could not be written to the docroot; NOTHING was stored\"}" as *u8) 1340 } 1341 let rsn: *u8 = sys_mmap(128) 1342 acr_reason(v, rsn) 1343 let eb: *u8 = sys_mmap(512) 1344 var e: i64 = sd_cat(eb, 0, "{\"action\":\"CREATIVE-REFUSED\",\"reason\":\"" as *u8) 1345 e = sd_cat(eb, e, rsn) 1346 e = sd_cat(eb, e, "\",\"spec\":\"png, exactly 728x90, at most 65536 bytes\",\"why\":\"the weight ceiling is enforced at intake: a banner heavy enough to slow the host page reflects on the client who paid for it\"}" as *u8) 1347 eb[e] = 0 as u8 1348 return ma_emit_400(out, eb) 1349} 1350 1351func ma_do_adnet_invoice(out: *u8) -> i64 { 1352 let rep: *u8 = sys_mmap(MA_MAGIC_65536) 1353 let n: i64 = md_adnet_invoice_report(rep, MA_MAGIC_65536) 1354 if n <= 0 { 1355 return ma_emit_503(out, "{\"error\":\"adnet invoice unavailable: inventory or rate card unreadable. Refusing to emit an empty invoice, which a biller cannot tell apart from a genuinely zero one.\",\"basis\":\"viewable\"}" as *u8) 1356 } 1357 return ma_emit_json(out, "HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\nConnection: close\r\nContent-Length: " as *u8, rep, n) 1358} 1359 1360func ma_do_deploy_status(out: *u8) -> i64 { 1361 let b: *u8 = sys_mmap(256); var n: i64 = 0 1362 let fd: i64 = sys_openat_rd(MA_DEPLOY_STATUS) 1363 if fd >= 0 { n = sys_read(fd, b, 200); sys_close(fd) } 1364 let rb: *u8 = sys_mmap(512); var o: i64 = sd_cat(rb, 0, "{\"deploy_status\":\"" as *u8) 1365 if n > 0 { var i: i64=0; while i<n { if b[i]!=(10 as u8) { if b[i]!=(13 as u8) { rb[o]=b[i]; o=o+1 } } i=i+1 } } else { o = sd_cat(rb, o, "none" as *u8) } 1366 o = sd_cat(rb, o, "\"}" as *u8); rb[o] = 0 as u8 1367 return ma_emit_200(out, rb) 1368} 1369 1370// sanitize a build target name to [a-zA-Z0-9_] ONLY (no /, ., ..) -> prevents path escape in runtime/<name>.nx. 1371// Copies the slice into buf (NUL-terminated). Returns 1 if valid+copied, 0 if empty/too-long/illegal char. 1372func ma_sanitize_name(src: *u8, off: i64, len: i64, buf: *u8, cap: i64) -> i64 { 1373 if len <= 0 { return 0 } 1374 if len >= cap { return 0 } 1375 var i: i64 = 0 1376 while i < len { 1377 let c: i64 = src[off + i] as i64 1378 var ok: i64 = 0 1379 if c >= 48 { if c <= 57 { ok = 1 } } 1380 if c >= 65 { if c <= 90 { ok = 1 } } 1381 if c >= 97 { if c <= 122 { ok = 1 } } 1382 if c == 95 { ok = 1 } 1383 if ok == 0 { return 0 } 1384 buf[i] = src[off + i] 1385 i = i + 1 1386 } 1387 buf[len] = 0 as u8 1388 return 1 1389} 1390// JSON-escape the LAST <maxsrc> bytes of src[0..n) into dst (NUL-terminated), for a build-diagnostic tail. 1391// Escapes " and \ and control bytes (newline/CR/tab -> \n \r \t; other <0x20 dropped). Bounds dst to <cap>. 1392// Returns the dst byte length. Surfaces the real nx_cc/nxasm error+line in a BUILD-FAILED JSON string field. 1393func ma_json_esc_tail(src: *u8, n: i64, maxsrc: i64, dst: *u8, cap: i64) -> i64 { 1394 var start: i64 = 0 1395 if n > maxsrc { start = n - maxsrc } 1396 var o: i64 = 0 1397 var i: i64 = start 1398 while i < n { 1399 if o + 8 >= cap { i = n } else { 1400 let c: i64 = src[i] as i64 1401 if c == 34 { dst[o] = 92 as u8; o = o + 1; dst[o] = 34 as u8; o = o + 1 } 1402 else { if c == 92 { dst[o] = 92 as u8; o = o + 1; dst[o] = 92 as u8; o = o + 1 } 1403 else { if c == 10 { dst[o] = 92 as u8; o = o + 1; dst[o] = 110 as u8; o = o + 1 } 1404 else { if c == 13 { dst[o] = 92 as u8; o = o + 1; dst[o] = 114 as u8; o = o + 1 } 1405 else { if c == 9 { dst[o] = 92 as u8; o = o + 1; dst[o] = 116 as u8; o = o + 1 } 1406 else { if c >= 32 { dst[o] = src[i]; o = o + 1 } } } } } } 1407 i = i + 1 1408 } 1409 } 1410 dst[o] = 0 as u8 1411 return o 1412} 1413// Read the LAST <cap> bytes of a file (0 if unreadable). The builder's full capture can be 1414// megabytes of per-function progress dots; the diagnostics sit at the END, so a bounded tail 1415// always contains them without ever loading the whole log. 1416func ma_read_tail(path: *u8, buf: *u8, cap: i64) -> i64 { 1417 let fd: i64 = sys_openat_rd(path) 1418 if fd < 0 { return 0 } 1419 let sz: i64 = sys_lseek(fd, 0, 2) 1420 var off: i64 = 0 1421 if sz > cap { off = sz - cap } 1422 sys_lseek(fd, off, 0) 1423 let n: i64 = sys_read(fd, buf, cap) 1424 sys_close(fd) 1425 if n < 0 { return 0 } 1426 return n 1427} 1428// First offset of NUL-terminated needle in src[0..n), or -1. Naive scan -- build logs are 1429// tail-bounded 16KB here, so there is no pathological input to be clever about. 1430func ma_find(src: *u8, n: i64, pat: *u8) -> i64 { 1431 var pl: i64 = 0 1432 while pat[pl] != (0 as u8) { pl = pl + 1 } 1433 if pl == 0 { return 0 - 1 } 1434 var i: i64 = 0 1435 var found: i64 = 0 - 1 1436 while i + pl <= n { 1437 var k: i64 = 0 1438 var ok: i64 = 1 1439 while k < pl { 1440 if src[i + k] != pat[k] { ok = 0; k = pl } else { k = k + 1 } 1441 } 1442 if ok == 1 { found = i; i = n } else { i = i + 1 } 1443 } 1444 return found 1445} 1446// file exists (openable for read)? 1 yes / 0 no. 1447func ma_path_exists(path: *u8) -> i64 { 1448 let fd: i64 = sys_openat_rd(path) 1449 if fd >= 0 { sys_close(fd); return 1 } 1450 return 0 1451} 1452// CROSS-TREE DUP-SHADOW detector (seq207/seq164, the clobber-landmine class): a <name>.nx present in BOTH 1453// buildroot/runtime/_hdl_build (probed FIRST by nx_sov_build_run) AND buildroot/runtime (the flat shadow) is a 1454// hazard -- a resolution-order change or a stale flat copy silently regresses the service (it detonated on 1455// nx_mgmt_api this session, dropping the F-210 control plane). Returns 1 if <name>.nx exists in both dirs. 1456// Composes nx_dup_source_check's exact detection logic, wired INLINE at build time = fail-loud, non-blocking. 1457// BANK THE STAGED SLOT BEFORE A REBUILD OVERWRITES IT (2026-08-03, debt 1785771729). 1458// MEASURED: /api/build stages <t>.sov.elf.new by overwrite, with NO warning and NO backup -- so a second 1459// seat's pending release vanishes without a trace the moment anyone rebuilds that target. That is the SAME 1460// blind-clobber class nx_fs_write already refuses via expect= (seq1379); here BANKING is the right remedy 1461// rather than refusing, because refusing would break every ordinary rebuild, while a .prev costs one rename 1462// and keeps the bytes. Wires the EXISTING .prev primitive (promote/deploy/route all use it) -- never a 2nd. 1463// Returns 1 if a prior staged artifact was banked, else 0. Fail-safe: any failure leaves the slot untouched. 1464func ma_bank_staged(nm: *u8) -> i64 { 1465 let cur: *u8 = sys_mmap(512) 1466 var c: i64 = sd_cat(cur, 0, nm) 1467 c = sd_cat(cur, c, ".sov.elf.new" as *u8) 1468 cur[c] = 0 as u8 1469 let fd: i64 = sys_openat_rd(cur) 1470 if fd < 0 { return 0 } 1471 sys_close(fd) 1472 let prev: *u8 = sys_mmap(512) 1473 var p: i64 = sd_cat(prev, 0, cur) 1474 p = sd_cat(prev, p, ".prev" as *u8) 1475 prev[p] = 0 as u8 1476 if sys_renameat(cur, prev) != 0 { return 0 } 1477 return 1 1478} 1479// RESTORE the banked staged artifact when the compile FAILED (2026-08-03, same debt). 1480// WHY THIS IS MANDATORY, not tidiness: 45 tool_allowlist rows EXECUTE a `<t>.sov.elf.new` directly (the 1481// `stagedref` class, incl. 5 deliberate `*_staged` tools). BEFORE banking, a failed rebuild left the old .new 1482// untouched and those tools kept working; WITH banking and no restore, a failed compile would leave the slot 1483// EMPTY and silently break every one of them. A BANK WITHOUT A RESTORE-ON-FAILURE CONVERTS A HARMLESS FAILED 1484// BUILD INTO AN OUTAGE -- pair the copy with the exit code, always. 1485func ma_restore_staged(nm: *u8) -> i64 { 1486 let cur: *u8 = sys_mmap(512) 1487 var c: i64 = sd_cat(cur, 0, nm) 1488 c = sd_cat(cur, c, ".sov.elf.new" as *u8) 1489 cur[c] = 0 as u8 1490 let prev: *u8 = sys_mmap(512) 1491 var p: i64 = sd_cat(prev, 0, cur) 1492 p = sd_cat(prev, p, ".prev" as *u8) 1493 prev[p] = 0 as u8 1494 // Only restore into an EMPTY slot: if the compile actually produced a .new we must never clobber it 1495 // with the older banked copy (that would be the very silent-overwrite this whole change exists to stop). 1496 let fd: i64 = sys_openat_rd(cur) 1497 if fd >= 0 { sys_close(fd); return 0 } 1498 if sys_renameat(prev, cur) != 0 { return 0 } 1499 return 1 1500} 1501// hex-STRING equality (two NUL-terminated renderings). NAMED ma_hexstr_eq because ma_hex_eq is ALREADY 1502// TAKEN at nx_mgmt_api.nx:2582 with a different arity (hex, buf, off, n) -- NishiLang has no overloading, so 1503// the build failed CLOSED on the collision. ⚠the compiler reported the clash at "line 21181", which is BEYOND 1504// EOF for this 290KB file; the real prior definition is at 2582. A diagnostic with a bogus line number sends 1505// you to the wrong place -- grep the NAME, do not trust the number. 1506func ma_hexstr_eq(a: *u8, b: *u8) -> i64 { 1507 var i: i64 = 0 1508 while a[i] != (0 as u8) { 1509 if a[i] != b[i] { return 0 } 1510 i = i + 1 1511 } 1512 if b[i] != (0 as u8) { return 0 } 1513 return 1 1514} 1515// sha256 of a file bytes, rendered hex into `hexout` (65 bytes incl NUL). 1 = ok, 0 = unreadable. 1516// Same sha256_digest + mau_hex32 pair the staged-artifact digest already uses -- not a second derivation. 1517 1518// Identity is read from the executing inode, never the mutable install pathname. 1519// This identifies the process answering this request; it is not a hardware attestation. 1520func ma_release_identity(out: *u8) -> i64 { 1521 let hex: *u8=sys_mmap(65) 1522 if ma_file_sha_hex("/proc/self/exe",hex) != 1 { 1523 sys_munmap(hex,65) 1524 return ma_emit_503(out,"{\"error\":\"running executable identity could not be read\",\"stage\":\"release-identity\",\"action\":\"inspect this process executable mapping; do not accept release readiness\"}") 1525 } 1526 let prefix: *u8="{\"schema\":\"nishi.release-identity.v1\",\"sha256\":\"" 1527 let suffix: *u8="\",\"basis\":\"running-executable\"}" 1528 let capacity: i64=sd_len(prefix)+64+sd_len(suffix)+1 1529 let body: *u8=sys_mmap(capacity) 1530 var n: i64=sd_cat(body,0,prefix) 1531 n=sd_cat(body,n,hex);n=sd_cat(body,n,suffix);body[n]=0 as u8 1532 let result: i64=ma_emit_200(out,body) 1533 sys_munmap(body,capacity);sys_munmap(hex,65) 1534 return result 1535} 1536func ma_file_sha_hex(path: *u8, hexout: *u8) -> i64 { 1537 var size: i64=0 1538 let bytes: *u8 = tea_read_conf(path, &size) 1539 if (bytes as i64) == 0 { return 0 } 1540 let dig: *u8 = sys_mmap(32) 1541 sha256_digest(bytes, size, dig) 1542 mau_hex32(dig, hexout) 1543 sys_munmap(bytes,size+1) 1544 sys_munmap(dig,32) 1545 return 1 1546} 1547 1548func ma_build_dup_shadow(nm: *u8) -> i64 { 1549 let pa: *u8 = sys_mmap(256) 1550 var a: i64 = sd_cat(pa, 0, "buildroot/runtime/_hdl_build/" as *u8) 1551 a = sd_cat(pa, a, nm); a = sd_cat(pa, a, ".nx" as *u8); pa[a] = 0 as u8 1552 let pb: *u8 = sys_mmap(256) 1553 var b: i64 = sd_cat(pb, 0, "buildroot/runtime/" as *u8) 1554 b = sd_cat(pb, b, nm); b = sd_cat(pb, b, ".nx" as *u8); pb[b] = 0 as u8 1555 if ma_path_exists(pa) == 1 { if ma_path_exists(pb) == 1 { return 1 } } 1556 return 0 1557} 1558// POST /api/build {target=<name>}: COMPILE a target ON THE NAS via the on-NAS toolchain (nx_hostctl buildrun) 1559// -> stage <name>.sov.elf.new for /api/deploy. The build half of build-over-API: source->binary with ZERO WSL. 1560// Name sanitized to [a-zA-Z0-9_] (no path escape); target must already exist in the synced buildroot/runtime. 1561// On success, a `dup_shadow` field warns fail-loud if the source basename exists in BOTH source dirs (seq207). 1562// PURE RENDERER FOR THE BUILD-ADMISSION REFUSAL, EXTRACTED 2026-08-20 SO THE PROPERTY IS TESTABLE. 1563// The branch that produces this body only fires when the real host is saturated, and a gate must never 1564// be asked to reproduce a volatile host condition -- that is a request to remove the sensor, not to test 1565// it. Splitting the DECISION (host state, nx_build_admit's job) from the RENDERING (this function) puts 1566// the half that can silently drift -- the words -- somewhere a gate can hold it with a fixture. 1567// A MESSAGE NOBODY CAN TEST IS A MESSAGE THAT WILL DRIFT, AND THIS ONE DRIFTED LONG ENOUGH TO COST A DAY 1568// OF LANES RE-PLANNING AROUND A CAUSE THAT COULD NOT HAVE FIRED. 1569// 1570// AND THE PROSE BRANCHES ON THE RECEIPT (2026-08-20, closes debt 1787178882). It used to promise "NOT 1571// forgotten: an enqueue was launched" UNCONDITIONALLY, while the rc it printed two fields later said the 1572// enqueue had failed -- measured 2026-08-19 as queue_launch_rc=4 with the deployq- row MISSING and the 1573// capture file ABSENT. A RECEIPT THAT STATES AN OUTCOME IT ALSO REPORTS AS FAILED IS WORSE THAN SILENCE: 1574// the machine-readable field was right and the sentence everybody actually reads was wrong, so callers 1575// went away to wait for a build nothing was going to run. The rc now decides the sentence. 1576func ma_build_refusal_body(bao: *u8, ban: i64, batr: i64, nm: *u8, qrc: i64, qout: *u8) -> *u8 { 1577 let qb: *u8 = sys_mmap(MA_MAGIC_32768) 1578 var qp: i64 = sd_cat(qb, 0, "{\"error\":\"build REFUSED by nx_build_admit. THIS ENDPOINT DELIBERATELY DOES NOT RESTATE THE CAUSE -- read admit_detail: it is the detector's own verdict line plus the live /proc figures behind it, and those figures name WHICH of its three conjuncts fired (an I/O storm on the D-state roster, run-queue CPU saturation, or the storm load ceiling). Do not assume CPU: on this host the load ceiling is set far above any reachable load, so an I/O storm is the usual firing conjunct. The build did NOT run. " as *u8) 1579 if qrc == 0 { qp = sd_cat(qb, qp, "It is NOT forgotten: the enqueue was LAUNCHED AND RETURNED rc=0, so this build fires on the first nx_orchestrate pass with build headroom (headroom: predicate, ~5 min cadence) -- verify the row landed with nx_store_put knowledge/store/deployq- load and find the BQ-<target> row: its status column reads queued until nx_orchestrate fires it and fired-rc0 afterwards. DO NOT reach for nx_planepeek here -- it resolves a RAW SEG-STORE KEY (q:<n>), never a row id, so nx_planepeek deployq- BQ-<target> answers MISS for a row that IS present, which reads exactly like a failed enqueue. That instruction was wrong from 2026-08-18 until it was measured and corrected 2026-08-20: A RECEIPT THAT NAMES THE WRONG VERIFICATION COMMAND MANUFACTURES THE VERY FAILURE IT WAS WRITTEN TO DISPROVE. The build result lands in knowledge/store/planrun-build-<target>-; promote deliberately afterwards. WHERE THIS AND admit_detail DISAGREE ABOUT QUEUING, BELIEVE THIS ONE -- queue_launch_rc is the receipt and the detector cannot see it. The detector's own text was CORRECTED 2026-08-20 and now agrees: it says it queues nothing itself and points at this very field, so the two should no longer disagree at all. If you are reading an admit_detail that still ends NOTHING IS QUEUED for you anywhere, you are looking at an OLDER nx_build_admit binary -- that is staleness in the detector, not here. " as *u8) } 1580 if qrc != 0 { qp = sd_cat(qb, qp, "AND THE ENQUEUE FAILED -- NOTHING IS QUEUED FOR YOU ANYWHERE. queue_launch_rc below is NON-ZERO, so the absorber did not take this build and nothing will retry it on your behalf: RE-ISSUE IT YOURSELF once the load clears, paced a minute or more apart, and read queue_launch_out for the capture. This endpoint used to promise an enqueue unconditionally while its rc said otherwise (debt 1787178882, measured rc=4 with the deployq- row MISSING), which sent callers away to wait for a build nobody was going to run. " as *u8) } 1581 qp = sd_cat(qb, qp, "If this build is itself the repair for the saturation, use the sovereign path _offc/nx_sov_build_run.elf <target> --build-only, which does not consult mgmt admission.\",\"detector\":\"nx_build_admit\",\"verdict\":\"REFUSED-BUILD-ADMIT\",\"queued\":" as *u8) 1582 var qok: i64 = 0 1583 if qrc == 0 { qok = 1 } 1584 qp = sd_catn(qb, qp, qok) 1585 qp = sd_cat(qb, qp, ",\"admit_detail\":\"" as *u8) 1586 qp = ma_gate_esc(qb, qp, bao, ban) 1587 qp = sd_cat(qb, qp, "\",\"admit_detail_bytes\":" as *u8) 1588 qp = sd_catn(qb, qp, ban) 1589 qp = sd_cat(qb, qp, ",\"admit_detail_truncated\":" as *u8) 1590 qp = sd_catn(qb, qp, batr) 1591 qp = sd_cat(qb, qp, ",\"queue_row\":\"BQ-" as *u8) 1592 qp = sd_cat(qb, qp, nm) 1593 qp = sd_cat(qb, qp, "\",\"queue_launch\":\"nx_job_run nx_buildq add\",\"queue_launch_rc\":" as *u8) 1594 qp = sd_catn(qb, qp, qrc) 1595 qp = sd_cat(qb, qp, ",\"queue_launch_out\":\"" as *u8) 1596 qp = sd_cat(qb, qp, qout) 1597 qp = sd_cat(qb, qp, "\"}}" as *u8) 1598 qb[qp] = 0 as u8 1599 return qb 1600} 1601 1602// PURE RENDERER FOR THE PROMOTE REFUSAL, EXTRACTED 2026-08-20 -- the same move, for the same reason, as 1603// ma_build_refusal_body directly above it. The branch that produces this body needs a staged artifact 1604// PLUS a provenance history to fire, and a gate must never be asked to reproduce that state; splitting 1605// the DECISION (md_promote_staged_ex) from the RENDERING (here) puts the half that silently drifts -- 1606// the words -- somewhere a fixture can hold it. 1607// A MESSAGE NOBODY CAN TEST IS A MESSAGE THAT WILL DRIFT, AND THIS ONE'S DRIFT WAS MEASURED IN 1608// BREAK-GLASS COPIES: labelled NOTHING-STAGED, it sent a seat to nx_filecopy twice in one day to restore 1609// gate binaries by hand, because a refusal that misdescribes itself teaches every reader to bypass it. 1610// Returns 0 for any code this renderer does not own -- the caller falls through to its existing paths. 1611const MA_PROMOTE_REFUSE_BACKWARDS: i64 = 0 - 2 1612const MA_PROMOTE_REFUSE_CAPLOSS: i64 = 0 - 3 1613func ma_promote_refusal_body(mprc: i64, nm: *u8, livehex: *u8) -> *u8 { 1614 var owned: i64 = 0 1615 if mprc == MA_PROMOTE_REFUSE_BACKWARDS { owned = 1 } 1616 if mprc == MA_PROMOTE_REFUSE_CAPLOSS { owned = 1 } 1617 if owned == 0 { return 0 as *u8 } 1618 let pb: *u8 = sys_mmap(MA_MAGIC_4096) 1619 var p: i64 = 0 1620 if mprc == MA_PROMOTE_REFUSE_BACKWARDS { p = sd_cat(pb, 0, "{\"action\":\"REFUSED-BACKWARDS-WALK\",\"target\":\"" as *u8) } 1621 if mprc == MA_PROMOTE_REFUSE_CAPLOSS { p = sd_cat(pb, 0, "{\"action\":\"REFUSED-CAPABILITY-LOSS\",\"target\":\"" as *u8) } 1622 p = sd_cat(pb, p, nm) 1623 p = sd_cat(pb, p, "\",\"staged\":\"the staged .elf.new IS in place and UNTOUCHED -- this is a REFUSAL, not an absence\",\"live_sha256\":\"" as *u8) 1624 p = sd_cat(pb, p, livehex) 1625 p = sd_cat(pb, p, "\",\"reason\":\"" as *u8) 1626 if mprc == MA_PROMOTE_REFUSE_BACKWARDS { p = sd_cat(pb, p, "PROVENANCE (seq1484): the staged bytes are a generation this target ALREADY HELD and are not its newest, so promoting them would walk it BACKWARDS. THE allow_capability_loss FLAG DOES NOT COVER THIS AND NEVER DID -- md_prov_ok runs unconditionally and that flag gates a different conjunct entirely. WHAT TO DO: if this is a deliberate rollback use /api/rollback, which is the reverse gear and records itself as one -- do NOT copy the binary into place by hand, that is how a restore stops being auditable. If you believe these bytes are NEW, compare live_sha256 above with the artefact you built: equal means it is ALREADY live and only your receipt was lost in transport. If you are re-promoting a rebuilt organ, rebuild from CURRENT source -- a binary identical to an older generation means your source is behind, not that the guard is wrong." as *u8) } 1627 if mprc == MA_PROMOTE_REFUSE_CAPLOSS { p = sd_cat(pb, p, "STAGING HYGIENE: the staged artifact would replace the live one with something the hygiene classifier judges a capability LOSS -- older than what it replaces, or dropping live capability tokens even while LARGER, since neither mtime nor size alone catches the class. THIS is the conjunct that allow_capability_loss=yes covers. WHAT TO DO: run nx_contentdiff on the live elf against the staged one and READ ITS LOST lines. If every lost run is a deliberate reword you can NAME, re-issue with allow_capability_loss=yes and name them in the same breath; if you cannot name them, the staged build is a regression and the flag would ship it." as *u8) } 1628 p = sd_cat(pb, p, "\"}" as *u8) 1629 pb[p] = 0 as u8 1630 return pb 1631} 1632 1633// ---- THE ENQUEUE, EXTRACTED (2026-09-02) so the two refusal sites below cannot drift ------------------- 1634// Launch `nx_buildq add <target>` DETACHED through nx_job_run (it forks the job and returns in milliseconds; 1635// a plane put can take ~90 s under contention and this handler must never block on it). Returns the 1636// launcher rc. The row id is deterministic (BQ-<target>) and nx_store_put re-puts BY ID, so calling this 1637// twice for one target yields ONE row -- MEASURED 2026-09-02 over the whole deployq- plane: 231 rows, 1638// 231 distinct ids, zero duplicates. The queue is idempotent by construction, which is why every refusal 1639// path may call this without dedupe bookkeeping. 1640func ma_build_enqueue(nm: *u8, qout: *u8) -> i64 { 1641 var qo: i64 = sd_cat(qout, 0, "/tmp/nx_buildq_" as *u8) 1642 qo = sd_cat(qout, qo, nm) 1643 qo = sd_cat(qout, qo, ".out" as *u8) 1644 qout[qo] = 0 as u8 1645 let qargs: *i64 = sys_mmap(8 * 6) as *i64 1646 qargs[0] = "nx_buildq" as *u8 as i64 1647 qargs[1] = qout as i64 1648 qargs[2] = "add" as *u8 as i64 1649 qargs[3] = nm as i64 1650 return dep_run_capture("/volume1/homes/elderwesto/nishihost/nx_job_run.elf" as *u8, qargs, 4, "/tmp/nx_buildq_launch.out" as *u8) 1651} 1652// ---- THE RUNNER'S OWN ADMISSION REFUSAL, RECOGNISED (2026-09-02; debt 1787939090, the FIFTH filing) ----- 1653// /api/build admits ONCE (md_exec_build_admit) and then forks hostctl buildrun, whose child 1654// nx_sov_build_run consults the SAME ruler again moments later and exits SBR_ADMIT_REFUSED (6) when the 1655// box moved under it. hostctl echoes `child exit=6 sig=0` into the capture. Until now that fell through 1656// to BUILD-FAILED ("nx_cc/nxasm produced no elf; is the target in buildroot/runtime?") -- an admission 1657// refusal wearing a compile failure's clothes -- so under a real storm the absorber branch was NEVER 1658// REACHED, nothing was queued, and the caller was sent to inspect a target that was never compiled. 1659// Measured 2026-08-28 at procs_blocked=8 of 8 and re-derived here from source. TWO ADMISSION CHECKS IN 1660// SERIES ARE A RACE WHOSE LOSING BRANCH MUST STILL LAND IN THE QUEUE, OR THE QUEUE IS DECORATION. 1661// Returns 1 iff the capture carries the runner's refusal; the caller then takes the QUEUE branch. 1662func ma_runner_refused(pbuf: *u8, pn: i64) -> i64 { 1663 if ma_find(pbuf, pn, "child exit=6 sig=0" as *u8) >= 0 { return 1 } 1664 return 0 1665} 1666 1667func ma_do_build(req: *u8, req_n: i64, out: *u8) -> i64 { 1668 let body_off: i64 = sd_body_off(req, req_n) 1669 let body: *u8 = ((req as i64) + body_off) as *u8 1670 let body_n: i64 = req_n - body_off 1671 let toff: *i64 = sys_mmap(8) as *i64 1672 let tn: *i64 = sys_mmap(8) as *i64 1673 if sd_form_field(body, body_n, "target" as *u8, 6, toff, tn) != 1 { 1674 return ma_emit_400(out, "{\"error\":\"missing target\"}" as *u8) 1675 } 1676 let nm: *u8 = sys_mmap(128) 1677 if ma_sanitize_name(body, toff[0], tn[0], nm, 120) != 1 { 1678 return ma_emit_400(out, "{\"error\":\"invalid target name (only [a-zA-Z0-9_])\"}" as *u8) 1679 } 1680 // BUILD ADMISSION -- MUST run BEFORE the nx_cc fork below (seq708/768/1390). Forking the compiler on 1681 // a memory-wedged host is what OOM-reaps this very daemon and takes the deploy path down for every 1682 // seat, so the check has to gate the fork, not report on it afterwards. 1683 // 1684 // TWO BLOCKING VERDICTS (corrected 2026-07-30). Exit 3 = DENY, MemAvailable below the floor: the 1685 // measured 2026-07-20 wedge, where userspace could not fork at all. Exit 4 = QUEUE, the load ceiling. 1686 // THE EXIT-4 BLOCK WAS LIVE IN THE DEPLOYED BINARY AND IN THE LAPTOP TREE BUT ABSENT FROM THIS ONE -- 1687 // the buildroot /api/build actually compiles -- so the next build by ANY seat would have silently 1688 // deleted seq1475's backpressure, with no error anywhere. Landed here so a rebuild cannot lose it. 1689 // Blocking on exit 4 is safe ONLY because nx_build_admit now CONFIRMS the load against procs_running 1690 // (the TRUE run queue, R not D) before returning it: a disk-bound host no longer reads as CPU 1691 // saturation, so the false refusals that deadlocked every seat are gone. Gate nx_build_admit_gate 1692 // 10/10 including a revert-detecting neg-control. usage/unreadable-proc still fall through to build. 1693 let admit: i64 = md_exec_build_admit() 1694 if admit == 3 { 1695 return ma_emit_503(out, "{\"error\":\"build refused: host below the memory floor. Forking the compiler now risks wedging the host and OOM-reaping the mgmt API for every seat. The detector prints the live figure and the floor it used -- run nx_build_admit.elf check to see both. Retry after 30s.\",\"detector\":\"nx_build_admit\",\"verdict\":\"DENY-MEM\"}" as *u8) 1696 } 1697 if admit == 4 { 1698 // QUEUE INSTEAD OF FORGET (2026-08-18). This branch used to say "nothing is queued for you anywhere -- 1699 // re-issue it yourself", which made every seat the retry loop for the box. The absorber now exists: 1700 // nx_orchestrate's `headroom:` predicate + nx_buildq (plan-build-<t>- + deployq BQ-<t>). Launch the 1701 // enqueue DETACHED through nx_job_run (it forks the job and returns in milliseconds; a plane put can 1702 // take ~90 s under contention and this handler must never block on it), then answer honestly: the 1703 // build did NOT run (still 503), the enqueue was LAUNCHED (rc reported), and the row is the proof -- 1704 // the response names where to look rather than claiming QUEUED from intention. Fail-open: a failed 1705 // launch changes nothing about the refusal, it only reports its rc. 1706 let qout: *u8 = sys_mmap(MA_MAGIC_1024) 1707 // no thresholds relayed: the queue row's bare `headroom:` and this path's own admission both read 1708 // knowledge/build_admit.conf, so "fires when this build would have been admitted" holds by 1709 // construction with ONE definition of the envelope. The launch itself is ma_build_enqueue (above), 1710 // SHARED with the runner-refusal branch in the BUILD-FAILED path so the two sites cannot drift. 1711 let qrc: i64 = ma_build_enqueue(nm, qout) 1712 // ---- STOP PARAPHRASING ANOTHER ORGAN'S VERDICT (2026-08-20, upgrades debt 1787178882) ---- 1713 // A HAND-COPIED RESTATEMENT OF ANOTHER ORGAN'S VERDICT IS A DUPLICATE RULER MADE OF PROSE: it 1714 // drifts silently, no gate can see it drift, and it sends every reader at the wrong cause. 1715 // WHAT THIS SAID AND WHY IT WAS WRONG: "host load above 1.00 x ncpu AND the run queue confirms 1716 // CPU saturation". nx_build_admit's OWN verdict text states a THREE-WAY DISJUNCTION -- the 1717 // D-state roster shows an I/O storm (procs_blocked >= blocked_max), OR the run queue confirms 1718 // CPU saturation (procs_running >= ncpu), OR load exceeds the storm ceiling -- and it adds "the 1719 // figures above name which fired". The paraphrase collapsed that into a definite AND, which is a 1720 // COMPOUND ASSERTION THAT WILL NOT NAME ITS FAILING CONJUNCT, so the reader always guesses. 1721 // MEASURED HERE 2026-08-20 from the detector's own live line: max_centiload=100000 against 1722 // load1_centi=1552, so the LOAD conjunct is structurally unreachable on this lane -- the one 1723 // cause this sentence named is the one cause that cannot have fired, while procs_blocked was 1724 // observed at 7 of 8. Lanes spent a day re-planning around a cause that was never the cause. 1725 // THE FIX IS PASS-THROUGH, NOT A BETTER SENTENCE. Correcting the paraphrase would only reset its 1726 // drift clock. md_exec_build_admit already captures the detector's stdout to this exact path, so 1727 // the authoritative text costs one read; it is carried VERBATIM in admit_detail and this handler 1728 // now asserts NOTHING about the cause. 1729 // ONE CLAIM STAYS LOCAL, DELIBERATELY, AND THE CONTRADICTION IS NAMED RATHER THAN INHERITED: 1730 // the detector's text still ends "NOTHING IS QUEUED for you anywhere (the planned wait-for- 1731 // opening absorber was retired unbuilt)". That sentence is stale IN THE DETECTOR, not here -- 1732 // the absorber was built on 2026-08-18 (nx_buildq + nx_orchestrate's headroom: predicate) and 1733 // THIS branch launches the enqueue a few lines above and holds its rc. A blind pass-through 1734 // would therefore have shipped a REGRESSION, replacing a true local statement with a stale 1735 // remote one. Pass through what the other organ OWNS (the cause); keep what this one owns (that 1736 // it queued, and the receipt); and say which is authoritative so the next reader fixes the 1737 // detector's sentence instead of re-deriving all of this. 1738 let bao: *u8 = sys_mmap(MA_MAGIC_4096) 1739 let ban: i64 = dp_read("/tmp/nx_build_admit.out" as *u8, bao, MA_MAGIC_4000) 1740 // NO SILENT CAP: the read is bounded, so the bound and whether it bit are both reported. 1741 var batr: i64 = 0 1742 if ban >= MA_MAGIC_4000 { batr = 1 } 1743 return ma_emit_503(out, ma_build_refusal_body(bao, ban, batr, nm, qrc, qout)) 1744 } 1745 // ---- GATE-DRY RATCHET (2026-07-31, debts 1785529506 / 1785530277): STOP THE BLEEDING ON D001 ---- 1746 // L009 -- gates that hand-roll their verdict instead of inheriting nx_gate_verdict -- grew from 1747 // 2035/2167 to 2041/2182 within a SINGLE SESSION on 2026-07-31. A campaign that only migrates old 1748 // gates LOSES to a tree that adds new ones, so the count is gated HERE, at the one act that admits 1749 // a new gate to the ecosystem. This is the missing half: the migrator removes, the ratchet holds. 1750 // 1751 // IT IS A RATCHET, NOT A WALL. Only a gate with NO deployed artefact -- a NEW one -- is held to the 1752 // base class. The 2041 existing breaches are GRANDFATHERED and migrated by their owner lanes; 1753 // refusing them here would stop every seat dead. Same grandfathering nx_magicratchet described. 1754 // 1755 // u26a0THE PREDECESSOR THIS SHOULD HAVE COPIED DOES NOT EXIST: nx_magicratchet is asserted "wired into 1756 // /api/build" in FOUR comments in nx_law_warden.nx, yet grep finds ZERO call sites here AND ZERO in 1757 // the deployed mgmt binary, and a two-build experiment (clean -> BUILT, +3 literals >=1024 -> BUILT) 1758 // proves it never fires. Rule 11 has no submission gate. This one is written fresh and, unlike that 1759 // one, is proven by a NEGATIVE CONTROL rather than by a comment. 1760 // 1761 // FAIL-OPEN: md_exec_gatedry returns -1 when the detector is absent, and the build proceeds. 1762 // u26a0ENFORCEMENT WITHDRAWN 2026-07-31, SAME SESSION IT LANDED -- MY GRANDFATHER TEST WAS WRONG. 1763 // I keyed "is this gate NEW?" on "has no deployed .elf". That is FALSE for most of the corpus: 1764 // the ledger measures 2877 gate sources against 175 binaries, i.e. ~94pc of gates WERE NEVER 1765 // COMPILED. So deployclass_gate and roleaccess_gate -- in the tree for weeks -- both read as NEW 1766 // and their rebuilds were REFUSED. A ratchet that blocks the existing corpus is a WALL, and a wall 1767 // at a shared chokepoint stops every seat. 1768 // The detector (nx_gatedry) is sound and stays live; only the REFUSAL is withdrawn until the 1769 // grandfather test is sound. A correct one needs a BANKED BASELINE of known gate names (the 1770 // Notion model: violations are recorded, and only an INCREASE against the record is refused) -- 1771 // absence of a build artefact is not evidence of newness. 1772 // Per the 2026 guidance this should also re-enter as a WARNING first and escalate to an error. 1773 if md_name_is_gate(nm) == 1 { 1774 if md_gate_in_baseline(nm) == 0 { 1775 let gsrc: *u8 = sys_mmap(256) 1776 var gp: i64 = 0 1777 let gpre: *u8 = "buildroot/runtime/_hdl_build/" 1778 var gi: i64 = 0 1779 while gpre[gi] != (0 as u8) { gsrc[gp] = gpre[gi]; gp = gp + 1; gi = gi + 1 } 1780 gi = 0 1781 while nm[gi] != (0 as u8) { gsrc[gp] = nm[gi]; gp = gp + 1; gi = gi + 1 } 1782 let gsuf: *u8 = ".nx" 1783 gi = 0 1784 while gsuf[gi] != (0 as u8) { gsrc[gp] = gsuf[gi]; gp = gp + 1; gi = gi + 1 } 1785 gsrc[gp] = 0 as u8 1786 let gdv: i64 = md_exec_gatedry(gsrc) 1787 if gdv == 1 { 1788 return ma_emit_400(out, "{\"error\":\"NEW GATE REFUSED: it hand-rolls its verdict instead of inheriting nx_gate_verdict (L009/D001). Existing gates are GRANDFATHERED -- this applies only to a gate with no deployed artefact, so the fix is to write the new one on the base class, not to migrate anything. Use gv_ctr/gv_head/gv_check/gv_verdict. Run nx_gatedry <src> to see the classification.\",\"detector\":\"nx_gatedry\",\"verdict\":\"CUSTOM-VERDICT\"}" as *u8) 1789 } 1790 if gdv == 2 { 1791 return ma_emit_400(out, "{\"error\":\"NEW GATE REFUSED: it emits no verdict= anchor, so nx_gate_green reads a PASSING run as NOT-GREEN and the gate is structurally unjudgeable (seq585). Emit through nx_gate_verdict (gv_verdict) and the anchor comes with it. Run nx_gatedry <src> to see the classification.\",\"detector\":\"nx_gatedry\",\"verdict\":\"NO-VERDICT\"}" as *u8) 1792 } 1793 } 1794 } 1795 1796 // ---- F881: RULE 11 FINALLY GETS ITS SUBMISSION GATE (2026-08-15, debt 1785530277) ----------------- 1797 // OUTSIDE the gate-name test on purpose: rule 11 is not a gate-only law, so every organ is checked. 1798 // nx_magicratchet exits 0 GRANT -- including first-sight self-baseline and ALLOW-UNCOUNTED -- and 3 1799 // ONLY when a MEASURED count exceeds a MEASURED baseline. Absent detector, unreadable source and 1800 // usage error all return non-3 and the build proceeds. The failure direction is therefore "an organ 1801 // that should have been refused gets built", which is the correct direction at a shared chokepoint 1802 // and the same stance build admission and the gate-dry runner already take. 1803 // THE REFUSAL CARRIES THE DETECTOR'S OWN WORDS -- file, line, column, value, proposed const. A 1804 // refusal that does not say what and how is a guard people learn to route around. 1805 let mrv: i64 = md_exec_magicratchet(nm) 1806 if mrv == 3 { 1807 return ma_emit_400(out, "{\"error\":\"BUILD REFUSED: this build ADDS inline magic numbers (rule 11) against the organ's banked baseline. The ratchet only lets the count go DOWN, and existing violations are grandfathered at first sight -- so this is a NEW literal, not old debt. Run nx_magicratchet check <organ> for the offending line/col/value and a proposed const, then hoist it to a NAMED const -- named for its PURPOSE, never for its value.\",\"detector\":\"nx_magicratchet\",\"verdict\":\"MAGIC-INCREASE\"}" as *u8) 1808 } 1809 1810 // ---- R1 (seq1506): LEASE-GATE THE BUILD -- the flagger, not a brave driver ---------------------------- 1811 // OPERATOR: "why cant we clearly state when we are switching out or updating and coordinate like road 1812 // construction". Concurrent builds of the SAME target are how a session ships a regression from a 1813 // mid-churn snapshot: it happened TWICE today (mgmt lost /api/gate_run + /api/proc_kill, 21->19 routes, 1814 // because a sibling built while the tree was being edited). A race nobody can see is not a risk anyone 1815 // can manage -- so make the collision IMPOSSIBLE and, when it happens, NAME THE HOLDER. 1816 // ADOPTION not invention (seq1410, 4th instance today): nx_lease already existed, gate-proven, with ZERO 1817 // callers here. Reused by its exit-code contract (0=acquired, 3=BUSY) -- no import, no reimplementation. 1818 // TTL 600s is why this cannot deadlock the ecosystem: a session that dies mid-build cannot hold the lane 1819 // closed. A lock without a TTL would be a worse defect than the race it prevents. 1820 // ---- seq1337 RESTORED (lost to source churn; operator: "this is the top fix as its wasting our work") ---- 1821 // WHY THIS MUST EXIST: a compile that outlives the edge read window is INDISTINGUISHABLE from an infra 503 1822 // at the caller, which is exactly how a COMPILER HANG masquerades as an outage. I lived it repeatedly today: 1823 // FETCH-FAIL/503 with no way to tell "still compiling" from "the edge died" from "the host is wedged", so the 1824 // only strategy left is retry-hammering -- which adds load to the very condition being waited on. 1825 // async=yes DETACHES the compile and returns AT ONCE with a poll path. The caller then polls a marker that 1826 // can ONLY exist once the build actually finished, so the two states become DIFFERENT OBSERVABLES rather 1827 // than one ambiguous timeout. The marker is written to a tmp path and RENAMED (atomic), so a reader never 1828 // sees a half-written verdict. The path carries a millisecond timestamp, so a PREVIOUS run's marker can 1829 // never be mistaken for this one's result -- staleness is foreclosed by construction, not by cleanup. 1830 let aoff: *i64 = sys_mmap(8) as *i64 1831 let anf: *i64 = sys_mmap(8) as *i64 1832 var want_async: i64 = 0 1833 if sd_form_field(body, body_n, "async" as *u8, 5, aoff, anf) == 1 { if anf[0] >= 1 { if body[aoff[0]] == (121 as u8) { want_async = 1 } } } 1834 if want_async == 1 { 1835 sys_mkdir("_jobs" as *u8, 0x1ed) 1836 let stamp: i64 = sys_now_realtime_ms() 1837 let jdone: *u8 = sys_mmap(256) 1838 let jout: *u8 = sys_mmap(256) 1839 let jtmp: *u8 = sys_mmap(256) 1840 var jo: i64 = sd_cat(jdone, 0, "_jobs/build_" as *u8); jo = sd_cat(jdone, jo, nm); jo = sd_cat(jdone, jo, "_" as *u8); jo = sd_catn(jdone, jo, stamp); jo = sd_cat(jdone, jo, ".done" as *u8); jdone[jo] = 0 as u8 1841 var jq: i64 = sd_cat(jout, 0, "_jobs/build_" as *u8); jq = sd_cat(jout, jq, nm); jq = sd_cat(jout, jq, "_" as *u8); jq = sd_catn(jout, jq, stamp); jq = sd_cat(jout, jq, ".out" as *u8); jout[jq] = 0 as u8 1842 var jt: i64 = sd_cat(jtmp, 0, "_jobs/build_" as *u8); jt = sd_cat(jtmp, jt, nm); jt = sd_cat(jtmp, jt, "_" as *u8); jt = sd_catn(jtmp, jt, stamp); jt = sd_cat(jtmp, jt, ".tmp" as *u8); jtmp[jt] = 0 as u8 1843 // Acquire BEFORE forking: the parent returns immediately, so if we left the lease to the sync path 1844 // below an async build would run UNGATED and a sibling could start a racing build of the same target. 1845 // The CHILD releases it when the compile actually ends (see below) -- releasing in the parent would 1846 // reopen the lane while the compiler is still running, which is the exact race R1 exists to prevent. 1847 let alnm: *u8 = sys_mmap(192) 1848 md_lease_name(nm, alnm) 1849 if md_lease_run("acquire" as *u8, alnm, "mgmt-api-build" as *u8, ma_lease_ttl_txt(MA_BUILD_LEASE_TTL_S), 4, "/tmp/nx_ma_lease.out" as *u8) == 3 { 1850 let albb: *u8 = sys_mmap(MA_MAGIC_2048) 1851 let albn: i64 = dp_read("/tmp/nx_ma_lease.out" as *u8, albb, 900) 1852 let acb: *u8 = sys_mmap(MA_MAGIC_4096) 1853 var aco: i64 = sd_cat(acb, 0, "{\"conflict\":\"lease-busy\",\"error\":\"another session is ALREADY BUILDING this exact target -- refusing to race it (seq1506 R1). The holder is named below; the lease is TTL-bounded so a dead session cannot hold the lane closed.\",\"holder\":\"" as *u8) 1854 aco = ma_gate_esc(acb, aco, albb, albn) 1855 aco = ts_retry_after_derived(acb, aco, MA_BUILD_LEASE_TTL_S) 1856 acb[aco] = 0 as u8 1857 return ma_emit_400(out, acb) 1858 } 1859 let abanked: i64 = ma_bank_staged(nm) // bank BEFORE the fork so BOTH build paths are covered (debt 1785771729) 1860 let apid: i64 = sys_fork() 1861 if apid == 0 { 1862 // DETACHED WORKER: shed the request fds so the parent's response is not held open by us, then 1863 // compile, then publish the verdict by ATOMIC RENAME. The lease is released HERE, not in the 1864 // parent, because the parent returns long before the compile ends -- releasing early would let a 1865 // sibling start a racing build of the same target while this one is still running. 1866 nx_setsid() 1867 let dn: i64 = sys_openat_wr("/dev/null" as *u8, 0x1a4) 1868 if dn >= 0 { sys_dup3(dn, 0, 0); sys_dup3(dn, 1, 0); sys_dup3(dn, 2, 0) } 1869 md_exec_hostctl_capture2("buildrun" as *u8, nm, jout) 1870 let abuf: *u8 = sys_mmap(MA_MAGIC_16384) 1871 let an2: i64 = dp_read(jout, abuf, MA_MAGIC_16380) 1872 var built: i64 = 0 1873 var abytes: i64 = 0 1874 if an2 > 0 { abytes = hh_after(abuf, an2, "size=" as *u8); if abytes > 0 { built = 1 } } 1875 // same restore contract as the sync path: a failed async compile must not strand a stagedref tool 1876 if built == 0 { if abanked == 1 { ma_restore_staged(nm) } } 1877 let mb: *u8 = sys_mmap(256) 1878 var mo: i64 = sd_cat(mb, 0, "state=DONE built=" as *u8) 1879 mo = sd_catn(mb, mo, built) 1880 mo = sd_cat(mb, mo, " bytes=" as *u8) 1881 mo = sd_catn(mb, mo, abytes) 1882 mo = sd_cat(mb, mo, "\n" as *u8) 1883 let mfd: i64 = sys_openat_wr(jtmp, 0x1a4) 1884 if mfd >= 0 { sys_write(mfd, mb, mo); sys_close(mfd); sys_renameat(jtmp, jdone) } 1885 md_lease_run("release" as *u8, alnm, "mgmt-api-build" as *u8, "0" as *u8, 3, "/tmp/nx_ma_lease_async.out" as *u8) 1886 sys_exit(0) 1887 } 1888 let ab: *u8 = sys_mmap(MA_MAGIC_2048) 1889 var abo: i64 = sd_cat(ab, 0, "{\"action\":\"BUILD-STARTED\",\"target\":\"" as *u8) 1890 abo = sd_cat(ab, abo, nm) 1891 abo = sd_cat(ab, abo, "\",\"poll\":\"" as *u8); abo = sd_cat(ab, abo, jdone) 1892 abo = sd_cat(ab, abo, "\",\"out\":\"" as *u8); abo = sd_cat(ab, abo, jout) 1893 abo = sd_cat(ab, abo, "\",\"note\":\"ABSENT poll-file = STILL COMPILING, which is NOT an edge failure -- do not retry the build. When it appears it reads state=DONE built=<0|1> bytes=<n> and is written by ATOMIC RENAME so you never read a partial verdict. A build that NEVER produces it is a COMPILER HANG (seq1337), not an outage. Read it with nx_fs read.\"}" as *u8) 1894 ab[abo] = 0 as u8 1895 return ma_emit_200(out, ab) 1896 } 1897 let lnm: *u8 = sys_mmap(192) 1898 md_lease_name(nm, lnm) 1899 if md_lease_run("acquire" as *u8, lnm, "mgmt-api-build" as *u8, ma_lease_ttl_txt(MA_BUILD_LEASE_TTL_S), 4, "/tmp/nx_ma_lease.out" as *u8) == 3 { 1900 let lb: *u8 = sys_mmap(MA_MAGIC_2048) 1901 let ln: i64 = dp_read("/tmp/nx_ma_lease.out" as *u8, lb, 900) 1902 let cb: *u8 = sys_mmap(MA_MAGIC_4096) 1903 var co: i64 = sd_cat(cb, 0, "{\"conflict\":\"lease-busy\",\"error\":\"another session is ALREADY BUILDING this exact target -- refusing to race it (seq1506 R1). Building concurrently is how a mid-churn snapshot ships a regression. The holder is named below; the lease carries a TTL so a dead session can never hold the lane closed.\",\"holder\":\"" as *u8) 1904 co = ma_gate_esc(cb, co, lb, ln) 1905 co = ts_retry_after_derived(cb, co, MA_BUILD_LEASE_TTL_S) 1906 cb[co] = 0 as u8 1907 return ma_emit_400(out, cb) 1908 } 1909 let banked: i64 = ma_bank_staged(nm) // debt 1785771729: never silently clobber a staged artifact 1910 // PROVENANCE, CAPTURED AT THE MOMENT OF PRODUCTION (2026-08-07, debt 1786113214). mtime can ORDER two 1911 // writes but it cannot say one was MADE from the other: any promote by any seat resets an artifact mtime 1912 // and erases the evidence of an unadopted source edit, so a freshness check built on mtime has a 1913 // FALSE-FRESH direction -- the dangerous one, because FRESH is the answer that stops you looking. 1914 // A CLOCK CANNOT ESTABLISH PROVENANCE. RECORD IT WHERE IT IS CHEAP: HERE. LATER IT IS UNRECOVERABLE. 1915 // Hashed BEFORE and AFTER the compile: this tree has concurrent writers as its NORMAL condition (proven 1916 // repeatedly today), so a single hash could describe a different version than the compiler read. If the 1917 // two disagree the source moved mid-build and src_stable=0 says so rather than pretending precision. 1918 let pv_src: *u8 = sys_mmap(512) 1919 let pv_a: *u8 = sys_mmap(80) 1920 var pv_have: i64 = 0 1921 if ma_gate_src(nm, pv_src) == 1 { pv_have = ma_file_sha_hex(pv_src, pv_a) } 1922 // ---- ROOT CAUSE OF THE CROSS-TARGET COMPILE (2026-08-07, debt 1786128134 sev-9) ------------------ 1923 // This captured to the FIXED path /tmp/nx_ma_build.out. Every concurrent /api/build wrote and then 1924 // READ THE SAME FILE, so under load one request parsed another request's builder output and reported 1925 // that compile as its own. MEASURED TWICE TODAY: a build of nx_filecopy echoed 'nx_seg_store_gate', 1926 // and a build of nx_mgmt_api echoed 'nx_wasm_craft_gate' -- both while census jobs were forking builds. 1927 // It was never a mysterious lane gremlin: it is shared mutable state with a hardcoded name. 1928 // *A PER-REQUEST RESULT WRITTEN TO A PROCESS-WIDE PATH IS A RACE THAT REPORTS SOMEONE ELSE'S ANSWER AS 1929 // YOURS* -- and it fails SILENTLY whenever the two compiles both succeed, which is the common case. 1930 // The capture path is now per-target, so two builds cannot collide by construction. The name echo is 1931 // still compared below: the unique path removes the race, the comparison proves it stayed removed. 1932 let capp: *u8 = sys_mmap(256) 1933 var capo: i64 = sd_cat(capp, 0, "/tmp/nx_ma_build_" as *u8) 1934 capo = sd_cat(capp, capo, nm) 1935 capo = sd_cat(capp, capo, ".out" as *u8) 1936 capp[capo] = 0 as u8 1937 md_exec_hostctl_capture2("buildrun" as *u8, nm, capp) 1938 // Release IMMEDIATELY after the compile: everything below is formatting, so every later return path is 1939 // already covered and no exit can strand the lease. 1940 md_lease_run("release" as *u8, lnm, "mgmt-api-build" as *u8, "0" as *u8, 3, "/tmp/nx_ma_lease.out" as *u8) 1941 let pbuf: *u8 = sys_mmap(MA_MAGIC_16384) 1942 let pn: i64 = dp_read(capp, pbuf, MA_MAGIC_16380) 1943 // ---- CROSS-TARGET COMPILE REFUSAL (2026-08-07, debt 1786128134 sev-9) ----------------------------- 1944 // MEASURED LIVE under concurrent load: `POST /api/build target=nx_filecopy` returned a diag reading 1945 // `[hostctl] buildrun: compile 'nx_seg_store_gate' on the NAS` -- the lane compiled a DIFFERENT TARGET 1946 // than the one requested. THAT run failed loudly. The silent case is the hazard: a SUCCESSFUL 1947 // wrong-target compile stages one organ's binary under another organ's name. 1948 // ★★★★★★expect_sha256 CANNOT CATCH THIS. It proves the staged bytes are the ones just built, and when 1949 // the wrong source was compiled that digest IS the wrong binary's digest -- so /api/promote installs 1950 // the wrong organ under the right name and answers PROMOTED. A GUARD THAT CHECKS THE ARTIFACT AGAINST 1951 // THE BUILD CANNOT TELL YOU THE BUILD WAS OF THE WRONG THING. 1952 // src_path/src_sha256 do not close it either: ma_gate_src DERIVES the path from the REQUESTED name, so 1953 // it agrees BY CONSTRUCTION regardless of what the compiler actually read. A field computed from the 1954 // question cannot corroborate the answer. 1955 // ★★★★★★THE ONLY WITNESS TO WHAT WAS COMPILED IS THE BUILDER'S OWN ECHO -- compare it HERE, once, in 1956 // the one place that already has it, instead of leaving the comparison to every caller forever. 1957 let xnm: *u8 = sys_mmap(256) 1958 if ma_compiled_name(pbuf, pn, xnm) == 1 { 1959 var xsame: i64 = 1 1960 var xi: i64 = 0 1961 var xgo: i64 = 1 1962 while xgo == 1 { 1963 let xa: i64 = xnm[xi] as i64 1964 let xbc: i64 = nm[xi] as i64 1965 if xa != xbc { xsame = 0; xgo = 0 } 1966 if xa == 0 { xgo = 0 } 1967 xi = xi + 1 1968 } 1969 if xsame == 0 { 1970 let xb: *u8 = sys_mmap(MA_MAGIC_2048) 1971 var xo: i64 = sd_cat(xb, 0, "{\"error\":\"CROSS-TARGET COMPILE REFUSED: you asked to build '" as *u8) 1972 xo = sd_cat(xb, xo, nm) 1973 xo = sd_cat(xb, xo, "' but the builder echoed compile '" as *u8) 1974 xo = sd_cat(xb, xo, xnm) 1975 xo = sd_cat(xb, xo, "'. NOTHING is reported as staged under your name from this run. expect_sha256 could not have caught this -- it verifies the artifact against the build, never the build against the request -- and src_path cannot either, because it is derived from the name you asked for. This is a concurrency fault in the lane, not a defect in your target: retry.\",\"requested\":\"" as *u8) 1976 xo = sd_cat(xb, xo, nm) 1977 xo = sd_cat(xb, xo, "\",\"compiled\":\"" as *u8) 1978 xo = sd_cat(xb, xo, xnm) 1979 xo = sd_cat(xb, xo, "\"" as *u8) 1980 xb[xo] = 0 as u8 1981 return ma_emit_400(out, xb) 1982 } 1983 } 1984 let sz: i64 = hh_after(pbuf, pn, "size=" as *u8) 1985 if sz > 0 { 1986 let rb: *u8 = sys_mmap(MA_MAGIC_2048) 1987 var b: i64 = sd_cat(rb, 0, "{\"action\":\"BUILT\",\"bytes\":" as *u8) 1988 b = sd_catn(rb, b, sz) 1989 b = sd_cat(rb, b, ",\"staged\":\"" as *u8) 1990 b = sd_cat(rb, b, nm) 1991 b = sd_cat(rb, b, ".sov.elf.new\"" as *u8) 1992 // ---- DL9 bq_dedupe_target (2026-09-02): A SYNC BUILD THAT SUCCEEDS CLOSES ITS OWN QUEUE ROW ---- 1993 // The QUEUE branch above seeds BQ-<nm> when admission refuses; if a later sync build of the same 1994 // target succeeds here, that row stayed `queued` and the poller rebuilt the same source on its next 1995 // opening. Launch `nx_buildq close <nm> 0` DETACHED through nx_job_run, exactly as the enqueue is 1996 // launched, and report its launch rc in the receipt. Fail-open: a failed launch changes nothing about 1997 // BUILT, it only reports; nothing to close is nx_buildq's own named NO-ROW, never an error. 1998 let cqout: *u8 = sys_mmap(MA_MAGIC_1024) 1999 var cqo: i64 = sd_cat(cqout, 0, "/tmp/nx_buildq_close_" as *u8) 2000 cqo = sd_cat(cqout, cqo, nm) 2001 cqo = sd_cat(cqout, cqo, ".out" as *u8) 2002 cqout[cqo] = 0 as u8 2003 let cqargs: *i64 = sys_mmap(8 * 6) as *i64 2004 cqargs[0] = "nx_buildq" as *u8 as i64 2005 cqargs[1] = cqout as i64 2006 cqargs[2] = "close" as *u8 as i64 2007 cqargs[3] = nm as i64 2008 cqargs[4] = "0" as *u8 as i64 2009 let cqrc: i64 = dep_run_capture("/volume1/homes/elderwesto/nishihost/nx_job_run.elf" as *u8, cqargs, 5, "/tmp/nx_buildq_close_launch.out" as *u8) 2010 b = sd_cat(rb, b, ",\"queue_close_launch\":\"nx_job_run nx_buildq close\",\"queue_close_launch_rc\":" as *u8) 2011 b = sd_catn(rb, b, cqrc) 2012 // ---- DIGEST RECEIPT ON THE BUILD (2026-08-06) ------------------------------------------------ 2013 // ★★★A GUARD WHOSE INPUT THE PREVIOUS STEP DOES NOT EMIT IS A GUARD NOBODY CAN USE. 2014 // /api/promote has carried an expect_sha256 refusal since 2026-07-30 -- it hashes the STAGED bytes 2015 // before any mutation and refuses if they are not the ones the caller says it built. That is exactly 2016 // the guard that stops a STALE <t>.sov.elf.new from being promoted and reported as a success. But 2017 // BUILD never emitted the digest, so nobody in the natural build->promote loop could supply it, and 2018 // in practice nobody ever did. The guard was live, correct, and unusable. 2019 // MEASURED THE COST 2026-08-06: promote installed a months-old build of the LIBRARY nx_https_get.nx 2020 // that happened to be sitting at nx_https_get.sov.elf.new, over a freshly staged artifact, and 2021 // answered {"action":"PROMOTED"} with the STALE artifact's bytes. It was caught only because the 2022 // byte count went DOWN after an addition -- i.e. by a human heuristic, not by the machine. 2023 // Emitting the digest here closes the loop: build hands you the number, promote refuses on mismatch. 2024 let sp: *u8 = sys_mmap(160) 2025 mau_build_path(nm, 0, sd_len(nm), ".sov.elf.new" as *u8, sp) 2026 let sszp: *i64 = sys_mmap(16) as *i64 2027 let sbytes: *u8 = md_read_file(sp, sszp) 2028 if (sbytes as i64) != 0 { 2029 let sdig: *u8 = sys_mmap(32) 2030 sha256_digest(sbytes, sszp[0], sdig) 2031 let shex: *u8 = sys_mmap(72) 2032 mau_hex32(sdig, shex) 2033 b = sd_cat(rb, b, ",\"sha256\":\"" as *u8) 2034 b = sd_cat(rb, b, shex) 2035 b = sd_cat(rb, b, "\",\"promote_hint\":\"pass expect_sha256=<this sha256> to /api/promote: it refuses unless the staged bytes are exactly these, which is the only mechanism that stops a stale or sibling-overwritten .sov.elf.new from going live and being reported as success\"" as *u8) 2036 // ---- PROVENANCE RECEIPT + SIDECAR (2026-08-07, debt 1786113214) -------------------------- 2037 // Re-hash the source now and compare with the pre-compile hash. Equal => the recorded digest 2038 // really describes the bytes that were compiled. Unequal => a concurrent writer moved the source 2039 // mid-build, and src_stable=0 declares that instead of implying a precision we do not have. 2040 if pv_have == 1 { 2041 let pv_b: *u8 = sys_mmap(80) 2042 var pv_stable: i64 = 0 2043 if ma_file_sha_hex(pv_src, pv_b) == 1 { pv_stable = ma_hexstr_eq(pv_a, pv_b) } 2044 b = sd_cat(rb, b, ",\"src_sha256\":\"" as *u8) 2045 b = sd_cat(rb, b, pv_a) 2046 b = sd_cat(rb, b, "\",\"src_path\":\"" as *u8) 2047 b = sd_cat(rb, b, pv_src) 2048 b = sd_cat(rb, b, "\",\"src_stable\":" as *u8) 2049 b = sd_catn(rb, b, pv_stable) 2050 // ---- CLOSURE PROVENANCE (written 2026-08-07, INSTALLED 2026-08-08) ---------------- 2051 // The receipt above describes the TARGET'S OWN source. It cannot answer the question 2052 // that actually blocks this estate: "was this artifact built from the same 2053 // DEPENDENCIES as that one?" -- the question the whole treecanon manifest exists to 2054 // approximate, and approximates BACKWARDS: the manifest is generated from the LAPTOP 2055 // mirror and used to judge the NAS tree, while edits land on the NAS via nx_fs_write 2056 // and builds compile FROM the NAS. So the guard compares truth against a stale mirror 2057 // and calls truth a fork. 2058 // ★★★★★★A MANIFEST IS A CLAIM ABOUT A TREE AT A PAST INSTANT; A CLOSURE HASH IS A 2059 // FACT ABOUT THE BINARY IN YOUR HAND. Recorded HERE it needs no push, no watermark, 2060 // no census, and nothing that can go stale between the write and the read. 2061 // ABSTAINS BY CONSTRUCTION: if nx_closurehash.elf is absent the field is simply 2062 // omitted and the build proceeds exactly as before. 2063 // ★A NEW RECEIPT MUST NEVER BE ABLE TO FAIL A BUILD. 2064 let clp: *u8 = sys_mmap(256) 2065 var clo: i64 = sd_cat(clp, 0, "/volume1/homes/elderwesto/nishihost/nx_closurehash.elf" as *u8) 2066 clp[clo] = 0 as u8 2067 let clh: *u8 = sys_mmap(80) 2068 var have_cl: i64 = 0 2069 let clfd: i64 = sys_openat_rd(clp) 2070 if clfd >= 0 { 2071 sys_close(clfd) 2072 let clout: *u8 = sys_mmap(MA_MAGIC_262144) 2073 let cll: *i64 = sys_mmap(16) as *i64 2074 let clav: *i64 = sys_mmap(64) as *i64 2075 clav[0] = clp as i64 2076 clav[1] = nm as i64 2077 clav[2] = "/volume1/homes/elderwesto/nishihost/buildroot" as *u8 as i64 2078 clav[3] = 0 2079 cll[0] = 0 2080 tr_run_capture_to(clp, clav, clout, MA_MAGIC_262140, cll, MA_MAGIC_60000) 2081 if be_after_hex(clout, cll[0], "closure_sha=" as *u8, clh) == 1 { have_cl = 1 } 2082 if have_cl == 1 { 2083 b = sd_cat(rb, b, ",\"closure_sha256\":\"" as *u8) 2084 b = sd_cat(rb, b, clh) 2085 b = sd_cat(rb, b, "\"" as *u8) 2086 } 2087 } 2088 // SIDECAR <target>.provenance: additive, one line, nothing reads it until something asks. 2089 // It exists so freshness can become an EXACT content comparison instead of a clock guess, 2090 // and it distinguishes the comment-only edit for free: the source hash moves while the elf 2091 // hash stays identical, which is precisely the pair a reader wants to see. 2092 let pvp: *u8 = sys_mmap(256) 2093 mau_build_path(nm, 0, sd_len(nm), ".provenance" as *u8, pvp) 2094 let pvb: *u8 = sys_mmap(MA_MAGIC_1024) 2095 var pvo: i64 = sd_cat(pvb, 0, "src_sha256=" as *u8) 2096 pvo = sd_cat(pvb, pvo, pv_a) 2097 pvo = sd_cat(pvb, pvo, " elf_sha256=" as *u8) 2098 pvo = sd_cat(pvb, pvo, shex) 2099 pvo = sd_cat(pvb, pvo, " src_stable=" as *u8) 2100 pvo = sd_catn(pvb, pvo, pv_stable) 2101 pvo = sd_cat(pvb, pvo, " src_path=" as *u8) 2102 pvo = sd_cat(pvb, pvo, pv_src) 2103 // CLOSURE ON THE SIDECAR, NOT JUST THE RESPONSE. A response is read once, by whoever 2104 // made the call; the sidecar is what a LATER reader can compare against. src_sha256 2105 // already makes freshness an exact content comparison for ONE file -- this extends the 2106 // same property to every dependency, which is the actual question the treecanon 2107 // manifest is trying to answer and cannot, because it describes a TREE instead of an 2108 // ARTIFACT. This field is what nx_provcheck reads to say CURRENT vs DRIFTED. 2109 // OMITTED WHEN UNKNOWN, never emitted empty: an absent field says "not measured", 2110 // while `closure_sha256=` with nothing after it would read as "measured, and it is 2111 // nothing". ★A GUARD THAT TURNS ABSENCE INTO A VERDICT IS THE ONE THAT GETS SWITCHED 2112 // OFF AFTER IT LIES ONCE -- which is why nx_provcheck's third state is UNRECORDED. 2113 if have_cl == 1 { 2114 pvo = sd_cat(pvb, pvo, " closure_sha256=" as *u8) 2115 pvo = sd_cat(pvb, pvo, clh) 2116 } 2117 pvo = sd_cat(pvb, pvo, "\n" as *u8) 2118 let pfd: i64 = sys_openat_wr(pvp, 0x1a4) 2119 if pfd >= 0 { sys_write(pfd, pvb, pvo); sys_close(pfd) } 2120 } 2121 // ENVELOPE: the SYNC build path only. The async worker (_async=1) does not write a sidecar yet, 2122 // so a consumer MUST treat an absent sidecar as "unknown, fall back to mtime" and never as stale. 2123 } 2124 // FAIL-LOUD, non-blocking: a SILENT bank is just a quieter clobber -- say so, and name where it went. 2125 if banked == 1 { 2126 b = sd_cat(rb, b, ",\"banked_prev\":\"" as *u8) 2127 b = sd_cat(rb, b, nm) 2128 b = sd_cat(rb, b, ".sov.elf.new.prev (a PRIOR staged artifact existed and was banked, not overwritten -- if you did not stage it, another seat did: check it before promoting)\"" as *u8) 2129 } 2130 // seq207 fail-loud, non-blocking: warn if a stale flat shadow of this source exists (clobber landmine). 2131 if ma_build_dup_shadow(nm) == 1 { 2132 b = sd_cat(rb, b, ",\"dup_shadow\":\"" as *u8) 2133 b = sd_cat(rb, b, nm) 2134 b = sd_cat(rb, b, ".nx exists in BOTH buildroot/runtime/_hdl_build (resolved first) AND buildroot/runtime (stale shadow); reconcile to ONE canonical dir (seq207)\"" as *u8) 2135 } 2136 b = sd_cat(rb, b, "}" as *u8) 2137 rb[b] = 0 as u8 2138 return ma_emit_200(out, rb) 2139 } 2140 // FAIL-LOUD (seq202, the organ-authoring multiplier): surface the captured nx_cc/nxasm diagnostic tail so an 2141 // API-first session sees the actual error+line, not a blind "no elf". The tail is the last of the build output. 2142 // COMPILE FAILED -> put the banked staged artifact BACK, or a stagedref tool that executes it breaks. 2143 var restored: i64 = 0 2144 if banked == 1 { restored = ma_restore_staged(nm) } 2145 // ---- RUNNER ADMISSION REFUSAL -> THE QUEUE BRANCH, NOT BUILD-FAILED (2026-09-02) ----------------- 2146 // See ma_runner_refused above. The restore has already run (the build did not happen, the banked stage 2147 // is back) and the lease is already released; what remains is to route this where an admission refusal 2148 // belongs: the same enqueue and the same REFUSED-BUILD-ADMIT body the pre-fork refusal answers with. 2149 if ma_runner_refused(pbuf, pn) == 1 { 2150 let rqout: *u8 = sys_mmap(MA_MAGIC_1024) 2151 let rqrc: i64 = ma_build_enqueue(nm, rqout) 2152 // admit_detail = the builder's OWN BUILD-ADMIT line, taken from the per-target capture (hostctl 2153 // echoes the builder's tail into it) or, failing that, from /tmp/buildrun.out -- never paraphrased 2154 // (the duplicate-ruler-made-of-prose law, 2026-08-20). Absent both, say so instead of inventing a cause. 2155 let rbao: *u8 = sys_mmap(MA_MAGIC_4096) 2156 var rban: i64 = 0 2157 var rsrc: *u8 = pbuf 2158 var rsn: i64 = pn 2159 var rap: i64 = ma_find(pbuf, pn, "BUILD-ADMIT" as *u8) 2160 if rap < 0 { 2161 let rfb: *u8 = sys_mmap(MA_MAGIC_65536) 2162 let rfn: i64 = ma_read_tail("/tmp/buildrun.out" as *u8, rfb, MA_MAGIC_65500) 2163 rap = ma_find(rfb, rfn, "BUILD-ADMIT" as *u8) 2164 rsrc = rfb 2165 rsn = rfn 2166 } 2167 if rap >= 0 { 2168 var rq: i64 = rap 2169 while rq < rsn { if rban < MA_MAGIC_4000 { rbao[rban] = rsrc[rq]; rban = rban + 1 } rq = rq + 1 } 2170 } else { 2171 rban = sd_cat(rbao, 0, "runner refused admission (hostctl echoed child exit=6 = SBR_ADMIT_REFUSED) but its BUILD-ADMIT line was in neither capture; the refusal is real, its printed figures were lost" as *u8) 2172 } 2173 var rbatr: i64 = 0 2174 if rban >= MA_MAGIC_4000 { rbatr = 1 } 2175 return ma_emit_503(out, ma_build_refusal_body(rbao, rban, rbatr, nm, rqrc, rqout)) 2176 } 2177 let fb: *u8 = sys_mmap(MA_MAGIC_32768) 2178 var fo: i64 = sd_cat(fb, 0, "{\"action\":\"BUILD-FAILED\",\"verdict\":\"nx_cc/nxasm produced no elf; is the target in buildroot/runtime?\",\"diag\":\"" as *u8) 2179 let db: *u8 = sys_mmap(MA_MAGIC_2048) 2180 let dl: i64 = ma_json_esc_tail(pbuf, pn, MA_MAGIC_1400, db, MA_MAGIC_2040) 2181 fo = sd_cat(fb, fo, db) 2182 fo = sd_cat(fb, fo, "\"" as *u8) 2183 // MULTI-ERROR DIAG (2026-08-05). The tail window above was right when the compiler died AT 2184 // its first error (the error WAS the tail). With multi-error recovery the compiler parses 2185 // PAST its errors, so on a big target the error lines sit mid-log and the tail shows only 2186 // progress dots + the N-error summary -- a diag that names the count but hides every error. 2187 // Surface a second window anchored at the FIRST nx_parse: line; errors cluster from there. 2188 // Voice v3 (2026-08-06): user-facing diagnostics open with "error at line"; the older 2189 // organ-prefixed sites still say "nx_parse:" until their rewrite -- anchor on EITHER, 2190 // preferring whichever appears FIRST in the log so no error line is ever above the window. 2191 // READ THE BUILDER'S FULL CAPTURE (2026-08-06): hostctl echoes only the LAST 600 bytes of 2192 // /tmp/buildrun.out (hc_tail) into the stream this handler captures -- and one 5W+H-voice 2193 // diagnostic is BIGGER than that window, so the head of the first error could never reach 2194 // the echo at all. Anchor-scan the full capture instead; the build lease serializes 2195 // /api/build, which bounds the shared-path race until hostctl (deploy-frozen) uniquifies. 2196 let fbuf: *u8 = sys_mmap(MA_MAGIC_65536) 2197 let fn2: i64 = ma_read_tail("/tmp/buildrun.out" as *u8, fbuf, MA_MAGIC_65500) 2198 // ANCHOR WIDENED 2026-08-06: diagnostics now carry a per-file location, so the 5W+H voice 2199 // emits "error at <file>:<line>:" and no longer contains the literal "error at line ". 2200 // Anchoring on the SHORTEST STABLE PREFIX matches BOTH the mapped and unmapped forms, so 2201 // this reader needs no flag day with the writer and cannot silently return zero errors 2202 // again. (It did exactly that for one build: the compiler was promoted before this edit, 2203 // and diag_errors vanished from every failing build until the anchor caught up.) 2204 var ep: i64 = ma_find(fbuf, fn2, "error at " as *u8) 2205 let ep2: i64 = ma_find(fbuf, fn2, "nx_parse:" as *u8) 2206 if ep < 0 { ep = ep2 } 2207 if ep2 >= 0 { if ep2 < ep { ep = ep2 } } 2208 if ep >= 0 { 2209 var ewin: i64 = fn2 - ep 2210 if ewin > MA_MAGIC_8000 { ewin = MA_MAGIC_8000 } 2211 let eb2: *u8 = sys_mmap(MA_MAGIC_32768) 2212 let el: i64 = ma_json_esc_tail(((fbuf as i64) + ep) as *u8, ewin, ewin, eb2, MA_MAGIC_16000) 2213 fo = sd_cat(fb, fo, ",\"diag_errors\":\"" as *u8) 2214 fo = sd_cat(fb, fo, eb2) 2215 fo = sd_cat(fb, fo, "\"" as *u8) 2216 } 2217 // ---- CAPABILITY-DEMAND SINK (2026-08-13, the growing-loop counting half) ------------------- 2218 // Capability-limit refusals stamp greppable `capability=<slug>` markers in the compiler 2219 // output, but /tmp/buildrun.out is TRANSIENT -- without a durable sink the loop (refusal -> 2220 // counted demand -> re-ranked roadmap) has nothing to count NAS-side. Append one row per 2221 // marker: "<epoch> <slug> <target>" to knowledge/status/lang_demand.jrnl. TELEMETRY 2222 // CONTRACT, declared: bounded at 8 rows per build; append-only; a failed open SKIPS -- demand 2223 // counting must never fail a build. Build-time slugs only (runtime crash slugs stay in the 2224 // transcript mine); the journal is a FLOOR, not a census. 2225 var dsp: i64 = 0 2226 var dsn: i64 = 0 2227 let dfd: i64 = sys_openat_append("knowledge/status/lang_demand.jrnl" as *u8, 0x1a4) 2228 if dfd >= 0 { 2229 while dsn < 8 { 2230 let dhit: i64 = ma_find(((fbuf as i64) + dsp) as *u8, fn2 - dsp, "capability=" as *u8) 2231 if dhit < 0 { break } 2232 let dst0: i64 = dsp + dhit + 11 2233 var dse: i64 = dst0 2234 while dse < fn2 { 2235 let dc: i64 = fbuf[dse] as i64 2236 var dok: i64 = 0 2237 if dc >= 0x61 { if dc <= 0x7A { dok = 1 } } 2238 if dc >= 0x30 { if dc <= 0x39 { dok = 1 } } 2239 if dc == 0x2D { dok = 1 } 2240 if dok == 0 { break } 2241 dse = dse + 1 2242 } 2243 if dse > dst0 { 2244 let drow: *u8 = sys_mmap(512) 2245 var dro: i64 = sd_catn(drow, 0, sys_now_realtime_sec()) 2246 dro = sd_cat(drow, dro, " " as *u8) 2247 var dci: i64 = dst0 2248 while dci < dse { drow[dro] = fbuf[dci]; dro = dro + 1; dci = dci + 1 } 2249 dro = sd_cat(drow, dro, " " as *u8) 2250 dro = sd_cat(drow, dro, nm) 2251 drow[dro] = 10 as u8 2252 sys_write(dfd, drow, dro + 1) 2253 } 2254 dsp = dse 2255 dsn = dsn + 1 2256 } 2257 sys_close(dfd) 2258 } 2259 if restored == 1 { fo = sd_cat(fb, fo, ",\"staged_restored\":\"the prior staged artifact was put BACK after this failed compile (a stagedref tool executes it directly)\"" as *u8) } 2260 fo = sd_cat(fb, fo, "}" as *u8) 2261 fb[fo] = 0 as u8 2262 return ma_emit_200(out, fb) 2263} 2264 2265// POST /api/unpack {dest=<key>}: unpack a STAGED source-tree blob (<key>.pack.new from /api/upload) into a 2266// fail-closed NAS dir via the on-NAS nx_treepack. The tree-sync half of build-over-API: the whole source tree 2267// arrives in ONE /api/upload + this one call, instead of ~15k per-file SSH pushes. Never-brick: dest is 2268// allowlisted (unknown -> 400); nx_treepack writes only under the resolved dir. 2269// CONTRACT CHANGE (seq1807, deliberate fail-closed break): `sha256=<hex of the pack you uploaded>` is now 2270// REQUIRED. The staging slot is global and a sibling can overwrite it between your upload and your unpack, so 2271// a call that does not name its own bytes CANNOT be served safely -- omitting it is 400, never a best-effort 2272// unpack. Callers: take the digest /api/upload returns (or sha256 your pack locally) and pass it through. 2273func ma_do_unpack(req: *u8, req_n: i64, out: *u8) -> i64 { 2274 let body_off: i64 = sd_body_off(req, req_n) 2275 let body: *u8 = ((req as i64) + body_off) as *u8 2276 let body_n: i64 = req_n - body_off 2277 let doff: *i64 = sys_mmap(8) as *i64 2278 let dn: *i64 = sys_mmap(8) as *i64 2279 if sd_form_field(body, body_n, "dest" as *u8, 4, doff, dn) != 1 { 2280 return ma_emit_400(out, "{\"error\":\"missing dest\"}" as *u8) 2281 } 2282 let packbuf: *u8 = sys_mmap(128) 2283 let destbuf: *u8 = sys_mmap(256) 2284 if md_unpack_resolve(body, doff[0], dn[0], packbuf, destbuf) != 1 { 2285 return ma_emit_400(out, "{\"error\":\"unknown unpack dest (not in allowlist)\"}" as *u8) 2286 } 2287 // seq1807 CAS -- A SHARED MUTABLE STAGING SLOT WITH NO OWNERSHIP IS A RACE THAT SILENTLY SHIPS THE WRONG 2288 // SOURCE. `<key>.pack.new` is ONE global slot, so a sibling's in-flight /api/upload can replace the blob 2289 // between MY upload and MY unpack -- and this route used to apply whatever happened to be sitting there. 2290 // MEASURED cross-session source contamination: a 14,334B pack was staged, 114,316B was on disk, and 11 2291 // files from a FOREIGN pack were written into buildroot/runtime. The caller must now NAME THE BYTES IT 2292 // STAGED; we hash the slot and refuse on mismatch. This is the SAME guard already proven live on 2293 // /api/compare/publish -- it existed on a STATIC PAGE and not on the SOURCE TREE (an adoption gap, not 2294 // missing code). It also subsumes a declared-file-count check: bytes that hash equal cannot contain a 2295 // different file count. Fail-closed: no sha256 -> 400, nothing unpacked. 2296 let hoff: *i64 = sys_mmap(8) as *i64 2297 let hn: *i64 = sys_mmap(8) as *i64 2298 if sd_form_field(body, body_n, "sha256" as *u8, 6, hoff, hn) != 1 { 2299 return ma_emit_400(out, "{\"error\":\"missing sha256 (hex of the pack bytes you uploaded -- pins the unpack to YOUR source; a shared staging slot without it can apply another session tree)\"}" as *u8) 2300 } 2301 let szp: *i64 = sys_mmap(16) as *i64 2302 let stg: *u8 = md_read_file(packbuf, szp) 2303 if (stg as i64) == 0 { 2304 return ma_emit_400(out, "{\"error\":\"nothing staged; chunk-upload to /api/upload?target=buildsrc.pack first\"}" as *u8) 2305 } 2306 let dig: *u8 = sys_mmap(32) 2307 sha256_digest(stg, szp[0], dig) 2308 let hexbuf: *u8 = sys_mmap(72) 2309 mau_hex32(dig, hexbuf) 2310 if mau_hex_eq(body, hoff[0], hn[0], hexbuf) != 1 { 2311 return ma_emit_400(out, "{\"error\":\"sha256 mismatch: the staging slot holds different bytes than you staged (another session re-staged it) -- REFUSING to unpack a tree you did not review; re-upload and retry\"}" as *u8) 2312 } 2313 md_exec_treepack(packbuf, destbuf, "/tmp/nx_ma_unpack.out" as *u8) 2314 let pbuf: *u8 = sys_mmap(MA_MAGIC_16384) 2315 let pn: i64 = dp_read("/tmp/nx_ma_unpack.out" as *u8, pbuf, MA_MAGIC_16380) 2316 let files: i64 = hh_after(pbuf, pn, "files=" as *u8) 2317 let failed: i64 = hh_after(pbuf, pn, "failed=" as *u8) 2318 // 2026-08-06 -- SURFACE THE SKIP (debt 1785523434, the 'add-only / reports the silent skip as success' 2319 // report). nx_treepack REFUSES TO BACKDATE: when the destination copy is NEWER than the packed one it 2320 // writes nothing and counts it as `skipped-newer=N` in its own envelope. That refusal is CORRECT -- 2321 // it is the guard that stops a stale pack from reverting a sibling's landed work. The DEFECT was here: 2322 // this handler parsed only files= and failed=, so a run that declined to apply the caller's edits still 2323 // returned a clean {"action":"UNPACKED","failed":0}. The caller then runs /api/build, the compiler reads 2324 // the OLD text, and every downstream symptom points anywhere except at the unpack that never happened. 2325 // => A PARTIAL APPLY MUST NOT WEAR THE SUCCESS WORD. Skips get their OWN action so no caller can branch 2326 // past them, and the count is reported either way. A guard that fires silently is indistinguishable 2327 // from a guard that never ran. 2328 let skipped: i64 = hh_after(pbuf, pn, "skipped-newer=" as *u8) 2329 if failed == 0 { if files > 0 { 2330 let rb: *u8 = sys_mmap(MA_MAGIC_1024) 2331 var b: i64 = 0 2332 if skipped > 0 { b = sd_cat(rb, 0, "{\"action\":\"UNPACKED-WITH-SKIPS\",\"files\":" as *u8) } 2333 if skipped <= 0 { b = sd_cat(rb, 0, "{\"action\":\"UNPACKED\",\"files\":" as *u8) } 2334 b = sd_catn(rb, b, files) 2335 b = sd_cat(rb, b, ",\"failed\":0,\"skipped_newer\":" as *u8) 2336 b = sd_catn(rb, b, skipped) 2337 if skipped > 0 { b = sd_cat(rb, b, ",\"verdict\":\"NOT FULLY APPLIED: nx_treepack refused to backdate these files because the destination copy is NEWER than the packed one, so YOUR BYTES WERE NOT WRITTEN. Building now compiles the OLD text. Re-read the destination, merge, then re-pack from current source.\"" as *u8) } 2338 if skipped < 0 { b = sd_cat(rb, b, ",\"verdict\":\"UNKNOWN-SKIPS: the running nx_treepack.elf does not emit skipped-newer= in its envelope, so this route CANNOT tell you whether files were silently declined. Rebuild and promote nx_treepack before trusting a clean result.\"" as *u8) } 2339 b = sd_cat(rb, b, "}" as *u8) 2340 rb[b] = 0 as u8 2341 return ma_emit_200(out, rb) 2342 } } 2343 return ma_emit_200(out, "{\"action\":\"UNPACK-FAILED\",\"verdict\":\"nx_treepack reported failures or zero files\"}" as *u8) 2344} 2345 2346// POST /api/put_source?name=<name> {body = raw .nx source text}: WRITE ONE source file to buildroot/runtime/<name>.nx 2347// over the pure API. NishiLang source is TEXT, so it rides the request body verbatim -- no pack, no binary upload, 2348// no WSL. Then /api/build compiles it -> a brand-new organ goes source->binary with ZERO shell. Fail-closed: name 2349// sanitized to [a-zA-Z0-9_] (no dot/slash/dot-dot -> no path escape); writes EXACTLY runtime/<name>.nx (O_TRUNC). 2350// Additive/never-brick: only overwrites that one SOURCE file (never a live artifact); the compiler is the next step. 2351func ma_gate_esc(d: *u8, o: i64, s: *u8, n: i64) -> i64 { 2352 var i: i64 = 0 2353 var b: i64 = o 2354 while i < n { 2355 let c: i64 = (s[i] as i64) & 0xff 2356 var hit: i64 = 0 2357 if c == 34 { d[b] = 92 as u8; b = b + 1; d[b] = 34 as u8; b = b + 1; hit = 1 } 2358 if c == 92 { d[b] = 92 as u8; b = b + 1; d[b] = 92 as u8; b = b + 1; hit = 1 } 2359 if c == 10 { d[b] = 92 as u8; b = b + 1; d[b] = 110 as u8; b = b + 1; hit = 1 } 2360 if c == 13 { d[b] = 92 as u8; b = b + 1; d[b] = 114 as u8; b = b + 1; hit = 1 } 2361 if c == 9 { d[b] = 92 as u8; b = b + 1; d[b] = 116 as u8; b = b + 1; hit = 1 } 2362 if hit == 0 { if c >= 32 { d[b] = s[i]; b = b + 1 } } 2363 i = i + 1 2364 } 2365 return b 2366} 2367 2368// ---- /api/organ_run: run an ALREADY-VETTED organ over the control plane (seq1426) ------------------ 2369// THE GAP IT CLOSES. The ship loop is API-pure end to end -- build, promote, register, mint, gate_run -- 2370// except for the last step: actually RUNNING what you just shipped. /api/gate_run deliberately executes 2371// VERIFIERS ONLY (name must end gate/test/kat) and that bound must stay, and a freshly registered tool 2372// has no mcp__nishi__ stub until a FULL client restart. So a brand-new organ was unreachable in-session 2373// and every session fell back to ssh -- measured at 33-44% of all tool calls, the single largest 2374// self-sufficiency leak in the ecosystem. 2375// 2376// AUTHORITY: this grants NOTHING NEW. tool_allowlist.conf is the set an operator has already vetted as 2377// callable-over-MCP (field 0 = name, field 1 = absolute elf, field 2 = GREEN). /mcp tools/call already 2378// executes exactly that set. This route is a SECOND PRESENTER of the SAME authority, the way 2379// Authorization: Bearer is a second presenter of the X-Nishi-Cap token -- it changes WHICH DOOR the 2380// request arrives at, never WHAT MAY BE RUN. An organ absent from the allowlist, or not GREEN, is 2381// refused here exactly as it is there. 2382// 2383// NEVER-BRICK: the elf path comes from the ALLOWLIST ROW, never from the caller, so no argument can 2384// redirect execution; the run is deadline-bounded and process-group reaped (dep_run_capture_bounded); 2385// and callers cannot reach a daemon or deployer unless an operator deliberately vetted it GREEN, which 2386// is the same decision that already exposes it over /mcp. 2387const MA_ORGAN_ALLOWLIST: *u8 = "tool_allowlist.conf" as *u8 2388const MA_ORGAN_CONFCAP: i64 = 262144 2389const MA_ORGAN_MAXARGS: i64 = 12 2390 2391// Resolve `nm` to its allowlisted absolute elf path. 1 = found + GREEN (path written to outp), 2392// 0 = absent or not GREEN. Fail-closed: an unreadable/truncated conf resolves NOTHING. 2393func ma_organ_resolve(nm: *u8, outp: *u8) -> i64 { 2394 let buf: *u8 = sys_mmap(MA_ORGAN_CONFCAP) 2395 let n: i64 = dp_read(MA_ORGAN_ALLOWLIST, buf, MA_ORGAN_CONFCAP - 1) 2396 if n <= 0 { return 0 } 2397 var nl: i64 = 0 2398 while nm[nl] != (0 as u8) { nl = nl + 1 } 2399 var ls: i64 = 0 2400 var i: i64 = 0 2401 while i <= n { 2402 var eol: i64 = 0 2403 if i == n { eol = 1 } else { if buf[i] == (10 as u8) { eol = 1 } } 2404 if eol == 1 { 2405 if i > ls { if buf[ls] != (35 as u8) { 2406 // field 0 = name, up to the first TAB 2407 var t0: i64 = ls 2408 while t0 < i { if buf[t0] == (9 as u8) { t0 = i + 1 } else { t0 = t0 + 1 } } 2409 var tab1: i64 = ls 2410 var found1: i64 = 0 - 1 2411 while tab1 < i { if buf[tab1] == (9 as u8) { found1 = tab1; tab1 = i } else { tab1 = tab1 + 1 } } 2412 if found1 > 0 { if found1 - ls == nl { 2413 var m: i64 = 1 2414 var c: i64 = 0 2415 while c < nl { if buf[ls+c] != nm[c] { m = 0; c = nl } else { c = c + 1 } } 2416 if m == 1 { 2417 // field 1 = elf path, field 2 = status 2418 var p2: i64 = found1 + 1 2419 var found2: i64 = 0 - 1 2420 var q: i64 = p2 2421 while q < i { if buf[q] == (9 as u8) { found2 = q; q = i } else { q = q + 1 } } 2422 if found2 > 0 { 2423 // status must begin GREEN 2424 var s3: i64 = found2 + 1 2425 var green: i64 = 0 2426 if s3 + 5 <= i { 2427 if buf[s3] == (71 as u8) { if buf[s3+1] == (82 as u8) { if buf[s3+2] == (69 as u8) { 2428 if buf[s3+3] == (69 as u8) { if buf[s3+4] == (78 as u8) { green = 1 } } } } } 2429 } 2430 if green == 1 { 2431 var o: i64 = 0 2432 var k: i64 = p2 2433 while k < found2 { outp[o] = buf[k]; o = o + 1; k = k + 1 } 2434 outp[o] = 0 as u8 2435 if o > 0 { return 1 } 2436 } 2437 return 0 2438 } 2439 } 2440 } } 2441 } } 2442 ls = i + 1 2443 } 2444 i = i + 1 2445 } 2446 return 0 2447} 2448 2449// Argument decoding is explicit. Legacy callers retain their documented token alphabet; 2450// percent-v1 splits raw spaces/pluses then decodes each token, preserving encoded delimiters. 2451// Errors stop execution: never truncate a token, discard an argument, or sanitize its meaning. 2452const MA_OA_INVALID: i64 = 0 - 1 2453const MA_OA_CAPACITY: i64 = 0 - 2 2454const MA_OA_ENCODING: i64 = 0 - 3 2455func ma_organ_arg_hex(c: i64) -> i64 { 2456 if c >= 48 { if c <= 57 { return c - 48 } } 2457 if c >= 65 { if c <= 70 { return c - 65 + 10 } } 2458 if c >= 97 { if c <= 102 { return c - 97 + 10 } } 2459 return 0 - 1 2460} 2461func ma_organ_arg_legacy(c: i64) -> i64 { 2462 if c >= 48 { if c <= 57 { return 1 } } 2463 if c >= 65 { if c <= 90 { return 1 } } 2464 if c >= 97 { if c <= 122 { return 1 } } 2465 if c == 95 { return 1 } 2466 if c == 46 { return 1 } 2467 if c == 47 { return 1 } 2468 if c == 45 { return 1 } 2469 return 0 2470} 2471func ma_organ_args_parse(raw: *u8, n: i64, encoded: i64, dst: *u8, cap: i64, av: *i64, maxargs: i64) -> i64 { 2472 av[0] = 0 2473 if n < 0 { return MA_OA_INVALID } 2474 if cap <= 0 { return MA_OA_CAPACITY } 2475 if maxargs < 0 { return MA_OA_CAPACITY } 2476 if encoded != 0 { if encoded != 1 { return MA_OA_ENCODING } } 2477 var k: i64 = 0 2478 var w: i64 = 0 2479 var count: i64 = 0 2480 while k < n { 2481 if raw[k] == (32 as u8) { k = k + 1 } else { 2482 if raw[k] == (43 as u8) { k = k + 1 } else { 2483 if count >= maxargs { return MA_OA_CAPACITY } 2484 av[count] = (dst as i64) + w 2485 var token: i64 = 1 2486 while token == 1 { 2487 if k >= n { token = 0 } else { 2488 var ch: i64 = raw[k] as i64 2489 if ch == 32 { token = 0 } else { 2490 if ch == 43 { token = 0 } else { 2491 if encoded == 1 { 2492 if ch == 37 { 2493 if k + 2 >= n { return MA_OA_ENCODING } 2494 let hi: i64 = ma_organ_arg_hex(raw[k+1] as i64) 2495 let lo: i64 = ma_organ_arg_hex(raw[k+2] as i64) 2496 if hi < 0 { return MA_OA_ENCODING } 2497 if lo < 0 { return MA_OA_ENCODING } 2498 ch = hi * 16 + lo 2499 k = k + 2 2500 } 2501 if ch < 32 { return MA_OA_INVALID } 2502 if ch == 127 { return MA_OA_INVALID } 2503 } else { 2504 if ma_organ_arg_legacy(ch) != 1 { return MA_OA_INVALID } 2505 } 2506 if w >= cap - 1 { return MA_OA_CAPACITY } 2507 dst[w] = ch as u8 2508 w = w + 1 2509 k = k + 1 2510 } } 2511 } 2512 } 2513 dst[w] = 0 as u8 2514 w = w + 1 2515 count = count + 1 2516 } } 2517 } 2518 av[count] = 0 2519 return count 2520} 2521func ma_organ_args_form(body: *u8, n: i64, dst: *u8, cap: i64, av: *i64, maxargs: i64) -> i64 { 2522 let off: *i64 = sys_mmap(8) as *i64 2523 let len: *i64 = sys_mmap(8) as *i64 2524 var encoded: i64 = 0 2525 if sd_form_field(body, n, "args_encoding" as *u8, 13, off, len) == 1 { 2526 let mode: *u8 = "percent-v1" as *u8 2527 if len[0] != 10 { return MA_OA_ENCODING } 2528 var j: i64 = 0 2529 while j < 10 { 2530 if body[off[0]+j] != mode[j] { return MA_OA_ENCODING } 2531 j = j + 1 2532 } 2533 encoded = 1 2534 } 2535 if sd_form_field(body, n, "args" as *u8, 4, off, len) != 1 { av[0] = 0; return 0 } 2536 return ma_organ_args_parse(body + off[0], len[0], encoded, dst, cap, av, maxargs) 2537} 2538 2539// Install request boundary. The transport authenticates the session and supplies 2540// its resolved access level plus server-admitted resource allowances. This adapter 2541// never accepts a registry path or a memory allowance from the network body. 2542struct NxInstallRequest { 2543 bytes: *u8, 2544 allocation: i64, 2545 target: *u8, 2546 intent: *u8, 2547 digest: *u8, 2548 stage: *u8, 2549 code: i64, 2550} 2551func ma_install_request_init(r: *NxInstallRequest) -> i64 { 2552 let p: *u8=r as *u8;var i: i64=0 2553 while i<__size_of(NxInstallRequest) { p[i]=0 as u8;i=i+1 } 2554 r.stage="request-input";r.code=400;return 0 2555} 2556func ma_install_request_close(r: *NxInstallRequest) -> i64 { 2557 var rc: i64=0 2558 if (r.digest as i64)!=0 { rc=sys_munmap(r.digest,FI_DIGEST_BYTES) } 2559 if (r.bytes as i64)!=0 { let freed: i64=sys_munmap(r.bytes,r.allocation);if rc==0 { rc=freed } } 2560 ma_install_request_init(r);return rc 2561} 2562// Decode one form component in-place. Encoded separators remain part of that 2563// component; NUL/control bytes are never allowed to change downstream meaning. 2564func ma_install_component(p: *u8,n: i64) -> i64 { 2565 var read: i64=0;var written: i64=0 2566 while read<n { 2567 var ch: i64=p[read] as i64 2568 if ch==37 { 2569 if n-read<3 { return 0-1 } 2570 let hi: i64=ma_organ_arg_hex(p[read+1] as i64) 2571 let lo: i64=ma_organ_arg_hex(p[read+2] as i64) 2572 if hi<0 || lo<0 { return 0-1 } 2573 ch=hi*16+lo;read=read+2 2574 } else { if ch==43 { ch=32 } } 2575 if ch<32 || ch==127 { return 0-1 } 2576 p[written]=ch as u8;written=written+1;read=read+1 2577 } 2578 p[written]=0 as u8;return written 2579} 2580// Exactly four named fields; duplicate/unknown fields fail instead of choosing 2581// whichever occurrence a later layer happens to read. 2582func ma_install_request_decode(body: *u8,n: i64,r: *NxInstallRequest) -> i64 { 2583 ma_install_request_init(r) 2584 if (body as i64)==0 || n<=0 || n==0x7fffffffffffffff { return r.code } 2585 r.bytes=sys_mmap(n+1) 2586 if (r.bytes as i64)<0 { r.bytes=0 as *u8;r.stage="request-allocation";r.code=503;return r.code } 2587 r.allocation=n+1;fi_copy(r.bytes,body,n);r.bytes[n]=0 as u8 2588 var cursor: i64=0;var fields: i64=0;var hex: *u8=0 as *u8 2589 r.stage="request-fields" 2590 while cursor<n { 2591 var end: i64=cursor 2592 while end<n && r.bytes[end]!=(38 as u8) { end=end+1 } 2593 var eq: i64=cursor 2594 while eq<end && r.bytes[eq]!=(61 as u8) { eq=eq+1 } 2595 if eq==cursor || eq==end || end==cursor { return r.code } 2596 r.bytes[eq]=0 as u8;r.bytes[end]=0 as u8 2597 let key: *u8=r.bytes+cursor;let value: *u8=r.bytes+eq+1 2598 if ma_install_component(key,eq-cursor)<0 || ma_install_component(value,end-eq-1)<0 { r.stage="request-encoding";return r.code } 2599 var bit: i64=0 2600 if fi_len(key)==6 && fi_same(key,"target",6)==1 { bit=1;r.target=value } 2601 if fi_len(key)==6 && fi_same(key,"intent",6)==1 { bit=2;r.intent=value } 2602 if fi_len(key)==20 && fi_same(key,"expect_intent_sha256",20)==1 { bit=4;hex=value } 2603 if fi_len(key)==7 && fi_same(key,"confirm",7)==1 { 2604 bit=8 2605 if fi_len(value)!=3 || fi_same(value,"yes",3)==0 { r.stage="request-confirmation";return r.code } 2606 } 2607 if bit==0 || (fields & bit)!=0 { return r.code } 2608 fields=fields | bit 2609 if end==n-1 { return r.code } 2610 cursor=end+1 2611 } 2612 if fields!=15 { return r.code } 2613 r.stage="request-target" 2614 let target_n: i64=fi_len(r.target) 2615 if target_n==0 { return r.code } 2616 var i: i64=0 2617 while i<target_n { 2618 let ch: i64=r.target[i] as i64 2619 if !((ch>=48 && ch<=57) || (ch>=65 && ch<=90) || (ch>=97 && ch<=122) || ch==95 || ch==45) { return r.code } 2620 i=i+1 2621 } 2622 r.stage="request-intent-path" 2623 if fi_path_valid(r.intent)==0 { return r.code } 2624 r.stage="request-intent-digest" 2625 if fi_len(hex)!=FI_DIGEST_BYTES*2 { return r.code } 2626 r.digest=sys_mmap(FI_DIGEST_BYTES) 2627 if (r.digest as i64)<0 { r.digest=0 as *u8;r.stage="digest-allocation";r.code=503;return r.code } 2628 i=0 2629 while i<FI_DIGEST_BYTES { 2630 let hi: i64=ma_organ_arg_hex(hex[i*2] as i64) 2631 let lo: i64=ma_organ_arg_hex(hex[i*2+1] as i64) 2632 if hi<0 || lo<0 { return r.code } 2633 r.digest[i]=(hi*16+lo) as u8;i=i+1 2634 } 2635 r.stage="request-decoded";r.code=0;return 0 2636} 2637// HTTP status result; nested evidence retains the exact failing layer. 2638// Call only with a session level resolved by ma_level_of, never from form input. 2639func ma_install_dispatch(req: *u8,n: i64,level: i64,registry: *u8,snapshot_allowance: i64,intent_allowance: i64,scratch: *u8,scratch_bytes: i64,parsed: *NxInstallRequest,result: *NxRegisteredInstallResult) -> i64 { 2640 ma_install_request_init(parsed);md_registered_install_init(result) 2641 if level<0 { parsed.stage="authentication";parsed.code=401;return parsed.code } 2642 if level<MA_LVL_ACT { parsed.stage="authorization";parsed.code=403;return parsed.code } 2643 if n<5 || fi_same(req,"POST ",5)==0 { parsed.stage="request-method";parsed.code=405;return parsed.code } 2644 let prefix: *u8="POST /api/install " 2645 if n<fi_len(prefix) || fi_same(req,prefix,fi_len(prefix))==0 { parsed.stage="request-route";parsed.code=404;return parsed.code } 2646 let off: i64=sd_body_off(req,n) 2647 if off<=0 || off>=n { parsed.stage="request-body";return parsed.code } 2648 let decoded: i64=ma_install_request_decode(req+off,n-off,parsed) 2649 if decoded!=0 { return decoded } 2650 let rc: i64=md_install_registered(registry,snapshot_allowance,parsed.target,fi_len(parsed.target),parsed.intent,intent_allowance,parsed.digest,scratch,scratch_bytes,result) 2651 if rc==0 { return 200 } 2652 if rc==FI_ENOENT { return 404 } 2653 if rc==FI_EACCES { return 403 } 2654 if rc==FIO_EBADMSG || rc==FIO_EEXIST { return 409 } 2655 if rc==FIO_EINVAL { return 400 } 2656 return 503 2657} 2658// Capacity-aware receipt emission. Counting and writing use the same schema; 2659// insufficient output space returns the required byte count without touching it. 2660struct NxInstallReceiptWriter { 2661 bytes: *u8, 2662 capacity: i64, 2663 count: i64, 2664 code: i64, 2665} 2666func ma_ir_byte(w: *NxInstallReceiptWriter,ch: u8) -> i64 { 2667 if w.code!=0 { return w.code } 2668 if w.count==0x7fffffffffffffff { w.code=FIO_EINVAL;return w.code } 2669 if (w.bytes as i64)!=0 { 2670 if w.count>=w.capacity { w.code=FIO_EINVAL;return w.code } 2671 w.bytes[w.count]=ch 2672 } 2673 w.count=w.count+1;return 0 2674} 2675func ma_ir_text(w: *NxInstallReceiptWriter,s: *u8) -> i64 { 2676 var i: i64=0 2677 while s[i]!=(0 as u8) { ma_ir_byte(w,s[i]);i=i+1 } 2678 return w.code 2679} 2680func ma_ir_string(w: *NxInstallReceiptWriter,s: *u8) -> i64 { 2681 ma_ir_byte(w,34 as u8);var i: i64=0 2682 if (s as i64)!=0 { 2683 while s[i]!=(0 as u8) { 2684 let ch: i64=s[i] as i64 2685 if ch==34 || ch==92 { ma_ir_byte(w,92 as u8);ma_ir_byte(w,s[i]) } 2686 else { 2687 if ch<32 { 2688 ma_ir_text(w,"\\u00") 2689 let hex: *u8="0123456789abcdef" 2690 ma_ir_byte(w,hex[ch>>4]);ma_ir_byte(w,hex[ch&15]) 2691 } else { ma_ir_byte(w,s[i]) } 2692 } 2693 i=i+1 2694 } 2695 } 2696 ma_ir_byte(w,34 as u8);return w.code 2697} 2698// Negative-domain conversion also represents the minimum signed value without 2699// negating it, which would overflow. Decimal digits derive from the numeric base. 2700func ma_ir_number(w: *NxInstallReceiptWriter,value: i64) -> i64 { 2701 var v: i64=value 2702 if v<0 { ma_ir_byte(w,45 as u8) } else { v=0-v } 2703 var place: i64=1 2704 while v/place<=0-10 { place=place*10 } 2705 while place>0 { 2706 let digit: i64=0-(v/place) 2707 ma_ir_byte(w,(48+digit) as u8) 2708 v=v+(digit*place);place=place/10 2709 } 2710 return w.code 2711} 2712func ma_ir_named_string(w: *NxInstallReceiptWriter,key: *u8,value: *u8) -> i64 { 2713 ma_ir_string(w,key);ma_ir_byte(w,58 as u8);return ma_ir_string(w,value) 2714} 2715func ma_ir_named_number(w: *NxInstallReceiptWriter,key: *u8,value: i64) -> i64 { 2716 ma_ir_string(w,key);ma_ir_byte(w,58 as u8);return ma_ir_number(w,value) 2717} 2718func ma_install_receipt_fields(w: *NxInstallReceiptWriter,status: i64,when: i64,request: *NxInstallRequest,result: *NxRegisteredInstallResult) -> i64 { 2719 ma_ir_text(w,"{");ma_ir_named_string(w,"schema","nishi.install-receipt.v1") 2720 ma_ir_text(w,",");ma_ir_named_string(w,"owner","nx_mgmt_api") 2721 ma_ir_text(w,",");ma_ir_named_number(w,"status",status) 2722 ma_ir_text(w,",");ma_ir_named_number(w,"observed_at_unix_s",when) 2723 ma_ir_text(w,",");ma_ir_named_string(w,"target",request.target) 2724 ma_ir_text(w,",");ma_ir_named_string(w,"intent",request.intent) 2725 ma_ir_text(w,",\"intent_sha256\":\"") 2726 if (request.digest as i64)!=0 { 2727 let digits: *u8="0123456789abcdef";var i: i64=0 2728 while i<FI_DIGEST_BYTES { 2729 let value: i64=request.digest[i] as i64 2730 ma_ir_byte(w,digits[value>>4]);ma_ir_byte(w,digits[value&15]);i=i+1 2731 } 2732 } 2733 ma_ir_byte(w,34 as u8) 2734 ma_ir_text(w,",");ma_ir_named_string(w,"live",result.target.live) 2735 ma_ir_text(w,",\"request\":{");ma_ir_named_string(w,"stage",request.stage) 2736 ma_ir_text(w,",");ma_ir_named_number(w,"code",request.code) 2737 ma_ir_text(w,"},\"resolution\":{");ma_ir_named_string(w,"stage",result.target.stage) 2738 ma_ir_text(w,",");ma_ir_named_number(w,"code",result.target.code) 2739 ma_ir_text(w,",");ma_ir_named_number(w,"line",result.target.line) 2740 ma_ir_text(w,",");ma_ir_named_number(w,"conflicting_line",result.target.conflicting_line) 2741 ma_ir_text(w,"},\"installation\":{");ma_ir_named_string(w,"stage",result.install.stage) 2742 ma_ir_text(w,",");ma_ir_named_number(w,"code",result.install.code) 2743 ma_ir_text(w,",");ma_ir_named_number(w,"visible",result.install.replacement.publication.visible) 2744 ma_ir_text(w,",");ma_ir_named_number(w,"durable",result.install.replacement.publication.durable) 2745 ma_ir_text(w,",");ma_ir_named_number(w,"already_published",result.install.already_published) 2746 ma_ir_text(w,",");ma_ir_named_string(w,"candidate_stage",result.install.replacement.candidate.stage) 2747 ma_ir_text(w,",");ma_ir_named_number(w,"candidate_code",result.install.replacement.candidate.code) 2748 ma_ir_text(w,",");ma_ir_named_number(w,"candidate_bytes",result.install.replacement.candidate.copied) 2749 ma_ir_text(w,",");ma_ir_named_string(w,"backup_stage",result.install.replacement.backup.stage) 2750 ma_ir_text(w,",");ma_ir_named_number(w,"backup_code",result.install.replacement.backup.code) 2751 ma_ir_text(w,",");ma_ir_named_number(w,"backup_bytes",result.install.replacement.backup.copied) 2752 ma_ir_text(w,",");ma_ir_named_string(w,"io_stage",result.install.io.stage) 2753 ma_ir_text(w,",");ma_ir_named_number(w,"io_code",result.install.io.code) 2754 ma_ir_text(w,",");ma_ir_named_number(w,"io_close_code",result.install.io.close_code) 2755 ma_ir_text(w,",");ma_ir_named_string(w,"lock_stage",result.install.replacement.lock.stage) 2756 ma_ir_text(w,",");ma_ir_named_number(w,"lock_code",result.install.replacement.lock.code) 2757 ma_ir_text(w,",");ma_ir_named_number(w,"unlock_code",result.install.replacement.lock.unlock_code) 2758 ma_ir_text(w,",");ma_ir_named_number(w,"lock_close_code",result.install.replacement.lock.close_code) 2759 ma_ir_text(w,"},");ma_ir_named_string(w,"serving","not-verified") 2760 ma_ir_text(w,",");ma_ir_named_string(w,"restart","not-requested") 2761 ma_ir_text(w,",");ma_ir_named_string(w,"operation_stage",result.stage) 2762 ma_ir_text(w,",");ma_ir_named_number(w,"operation_code",result.code) 2763 var next: *u8="reconcile-approved-install-intent" 2764 if status==200 { next="verify-running-artifact-and-service" } 2765 else { if request.code!=0 { next="correct-request-or-session" } 2766 else { if result.target.code!=0 { next="repair-target-registry" } } } 2767 ma_ir_text(w,",");ma_ir_named_string(w,"next_action",next) 2768 ma_ir_text(w,"}");return w.code 2769} 2770// Return required/written bytes. A null destination measures only; otherwise 2771// count>capacity means no write occurred. Caller may then provide exact storage. 2772func ma_install_receipt_emit(w: *NxInstallReceiptWriter,status: i64,when: i64,request: *NxInstallRequest,result: *NxRegisteredInstallResult,destination: *u8,capacity: i64) -> i64 { 2773 w.bytes=0 as *u8;w.capacity=0;w.count=0;w.code=0 2774 ma_install_receipt_fields(w,status,when,request,result) 2775 if w.code!=0 { return w.code } 2776 let required: i64=w.count 2777 if (destination as i64)==0 || capacity<required { return required } 2778 w.bytes=destination;w.capacity=capacity;w.count=0 2779 ma_install_receipt_fields(w,status,when,request,result) 2780 if w.code!=0 { return w.code };return w.count 2781} 2782func ma_do_organ_run(req: *u8, req_n: i64, out: *u8) -> i64 { 2783 // Guard before any pointer walk or addition. This is representable address 2784 // arithmetic, not a policy limit on argument count or source length. 2785 if (req as i64)==0 || req_n<0 || req_n>(NX_RA_SIZE_MAX/8)-3 { 2786 return ma_emit_400(out,"{\"code\":\"ORGAN_REQUEST_BOUNDS\",\"executed\":false}") 2787 } 2788 let body_off: i64 = sd_body_off(req, req_n) 2789 if body_off<0 || body_off>req_n { return ma_emit_400(out,"{\"code\":\"ORGAN_REQUEST_BOUNDS\",\"executed\":false}") } 2790 let body: *u8 = ((req as i64) + body_off) as *u8 2791 let body_n: i64 = req_n - body_off 2792 let toff: *i64 = sys_mmap(8) as *i64 2793 let tn: *i64 = sys_mmap(8) as *i64 2794 if sd_form_field(body, body_n, "target" as *u8, 6, toff, tn) != 1 { 2795 return ma_emit_400(out, "{\"error\":\"missing target\"}" as *u8) 2796 } 2797 let nm: *u8 = sys_mmap(128) 2798 if ma_sanitize_name(body, toff[0], tn[0], nm, 120) != 1 { 2799 return ma_emit_400(out, "{\"error\":\"invalid target name (only [a-zA-Z0-9_])\"}" as *u8) 2800 } 2801 if ma_confirmed(req, req_n) == 0 { 2802 return ma_emit_400(out, "{\"error\":\"organ_run requires confirm=yes\"}" as *u8) 2803 } 2804 let ep: *u8 = sys_mmap(512) 2805 let pin: *u8 = sys_mmap(MA_MAGIC_4096) 2806 let haspin: *i64 = sys_mmap(16) as *i64 2807 if tea_resolve_pinned_from(MA_ORGAN_ALLOWLIST,nm,sd_len(nm),ep,512,pin,MA_MAGIC_4096,haspin) != TEA_OK { 2808 return ma_emit_400(out, "{\"error\":\"target refused: not a GREEN row in tool_allowlist.conf. This route runs only what an operator has ALREADY vetted as callable over /mcp -- it is a second door onto that same set, never a wider one. Register the organ first (POST /api/tools/register).\"}" as *u8) 2809 } 2810 var dl: i64 = MA_MAGIC_12000 2811 let doff: *i64 = sys_mmap(8) as *i64 2812 let dn: *i64 = sys_mmap(8) as *i64 2813 if sd_form_field(body, body_n, "deadline_ms" as *u8, 11, doff, dn) == 1 { 2814 let v: i64 = mau_qint(body, doff[0], dn[0]) 2815 if v > 0 { dl = v } 2816 } 2817 if dl < 1000 { dl = 1000 } 2818 if dl > MA_MAGIC_300000 { dl = MA_MAGIC_300000 } 2819 // Decoding cannot grow the admitted form body: each separator becomes a 2820 // terminator and percent escapes shrink. One extra byte terminates the last token. 2821 // Derive both buffers from that bound rather than rejecting a valid thirteenth argument. 2822 var argcap: i64 = body_n + 1 2823 if haspin[0] == 1 { argcap = sd_len(pin) + 1 } 2824 if argcap<=0 || argcap>(NX_RA_SIZE_MAX/8)-2 { return ma_emit_400(out,"{\"code\":\"ORGAN_REQUEST_BOUNDS\",\"executed\":false}") } 2825 let argv_bytes:i64=8*(argcap+2) 2826 let argbuf: *u8 = sys_mmap_try(argcap) 2827 let argv: *i64 = sys_mmap_try(argv_bytes) as *i64 2828 if (argbuf as i64) <= 0 || (argv as i64) <= 0 { 2829 if (argbuf as i64)>0 { sys_munmap(argbuf,argcap) } 2830 if (argv as i64)>0 { sys_munmap(argv as *u8,argv_bytes) } 2831 return ma_emit_503(out, "{\"code\":\"ORGAN_ARGUMENT_ALLOCATION_FAILED\",\"executed\":false}" as *u8) 2832 } 2833 var nargs: i64 = 0 2834 if haspin[0] == 1 { 2835 nargs = tea_tokenize_checked(pin,argv,0,argcap+1,argbuf,argcap) 2836 } else { 2837 nargs = ma_organ_args_form(body, body_n, argbuf, argcap, argv, argcap) 2838 } 2839 if nargs < 0 { 2840 sys_munmap(argbuf,argcap);sys_munmap(argv as *u8,argv_bytes) 2841 return ma_emit_400(out, "{\"code\":\"ORGAN_ARGS_INVALID\",\"executed\":false,\"error\":\"Arguments rejected without execution: invalid encoding, unsupported legacy byte, or argument capacity exceeded. Use args_encoding=percent-v1; separate tokens with + and percent-encode bytes inside tokens.\"}" as *u8) 2842 } 2843 2844 // seq1443 ADOPTION COMPLETED 2026-08-07. The definition of dep_run_capture_bounded was removed when 2845 // md_exec_gate_capture adopted tr_run_capture_to, but THIS live call site was left behind, so the 2846 // whole mgmt binary stopped compiling and the deploy path went down for every seat. 2847 // tr_run_capture_to captures to a BUFFER rather than a temp path -- which is the point of the 2848 // adoption, per its own header -- so the /tmp/nx_ma_organrun.out round trip disappears with it. 2849 // ⚠ARGV[0] IS NOT SUPPLIED FOR YOU. dep_run_capture_bounded prepended the elf path itself (the old 2850 // comment in the parse loop above says so); tr_run_capture_to does not -- md_exec_gate_capture sets 2851 // argv[0] = elfpath explicitly before calling. So the parsed args are copied up by one rather than 2852 // reindexed in the parser, which leaves that loop untouched. 2853 let argv2_bytes:i64=8*(nargs+2) 2854 let argv2: *i64 = sys_mmap_try(argv2_bytes) as *i64 2855 if (argv2 as i64) <= 0 { 2856 sys_munmap(argbuf,argcap);sys_munmap(argv as *u8,argv_bytes) 2857 return ma_emit_503(out,"{\"code\":\"ORGAN_ARGUMENT_ALLOCATION_FAILED\",\"executed\":false}") 2858 } 2859 argv2[0] = ep as i64 2860 var zc: i64 = 0 2861 while zc < nargs { argv2[zc + 1] = argv[zc]; zc = zc + 1 } 2862 argv2[nargs + 1] = 0 2863 let cbuf: *u8 = sys_mmap(MA_MAGIC_65536) 2864 let cnp: *i64 = sys_mmap(16) as *i64 2865 cnp[0] = 0 2866 let rc: i64 = tr_run_capture_to(ep, argv2, cbuf, MA_MAGIC_16384, cnp, dl) 2867 sys_munmap(argbuf,argcap);sys_munmap(argv as *u8,argv_bytes);sys_munmap(argv2 as *u8,argv2_bytes) 2868 let cn: i64 = cnp[0] 2869 let rb: *u8 = sys_mmap(MA_MAGIC_65536) 2870 var b: i64 = sd_cat(rb, 0, "{\"action\":\"ORGAN-RUN\",\"target\":\"" as *u8) 2871 b = sd_cat(rb, b, nm) 2872 b = sd_cat(rb, b, "\",\"elf\":\"" as *u8) 2873 b = sd_cat(rb, b, ep) 2874 b = sd_cat(rb, b, "\",\"argc\":" as *u8) 2875 b = sd_catn(rb, b, nargs) 2876 b = sd_cat(rb, b, ",\"exit_code\":" as *u8) 2877 if rc < 0 { b = sd_cat(rb, b, "-1" as *u8) } 2878 if rc >= 0 { b = sd_catn(rb, b, rc) } 2879 b = sd_cat(rb, b, ",\"deadline_ms\":" as *u8) 2880 b = sd_catn(rb, b, dl) 2881 b = sd_cat(rb, b, ",\"verdict\":\"" as *u8) 2882 if rc == 0 { b = sd_cat(rb, b, "OK" as *u8) } 2883 if rc == 127 { b = sd_cat(rb, b, "NOT-FOUND" as *u8) } 2884 if rc < 0 { b = sd_cat(rb, b, "TIMEOUT-OR-SIGNAL" as *u8) } 2885 if rc > 0 { if rc != 127 { b = sd_cat(rb, b, "NONZERO" as *u8) } } 2886 b = sd_cat(rb, b, "\",\"bytes\":" as *u8) 2887 b = sd_catn(rb, b, cn) 2888 b = sd_cat(rb, b, ",\"output\":\"" as *u8) 2889 b = ma_gate_esc(rb, b, cbuf, cn) 2890 b = sd_cat(rb, b, "\"}" as *u8) 2891 rb[b] = 0 as u8 2892 return ma_emit_200(out, rb) 2893} 2894 2895// POST /api/gate_run {target=<name>[&deadline_ms=<n>]} (seq1349): run a promoted gate/test ELF, return its 2896// transcript + exit code + verdict, so a session can PROVE what it just built with zero ssh. Verdict comes ONLY 2897// from the exit code -- a second, weaker judge is how a false GREEN gets manufactured (seq585). Wait is BOUNDED 2898// (seq1383): an unbounded wait in a request handler is a DoS on the whole daemon by construction; it took mgmt 2899// down once. Timeout returns NAME which half failed (seq1425) instead of one opaque code. 2900// Resolve a gate SOURCE path: /api/gate_run executes <t>.elf and the source is <t>.nx in one of the two dirs 2901// the build tree uses. Fills `sp` and returns 1 when found; returns 0 with sp empty when not. 2902// A NOT-FOUND MUST NEVER BE EMITTED AS FRESH. sf_src_stale answers 0 for an absent source ("nothing to be 2903// stale against"), correct for its own contract and exactly wrong as an answer to "is this verdict 2904// trustworthy" -- so the two cases are separated HERE rather than folded by the caller. 2905func ma_gate_src(nm: *u8, sp: *u8) -> i64 { 2906 // ORDER FIX 2026-08-07, and it was MY bug: this probed runtime/ first. nx_sov_build_run probes 2907 // runtime/_hdl_build/ FIRST, so a basename present in BOTH dirs compiles from _hdl_build and the 2908 // runtime copy is a SHADOW that never compiles (nx_janitor_dupname.nx:3 -- it found TWO 2909 // nx_sovereignty_audit.nx). Probing runtime/ first therefore reported freshness for a file the build 2910 // never reads: the same instrument-subject mismatch this field exists to expose, inside the field. 2911 // MATCH THE RESOLVER YOU ARE REPORTING ON, OR YOU ARE REPORTING ON A DIFFERENT FILE. 2912 var o: i64 = sd_cat(sp, 0, "/volume1/homes/elderwesto/nishihost/buildroot/runtime/_hdl_build/" as *u8) 2913 o = sd_cat(sp, o, nm) 2914 o = sd_cat(sp, o, ".nx" as *u8) 2915 sp[o] = 0 as u8 2916 if sf_mtime_ns(sp) >= 0 { return 1 } 2917 o = sd_cat(sp, 0, "/volume1/homes/elderwesto/nishihost/buildroot/runtime/" as *u8) 2918 o = sd_cat(sp, o, nm) 2919 o = sd_cat(sp, o, ".nx" as *u8) 2920 sp[o] = 0 as u8 2921 if sf_mtime_ns(sp) >= 0 { return 1 } 2922 sp[0] = 0 as u8 2923 return 0 2924} 2925 2926// ---- /api/gate_run: FAST verdict or PROMOTED job (lane J, 2026-08-23) ------------------------------ 2927// THE DEFECT. This route used to KILL the gate at its deadline and answer {"verdict":"TIMEOUT", 2928// "exit_code":-1} -- the ABSENCE of a verdict dressed as one. MEASURED 2026-08-23: nx_chkarith_gate and 2929// nx_boundscheck_gate both read TIMEOUT through this route under load 13/8, while nx_job_run of the SAME 2930// binaries returned 17/17 and 11/11 GREEN minutes later. That is the exact class the tools-API sync lane 2931// closed on 2026-08-22 (tr_run_capture_deadline + TR_PROMOTE: at the deadline the worker is handed back 2932// ALIVE instead of SIGKILLed), and this route now COMPOSES that same primitive: 2933// * finishes inside the window -> FAST: the verdict inline, byte-compatible with the old payload plus 2934// the additive fields path=FAST, deadline_src, capture_cap, capture_truncated; 2935// * still running at the deadline -> PROMOTED: the caller gets a JOB-STARTED handle (job id, .claim, 2936// .out) inside the reply window, the gate keeps running under its own pid, and ma_gate_run_finish -- 2937// called by main's HANDLER CHILD right after the response is on the wire -- drains the pipe to EOF, 2938// wait4()s the worker and publishes _jobs/job_<id>.out + the .claim (state=DONE rc= verdict=) by 2939// atomic rename. The handler child IS the worker's parent, so the exit code is REAL: a verifier's 2940// verdict is its exit code (seq585) and promoting must not trade it for PROMOTED-UNREAPED, which is 2941// why the drain lives in the handler child and not in a detached sibling that could never wait4(). 2942// The child holds a handler slot for the gate's duration -- exactly what a synchronous /api/build 2943// already does, bounded by MA_MAX_HANDLERS. 2944// THE DEADLINE IS DERIVED, NOT TYPED: knowledge/edge_window.conf (window - reply reserve) through the 2945// one-owner reader the tools API uses, so the two doors promote at the same instant and a retyped 2946// 12000 cannot drift from the edge again. An explicit deadline_ms still overrides it (a LAN caller on 2947// :18098 has no edge window), clamped exactly as before, and the payload names which source won. 2948// FIXTURE SEAMS (null = production): a gate importing this module points the elf root, the jobs dir and 2949// the window conf at its own scratch, so no gate shares a production plane (fixture-ratchet law). They 2950// are written ONLY by ma_gr_set_fixture, so one grep finds every writer. 2951const MA_GR_ROOT: *u8 = "/volume1/homes/elderwesto/nishihost/" as *u8 2952const MA_GR_JOBS: *u8 = "_jobs" as *u8 2953const MA_GR_CLAIM_PROBES: i64 = 100 // the tools-API job lane's anti-collision walk: epoch-second ids, +1 per O_EXCL collision 2954const MA_GR_O_EXCL_CREATE: i64 = 193 // O_CREAT(0x40)|O_EXCL(0x80)|O_WRONLY(0x1): the reservation IS the open 2955const MA_GR_CAPTURE_CAP: i64 = MA_MAGIC_16384 // FAST-path transcript cap (rb is MA_MAGIC_65536 and ma_gate_esc can double a byte); ANNOUNCED in the payload, no longer silent 2956const MA_GR_DEADLINE_MIN_MS: i64 = 1000 2957const MA_GR_DEADLINE_MAX_MS: i64 = MA_MAGIC_300000 2958const MA_GR_SRC_CALLER: i64 = 2 // deadline_src: 0 = compiled default, 1 = conf row (TEA_SRC_*), 2 = caller's deadline_ms 2959static ma_gr_root_ov: *u8 2960static ma_gr_jobs_ov: *u8 2961static ma_gr_conf_ov: *u8 2962static ma_gr_pend_pid: i64 2963static ma_gr_pend_rfd: i64 2964static ma_gr_pend_jid: i64 2965static ma_gr_pend_buf: *u8 2966static ma_gr_pend_n: i64 2967static ma_gr_pend_nm: *u8 2968func ma_gr_set_fixture(root: *u8, jobs: *u8, conf: *u8) -> i64 { ma_gr_root_ov = root; ma_gr_jobs_ov = jobs; ma_gr_conf_ov = conf; return 0 } 2969func ma_gr_root() -> *u8 { if (ma_gr_root_ov as i64) != 0 { return ma_gr_root_ov } return MA_GR_ROOT } 2970func ma_gr_jobs() -> *u8 { if (ma_gr_jobs_ov as i64) != 0 { return ma_gr_jobs_ov } return MA_GR_JOBS } 2971func ma_gr_conf() -> *u8 { if (ma_gr_conf_ov as i64) != 0 { return ma_gr_conf_ov } return TEA_WINDOW_CONF } 2972// ONE exit-code -> verdict mapping for BOTH paths. A second mapping is how a false GREEN gets manufactured. 2973func ma_gr_verdict(rc: i64) -> *u8 { 2974 if rc == 0 { return "GREEN" as *u8 } 2975 if rc == 127 { return "NOT-FOUND" as *u8 } 2976 if rc == 3 { return "SKIP" as *u8 } // gv_verdict precondition-missing: PROVED NOTHING, not a failure 2977 if rc == (0 - 1) { return "SIGNALLED" as *u8 } 2978 if rc == (0 - 5) { return "TIMEOUT" as *u8 } // TR_ERR_TIMEOUT: unreachable on the promotable path, kept total 2979 if rc == (0 - 2) { return "HARNESS-PIPE-FAIL" as *u8 } 2980 if rc == (0 - 3) { return "HARNESS-FORK-FAIL" as *u8 } 2981 if rc == (0 - 4) { return "HARNESS-WAIT-FAIL" as *u8 } 2982 if rc < 0 { return "HARNESS-FAIL" as *u8 } 2983 return "RED" as *u8 2984} 2985func ma_gr_src_txt(src: i64) -> *u8 { 2986 if src == MA_GR_SRC_CALLER { return "caller" as *u8 } 2987 if src == TEA_SRC_CONF { return "conf" as *u8 } 2988 return "default" as *u8 2989} 2990// <jobs>/job_<jid><sfx>, NUL-terminated into dst; returns the length. 2991func ma_gr_jobpath(dst: *u8, jid: i64, sfx: *u8) -> i64 { 2992 var o: i64 = sd_cat(dst, 0, ma_gr_jobs()) 2993 o = sd_cat(dst, o, "/job_" as *u8) 2994 o = sd_catn(dst, o, jid) 2995 o = sd_cat(dst, o, sfx) 2996 dst[o] = 0 as u8 2997 return o 2998} 2999// Reserve a job id by O_EXCL-creating its .claim (state=CLAIMED). The same epoch-second id space and 3000// the same reservation file the tools-API job lane uses, so the two doors cannot hand out one id twice. 3001// Returns the id, or -1 when every probe collided (pathbuf then holds the last path tried). 3002func ma_gr_claim(nm: *u8, pathbuf: *u8) -> i64 { 3003 sys_mkdir(ma_gr_jobs(), MODE_0755) 3004 var jid: i64 = sys_now_realtime_sec() 3005 var probe: i64 = 0 3006 var got: i64 = 0 - 1 3007 let cb: *u8 = sys_mmap(512) 3008 while probe < MA_GR_CLAIM_PROBES { 3009 ma_gr_jobpath(pathbuf, jid, ".claim" as *u8) 3010 let cfd: i64 = __syscall(SYS_OPENAT, AT_FDCWD, pathbuf, MA_GR_O_EXCL_CREATE, MODE_0644, 0, 0) 3011 if cfd >= 0 { 3012 var o: i64 = sd_cat(cb, 0, "state=CLAIMED ts=" as *u8) 3013 o = sd_catn(cb, o, jid) 3014 o = sd_cat(cb, o, " route=gate_run target=" as *u8) 3015 o = sd_cat(cb, o, nm) 3016 cb[o] = 10 as u8 3017 o = o + 1 3018 sys_write(cfd, cb, o) 3019 sys_close(cfd) 3020 got = jid 3021 probe = MA_GR_CLAIM_PROBES 3022 } else { jid = jid + 1; probe = probe + 1 } 3023 } 3024 return got 3025} 3026// THE PROMOTED TAIL. Called by main's handler child AFTER the JOB-STARTED reply is on the wire (and by the 3027// gate directly). Streams the pre-promotion capture plus everything the still-running gate writes into 3028// <jobs>/job_<jid>.tmp (no cap: a transcript is whatever the gate printed), wait4()s the worker for its 3029// REAL exit code, renames .tmp -> .out, then rewrites the .claim to state=DONE by rename. Returns the exit 3030// code, or -1 with nothing pending. Idempotent: the pending record is cleared before returning. 3031func ma_gate_run_finish() -> i64 { 3032 if ma_gr_pend_pid == 0 { return 0 - 1 } 3033 let pid: i64 = ma_gr_pend_pid 3034 let rfd: i64 = ma_gr_pend_rfd 3035 let jid: i64 = ma_gr_pend_jid 3036 let pre: *u8 = ma_gr_pend_buf 3037 let pren: i64 = ma_gr_pend_n 3038 let nm: *u8 = ma_gr_pend_nm 3039 ma_gr_pend_pid = 0 3040 let ptmp: *u8 = sys_mmap(512) 3041 let pout: *u8 = sys_mmap(512) 3042 let pclaim: *u8 = sys_mmap(512) 3043 let pctmp: *u8 = sys_mmap(512) 3044 ma_gr_jobpath(ptmp, jid, ".tmp" as *u8) 3045 ma_gr_jobpath(pout, jid, ".out" as *u8) 3046 ma_gr_jobpath(pclaim, jid, ".claim" as *u8) 3047 ma_gr_jobpath(pctmp, jid, ".ctmp" as *u8) 3048 let tfd: i64 = sys_openat_wr(ptmp, MODE_0644) 3049 var total: i64 = 0 3050 if tfd >= 0 { if pren > 0 { sys_write(tfd, pre, pren); total = pren } } 3051 let chunk: *u8 = sys_mmap(MA_MAGIC_65536) 3052 var run: i64 = 1 3053 var eintr: i64 = 0 3054 while run == 1 { 3055 let r: i64 = sys_read(rfd, chunk, MA_MAGIC_65536) 3056 if r > 0 { if tfd >= 0 { sys_write(tfd, chunk, r) } total = total + r } else { 3057 if r == 0 { run = 0 } else { 3058 if r == TR_EINTR { if eintr > TR_EINTR_MAX { run = 0 } else { eintr = eintr + 1 } } else { run = 0 } 3059 } 3060 } 3061 } 3062 sys_close(rfd) 3063 if tfd >= 0 { sys_close(tfd); sys_renameat(ptmp, pout) } 3064 let stp: *i64 = sys_mmap(16) as *i64 3065 let w: i64 = sys_wait4(pid, stp, 0) 3066 var rc: i64 = 0 - 4 3067 if w >= 0 { 3068 let termsig: i64 = stp[0] & 0x7F 3069 if termsig != 0 { rc = 0 - 1 } else { rc = wait_exit_code(stp[0]) } 3070 } 3071 let cb: *u8 = sys_mmap(512) 3072 var o: i64 = sd_cat(cb, 0, "state=DONE rc=" as *u8) 3073 if rc < 0 { o = sd_cat(cb, o, "-1" as *u8) } else { o = sd_catn(cb, o, rc) } 3074 o = sd_cat(cb, o, " verdict=" as *u8) 3075 o = sd_cat(cb, o, ma_gr_verdict(rc)) 3076 o = sd_cat(cb, o, " exit=REAPED bytes=" as *u8) 3077 o = sd_catn(cb, o, total) 3078 o = sd_cat(cb, o, " target=" as *u8) 3079 o = sd_cat(cb, o, nm) 3080 cb[o] = 10 as u8 3081 o = o + 1 3082 let cfd: i64 = sys_openat_wr(pctmp, MODE_0644) 3083 if cfd >= 0 { sys_write(cfd, cb, o); sys_close(cfd); sys_renameat(pctmp, pclaim) } 3084 return rc 3085} 3086// gate_src freshness block, ONE emitter for both payload shapes (it used to be inline in the FAST path). 3087func ma_gr_emit_freshness(rb: *u8, b0: i64, nm: *u8, ep: *u8) -> i64 { 3088 var b: i64 = b0 3089 let sp: *u8 = sys_mmap(512) 3090 b = sd_cat(rb, b, ",\"gate_src\":\"" as *u8) 3091 if ma_gate_src(nm, sp) == 1 { 3092 let sn: i64 = sf_src_stale(ep, sp) 3093 let lg: i64 = sf_lag_sec(ep, sp) 3094 b = sd_cat(rb, b, sp) 3095 b = sd_cat(rb, b, "\",\"source_newer\":" as *u8) 3096 b = sd_catn(rb, b, sn) 3097 b = sd_cat(rb, b, ",\"src_lag_sec\":" as *u8) 3098 if lg < 0 { b = sd_cat(rb, b, "-1" as *u8) } 3099 else { b = sd_catn(rb, b, lg) } 3100 } 3101 else { 3102 // sd_catn cannot render a negative -- the verdict block writes "-1" as a literal for the same 3103 // reason -- and -1 here means UNRESOLVED SOURCE, a different fact from 0 (fresh). 3104 b = sd_cat(rb, b, "\",\"source_newer\":-1,\"src_lag_sec\":-1" as *u8) 3105 } 3106 b = sd_cat(rb, b, ",\"freshness_scope\":\"own-source mtime only; shared-dep staleness is nx_rebuild_plan (it names the trigger file); nx_stale_check <target> rebuilds and byte-compares to confirm\"" as *u8) 3107 return b 3108} 3109 3110func ma_do_gate_run(req: *u8, req_n: i64, out: *u8) -> i64 { 3111 let body_off: i64 = sd_body_off(req, req_n) 3112 let body: *u8 = ((req as i64) + body_off) as *u8 3113 let body_n: i64 = req_n - body_off 3114 let toff: *i64 = sys_mmap(8) as *i64 3115 let tn: *i64 = sys_mmap(8) as *i64 3116 if sd_form_field(body, body_n, "target" as *u8, 6, toff, tn) != 1 { 3117 return ma_emit_400(out, "{\"error\":\"missing target\"}" as *u8) 3118 } 3119 let nm: *u8 = sys_mmap(128) 3120 if ma_sanitize_name(body, toff[0], tn[0], nm, 120) != 1 { 3121 return ma_emit_400(out, "{\"error\":\"invalid target name (only [a-zA-Z0-9_])\"}" as *u8) 3122 } 3123 if md_gate_name_ok(nm) != 1 { 3124 return ma_emit_400(out, "{\"error\":\"target refused: /api/gate_run executes VERIFIERS ONLY -- the name must end in gate, test or kat. That bound is what makes this route never-brick: it cannot reach a daemon, promoter or deployer.\"}" as *u8) 3125 } 3126 // DEADLINE = the one-owner edge pair (window - reply reserve), or the caller's explicit deadline_ms. 3127 let promsrc: *i64 = sys_mmap(16) as *i64 3128 var dl: i64 = tea_sync_promote_ms_from(ma_gr_conf(), promsrc) 3129 var dlsrc: i64 = promsrc[0] 3130 let doff: *i64 = sys_mmap(8) as *i64 3131 let dn: *i64 = sys_mmap(8) as *i64 3132 if sd_form_field(body, body_n, "deadline_ms" as *u8, 11, doff, dn) == 1 { 3133 let v: i64 = mau_qint(body, doff[0], dn[0]) 3134 if v > 0 { dl = v; dlsrc = MA_GR_SRC_CALLER } 3135 } 3136 if dl < MA_GR_DEADLINE_MIN_MS { dl = MA_GR_DEADLINE_MIN_MS } 3137 if dl > MA_GR_DEADLINE_MAX_MS { dl = MA_GR_DEADLINE_MAX_MS } 3138 let ep: *u8 = sys_mmap(256) 3139 var eo: i64 = sd_cat(ep, 0, ma_gr_root()) 3140 eo = sd_cat(ep, eo, nm) 3141 eo = sd_cat(ep, eo, ".elf" as *u8) 3142 ep[eo] = 0 as u8 3143 let cbuf: *u8 = sys_mmap(MA_MAGIC_65536) 3144 let clen: *i64 = sys_mmap(16) as *i64 3145 clen[0] = 0 3146 let gargv: *i64 = sys_mmap(32) as *i64 3147 gargv[0] = ep as i64 3148 gargv[1] = 0 3149 let wpid: *i64 = sys_mmap(16) as *i64 3150 let wrfd: *i64 = sys_mmap(16) as *i64 3151 let rc: i64 = tr_run_capture_deadline(ep, gargv, cbuf, MA_GR_CAPTURE_CAP, clen, dl, wpid, wrfd) 3152 let cn: i64 = clen[0] 3153 let rb: *u8 = sys_mmap(MA_MAGIC_65536) 3154 var b: i64 = sd_cat(rb, 0, "{\"action\":\"GATE-RUN\",\"target\":\"" as *u8) 3155 b = sd_cat(rb, b, nm) 3156 if rc == TR_PROMOTE { 3157 // The gate outran the window: hand the caller a job, keep the worker ALIVE, finish after replying. 3158 let cpath: *u8 = sys_mmap(512) 3159 let jid: i64 = ma_gr_claim(nm, cpath) 3160 if jid < 0 { 3161 // could not reserve an id: the only honest answer is the old one -- drain inline past the window 3162 // rather than orphan a running gate with no artifact. Named in the payload, never silent. 3163 ma_gr_pend_pid = wpid[0]; ma_gr_pend_rfd = wrfd[0]; ma_gr_pend_jid = 0; ma_gr_pend_buf = cbuf; ma_gr_pend_n = cn; ma_gr_pend_nm = nm 3164 let irc: i64 = ma_gate_run_finish() 3165 b = sd_cat(rb, b, "\",\"path\":\"INLINE-NO-CLAIM\",\"exit_code\":" as *u8) 3166 if irc < 0 { b = sd_cat(rb, b, "-1" as *u8) } else { b = sd_catn(rb, b, irc) } 3167 b = sd_cat(rb, b, ",\"deadline_ms\":" as *u8) 3168 b = sd_catn(rb, b, dl) 3169 b = sd_cat(rb, b, ",\"deadline_src\":\"" as *u8) 3170 b = sd_cat(rb, b, ma_gr_src_txt(dlsrc)) 3171 b = sd_cat(rb, b, "\",\"verdict\":\"" as *u8) 3172 b = sd_cat(rb, b, ma_gr_verdict(irc)) 3173 b = sd_cat(rb, b, "\",\"note\":\"the gate outran the reply window but every claim probe collided, so it was drained INLINE instead of promoted -- the verdict is real, the reply may have missed the edge window; check " as *u8) 3174 b = sd_cat(rb, b, cpath) 3175 b = sd_cat(rb, b, "\"}" as *u8) 3176 rb[b] = 0 as u8 3177 return ma_emit_200(out, rb) 3178 } 3179 ma_gr_pend_pid = wpid[0] 3180 ma_gr_pend_rfd = wrfd[0] 3181 ma_gr_pend_jid = jid 3182 ma_gr_pend_buf = cbuf 3183 ma_gr_pend_n = cn 3184 ma_gr_pend_nm = nm 3185 let opath: *u8 = sys_mmap(512) 3186 ma_gr_jobpath(opath, jid, ".out" as *u8) 3187 b = sd_cat(rb, b, "\",\"path\":\"PROMOTED\",\"job\":" as *u8) 3188 b = sd_catn(rb, b, jid) 3189 b = sd_cat(rb, b, ",\"claim\":\"" as *u8) 3190 b = sd_cat(rb, b, cpath) 3191 b = sd_cat(rb, b, "\",\"out\":\"" as *u8) 3192 b = sd_cat(rb, b, opath) 3193 b = sd_cat(rb, b, "\",\"exit_code\":-7,\"verdict\":\"PROMOTED\",\"deadline_ms\":" as *u8) 3194 b = sd_catn(rb, b, dl) 3195 b = sd_cat(rb, b, ",\"deadline_src\":\"" as *u8) 3196 b = sd_cat(rb, b, ma_gr_src_txt(dlsrc)) 3197 b = sd_cat(rb, b, "\",\"bytes\":" as *u8) 3198 b = sd_catn(rb, b, cn) 3199 b = sd_cat(rb, b, ",\"note\":\"JOB-STARTED: the gate outran the reply window and was PROMOTED to the job lane, NOT killed -- it is still running under its own pid and its verdict is NOT in this reply. Poll the claim: state=CLAIMED -> state=DONE rc=<exit> verdict=<GREEN|RED|SKIP|...> (the exit code is the gate's own, reaped by this handler); the transcript is the out artifact. A previous build of this daemon would have SIGKILLed the gate here and answered verdict=TIMEOUT.\"" as *u8) 3200 b = ma_gr_emit_freshness(rb, b, nm, ep) 3201 b = sd_cat(rb, b, ",\"output\":\"" as *u8) 3202 b = ma_gate_esc(rb, b, cbuf, cn) 3203 b = sd_cat(rb, b, "\"}" as *u8) 3204 rb[b] = 0 as u8 3205 return ma_emit_200(out, rb) 3206 } 3207 b = sd_cat(rb, b, "\",\"path\":\"FAST\",\"exit_code\":" as *u8) 3208 if rc < 0 { b = sd_cat(rb, b, "-1" as *u8) } 3209 if rc >= 0 { b = sd_catn(rb, b, rc) } 3210 b = sd_cat(rb, b, ",\"deadline_ms\":" as *u8) 3211 b = sd_catn(rb, b, dl) 3212 b = sd_cat(rb, b, ",\"deadline_src\":\"" as *u8) 3213 b = sd_cat(rb, b, ma_gr_src_txt(dlsrc)) 3214 b = sd_cat(rb, b, "\",\"verdict\":\"" as *u8) 3215 b = sd_cat(rb, b, ma_gr_verdict(rc)) 3216 b = sd_cat(rb, b, "\",\"bytes\":" as *u8) 3217 b = sd_catn(rb, b, cn) 3218 b = sd_cat(rb, b, ",\"capture_cap\":" as *u8) 3219 b = sd_catn(rb, b, MA_GR_CAPTURE_CAP) 3220 b = sd_cat(rb, b, ",\"capture_truncated\":" as *u8) 3221 if cn >= MA_GR_CAPTURE_CAP { b = sd_cat(rb, b, "1" as *u8) } else { b = sd_cat(rb, b, "0" as *u8) } 3222 // FRESHNESS TRAVELS WITH THE VERDICT (2026-08-07, debt 1786111257). A gate ELF STATICALLY LINKS its libs, 3223 // so verdict=GREEN is a claim about the tree AS OF THE BUILD -- never the tree on disk. This route is where 3224 // a gate verdict BECOMES the evidence a caller acts on, so the fact has to ride in THIS response. 3225 // MEASURED: nx_fsops_gate served GREEN pass=23/23 from a 2026-07-29 binary whose source declared 28 checks, 3226 // and the mtime that would have exposed it was ALREADY available to this same process (/api/promote prints 3227 // live_mtime in its refusal). The number was there; nothing put it next to the verdict. 3228 // IT DOES NOT DOWNGRADE THE VERDICT: a gate can be legitimately stale-by-comment -- a comment-only edit 3229 // moves the source mtime and leaves codegen byte-identical (proven the same day, same sha across a header 3230 // edit) -- so report the fact and let the caller judge. Own-source only: ONE stat, no import-closure walk, 3231 // therefore source_newer=0 is NOT a claim of full freshness and the scope says so in the payload. 3232 b = ma_gr_emit_freshness(rb, b, nm, ep) 3233 b = sd_cat(rb, b, ",\"output\":\"" as *u8) 3234 b = ma_gate_esc(rb, b, cbuf, cn) 3235 b = sd_cat(rb, b, "\"" as *u8) 3236 b = sd_cat(rb, b, "}" as *u8) 3237 rb[b] = 0 as u8 3238 return ma_emit_200(out, rb) 3239} 3240 3241// POST /api/proc_kill {match=<needle>&confirm=yes} (seq1383): the verb whose absence forced ssh. Bound in 3242// md_proc_kill_needle_ok, enforced in code. killed:0 is reported honestly as a MISS, never as success. 3243func ma_do_proc_kill(req: *u8, req_n: i64, out: *u8) -> i64 { 3244 let body_off: i64 = sd_body_off(req, req_n) 3245 let body: *u8 = ((req as i64) + body_off) as *u8 3246 let body_n: i64 = req_n - body_off 3247 let moff: *i64 = sys_mmap(8) as *i64 3248 let mn: *i64 = sys_mmap(8) as *i64 3249 if sd_form_field(body, body_n, "match" as *u8, 5, moff, mn) != 1 { 3250 return ma_emit_400(out, "{\"error\":\"missing match (the cmdline needle, e.g. nx_tools_api_serve.elf.new)\"}" as *u8) 3251 } 3252 if ma_confirmed(req, req_n) == 0 { 3253 return ma_emit_400(out, "{\"error\":\"proc_kill requires confirm=yes\"}" as *u8) 3254 } 3255 if mn[0] <= 0 { return ma_emit_400(out, "{\"error\":\"empty match\"}" as *u8) } 3256 if mn[0] > 120 { return ma_emit_400(out, "{\"error\":\"match too long\"}" as *u8) } 3257 let nd: *u8 = sys_mmap(256) 3258 var i: i64 = 0 3259 while i < mn[0] { nd[i] = body[moff[0] + i]; i = i + 1 } 3260 nd[mn[0]] = 0 as u8 3261 if md_proc_kill_needle_ok(nd) != 1 { 3262 return ma_emit_400(out, "{\"error\":\"match refused: proc_kill targets OUR OWN organs only -- the needle must be >=6 chars, must contain .elf, and must not reach the supervisor (nx_hostctl/supervise). Killing the guard would stop every respawn in the ecosystem.\"}" as *u8) 3263 } 3264 let killed: i64 = md_kill_by_name(nd) 3265 let rb: *u8 = sys_mmap(MA_MAGIC_1024) 3266 var b: i64 = sd_cat(rb, 0, "{\"action\":\"PROC-KILL\",\"match\":\"" as *u8) 3267 b = ma_gate_esc(rb, b, nd, mn[0]) 3268 b = sd_cat(rb, b, "\",\"killed\":" as *u8) 3269 b = sd_catn(rb, b, killed) 3270 b = sd_cat(rb, b, ",\"note\":\"guard-supervised daemons respawn from the on-disk binary; killed:0 means NOTHING matched, not success\"}" as *u8) 3271 rb[b] = 0 as u8 3272 return ma_emit_200(out, rb) 3273} 3274 3275func ma_do_put_source(req: *u8, req_n: i64, out: *u8) -> i64 { 3276 let poff: *i64 = sys_mmap(8) as *i64 3277 let plen: *i64 = sys_mmap(8) as *i64 3278 poff[0] = 0 3279 plen[0] = 0 3280 sd_find_path(req, req_n, poff, plen) 3281 let path: *u8 = ((req as i64) + poff[0]) as *u8 3282 let pn: i64 = plen[0] 3283 let qoff: i64 = mau_query_off(path, pn) 3284 if qoff < 0 { return ma_emit_400(out, "{\"error\":\"missing query param name\"}" as *u8) } 3285 let noff: *i64 = sys_mmap(8) as *i64 3286 let nlen: *i64 = sys_mmap(8) as *i64 3287 if mau_qparam(path, pn, qoff, "name" as *u8, 4, noff, nlen) != 1 { 3288 return ma_emit_400(out, "{\"error\":\"missing name\"}" as *u8) 3289 } 3290 let nm: *u8 = sys_mmap(128) 3291 if ma_sanitize_name(path, noff[0], nlen[0], nm, 120) != 1 { 3292 return ma_emit_400(out, "{\"error\":\"invalid name (only [a-zA-Z0-9_])\"}" as *u8) 3293 } 3294 let fp: *u8 = sys_mmap(256) 3295 var fo: i64 = sd_cat(fp, 0, "runtime/" as *u8) 3296 fo = sd_cat(fp, fo, nm) 3297 fo = sd_cat(fp, fo, ".nx" as *u8) 3298 fp[fo] = 0 as u8 3299 let body_off: i64 = sd_body_off(req, req_n) 3300 let body: *u8 = ((req as i64) + body_off) as *u8 3301 let body_n: i64 = req_n - body_off 3302 if body_n <= 0 { return ma_emit_400(out, "{\"error\":\"empty body (POST the raw .nx source)\"}" as *u8) } 3303 let fd: i64 = sys_openat_wr(fp, 0x1a4) 3304 if fd < 0 { return ma_emit_400(out, "{\"error\":\"cannot open source file for write\"}" as *u8) } 3305 var off: i64 = 0 3306 while off < body_n { 3307 let w: i64 = sys_write(fd, ((body as i64) + off) as *u8, body_n - off) 3308 if w <= 0 { sys_close(fd); return ma_emit_400(out, "{\"error\":\"write failed\"}" as *u8) } 3309 off = off + w 3310 } 3311 sys_close(fd) 3312 let rb: *u8 = sys_mmap(256) 3313 var b: i64 = sd_cat(rb, 0, "{\"action\":\"WROTE\",\"file\":\"runtime/" as *u8) 3314 b = sd_cat(rb, b, nm) 3315 b = sd_cat(rb, b, ".nx\",\"bytes\":" as *u8) 3316 b = sd_catn(rb, b, body_n) 3317 b = sd_cat(rb, b, "}" as *u8) 3318 rb[b] = 0 as u8 3319 return ma_emit_200(out, rb) 3320} 3321 3322func ma_do_deploy(req: *u8, req_n: i64, out: *u8) -> i64 { 3323 let body_off: i64 = sd_body_off(req, req_n) 3324 let body: *u8 = ((req as i64) + body_off) as *u8 3325 let body_n: i64 = req_n - body_off 3326 let toff: *i64 = sys_mmap(8) as *i64 3327 let tn: *i64 = sys_mmap(8) as *i64 3328 if sd_form_field(body, body_n, "target" as *u8, 6, toff, tn) != 1 { 3329 return ma_emit_400(out, "{\"error\":\"missing target\"}" as *u8) 3330 } 3331 let kindb: *i64 = sys_mmap(8) as *i64 3332 let srcbuf: *u8 = sys_mmap(512) 3333 let subbuf: *u8 = sys_mmap(64) 3334 let urlbuf: *u8 = sys_mmap(256) 3335 let rbbuf: *u8 = sys_mmap(64) // per-target rollback sub (generalized deploy; legacy rows default to "rollback") 3336 let target_rc:i64=md_resolve_target("knowledge/hosting/deploy_targets.conf" as *u8, body, toff[0], tn[0], kindb, srcbuf, subbuf, urlbuf, rbbuf) 3337 if target_rc==2 { let problem:*u8="{\"error\":\"VERSIONED_OPERATION_REQUIRED\",\"operation\":\"/api/v2/promote_toolchain\",\"published\":false}";return ma_emit_json(out,"HTTP/1.1 409 Conflict\r\nContent-Type: application/json\r\nConnection: close\r\nContent-Length: ",problem,sd_len(problem)) } 3338 if target_rc!=1 { 3339 return ma_emit_400(out, "{\"error\":\"unknown target (not in deploy_targets.conf allowlist)\"}" as *u8) 3340 } 3341 // Derive the build-path name when the row's artifact is absent. ⚠THE SUFFIX IS NOT ALWAYS ".new": rows 3342 // name EITHER "<t>.new" (hostctl) OR "<t>.elf.new" (mgmtapi, relate, opaquelogin...). Stripping a fixed 4 3343 // chars turned "nx_mgmt_api.elf.new" into "nx_mgmt_api.elf.sov.elf.new" -- a name that exists nowhere, so 3344 // the fallback silently did nothing for every .elf.new row. It LOOKED correct only because a stale 3345 // .elf.new was still on disk; consuming that leftover exposed the flaw immediately. Strip ".elf.new" 3346 // when present, else ".new". 3347 var valid: i64 = md_validate_artifact(srcbuf, kindb[0]); if valid == 0 { let sl: i64 = md_len(srcbuf); var cut: i64 = 4; if sl > 8 { if (srcbuf[sl-8] as i64) == 46 { if (srcbuf[sl-7] as i64) == 101 { if (srcbuf[sl-6] as i64) == 108 { if (srcbuf[sl-5] as i64) == 102 { cut = 8 } } } } } if sl > cut { let altp: *u8 = sys_mmap(512); md_copy_slice_z(altp, srcbuf, 0, sl - cut, 512); let ao: i64 = sd_cat(altp, sl - cut, ".sov.elf.new" as *u8); altp[ao] = 0 as u8; if md_validate_artifact(altp, kindb[0]) == 1 { md_copy_slice_z(srcbuf, altp, 0, ao, 512); valid = 1 } } } 3348 if valid == 0 { 3349 // honest ops: "no staged artifact" and "staged artifact failed validation" are different failures 3350 let pfd: i64 = sys_openat_rd(srcbuf) 3351 if pfd < 0 { return ma_emit_200(out, "{\"action\":\"ABORT\",\"verdict\":\"nothing staged for this target (chunk-upload to /api/upload first); NOTHING promoted, site untouched\"}" as *u8) } 3352 sys_close(pfd) 3353 return ma_emit_200(out, "{\"action\":\"ABORT\",\"verdict\":\"staged artifact failed validation (bad ELF/too small); NOTHING promoted, site untouched\"}" as *u8) 3354 } 3355 let alias_guard:i64=ma_stage_alias_guard(srcbuf,out) 3356 if alias_guard>0{return alias_guard} 3357 let admitted_stage_sha:*u8=sys_mmap(FI_DIGEST_BYTES*2+1) 3358 if ma_file_sha_hex(srcbuf,admitted_stage_sha)!=1{sys_munmap(admitted_stage_sha,FI_DIGEST_BYTES*2+1);return ma_emit_503(out,"{\"error\":\"STAGE_IDENTITY_UNAVAILABLE\",\"published\":false}")} 3359 // ---- ROUTE-SUPERSET GUARD (id=1785447778, the 5th mgmt route regression -- one of them mine) ------- 3360 // A deploy that DELETES live API surface is always wrong, whatever the host load. I removed 3361 // /api/gate_run + /api/proc_kill by promoting a 528323-byte artifact over a 575195-byte one; the 3362 // byte DECREASE was visible and nothing checked it. nx_route_diff already printed the right words 3363 // ('route(s) vanished = deploy contract regression') and was never wired into this path. 3364 // FAIL-OPEN BY CONSTRUCTION, and that is the whole safety argument: only a POSITIVE detection of a 3365 // vanished route refuses. Unreadable live artifact, unreadable candidate, zero routes extracted -- 3366 // every one of those PROCEEDS. A buggy guard here could otherwise refuse every future deploy 3367 // INCLUDING ITS OWN FIX, which is exactly the deadlock that made load-gating deploys the wrong 3368 // idea (id=1785450386). Deliberate surface removal stays possible via confirm_route_loss=yes. 3369 let rg_live: *u8 = sys_mmap(512) 3370 let rg_sl: i64 = md_len(srcbuf) 3371 if rg_sl > 4 { 3372 md_copy_slice_z(rg_live, srcbuf, 0, rg_sl - 4, 512) // strip the trailing ".new" 3373 let rg_lb: *u8 = sys_mmap(RG_BUF) 3374 let rg_ln: i64 = rg_read(rg_live, rg_lb, RG_BUF) 3375 if rg_ln > 0 { 3376 let rg_cb: *u8 = sys_mmap(RG_BUF) 3377 let rg_cn: i64 = rg_read(srcbuf, rg_cb, RG_BUF) 3378 if rg_cn > 0 { 3379 let rg_nm: *u8 = sys_mmap(RG_MAXR * RG_NAMEMAX) 3380 let rg_ls: *i64 = sys_mmap(RG_MAXR * 8) as *i64 3381 let rg_tr: *i64 = sys_mmap(16) as *i64 3382 let rg_ms: *i64 = sys_mmap(RG_MAXR * 8) as *i64 3383 let rg_rc: i64 = rg_extract(rg_lb, rg_ln, rg_nm, rg_ls, rg_tr) 3384 if rg_rc > 0 { 3385 let rg_miss: i64 = rg_missing(rg_nm, rg_ls, rg_rc, rg_cb, rg_cn, rg_ms, RG_MAXR) 3386 if rg_miss > 0 { 3387 let rg_co: *i64 = sys_mmap(8) as *i64 3388 let rg_cl: *i64 = sys_mmap(8) as *i64 3389 var rg_ok: i64 = 0 3390 if sd_form_field(body, body_n, "confirm_route_loss" as *u8, 18, rg_co, rg_cl) == 1 { 3391 if md_slice_eq(body, rg_co[0], rg_cl[0], "yes" as *u8, 0, 3) == 1 { rg_ok = 1 } 3392 } 3393 if rg_ok == 0 { 3394 let rgb: *u8 = sys_mmap(MA_MAGIC_4096) 3395 var rgo: i64 = sd_cat(rgb, 0, "{\"action\":\"ABORT\",\"verdict\":\"DEPLOY CONTRACT REGRESSION -- the staged artifact DROPS " as *u8) 3396 rgo = sd_catn(rgb, rgo, rg_miss) 3397 rgo = sd_cat(rgb, rgo, " of " as *u8) 3398 rgo = sd_catn(rgb, rgo, rg_rc) 3399 rgo = sd_cat(rgb, rgo, " /api routes the LIVE binary serves. Promoting it would DELETE working API surface -- this is how /api/gate_run and /api/proc_kill vanished five times. NOTHING promoted, live untouched. Rebuild the candidate from a source tree that still carries those routes (a byte-count DECREASE after an addition is a revert), or pass confirm_route_loss=yes if the removal is DELIBERATE.\",\"routes_live\":" as *u8) 3400 rgo = sd_catn(rgb, rgo, rg_rc) 3401 rgo = sd_cat(rgb, rgo, ",\"routes_missing\":" as *u8) 3402 rgo = sd_catn(rgb, rgo, rg_miss) 3403 rgo = sd_cat(rgb, rgo, ",\"detector\":\"nx_routeguard\"}" as *u8) 3404 rgb[rgo] = 0 as u8 3405 return ma_emit_200(out, rgb) 3406 } 3407 } 3408 } 3409 } 3410 } 3411 } 3412 3413 // ---- STAGING HYGIENE ON THE DAEMON LANE (2026-08-06, debt 1785531571) --------------------------- 3414 // /api/promote carries this guard, but DAEMONS cannot use /api/promote -- they come through here and 3415 // then through nx_hostctl's hc_promote_to, a SECOND promote primitive in a different binary. Guarding 3416 // only the organ lane would be the same lesson learned in one binary and not the other. The paths are 3417 // already resolved above, so this reuses rg_live (live) and srcbuf (staged) rather than re-deriving. 3418 // 3419 // FAIL-OPEN, for exactly the reason the routeguard above states: this verb deploys nx_mgmt_api ITSELF, 3420 // so a guard that refused on a read error could refuse its own fix and wedge every seat. ONLY a 3421 // POSITIVE classification with real numbers refuses; NONE, unreadable, and ORPHAN all PROCEED. 3422 // NOTE THE RESIDUAL, stated rather than hidden: when the .sov.elf.new fallback above rewrote srcbuf, 3423 // rg_live names a path that never exists, the classification is ORPHAN, and this guard is inert for 3424 // that row -- the same blind spot the routeguard has, and it fails in the safe direction. 3425 // ⚠hc_promote_to itself stays UNGUARDED ON PURPOSE: it is also the primitive behind all 12 rollback 3426 // verbs, and a rollback is a DELIBERATE backwards move. Guarding it there would remove the reverse 3427 // gear, which Rule 26 forbids outright. 3428 if rg_sl > 4 { 3429 let dhcfg: *i64 = sys_mmap(8 * SG_C_SLOTS) as *i64 3430 sg_conf_load(dhcfg) 3431 let dhout: *i64 = sys_mmap(8 * SG_OUT_SLOTS) as *i64 3432 let dhc: i64 = sg_classify(rg_live, srcbuf, sys_now_realtime_sec(), dhcfg, dhout) 3433 var dhdeny: i64 = 0 3434 if dhc == SG_BACKDATE { dhdeny = 1 } 3435 if dhc == SG_EXPIRED { dhdeny = 1 } 3436 if dhc == SG_SHRINK { dhdeny = 1 } 3437 if dhc == SG_CAPLOSS { dhdeny = 1 } 3438 if dhdeny == 1 { 3439 let dho: *i64 = sys_mmap(8) as *i64 3440 let dhl: *i64 = sys_mmap(8) as *i64 3441 var dhok: i64 = 0 3442 if sd_form_field(body, body_n, "allow_capability_loss" as *u8, 21, dho, dhl) == 1 { 3443 if md_slice_eq(body, dho[0], dhl[0], "yes" as *u8, 0, 3) == 1 { dhok = 1 } 3444 } 3445 if dhok == 0 { 3446 let dhb: *u8 = sys_mmap(MA_MAGIC_2048) 3447 var dhq: i64 = sd_cat(dhb, 0, "{\"action\":\"ABORT\",\"verdict\":\"STAGING HYGIENE -- the staged artifact would walk this daemon BACKWARDS. NOTHING promoted, live untouched. A .new older than the binary it replaces is a rollback wearing an upgrade filename; one that drops the live binary's printable capability runs is a silent feature regression, and neither size nor mtime alone catches that case. Rebuild the candidate so it is genuinely newer, or pass allow_capability_loss=yes if the regression is DELIBERATE.\",\"class\":\"" as *u8) 3448 dhq = sd_cat(dhb, dhq, sg_class_name(dhc)) 3449 dhq = sd_cat(dhb, dhq, "\",\"live_bytes\":" as *u8) 3450 dhq = sd_catn(dhb, dhq, dhout[SG_O_LIVESZ]) 3451 dhq = sd_cat(dhb, dhq, ",\"staged_bytes\":" as *u8) 3452 dhq = sd_catn(dhb, dhq, dhout[SG_O_NEWSZ]) 3453 dhq = sd_cat(dhb, dhq, ",\"live_mtime\":" as *u8) 3454 dhq = sd_catn(dhb, dhq, dhout[SG_O_LIVEMT]) 3455 dhq = sd_cat(dhb, dhq, ",\"staged_mtime\":" as *u8) 3456 dhq = sd_catn(dhb, dhq, dhout[SG_O_NEWMT]) 3457 dhq = sd_cat(dhb, dhq, ",\"staged_age_days\":" as *u8) 3458 dhq = sd_catn(dhb, dhq, dhout[SG_O_AGEDAYS]) 3459 dhq = sd_cat(dhb, dhq, ",\"shrink_permil\":" as *u8) 3460 dhq = sd_catn(dhb, dhq, dhout[SG_O_SHRINKPERMIL]) 3461 dhq = sd_cat(dhb, dhq, ",\"capability_loss_permil\":" as *u8) 3462 dhq = sd_catn(dhb, dhq, dhout[SG_O_LOSTPERMIL]) 3463 dhq = sd_cat(dhb, dhq, ",\"live_runs_absent\":" as *u8) 3464 dhq = sd_catn(dhb, dhq, dhout[SG_O_MISSING]) 3465 dhq = sd_cat(dhb, dhq, ",\"live_runs_checked\":" as *u8) 3466 dhq = sd_catn(dhb, dhq, dhout[SG_O_CHECKED]) 3467 dhq = sd_cat(dhb, dhq, ",\"override\":\"allow_capability_loss=yes\",\"detector\":\"nx_staging_guard\"}" as *u8) 3468 dhb[dhq] = 0 as u8 3469 return ma_emit_200(out, dhb) 3470 } 3471 } 3472 } 3473 3474 // ---- PRE-DEPLOY GATE, NOW ACTUALLY PRE-DEPLOY AND ACTUALLY A GATE (seq1798) ---------------------------- 3475 // WHAT WAS WRONG, AND IT WAS WORSE THAN 'ADVISORY': this check used to run AFTER md_exec_hostctl had 3476 // ALREADY PROMOTED the artifact, so it was a POST-DEPLOY REPORT WEARING A PRE-DEPLOY LABEL. The old 3477 // comment there claimed flipping it to a hard refusal was 'a ONE-LINE change here' -- it was not, because 3478 // by that point the irreversible act had happened and a refusal could only ever describe something that 3479 // was already live. Evaluating it HERE is what makes refusal mean anything at all. 3480 // PLACED BEFORE THE LEASE ON PURPOSE: a refusal returns early, and acquiring the lease first would STRAND 3481 // the lane until its TTL expired -- the same reasoning the lease block below already states for itself. 3482 // POLICY (operator decision, 2026-07-31): a BLOCK-severity blocker REFUSES. The escape hatch is 3483 // confirm_gate_override=yes -- deliberate, named, and echoed in the response, exactly the shape the 3484 // routeguard above uses for confirm_route_loss. An advisory BLOCK is a disabled gate arrived at SILENTLY; 3485 // an override is a disabled gate arrived at DELIBERATELY, and only the second one is honest. 3486 // UNAVAILABLE STAYS FAIL-OPEN BY DESIGN: if nx_deploy_ready cannot be read we do NOT wedge every seat on 3487 // a broken instrument. A gate that cannot be satisfied produces a bypass, not safety. 3488 var pdg: i64 = 0 - 1 3489 // LOOSE COUPLING (2026-09-02): hand the gate the deploy TARGET (this deploy_targets.conf row name) so its 3490 // evidence-honesty block is scoped to THIS target's blast radius, never to an unrelated domain's RED. 3491 let pdt: *u8 = sys_mmap(128) 3492 var pdti: i64 = 0 3493 while pdti < tn[0] { if pdti < 127 { pdt[pdti] = body[toff[0] + pdti] } pdti = pdti + 1 } 3494 if pdti > 127 { pdti = 127 } 3495 pdt[pdti] = 0 as u8 3496 let pdrc: i64 = md_exec_deploy_ready(pdt) 3497 if pdrc >= 0 { 3498 let pdsz: *i64 = sys_mmap(16) as *i64 3499 let pdbuf: *u8 = md_read_file("/tmp/nx_ma_deploy_ready.out" as *u8, pdsz) 3500 if (pdbuf as i64) != 0 { pdg = hh_after(pdbuf, pdsz[0], "\"blockers\":" as *u8) } 3501 } 3502 var pdg_ovr: i64 = 0 3503 let pgo: *i64 = sys_mmap(8) as *i64 3504 let pgl: *i64 = sys_mmap(8) as *i64 3505 if sd_form_field(body, body_n, "confirm_gate_override" as *u8, 21, pgo, pgl) == 1 { 3506 if md_slice_eq(body, pgo[0], pgl[0], "yes" as *u8, 0, 3) == 1 { pdg_ovr = 1 } 3507 } 3508 if pdg > 0 { if pdg_ovr == 0 { 3509 let pgb: *u8 = sys_mmap(MA_MAGIC_4096) 3510 var pgq: i64 = sd_cat(pgb, 0, "{\"action\":\"REFUSED\",\"verdict\":\"PRE-DEPLOY GATE BLOCKED -- an INDEPENDENT METHOD IS REPORTING FAILURE, so nothing ships. NOTHING promoted, live untouched. Run nx_deploy_ready check to see the blocker and its remediation (today: evidence-honesty -- nx_sota_status names the domain, then nx_swcompare_evidence <domain> re-measures it). If you must ship before that is green, pass confirm_gate_override=yes: it proceeds AND is reported as an AUDITED override, never a silent bypass.\",\"pre_deploy_gate\":\"DEPLOY-BLOCKED\",\"gate_blockers\":" as *u8) 3511 pgq = sd_catn(pgb, pgq, pdg) 3512 pgq = sd_cat(pgb, pgq, ",\"gate_exit\":" as *u8) 3513 pgq = sd_catn(pgb, pgq, pdrc) 3514 pgq = sd_cat(pgb, pgq, ",\"override\":\"confirm_gate_override=yes\",\"detector\":\"nx_deploy_ready\"}" as *u8) 3515 pgb[pgq] = 0 as u8 3516 return ma_emit_400(out, pgb) 3517 } } 3518 3519 // ---- R1b (seq1531 residual): LEASE-GATE THE DEPLOY ----------------------------------------------------- 3520 // A deploy race is STRICTLY WORSE than a build race: two sessions promoting the same target can interleave 3521 // a half-swapped artifact on the LIVE plane. Same nx_lease, same exit-code contract (0=acquired, 3=BUSY), 3522 // same TTL anti-deadlock property as R1. 3523 // ACQUIRED HERE, NOT EARLIER, ON PURPOSE: every failure path above (unknown target, nothing staged, failed 3524 // validation) returns early, so acquiring before them would STRAND the lane until the TTL expired. Taking 3525 // it immediately before the promote and releasing immediately after makes the guarded region atomic and 3526 // leaves no exit that can strand it. 3527 let dnmb: *u8 = sys_mmap(192) 3528 let dlease: *u8 = sys_mmap(224) 3529 dlease[0] = 0 as u8 3530 if ma_sanitize_name(body, toff[0], tn[0], dnmb, 120) == 1 { 3531 var dlo: i64 = sd_cat(dlease, 0, "deploy-" as *u8) 3532 dlo = sd_cat(dlease, dlo, dnmb) 3533 dlease[dlo] = 0 as u8 3534 if md_lease_run("acquire" as *u8, dlease, "mgmt-api-deploy" as *u8, ma_lease_ttl_txt(MA_DEPLOY_LEASE_TTL_S), 4, "/tmp/nx_ma_lease.out" as *u8) == 3 { 3535 let dlb: *u8 = sys_mmap(MA_MAGIC_2048) 3536 let dln: i64 = dp_read("/tmp/nx_ma_lease.out" as *u8, dlb, 900) 3537 let dcb: *u8 = sys_mmap(MA_MAGIC_4096) 3538 var dco: i64 = sd_cat(dcb, 0, "{\"conflict\":\"lease-busy\",\"error\":\"another session is ALREADY DEPLOYING this target -- refusing to race the LIVE plane (seq1531 R1b). Concurrent promotes can interleave a half-swapped artifact. The holder is named below; the lease is TTL-bounded so a dead session can never hold the lane closed.\",\"holder\":\"" as *u8) 3539 dco = ma_gate_esc(dcb, dco, dlb, dln) 3540 dco = ts_retry_after_derived(dcb, dco, MA_DEPLOY_LEASE_TTL_S) 3541 dcb[dco] = 0 as u8 3542 return ma_emit_400(out, dcb) 3543 } 3544 } 3545 var final_guard:i64=ma_stage_alias_guard(srcbuf,out) 3546 let current_stage_sha:*u8=sys_mmap(FI_DIGEST_BYTES*2+1) 3547 if final_guard==0{ 3548 if ma_file_sha_hex(srcbuf,current_stage_sha)!=1 || ma_hexstr_eq(admitted_stage_sha,current_stage_sha)!=1{ 3549 let message:*u8="{\"error\":\"STAGED_ARTIFACT_CHANGED\",\"published\":false}" 3550 final_guard=ma_emit_json(out,"HTTP/1.1 409 Conflict\r\nContent-Type: application/json\r\nConnection: close\r\nContent-Length: ",message,fi_len(message)) 3551 } 3552 } 3553 sys_munmap(current_stage_sha,FI_DIGEST_BYTES*2+1) 3554 sys_munmap(admitted_stage_sha,FI_DIGEST_BYTES*2+1) 3555 if final_guard>0{ 3556 if dlease[0]!=(0 as u8){md_lease_run("release",dlease,"mgmt-api-deploy","0",3,"/tmp/nx_ma_lease.out")} 3557 return final_guard 3558 } 3559 let promote_rc: i64 = md_exec_hostctl(subbuf) 3560 if dlease[0] != (0 as u8) { md_lease_run("release" as *u8, dlease, "mgmt-api-deploy" as *u8, "0" as *u8, 3, "/tmp/nx_ma_lease.out" as *u8) } 3561 if promote_rc != 0 { 3562 ma_write_status("PROMOTE-FAILED" as *u8) 3563 return ma_emit_200(out, "{\"action\":\"PROMOTE-FAILED\",\"verdict\":\"hostctl promote returned nonzero; nothing further\"}" as *u8) 3564 } 3565 // DETACHED health+rollback watchdog: waits out a slow guard-respawn (~up to 30s) WITHOUT racing the edge- 3566 // proxy read window (the sync path made restart-targets time out / conservatively roll back). Writes the 3567 // final verdict to a status file -> poll GET /api/deploy_status. NEVER-BRICK preserved: a failed health 3568 // check still auto-rolls-back to .prev inside the watchdog. 3569 ma_write_status("RUNNING" as *u8) 3570 let dpid: i64 = sys_fork() 3571 if dpid == 0 { 3572 let dpid2: i64 = sys_fork() 3573 if dpid2 == 0 { 3574 var fdc: i64 = 3; while fdc < 256 { sys_close(fdc); fdc = fdc + 1 } // release the inherited client socket + ALL fds -> the response returns cleanly (no status=0) AND the health fetch runs on clean fds 3575 // NAMED-OUTCOME LISTENER VERIFICATION (debt 1786068492). The three states are distinct ON PURPOSE: 3576 // NEVER_UP is the ONLY one that rolls back, so this change cannot make a deploy that passes today 3577 // begin failing. UNVERIFIED is a GREEN THAT ADMITS IT COULD NOT WITNESS THE HANDOFF -- which is the 3578 // state the old level-triggered probe silently reported as a full green while it was, in the measured 3579 // incident, looking at the OUTGOING process. The first status token is unchanged for every existing 3580 // reader of /api/deploy_status; the reason rides as an additive suffix (rule 19). 3581 let hpc: i64 = md_deploy_health(urlbuf) 3582 let stb: *u8 = sys_mmap(256) 3583 var sto: i64 = 0 3584 if hpc == MD_HP_NEVER_UP { md_exec_hostctl(rbbuf); sto = sd_cat(stb, 0, "ROLLED-BACK" as *u8) } else { sto = sd_cat(stb, 0, "DEPLOYED-GREEN" as *u8) } 3585 sto = sd_cat(stb, sto, md_hp_suffix(hpc)) 3586 stb[sto] = 0 as u8 3587 ma_write_status(stb) 3588 sys_exit(0) 3589 } 3590 sys_exit(0) 3591 } 3592 let dst: *i64 = sys_mmap(16) as *i64; sys_wait4(dpid, dst, 0) 3593 // PRE-DEPLOY GATE, now ATTACHED to every deploy verdict (2026-07-30). ADVISORY ON PURPOSE, and that is 3594 // a deliberate engineering call, not a half-measure: the live blocker (evidence-honesty) is unrelated to 3595 // any particular target, and nx_deploy_ready's own manifest says a gate that halts every deploy gets 3596 // disabled, and a disabled gate protects nothing. So step one is to make it IMPOSSIBLE TO DEPLOY BLIND -- 3597 // the verdict now rides on the response every caller already reads. Flipping it to a hard refusal is the 3598 // right end state and is a ONE-LINE change here, gated on blockers reaching 0 first. 3599 var drx: i64 = 0 - 1 3600 // seq1798: REUSE the PRE-PROMOTE evaluation. Re-forking the checker here would (a) waste a fork and 3601 // (b) risk REPORTING A DIFFERENT VERDICT than the one the gate decision was actually made on -- the 3602 // report must describe the decision that was taken, not a fresh roll of the same dice. 3603 let drc: i64 = pdrc 3604 if drc >= 0 { 3605 let dsz: *i64 = sys_mmap(16) as *i64 3606 let dbuf: *u8 = md_read_file("/tmp/nx_ma_deploy_ready.out" as *u8, dsz) 3607 if (dbuf as i64) != 0 { drx = hh_after(dbuf, dsz[0], "\"blockers\":" as *u8) } 3608 } 3609 // seq1798: 512 was sized for the old short verdicts; the OVERRIDDEN string alone is ~230B and would 3610 // have overrun it. A response buffer that silently overruns is how a truthful verdict becomes garbage. 3611 let gb: *u8 = sys_mmap(MA_MAGIC_2048) 3612 var gq: i64 = sd_cat(gb, 0, "{\"action\":\"PROMOTED\",\"verdict\":\"promoted; health+auto-rollback watchdog running\",\"status\":\"GET /api/deploy_status\",\"pre_deploy_gate\":\"" as *u8) 3613 if drx < 0 { gq = sd_cat(gb, gq, "UNAVAILABLE-fail-open (nx_deploy_ready unreadable; deploy proceeded rather than wedge every seat)" as *u8) } else { if drx > 0 { gq = sd_cat(gb, gq, "DEPLOY-BLOCKED-OVERRIDDEN (blockers were present and confirm_gate_override=yes was passed -- this deploy was DELIBERATELY and AUDITABLY allowed, not silently permitted; without that flag it would have been REFUSED before the promote)" as *u8) } else { gq = sd_cat(gb, gq, "DEPLOY-SAFE" as *u8) } } 3614 gq = sd_cat(gb, gq, "\",\"gate_blockers\":" as *u8) 3615 gq = sd_catn(gb, gq, drx) 3616 // gate_exit is the gate's OWN exit status. It was hardcoded 0 for every verdict until 2026-07-30, so 3617 // seeing a 3 here is the live proof that a gate which could not signal refusal now can. 3618 gq = sd_cat(gb, gq, ",\"gate_override\":" as *u8) 3619 if pdg_ovr == 1 { gq = sd_cat(gb, gq, "\"AUDITED\"" as *u8) } else { gq = sd_cat(gb, gq, "\"none\"" as *u8) } 3620 gq = sd_cat(gb, gq, ",\"gate_exit\":" as *u8) 3621 gq = sd_catn(gb, gq, drc) 3622 // NAME THE ARTIFACT THIS DEPLOY CONSUMED. A DEPLOY THAT CANNOT SAY WHAT IT DEPLOYED IS THE SILENT CLASS. 3623 // Escaped: a conf-read path is untrusted input to a JSON serializer. 3624 gq = sd_cat(gb, gq, ",\"staged_artifact\":\"" as *u8) 3625 gq = ma_gate_esc(gb, gq, srcbuf, md_len(srcbuf)) 3626 gq = sd_cat(gb, gq, "\",\"listen_check\":\"edge-verified; see deploy_status. PROVES THE PORT ANSWERS, NEVER THAT THE RIGHT BINARY ANSWERS.\"" as *u8) 3627 gq = sd_cat(gb, gq, "}" as *u8) 3628 gb[gq] = 0 as u8 3629 return ma_emit_200(out, gb) 3630} 3631 3632// ---- /api/hostctl (P2 off-LAN parity): run ONE allowlisted hostctl action + return its captured output ---- 3633// so the operator can drive the FULL control surface (torstat/routerctl/status/kick*/trackerrefresh) from a 3634// phone. Auth = MA_LVL_ACT (checked by ma_handle). Allowlist fail-closed (md_hostctl_action_ok); single argv 3635// element to execve (no shell). Output returned as text/plain (raw hostctl dump, capped to the response buffer). 3636func ma_do_hostctl(req: *u8, req_n: i64, out: *u8) -> i64 { 3637 let body_off: i64 = sd_body_off(req, req_n) 3638 let body: *u8 = ((req as i64) + body_off) as *u8 3639 let body_n: i64 = req_n - body_off 3640 let toff: *i64 = sys_mmap(8) as *i64 3641 let tn: *i64 = sys_mmap(8) as *i64 3642 if sd_form_field(body, body_n, "sub" as *u8, 3, toff, tn) != 1 { 3643 return ma_emit_400(out, "{\"error\":\"missing sub\"}" as *u8) 3644 } 3645 let subbuf: *u8 = sys_mmap(64); md_copy_slice_z(subbuf, body, toff[0], tn[0], 64) 3646 if md_hostctl_action_ok(subbuf) != 1 { 3647 return ma_emit_400(out, "{\"error\":\"sub not in hostctl action allowlist (status|torstat|routerctl|receipts|kick*|trackerrefresh)\"}" as *u8) 3648 } 3649 md_exec_hostctl_capture(subbuf, "/tmp/nx_ma_hostctl.out" as *u8) 3650 let szp: *i64 = sys_mmap(16) as *i64 3651 let outbuf: *u8 = md_read_file("/tmp/nx_ma_hostctl.out" as *u8, szp) 3652 if (outbuf as i64) == 0 { return ma_emit_200(out, "{\"action\":\"HOSTCTL\",\"out\":\"(no output)\"}" as *u8) } 3653 var on: i64 = szp[0] 3654 if on > MA_MAGIC_60000 { on = MA_MAGIC_60000 } // cap to fit the response buffer (raw dumps stay well under) 3655 return ma_emit_json(out, "HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\nConnection: close\r\nContent-Length: " as *u8, outbuf, on) 3656} 3657 3658// ---- /api/promote_content: promote a STAGED static file <t>.new -> live <t> (atomic, .prev-backed) ---------- 3659// STATIC CONTENT ONLY (md_content_target_ok namespace). Never touches a service binary; a bad promote reverts 3660// itself (if live->prev succeeded but new->live failed, prev is restored) so the live file is never lost. 3661// target rides in the form body (like /api/deploy); requires confirm=yes (a promote changes the public site). 3662func ma_do_promote_content(req: *u8, req_n: i64, out: *u8) -> i64 { 3663 let body_off: i64 = sd_body_off(req, req_n) 3664 let body: *u8 = ((req as i64) + body_off) as *u8 3665 let body_n: i64 = req_n - body_off 3666 let toff: *i64 = sys_mmap(8) as *i64 3667 let tn: *i64 = sys_mmap(8) as *i64 3668 if sd_form_field(body, body_n, "target" as *u8, 6, toff, tn) != 1 { 3669 return ma_emit_400(out, "{\"error\":\"missing target\"}" as *u8) 3670 } 3671 if md_content_target_ok(body, toff[0], tn[0]) != 1 { 3672 return ma_emit_400(out, "{\"error\":\"target not in the content namespace\"}" as *u8) 3673 } 3674 if ma_confirmed(req, req_n) == 0 { 3675 return ma_emit_400(out, "{\"error\":\"promote_content requires confirm=yes\"}" as *u8) 3676 } 3677 let livep: *u8 = sys_mmap(256) 3678 let newp: *u8 = sys_mmap(256) 3679 let prevp: *u8 = sys_mmap(256) 3680 // bare live path = just the target slice, NUL-terminated (no empty-literal suffix; that aliases the pool) 3681 var lo: i64 = 0 3682 while lo < tn[0] { livep[lo] = body[toff[0] + lo]; lo = lo + 1 } 3683 livep[lo] = 0 as u8 3684 mau_build_path(body, toff[0], tn[0], ".new" as *u8, newp) 3685 mau_build_path(body, toff[0], tn[0], ".prev" as *u8, prevp) 3686 // staged file must exist 3687 let nfd: i64 = sys_openat_rd(newp) 3688 if nfd < 0 { return ma_emit_400(out, "{\"error\":\"no staged .new for target (upload first)\"}" as *u8) } 3689 sys_close(nfd) 3690 // back up the live file if present (rename live -> .prev) 3691 var had_live: i64 = 0 3692 let lfd: i64 = sys_openat_rd(livep) 3693 if lfd >= 0 { sys_close(lfd); had_live = 1 } 3694 // DURABLE ROLLBACK CHAIN (2026-08-21). The comment above USED to end "atomically replacing any older 3695 // .prev" -- which is precisely the loss, written as though it were a feature. MEASURED THIS SESSION: 3696 // two promotes of ONE target left live and .prev BOTH holding new builds and the pre-change binary 3697 // GONE, and an older-generation binary CANNOT be rebuilt. This slot holds "the PREVIOUS PROMOTE", 3698 // never "the last known good", so the SECOND promote is the one that leaves you with no way back. 3699 // The only defence was the operator remembering to copy the artifact aside first, and 3700 // *A SAFETY PROPERTY THAT DEPENDS ON SOMEONE REMEMBERING IS AN ADOPTION GAP WITH EXTRA STEPS. 3701 // Rotate one generation deeper and REPORT it, so a third promote's loss is visible, not silent. 3702 // Bounded on purpose: exactly one extra file per target, no directory, no new import. 3703 // *THE TWIN IS NAMED, NOT HIDDEN: hc_promote_to (nx_hostctl) is a SECOND, INDEPENDENT promote 3704 // implementation and carries this same rotation -- one fix had to land TWICE, which is the cost of 3705 // the duplication and the reason it is recorded here instead of quietly patched in one place. 3706 // COMPOSED, NOT COPIED: md_rotate_prev (nx_mgmt_data) is the ONE rotation this daemon uses -- all 3707 // four of its live->.prev sites call it, so the chain cannot be right in one promote verb and wrong 3708 // in another. An inline twin stood here for exactly one edit and was collapsed into the shared 3709 // function before it could become the sixth copy. 3710 if had_live == 1 { md_rotate_prev(prevp) } 3711 if had_live == 1 { 3712 if sys_renameat(livep, prevp) != 0 { return ma_emit_400(out, "{\"error\":\"backup rename failed; live untouched\"}" as *u8) } 3713 } 3714 // promote 3715 if sys_renameat(newp, livep) != 0 { 3716 if had_live == 1 { sys_renameat(prevp, livep) } // restore -- the live file is never lost 3717 return ma_emit_400(out, "{\"error\":\"promote rename failed; previous file restored\"}" as *u8) 3718 } 3719 let rb: *u8 = sys_mmap(320) 3720 var b: i64 = sd_cat(rb, 0, "{\"action\":\"PROMOTE_CONTENT\",\"target\":\"" as *u8) 3721 b = md_cat_slice(rb, b, body, toff[0], tn[0]) 3722 b = sd_cat(rb, b, "\",\"live\":1,\"prev\":" as *u8) 3723 b = sd_catn(rb, b, had_live) 3724 b = sd_cat(rb, b, "}" as *u8) 3725 return ma_emit_200(out, rb) 3726} 3727 3728// NEVER-BRICK guard: is `path` a real ELF (magic 0x7f 'E' 'L' 'F')? A missing, empty, or truncated build 3729// output must NEVER be promoted onto a live organ path -- that would replace a working organ with garbage. 3730func mau_is_elf(path: *u8) -> i64 { 3731 let fd: i64 = sys_openat_rd(path) 3732 if fd < 0 { return 0 } 3733 let hb: *u8 = sys_mmap(8) 3734 let n: i64 = sys_read(fd, hb, 4) 3735 sys_close(fd) 3736 if n < 4 { return 0 } 3737 if hb[0] != (0x7f as u8) { return 0 } 3738 if hb[1] != (69 as u8) { return 0 } // 'E' 3739 if hb[2] != (76 as u8) { return 0 } // 'L' 3740 if hb[3] != (70 as u8) { return 0 } // 'F' 3741 return 1 3742} 3743 3744// Fold an ASCII hex digit to lowercase so a caller may send either case. 3745func ma_hexlc(c: i64) -> i64 { 3746 if c >= 65 { if c <= 70 { return c + 32 } } 3747 return c 3748} 3749// Compare a NUL-terminated 64-char hex digest against a form-field slice, case-insensitively. 3750// Length is checked FIRST: a short or long field is a MISMATCH, never a prefix match. 3751func ma_hex_eq(hex: *u8, buf: *u8, off: i64, n: i64) -> i64 { 3752 if n != 64 { return 0 } 3753 var i: i64 = 0 3754 while i < 64 { 3755 let a: i64 = ma_hexlc(hex[i] as i64) 3756 let b: i64 = ma_hexlc(buf[off+i] as i64) 3757 if a != b { return 0 } 3758 i = i + 1 3759 } 3760 return 1 3761} 3762 3763// POST /api/promote {target=<organ>&confirm=yes}: promote a built ONE-SHOT organ ELF (<target>.sov.elf.new from 3764// /api/build) to its live <target>.elf -- the API-pure replacement for the SSH `cp X.sov.elf.new X.elf` step, so 3765// the whole edit -> /api/build -> /api/promote loop needs zero shell. NEVER-BRICK, fail-closed at every step: 3766// (1) name sanitized to [a-zA-Z0-9_] (no dot/slash/dot-dot -> no path escape), 3767// (2) md_promote_organ_ok allowlist (daemons REFUSED -> they use the health-checked /api/deploy), 3768// (3) confirm=yes required, 3769// (4) the staged file must exist AND be a valid ELF (mau_is_elf) -- garbage is never promoted, 3770// (5) md_promote_staged keeps the old live as <target>.elf.prev (one-command rollback). 3771// Auth = MA_LVL_ACT, enforced by the dispatcher (ma_handle) before this is reached. 3772// ---- D001 STRUCTURAL GUARD: a gate that rolls its own verdict is NOT PROMOTABLE ---------------- 3773// WHY HERE AND NOT IN 2800 LEAVES: D001 (gates hand-rolling verdict emission instead of inheriting 3774// nx_gate_verdict) sat at 2 permil for nine days and was then moved to 172 permil by migrating leaves 3775// one at a time. That is O(LEAVES) FOREVER -- it remediates what exists and does nothing about the next 3776// gate someone hand-writes tomorrow. The corpus is a LINEAGE, and a constraint belongs at the ONE place 3777// every gate must pass through to become real. Promote is that place: a gate may be built and run and 3778// iterated on freely, but it cannot become a promoted organ of this ecosystem while it emits a verdict 3779// nothing else can read. A rule nothing must remember beats a list. 3780// NAME-BASED, matching /api/gate_run's own bound (_gate/_test/_kat) -- a rule nothing must remember 3781// beats a registry that must be maintained. 3782// ESCAPE HATCH, deliberate: allow_own_verdict=yes. A guard that CANNOT BE SATISFIED produces a bypass, 3783// not safety. Legitimate exceptions (a gate proving the base class itself, a fixture) say so explicitly 3784// and land in the audit trail instead of quietly routing around the check. 3785// FAIL-OPEN ON MISSING SOURCE, deliberate and narrow: if the .nx cannot be found we do NOT refuse -- 3786// mgmt promotes organs whose source may legitimately not be in this tree, and turning "I could not 3787// check" into "denied" would break unrelated promotes. Absent source is UNKNOWN, not GUILTY. 3788const MA_D001_BUF: i64 = 262144 3789 3790func ma_name_is_oracle(nm: *u8, n: i64) -> i64 { 3791 if n >= 5 { 3792 if nm[n-5] == (95 as u8) { if nm[n-4] == (103 as u8) { if nm[n-3] == (97 as u8) { if nm[n-2] == (116 as u8) { if nm[n-1] == (101 as u8) { return 1 } } } } } 3793 } 3794 if n >= 5 { 3795 if nm[n-5] == (95 as u8) { if nm[n-4] == (116 as u8) { if nm[n-3] == (101 as u8) { if nm[n-2] == (115 as u8) { if nm[n-1] == (116 as u8) { return 1 } } } } } 3796 } 3797 if n >= 4 { 3798 if nm[n-4] == (95 as u8) { if nm[n-3] == (107 as u8) { if nm[n-2] == (97 as u8) { if nm[n-1] == (116 as u8) { return 1 } } } } 3799 } 3800 return 0 3801} 3802 3803// ⚠ A TRUNCATED DUPLICATE OF THIS FUNCTION WAS REMOVED HERE (2026-07-31). A botched edit had left a 3804// half-written `ma_d001_scan` header followed by an ORPHANED TAIL of the previous function, then this 3805// complete definition -- so the file carried TWO definitions of one name and DID NOT COMPILE AT ALL. 3806// That is why this lane's edits sat SOURCE-ONLY-NOT-BUILT: not caution, a syntax error nobody had run 3807// into because nothing rebuilt the file. The compiler's dup-def guard (shipped today) named it exactly. 3808// ★★★★★ A FILE THAT DOES NOT COMPILE BLOCKS EVERY LANE THAT TOUCHES IT, SILENTLY, UNTIL SOMEONE BUILDS IT. 3809func ma_d001_scan(path: *u8, buf: *u8) -> i64 { 3810 let fd: i64 = sys_openat_rd(path) 3811 if fd < 0 { return 0 - 1 } 3812 var total: i64 = 0 3813 var run: i64 = 1 3814 while run == 1 { 3815 if total >= MA_D001_BUF { run = 0 } else { 3816 let r: i64 = sys_read(fd, ((buf as i64) + total) as *u8, MA_D001_BUF - total) 3817 if r <= 0 { run = 0 } else { total = total + r } 3818 } 3819 } 3820 sys_close(fd) 3821 let needle: *u8 = "nx_gate_verdict" as *u8 3822 var nl: i64 = 0 3823 while needle[nl] != (0 as u8) { nl = nl + 1 } 3824 var i: i64 = 0 3825 while i + nl <= total { 3826 var m: i64 = 1 3827 var k: i64 = 0 3828 while k < nl { if buf[i+k] != needle[k] { m = 0; k = nl } else { k = k + 1 } } 3829 if m == 1 { return 1 } 3830 i = i + 1 3831 } 3832 return 0 3833} 3834 3835// 1 inherits · 0 rolls its own · -1 source not found (treated as UNKNOWN, never as a refusal) 3836func ma_inherits_verdict(nm: *u8, nmlen: i64) -> i64 { 3837 let buf: *u8 = sys_mmap(MA_D001_BUF) 3838 let p: *u8 = sys_mmap(256) 3839 var o: i64 = sd_cat(p, 0, "buildroot/runtime/_hdl_build/" as *u8) 3840 o = sd_cat(p, o, nm) 3841 o = sd_cat(p, o, ".nx" as *u8) 3842 p[o] = 0 as u8 3843 let r1: i64 = ma_d001_scan(p, buf) 3844 if r1 >= 0 { return r1 } 3845 o = sd_cat(p, 0, "buildroot/runtime/" as *u8) 3846 o = sd_cat(p, o, nm) 3847 o = sd_cat(p, o, ".nx" as *u8) 3848 p[o] = 0 as u8 3849 let r2: i64 = ma_d001_scan(p, buf) 3850 if r2 >= 0 { return r2 } 3851 // BOTH ROOTS. The first version probed only buildroot/... because that is where the TOOLS daemon 3852 // sees the tree -- and mgmt does not necessarily share that cwd. The guard therefore found no source, 3853 // returned UNKNOWN, failed open, and a non-inheriting gate promoted cleanly while the guard was live. 3854 // THIS IS THE EXACT DEFECT THAT MADE nx_gate_migrate INERT -- cwd-relative paths with an assumed cwd -- 3855 // reproduced by me in the fix for it, hours later, in the same session. gm_resolve solved it by 3856 // probing every plausible root instead of asserting one; do the same rather than assume again. 3857 o = sd_cat(p, 0, "runtime/_hdl_build/" as *u8) 3858 o = sd_cat(p, o, nm) 3859 o = sd_cat(p, o, ".nx" as *u8) 3860 p[o] = 0 as u8 3861 let r3: i64 = ma_d001_scan(p, buf) 3862 if r3 >= 0 { return r3 } 3863 o = sd_cat(p, 0, "runtime/" as *u8) 3864 o = sd_cat(p, o, nm) 3865 o = sd_cat(p, o, ".nx" as *u8) 3866 p[o] = 0 as u8 3867 return ma_d001_scan(p, buf) 3868} 3869 3870 3871// RENDER A LEASE TTL AS THE TEXT nx_lease expects. ONE renderer for every lane, so a lane cannot 3872// acquire for one duration while advertising another -- which is exactly how the pair drifted. 3873func ma_lease_ttl_txt(secs: i64) -> *u8 { 3874 let b: *u8 = sys_mmap(32) 3875 let o: i64 = sd_catn(b, 0, secs) 3876 b[o] = 0 as u8 3877 return b 3878} 3879 3880// TS9: render the wait-advice TAIL of a lease-busy refusal (closes the holder string and the JSON). 3881// ONE renderer for all five lease lanes -- a fix that lives in one lane and not its siblings is the 3882// exact recorded history of this file's retry story, so the siblings share the body by construction. 3883// See the TS_NONRETRY_TTL_S block up top for the derivation. 3884func ts_retry_after_derived(b: *u8, o: i64, ttl_s: i64) -> i64 { 3885 if ttl_s >= TS_NONRETRY_TTL_S { 3886 return sd_cat(b, o, "\",\"advice\":\"LEASE-HELD-DO-NOT-RETRY\",\"why\":\"an exclusive lease this long is not a retry situation -- polling it in step is the measured herd defect. Queue the work instead: a deployq row (status=queued, with your planid) fires via nx_orchestrate on the first pass with headroom.\"}" as *u8) 3887 } 3888 var jit: i64 = 0 3889 let span_s: i64 = ttl_s / TS_JITTER_DIV 3890 if span_s > 0 { jit = (sys_now_us() / 1000) % (span_s + 1) } 3891 var o2: i64 = sd_cat(b, o, "\",\"retry_after_s\":" as *u8) 3892 o2 = sd_catn(b, o2, ttl_s + jit) 3893 return sd_cat(b, o2, "}" as *u8) 3894} 3895 3896// RELEASE THE PROMOTE LEASE. Extracted (2026-08-20) so the release has ONE callable home. The leak this 3897// closes existed precisely because the release was WRITTEN ONCE, at the bottom of the success path, and 3898// the three later returns above it simply did not repeat it -- a lease with a 300s TTL then sat held 3899// until it expired, and every promote of that organ in the window was refused lease-busy. A correction 3900// with no callable home fixes exactly one site; this one is called from all four exits. 3901func ma_promote_lease_release(please: *u8) -> i64 { 3902 return md_lease_run("release" as *u8, please, "mgmt-api-promote" as *u8, "0" as *u8, 3, "/tmp/nx_ma_lease.out" as *u8) 3903} 3904 3905// ---- /api/promote REFUSALS, ONE PER CONJUNCT (lane J, 2026-08-23) --------------------------------- 3906// THE DEFECT: one 400 text served FOUR different refusals (declared daemon / declared lib / credential- 3907// class name / undeclared kind) AND, for an undeclared gate/test/kat name, "nothing staged" too -- 3908// measured 2026-08-23 by lane F: a 503'd promote had already consumed the stage, and the retry read as an 3909// undeclared-kind refusal. A refusal that will not name which conjunct fired sends every reader at the 3910// wrong fix. Each branch names ITS conjunct, the value it resolved, and the ONE action that clears it. 3911// The stage check no longer lives in the kind decision at all: it is the NOTHING-STAGED answer further 3912// down ma_do_promote, which also reports the live sha so a lost response can be reconciled. 3913func ma_promote_refuse(out: *u8, nm: *u8, kind: i64, sfx_kind: i64) -> i64 { 3914 let rb: *u8 = sys_mmap(MA_MAGIC_2048) 3915 var b: i64 = sd_cat(rb, 0, "{\"refusal\":\"" as *u8) 3916 if kind == OK_DAEMON { 3917 b = sd_cat(rb, b, "DECLARED-DAEMON\",\"kind\":\"daemon\",\"kind_src\":\"knowledge/status/organ_kind.conf\",\"error\":\"target refused: this name is DECLARED a daemon. /api/promote swaps a binary under nothing and probes nothing; a daemon ships through the health-checked /api/deploy (validate -> promote -> http-health -> auto-rollback). That is the correct path, not a workaround.\",\"fix\":\"POST /api/deploy target=" as *u8) 3918 b = sd_cat(rb, b, nm) 3919 b = sd_cat(rb, b, "&confirm=yes\"}" as *u8) 3920 } else { if kind == OK_LIB { 3921 b = sd_cat(rb, b, "DECLARED-LIB\",\"kind\":\"lib\",\"kind_src\":\"knowledge/status/organ_kind.conf\",\"error\":\"target refused: this name is DECLARED a lib. A lib is compiled INTO its consumers, so there is no binary of its own to promote; shipping it means rebuilding and promoting each consumer.\",\"fix\":\"/api/build + /api/promote each consumer of " as *u8) 3922 b = sd_cat(rb, b, nm) 3923 b = sd_cat(rb, b, "\"}" as *u8) 3924 } else { if md_promote_deny_hard(nm) == 1 { 3925 b = sd_cat(rb, b, "CREDENTIAL-CLASS\",\"kind\":\"undeclared\",\"error\":\"target refused NON-OVERRIDABLY: the name carries a credential-class word (mint/vault/secret/keygen/login/router/hostctl/signaling/gateway/torrent/mgmt/_gw/sites) and such organs never ship through /api/promote, declared or not.\",\"fix\":\"a credential organ ships only through its own reviewed lane; there is no promote override by design\"}" as *u8) 3926 } else { 3927 b = sd_cat(rb, b, "UNDECLARED-KIND\",\"kind\":\"undeclared\",\"kind_src\":\"knowledge/status/organ_kind.conf\",\"error\":\"target refused: no organ_kind.conf row names this organ, the name carries no gate/test/kat suffix, and it is not in the legacy allow -- so nothing says whether promoting it would swap a binary under a live process (rule 26). Nothing was inspected on disk; the stage was NOT the reason.\",\"fix\":\"add one row to knowledge/status/organ_kind.conf (values unhyphenated): `" as *u8) 3928 b = sd_cat(rb, b, nm) 3929 b = sd_cat(rb, b, " oneshot` (or oracle), then retry; the older plural knowledge/organ_kinds.conf is RETIRED and is NOT read\"}" as *u8) 3930 } } } 3931 rb[b] = 0 as u8 3932 return ma_emit_400(out, rb) 3933} 3934 3935func ma_do_promote(req: *u8, req_n: i64, out: *u8) -> i64 { 3936 let body_off: i64 = sd_body_off(req, req_n) 3937 let body: *u8 = ((req as i64) + body_off) as *u8 3938 let body_n: i64 = req_n - body_off 3939 let toff: *i64 = sys_mmap(8) as *i64 3940 let tn: *i64 = sys_mmap(8) as *i64 3941 if sd_form_field(body, body_n, "target" as *u8, 6, toff, tn) != 1 { 3942 return ma_emit_400(out, "{\"error\":\"missing target\"}" as *u8) 3943 } 3944 let nm: *u8 = sys_mmap(128) 3945 if ma_sanitize_name(body, toff[0], tn[0], nm, 120) != 1 { 3946 return ma_emit_400(out, "{\"error\":\"invalid target name (only [a-zA-Z0-9_])\"}" as *u8) 3947 } 3948 // seq1492: ROLE BEATS NAME. Both ship verbs used to guess from the NAME and DISAGREED -- promote 3949 // called nx_torrent_get a daemon while deploy had never heard of it, so a gate-proven binary was 3950 // unshippable by any sanctioned route. A DECLARED kind now decides: one-shot/oracle promote by right, 3951 // a declared daemon is refused here (it needs the health-probed /api/deploy), and an UNDECLARED name 3952 // falls through to the legacy allowlist -- so this is ADDITIVE and inert for every organ not yet in 3953 // organ_kind.conf. Asymmetry is deliberate: misfiling a daemon as a one-shot would let promote swap a 3954 // binary under a live process with no probe and no rollback (rule 26); the reverse merely blocks it. 3955 let ma_kind: i64 = ok_kind_of_path("knowledge/status/organ_kind.conf" as *u8, nm) 3956 var ma_shipok: i64 = 0 3957 if ma_kind == OK_UNKNOWN { if md_promote_organ_ok(nm) == 1 { ma_shipok = 1 } } 3958 if ma_kind != OK_UNKNOWN { if ok_may_promote(ma_kind) == 1 { ma_shipok = 1 } } 3959 // seq1789: THE SUFFIX IS A DECLARATION; THE SUBSTRING WAS A GUESS. The legacy fall-through 3960 // md_promote_organ_ok -> md_promote_deny asks `does the name CONTAIN "serve"`, so 3961 // nx_survey_serve_gate -- an oracle that runs to completion -- was refused as a daemon and could not 3962 // ship by any sanctioned route. Its gate read exit=127 and was the ONLY red holding the surveys 3963 // domain (35/35 grounded, 3/4 gates green) off MEASURED-HONEST. 3964 // SAFE BY CONSTRUCTION, not by promise: ok_kind_or_suffix can only ever yield OK_ORACLE for an 3965 // UNDECLARED name, which is the safe side of the asymmetry this policy protects -- a DECLARED daemon 3966 // still loses here because ok_may_promote(OK_DAEMON) is 0 and the declared kind takes precedence. 3967 // The two existing guards still bind: md_promote_deny_hard (credential oracles -- mint/vault/secret/ 3968 // keygen/login) refuses NON-OVERRIDABLY, and a staged ELF built HERE is still required, so this can 3969 // never promote a binary that did not come from /api/build on this host. 3970 var ma_sfx_kind: i64 = ma_kind 3971 if ma_shipok != 1 { 3972 ma_sfx_kind = ok_kind_or_suffix(ma_kind, nm) 3973 if ok_may_promote(ma_sfx_kind) == 1 { 3974 // The staged ELF is STILL required -- but it is checked BELOW, where an absent stage answers 3975 // NOTHING-STAGED by name (and reports the live sha for the lost-response case) instead of 3976 // being folded into the kind refusal. Lane J 2026-08-23: a 503'd promote had consumed the 3977 // stage and the retry of an oracle-suffixed name read as "undeclared kind" -- the wrong fix. 3978 if md_promote_deny_hard(nm) == 0 { ma_shipok = 1 } 3979 } 3980 } 3981 if ma_shipok != 1 { 3982 return ma_promote_refuse(out, nm, ma_kind, ma_sfx_kind) 3983 } 3984 if ma_confirmed(req, req_n) == 0 { 3985 return ma_emit_400(out, "{\"error\":\"promote requires confirm=yes\"}" as *u8) 3986 } 3987 let nmlen: i64 = sd_len(nm) 3988 // D001 STRUCTURAL GUARD. The helpers above were shipped without this call site once, so the guard 3989 // existed and nothing invoked it -- built-but-not-wired, the exact class this guard exists to end. 3990 if ma_name_is_oracle(nm, nmlen) == 1 { 3991 if ma_inherits_verdict(nm, nmlen) == 0 { 3992 let d1off: *i64 = sys_mmap(8) as *i64 3993 let d1n: *i64 = sys_mmap(8) as *i64 3994 if sd_form_field(body, body_n, "allow_own_verdict" as *u8, 17, d1off, d1n) != 1 { 3995 return ma_emit_400(out, "{\"error\":\"D001: this gate rolls its own verdict instead of inheriting nx_gate_verdict, so nothing can read its outcome -- nx_gate_green cannot judge it and it records no harness.jrnl frame, so flake and erosion stay invisible for it. Migrate it (nx_gate_dry_apply <gate> <out>, then nx_gate_migrate verify <gate> <out>) and promote again. Deliberate exception: resend with allow_own_verdict=yes.\"}" as *u8) 3996 } 3997 } 3998 } 3999 let stagedp: *u8 = sys_mmap(160) 4000 mau_build_path(nm, 0, nmlen, ".sov.elf.new" as *u8, stagedp) 4001 if mau_is_elf(stagedp) != 1 { 4002 // u2605RECOVERABLE AFTER A LOST RESPONSE (seq1780, the other half of the 4003 // self-verifying receipt). Transport loses RESPONSES, not requests 4004 // (seq290), so a caller who saw nothing must be able to ASK rather than 4005 // guess -- and "nothing staged" is EXACTLY what a promote that already 4006 // succeeded looks like on a retry. Answer with the LIVE bytes + sha256: 4007 // equal to the artefact you built means it landed, different means it 4008 // did not. A bare error here forced every caller to hash out-of-band, 4009 // which is the workaround this whole arc exists to delete. 4010 let livechk: *u8 = sys_mmap(160) 4011 mau_build_path(nm, 0, nmlen, ".elf" as *u8, livechk) 4012 let rszp: *i64 = sys_mmap(16) as *i64 4013 let rbytes: *u8 = md_read_file(livechk, rszp) 4014 if (rbytes as i64) != 0 { 4015 let rdig2: *u8 = sys_mmap(32) 4016 sha256_digest(rbytes, rszp[0], rdig2) 4017 let rhex2: *u8 = sys_mmap(72) 4018 mau_hex32(rdig2, rhex2) 4019 let rrb: *u8 = sys_mmap(640) 4020 var ro: i64 = sd_cat(rrb, 0, "{\"action\":\"NOTHING-STAGED\",\"target\":\"" as *u8) 4021 ro = sd_cat(rrb, ro, nm) 4022 ro = sd_cat(rrb, ro, "\",\"live_bytes\":" as *u8) 4023 ro = sd_catn(rrb, ro, rszp[0]) 4024 ro = sd_cat(rrb, ro, ",\"live_sha256\":\"" as *u8) 4025 ro = sd_cat(rrb, ro, rhex2) 4026 ro = sd_cat(rrb, ro, "\",\"note\":\"nothing staged. If you just promoted and lost the response, compare live_sha256 with the artefact you built: equal means it IS live. Otherwise run /api/build first.\"}" as *u8) 4027 rrb[ro] = 0 as u8 4028 return ma_emit_200(out, rrb) 4029 } 4030 let nsb: *u8 = sys_mmap(MA_MAGIC_1024) 4031 var nso: i64 = sd_cat(nsb, 0, "{\"refusal\":\"NOTHING-STAGED\",\"staged_path\":\"" as *u8) 4032 nso = sd_cat(nsb, nso, stagedp) 4033 nso = sd_cat(nsb, nso, "\",\"live_path\":\"" as *u8) 4034 nso = sd_cat(nsb, nso, livechk) 4035 nso = sd_cat(nsb, nso, "\",\"error\":\"nothing staged: no valid ELF at the staged path and no live artefact to report. The kind was accepted; the STAGE is the only missing conjunct.\",\"fix\":\"POST /api/build target=" as *u8) 4036 nso = sd_cat(nsb, nso, nm) 4037 nso = sd_cat(nsb, nso, " first (the stage must be an ELF built on this host), then promote with expect_sha256\"}" as *u8) 4038 nsb[nso] = 0 as u8 4039 return ma_emit_400(out, nsb) 4040 } 4041 // ---- EXPECTED-DIGEST GATE (2026-07-30): DEPLOY A DIGEST, NOT A TAG -------------------------------- 4042 // THE RACE THIS CLOSES, MEASURED: /api/build writes _build/<t>.sov.elf and a LATER promote copies that 4043 // PATH. Any sibling rebuilding the same target in between OVERWRITES it. I built nx_mgmt_api at 578865, 4044 // verified it, and a SIBLING'S 579263 WENT LIVE -- I verified one artifact and shipped another, and 4045 // nothing anywhere detected it. mgmt then walked 578789 -> 578865 -> 579263 -> 580657 inside ONE HOUR, 4046 // so this is the NORMAL condition on a shared tree, not a freak event. 4047 // A PATH IS