code wiki / _hdl_build / nx_publisher.nx

nx_publisher.nx source

↩ module page · 1404 lines · 79632 B

1// nx_publisher.nx -- THE NISHI PUBLISHER, R1: the single INTAKE. pub_submit() enqueues a publish REQUEST to a 2// durable, concurrency-safe queue so every workstream DECOUPLES from the live site (workstreams REQUEST; the 3// publisher SHIPS). The queue append reuses nx_framed_append's fa_appendz = O_APPEND + flock(LOCK_EX) + 4// write-until-complete, so N concurrent submitters can NEVER tear or lose a record -- the exact collision class 5// that caused the sites.elf outage. Each request carries a sha256 of the SOURCE CONTENT (honest identity -> 6// later enables idempotent dedup + post-deploy verification). One framed TSV line per request: 7// PENDING<TAB>site<TAB>requester<TAB>sha256<TAB>src<TAB>dest<TAB>policy 8// This is R1 of [[project-nishi-publisher-role-2026-06-20]] (R0 census GREEN). license_tier: ORIGINAL 9import "nx_syscalls.nx" 10import "nx_connect.nx" // bounded connect: a raw sys_connect hangs ~127s on a black-holed host 11import "nx_framed_append.nx" 12import "nx_sha256.nx" 13import "nx_arbiter.nx" 14const PUB_MAGIC_50000: i64 = 50000 15const PUB_MAGIC_4294967296: i64 = 4294967296 16const PUB_MAGIC_100000: i64 = 100000 17const PUB_MAGIC_1000000: i64 = 1000000 18const PUB_MAGIC_262144: i64 = 262144 19const PUB_MAGIC_4096: i64 = 4096 20 21const PUB_REC_CAP: i64 = 4096 22 23func pub_queue_default() -> *u8 { return "knowledge/publish/queue.tsv" as *u8 } 24 25// idempotent mkdir of the canonical queue dir (ignore EEXIST). raw x86_64 mkdir = 83 (mirrors nx_arbiter fl_mkdir). 26func pub_init() -> i64 { let d: *u8 = "knowledge/publish" as *u8; __syscall(83, d as i64, 493, 0, 0, 0, 0); return 0 } 27 28func pub_hexd(v: i64) -> i64 { if v < 10 { return 48 + v } return 87 + v } // 0-9 then a-f 29 30// write nul-terminated `s` to fd (no framing) -- used ONLY by the unlocked negative control below. 31func pub_uw(fd: i64, s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } sys_write(fd, s, n); return 0 } 32func pub_unap() -> i64 { let ts: *i64 = sys_mmap(16) as *i64; ts[0] = 0; ts[1] = PUB_MAGIC_50000; __syscall(35, ts as i64, 0, 0, 0, 0, 0); return 0 } 33 34// sha256 of the file at `path` -> 64 lowercase hex chars into outhex (NUL-terminated). 1 if read+hashed, 0 if missing. 35func pub_sha_file(path: *u8, outhex: *u8) -> i64 { 36 let lenp: *i64 = sys_mmap(8) as *i64 37 let data: *u8 = sys_read_file(path, lenp) 38 if (data as i64) == 0 { return 0 } 39 let dig: *u8 = sys_mmap(32) 40 sha256_digest(data, lenp[0], dig) 41 sys_munmap(data, PUB_MAGIC_4294967296 + 16) 42 var i: i64 = 0 43 while i < 32 { 44 let b: i64 = dig[i] & 0xff 45 outhex[i*2] = pub_hexd((b >> 4) & 0xf) as u8 46 outhex[i*2 + 1] = pub_hexd(b & 0xf) as u8 47 i = i + 1 48 } 49 outhex[64] = 0 as u8 50 return 1 51} 52 53// assemble the request record into `rec` (NUL-terminated); returns its byte length. shared by both write paths. 54func pub_build_rec(rec: *u8, site: *u8, requester: *u8, hex: *u8, src: *u8, dest: *u8, policy: *u8) -> i64 { 55 var o: i64 = 0 56 o = fa_cat(rec, o, "PENDING" as *u8); rec[o] = 9 as u8; o = o + 1 57 o = fa_cat(rec, o, site); rec[o] = 9 as u8; o = o + 1 58 o = fa_cat(rec, o, requester); rec[o] = 9 as u8; o = o + 1 59 o = fa_cat(rec, o, hex); rec[o] = 9 as u8; o = o + 1 60 o = fa_cat(rec, o, src); rec[o] = 9 as u8; o = o + 1 61 o = fa_cat(rec, o, dest); rec[o] = 9 as u8; o = o + 1 62 o = fa_cat(rec, o, policy) 63 rec[o] = 0 as u8 64 return o 65} 66 67// THE INTAKE. Enqueue a request to `qpath` as ONE atomic framed line. Returns 1 on durable append, else <=0 68// (src missing = -9; fa_appendz error otherwise). Concurrency-safe by construction (fa_appendz holds LOCK_EX). 69func pub_submit_to(qpath: *u8, src: *u8, dest: *u8, site: *u8, requester: *u8, policy: *u8) -> i64 { 70 let hex: *u8 = sys_mmap(72) 71 if pub_sha_file(src, hex) == 0 { return 0 - 9 } 72 let rec: *u8 = sys_mmap(PUB_REC_CAP) 73 pub_build_rec(rec, site, requester, hex, src, dest, policy) 74 let wr: i64 = fa_appendz(qpath, rec, PUB_REC_CAP) 75 if wr > 0 { return 1 } 76 return wr 77} 78 79// convenience: enqueue to the canonical shared queue (ensures the dir exists first). 80func pub_submit(src: *u8, dest: *u8, site: *u8, requester: *u8, policy: *u8) -> i64 { 81 pub_init() 82 return pub_submit_to(pub_queue_default(), src, dest, site, requester, policy) 83} 84 85// NEGATIVE CONTROL ONLY (the gate uses this to PROVE the framed path is load-bearing): assemble the SAME record 86// but emit it as SEVERAL separate writes with NO flock -> concurrent callers interleave -> TORN lines. This is 87// exactly the pre-fix outage bug; the real publisher NEVER calls it. Returns 0. 88func pub_append_unlocked(qpath: *u8, src: *u8, dest: *u8, site: *u8, requester: *u8, policy: *u8) -> i64 { 89 let hex: *u8 = sys_mmap(72) 90 pub_sha_file(src, hex) 91 let fd: i64 = sys_openat_append(qpath, 0x1a4) 92 if fd < 0 { return 0 - 1 } 93 pub_uw(fd, "PENDING\t" as *u8); pub_uw(fd, site); pub_uw(fd, "\t" as *u8) 94 pub_unap(); pub_uw(fd, requester); pub_uw(fd, "\t" as *u8); pub_uw(fd, hex); pub_uw(fd, "\t" as *u8) 95 pub_unap(); pub_uw(fd, src); pub_uw(fd, "\t" as *u8); pub_uw(fd, dest); pub_uw(fd, "\t" as *u8); pub_uw(fd, policy) 96 pub_uw(fd, "\n" as *u8) 97 sys_close(fd) 98 return 0 99} 100 101// ============================================================================================================ 102// R2 -- THE PUBLISHER CORE LOOP: dequeue PENDING -> serialize (fl_acquire per critical section) -> idempotent 103// sha-skip (already-in-ledger -> no-op, rule #10) -> record to the append-only ledger. The fl_acquire makes the 104// check-then-record ATOMIC across concurrent publisher instances, so the same request is NEVER double-published. 105// ============================================================================================================ 106func pub_ledger_default() -> *u8 { return "knowledge/publish/ledger.tsv" as *u8 } 107func pub_nap_us(us: i64) -> i64 { let ts: *i64 = sys_mmap(16) as *i64; ts[0]=0; ts[1]=us*1000; __syscall(35, ts as i64, 0, 0, 0, 0, 0); return 0 } 108 109// 1 iff NUL-terminated a == b. 110func pub_streq(a: *u8, b: *u8) -> i64 { 111 var i: i64 = 0 112 while a[i] != (0 as u8) { if a[i] != b[i] { return 0 } i = i + 1 } 113 if b[i] != (0 as u8) { return 0 } 114 return 1 115} 116// copy the idx-th TAB-delimited field of line[0..linelen) into out (NUL-terminated). returns 1. 117func pub_field(line: *u8, linelen: i64, idx: i64, out: *u8) -> i64 { 118 var f: i64 = 0 119 var i: i64 = 0 120 while f < idx { if i < linelen { if line[i] == (9 as u8) { f = f + 1 } i = i + 1 } else { f = idx; i = linelen } } 121 var o: i64 = 0 122 var stop: i64 = 0 123 while i < linelen { 124 if stop == 0 { if line[i] == (9 as u8) { stop = 1 } } 125 if stop == 0 { out[o] = line[i]; o = o + 1 } 126 i = i + 1 127 } 128 out[o] = 0 as u8 129 return 1 130} 131// 1 iff the ledger already has a line whose field0==sha AND field1==dest (the idempotency key). 132func pub_led_has(ledpath: *u8, sha: *u8, dest: *u8) -> i64 { 133 let lenp: *i64 = sys_mmap(8) as *i64 134 let data: *u8 = sys_read_file(ledpath, lenp) 135 if (data as i64) == 0 { return 0 } 136 let n: i64 = lenp[0] 137 let f0: *u8 = sys_mmap(256) 138 let f1: *u8 = sys_mmap(256) 139 var i: i64 = 0 140 var ls: i64 = 0 141 var found: i64 = 0 142 while i < n { 143 if data[i] == (10 as u8) { 144 let line: *u8 = ((data as i64) + ls) as *u8 145 pub_field(line, i - ls, 0, f0) 146 pub_field(line, i - ls, 1, f1) 147 if pub_streq(f0, sha) == 1 { if pub_streq(f1, dest) == 1 { found = 1 } } 148 ls = i + 1 149 } 150 i = i + 1 151 } 152 sys_munmap(data, PUB_MAGIC_4294967296 + 16) 153 return found 154} 155// append a PUBLISHED ledger record (idempotency key first): sha<TAB>dest<TAB>site<TAB>PUBLISHED. 156func pub_record_ledger(ledpath: *u8, sha: *u8, dest: *u8, site: *u8) -> i64 { 157 let rec: *u8 = sys_mmap(PUB_REC_CAP) 158 var o: i64 = 0 159 o = fa_cat(rec, o, sha); rec[o]=9 as u8; o=o+1 160 o = fa_cat(rec, o, dest); rec[o]=9 as u8; o=o+1 161 o = fa_cat(rec, o, site); rec[o]=9 as u8; o=o+1 162 o = fa_cat(rec, o, "PUBLISHED" as *u8); rec[o]=9 as u8; o=o+1 // outcome (field3) 163 o = fa_catn(rec, o, sys_now_realtime_sec()); rec[o]=9 as u8; o=o+1 // pub_ts (field4) -- enables DORA 164 o = fa_catn(rec, o, 0) // lead_sec (field5); live submit-ts plumb = v2 165 rec[o] = 0 as u8 166 return fa_appendz(ledpath, rec, PUB_REC_CAP) 167} 168// Process the queue ONCE. For each PENDING request: (under lockres if locked==1) skip if already in the ledger, 169// else record it. racewin_us = a deliberate window between check and record so a gate can force the race; the 170// REAL publisher passes 0. Returns the number newly published this pass. lockres = the serialize resource 171// (real publisher: keyed by site; gate: per-wsid). Idempotent: re-running over the same queue publishes 0. 172func pub_run(qpath: *u8, ledpath: *u8, lockres: *u8, locked: i64, racewin_us: i64) -> i64 { 173 let lenp: *i64 = sys_mmap(8) as *i64 174 let data: *u8 = sys_read_file(qpath, lenp) 175 if (data as i64) == 0 { return 0 } 176 let n: i64 = lenp[0] 177 let st: *u8 = sys_mmap(64) 178 let sha: *u8 = sys_mmap(256) 179 let dest: *u8 = sys_mmap(256) 180 let site: *u8 = sys_mmap(256) 181 var i: i64 = 0 182 var ls: i64 = 0 183 var published: i64 = 0 184 while i < n { 185 if data[i] == (10 as u8) { 186 let line: *u8 = ((data as i64) + ls) as *u8 187 let ll: i64 = i - ls 188 pub_field(line, ll, 0, st) 189 if pub_streq(st, "PENDING" as *u8) == 1 { 190 pub_field(line, ll, 1, site) 191 pub_field(line, ll, 3, sha) 192 pub_field(line, ll, 5, dest) 193 var lfd: i64 = 0 - 1 194 if locked == 1 { lfd = fl_acquire(lockres, PUB_MAGIC_100000, 1) } 195 if pub_led_has(ledpath, sha, dest) == 0 { 196 if racewin_us > 0 { pub_nap_us(racewin_us) } 197 pub_record_ledger(ledpath, sha, dest, site) 198 published = published + 1 199 } 200 if locked == 1 { fl_release(lfd) } 201 } 202 ls = i + 1 203 } 204 i = i + 1 205 } 206 return published 207} 208 209// ============================================================================================================ 210// R3 -- STAGE + VERIFY-BEFORE-PROMOTE (fail-closed). The publisher NEVER copies an artifact straight to live: it 211// stages it, RE-HASHES the staged bytes, and promotes ONLY if the hash still equals the approved sha. If the 212// artifact was corrupted/swapped between submit and publish (TOCTOU), the hashes differ -> REJECT, live untouched. 213// (The HTTP-level "does it actually serve" check = nx_url_truth_gate, wired at R8 against the real site.) 214// ============================================================================================================ 215func pub_exists(path: *u8) -> i64 { let fd: i64 = sys_openat_rd(path); if fd < 0 { return 0 } sys_close(fd); return 1 } 216 217// copy whole file src -> dst (O_TRUNC). returns bytes copied, or <0 (-1 read fail, -2 open-dst fail). 218func pub_copy(src: *u8, dst: *u8) -> i64 { 219 let lenp: *i64 = sys_mmap(8) as *i64 220 let data: *u8 = sys_read_file(src, lenp) 221 if (data as i64) == 0 { return 0 - 1 } 222 let fd: i64 = sys_openat_wr(dst, 0x1a4) 223 if fd < 0 { return 0 - 2 } 224 sys_write(fd, data, lenp[0]) 225 sys_close(fd) 226 return lenp[0] 227} 228// 1 iff sha256(file at path) equals expect_hex. 229func pub_sha_match(path: *u8, expect_hex: *u8) -> i64 { 230 let h: *u8 = sys_mmap(72) 231 if pub_sha_file(path, h) == 0 { return 0 } 232 return pub_streq(h, expect_hex) 233} 234// ============================================================================================================ 235// R4 -- ATOMIC promote (never half-published) + ROLLBACK (keep the previous live version, restore on demand). 236// ============================================================================================================ 237func pub_pcat(base: *u8, suffix: *u8, out: *u8) -> i64 { 238 var o: i64 = 0; var i: i64 = 0 239 while base[i] != (0 as u8) { out[o]=base[i]; o=o+1; i=i+1 } 240 i = 0; while suffix[i] != (0 as u8) { out[o]=suffix[i]; o=o+1; i=i+1 } 241 out[o] = 0 as u8; return o 242} 243func pub_rename(old: *u8, neu: *u8) -> i64 { return __syscall(82, old as i64, neu as i64, 0, 0, 0, 0) } // x86_64 rename 244 245// ATOMIC promote: copy stage -> live.tmp, then rename(live.tmp, live). rename is atomic on one filesystem, so a 246// concurrent reader sees the OLD or the NEW live -- never a half-written file. returns 1, or <0 on error. 247func pub_promote_atomic(stage: *u8, live: *u8) -> i64 { 248 let tmp: *u8 = sys_mmap(640); pub_pcat(live, ".tmp" as *u8, tmp) 249 if pub_copy(stage, tmp) < 0 { return 0 - 1 } 250 if pub_rename(tmp, live) != 0 { return 0 - 2 } 251 return 1 252} 253// keep the current live as live.prev BEFORE overwriting it (the rollback target). no-op if live absent. 254func pub_backup_prev(live: *u8) -> i64 { 255 if pub_exists(live) == 0 { return 0 } 256 let prev: *u8 = sys_mmap(640); pub_pcat(live, ".prev" as *u8, prev) 257 pub_copy(live, prev) 258 return 1 259} 260// restore live from live.prev (atomically, via a temp + rename). returns 1 if rolled back, 0 if no prev exists. 261func pub_rollback(live: *u8) -> i64 { 262 let prev: *u8 = sys_mmap(640); pub_pcat(live, ".prev" as *u8, prev) 263 if pub_exists(prev) == 0 { return 0 } 264 let tmp: *u8 = sys_mmap(640); pub_pcat(live, ".rbk" as *u8, tmp) 265 if pub_copy(prev, tmp) < 0 { return 0 - 1 } 266 if pub_rename(tmp, live) != 0 { return 0 - 2 } 267 return 1 268} 269 270// STAGE -> VERIFY -> (keep prev) -> ATOMIC PROMOTE. Returns 1 if PROMOTED, 0 if REJECTED (fail-closed, live NOT 271// written), <0 on a copy error. live is updated ONLY after the staged bytes verify against expect_sha, and only 272// via an atomic rename; the prior live is preserved as live.prev so pub_rollback can restore it. 273// R8-asset rung (operator 2026-06-21 "if it cant then build hardware rung up each rung"): create dest PARENT 274// subdirs so the publisher can ship NESTED artifacts (e.g. reader/<slug>/cover.png), not just flat files. 275// mkdirat each path prefix in place (NUL-terminate at each '/', mkdir, restore); EEXIST is harmless. Additive: 276// flat dests have no '/' after the root so this is a no-op for them. 277func pub_mkdirp(path: *u8) -> i64 { 278 var i: i64 = 1 279 while path[i] != (0 as u8) { 280 if path[i] == (0x2f as u8) { path[i] = 0 as u8; __syscall(258, 0-100, path, 0x1ed, 0, 0, 0); path[i] = 0x2f as u8 } 281 i = i + 1 282 } 283 return 0 284} 285func pub_deploy(expect_sha: *u8, src: *u8, stagepath: *u8, livepath: *u8) -> i64 { 286 pub_mkdirp(stagepath) // ensure dest subdirs exist (nested artifacts) 287 pub_mkdirp(livepath) 288 if pub_copy(src, stagepath) < 0 { return 0 - 1 } // STAGE 289 if pub_sha_match(stagepath, expect_sha) == 0 { return 0 } // VERIFY -> FAIL-CLOSED: do not promote 290 pub_backup_prev(livepath) // KEEP-PREVIOUS (rollback target) 291 if pub_promote_atomic(stagepath, livepath) < 0 { return 0 - 2 } // ATOMIC PROMOTE 292 return 1 293} 294 295// ============================================================================================================ 296// R7 -- THE NO-BYPASS LAW (SEAM audit). Workstreams must publish via pub_submit ONLY; the raw transport organs 297// (nx_aw_send / nx_aw_push) are publisher-INTERNAL. This audit flags any source that references the raw transport 298// and is NOT allowlisted (the publisher itself) -> "no more direct publishing from workstreams" is made true by 299// a MECHANICAL gate, not a promise (mirrors the writer's mode-SEAM audit). 300// ============================================================================================================ 301// substring search ('match' is a NishiLang reserved word -> use 'hit'). 302func pub_substr(hay: *u8, haylen: i64, needle: *u8) -> i64 { 303 var nl: i64 = 0; while needle[nl] != (0 as u8) { nl = nl + 1 } 304 if nl == 0 { return 0 } 305 var i: i64 = 0 306 while i + nl <= haylen { 307 var hit: i64 = 1; var j: i64 = 0 308 while j < nl { if hay[i+j] != needle[j] { hit = 0; j = nl } else { j = j + 1 } } 309 if hit == 1 { return 1 } 310 i = i + 1 311 } 312 return 0 313} 314func pub_file_has(path: *u8, needle: *u8) -> i64 { 315 let lenp: *i64 = sys_mmap(8) as *i64 316 let data: *u8 = sys_read_file(path, lenp) 317 if (data as i64) == 0 { return 0 } 318 return pub_substr(data, lenp[0], needle) 319} 320// 1 iff the file is a direct-publish BYPASS: references a raw-transport organ AND is not allowlisted. 321func pub_audit_file(path: *u8, allowlisted: i64) -> i64 { 322 if allowlisted == 1 { return 0 } 323 if pub_file_has(path, "nx_aw_send" as *u8) == 1 { return 1 } 324 if pub_file_has(path, "nx_aw_push" as *u8) == 1 { return 1 } 325 return 0 326} 327// STRICT no-bypass audit: workstreams may touch publishing ONLY via pub_submit. This flags a non-allowlisted source 328// that references ANY live-touching primitive -- raw transport OR the publisher's own deploy/promote/rollback/ 329// progressive-delivery/ledger internals -- so the law covers the WHOLE dangerous surface, not just transport. 330// Reads the file ONCE, scans all forbidden symbols. (allowlisted = the sanctioned publisher family, set by caller.) 331func pub_audit_file_strict(path: *u8, allowlisted: i64) -> i64 { 332 if allowlisted == 1 { return 0 } 333 let lenp: *i64 = sys_mmap(8) as *i64 334 let data: *u8 = sys_read_file(path, lenp) 335 if (data as i64)==0 { return 0 } 336 let n: i64 = lenp[0] 337 if pub_substr(data, n, "nx_aw_send" as *u8)==1 { return 1 } // raw transport 338 if pub_substr(data, n, "nx_aw_push" as *u8)==1 { return 1 } 339 if pub_substr(data, n, "pub_deploy" as *u8)==1 { return 1 } // direct stage->promote 340 if pub_substr(data, n, "pub_promote_atomic" as *u8)==1 { return 1 } // direct atomic live-write 341 if pub_substr(data, n, "pub_rollback" as *u8)==1 { return 1 } // direct rollback 342 if pub_substr(data, n, "pub_blue_green_flip" as *u8)==1 { return 1 } // direct blue-green flip 343 if pub_substr(data, n, "pub_canary_rollout" as *u8)==1 { return 1 } // direct canary 344 if pub_substr(data, n, "pub_record_ledger" as *u8)==1 { return 1 } // direct ledger write 345 if pub_substr(data, n, "pub_record_outcome" as *u8)==1 { return 1 } 346 return 0 347} 348// scan a NUL-terminated forbidden symbol over a code buffer -> 1 if found. (the strict forbidden set, one place.) 349func pub_forbidden_in(code: *u8, n: i64) -> i64 { 350 if pub_substr(code, n, "nx_aw_send" as *u8)==1 { return 1 } 351 if pub_substr(code, n, "nx_aw_push" as *u8)==1 { return 1 } 352 if pub_substr(code, n, "pub_deploy" as *u8)==1 { return 1 } 353 if pub_substr(code, n, "pub_promote_atomic" as *u8)==1 { return 1 } 354 if pub_substr(code, n, "pub_rollback" as *u8)==1 { return 1 } 355 if pub_substr(code, n, "pub_blue_green_flip" as *u8)==1 { return 1 } 356 if pub_substr(code, n, "pub_canary_rollout" as *u8)==1 { return 1 } 357 if pub_substr(code, n, "pub_record_ledger" as *u8)==1 { return 1 } 358 if pub_substr(code, n, "pub_record_outcome" as *u8)==1 { return 1 } 359 return 0 360} 361// COMMENT-AWARE strict audit: strips // line-comments to end-of-line BEFORE matching, so a comment-only mention of a 362// primitive (e.g. nx_runpath's WIRING-PLAN comment) is NOT a false bypass. Reduces the coarse audit's false positives. 363// (Limitation: a "//" inside a same-line string literal would also be stripped -> rare false-negative; noted.) 364func pub_audit_src_strict(path: *u8, allowlisted: i64) -> i64 { 365 if allowlisted == 1 { return 0 } 366 let lenp: *i64 = sys_mmap(8) as *i64 367 let data: *u8 = sys_read_file(path, lenp) 368 if (data as i64)==0 { return 0 } 369 let n: i64 = lenp[0] 370 let code: *u8 = sys_mmap(n + 16) 371 var i: i64=0; var o: i64=0; var incomment: i64=0 372 while i < n { 373 let c: i64 = data[i] & 0xff 374 if c == 10 { incomment=0; code[o]=10 as u8; o=o+1 } 375 else { 376 if incomment == 0 { 377 if c == 47 { if i+1 < n { if (data[i+1] & 0xff) == 47 { incomment = 1 } } } 378 if incomment == 0 { code[o]=c as u8; o=o+1 } 379 } 380 } 381 i = i + 1 382 } 383 return pub_forbidden_in(code, o) 384} 385 386// ============================================================================================================ 387// R8 -- the PRODUCTION loop: compose the whole pipeline. dequeue PENDING → serialize → idempotent-skip → DEPLOY 388// (stage→verify→atomic-promote, R3/R4) → record ledger. This is what a workstream's pub_submit'd request flows 389// through; the only remaining step to go truly live is the sovereign transport push of liveroot → the host. 390// ============================================================================================================ 391func pub_join(root: *u8, name: *u8, out: *u8) -> i64 { 392 var o: i64 = pub_pcat(root, "/" as *u8, out) 393 var i: i64 = 0 394 while name[i] != (0 as u8) { out[o]=name[i]; o=o+1; i=i+1 } 395 out[o] = 0 as u8 396 return o 397} 398// publish ONE request end-to-end. returns 1 published, 0 idempotent-skip, <0 deploy reject/error. 399func pub_publish_one(sha: *u8, src: *u8, dest: *u8, site: *u8, stageroot: *u8, liveroot: *u8, ledpath: *u8) -> i64 { 400 if pub_led_has(ledpath, sha, dest) == 1 { return 0 } // idempotent (rule #10) 401 let stagepath: *u8 = sys_mmap(700); pub_join(stageroot, dest, stagepath) 402 let livepath: *u8 = sys_mmap(700); pub_join(liveroot, dest, livepath) 403 let r: i64 = pub_deploy(sha, src, stagepath, livepath) // STAGE→VERIFY→ATOMIC-PROMOTE 404 if r == 1 { pub_record_ledger(ledpath, sha, dest, site); return 1 } 405 return r 406} 407// process the queue, publishing each PENDING request under the serialize lock. returns #published this pass. 408func pub_run_full(qpath: *u8, ledpath: *u8, stageroot: *u8, liveroot: *u8, lockres: *u8) -> i64 { 409 let lenp: *i64 = sys_mmap(8) as *i64 410 let data: *u8 = sys_read_file(qpath, lenp) 411 if (data as i64) == 0 { return 0 } 412 let n: i64 = lenp[0] 413 let st: *u8 = sys_mmap(64) 414 let sha: *u8 = sys_mmap(256) 415 let src: *u8 = sys_mmap(512) 416 let dest: *u8 = sys_mmap(256) 417 let site: *u8 = sys_mmap(256) 418 var i: i64 = 0 419 var ls: i64 = 0 420 var published: i64 = 0 421 while i < n { 422 if data[i] == (10 as u8) { 423 let line: *u8 = ((data as i64) + ls) as *u8 424 let ll: i64 = i - ls 425 pub_field(line, ll, 0, st) 426 if pub_streq(st, "PENDING" as *u8) == 1 { 427 pub_field(line, ll, 1, site) 428 pub_field(line, ll, 3, sha) 429 pub_field(line, ll, 4, src) 430 pub_field(line, ll, 5, dest) 431 let lfd: i64 = fl_acquire(lockres, PUB_MAGIC_100000, 1) 432 let pr: i64 = pub_publish_one(sha, src, dest, site, stageroot, liveroot, ledpath) 433 fl_release(lfd) 434 if pr == 1 { published = published + 1 } 435 } 436 ls = i + 1 437 } 438 i = i + 1 439 } 440 return published 441} 442 443// ============================================================================================================ 444// R6 -- RELEASE POLICY / approval gate. Internal publishes proceed; OUTWARD-facing publishes require an explicit 445// operator approval of the EXACT artifact (an approval token keyed by sha, created out-of-band) -> the publisher 446// will not push outward, unapproved content BY CONSTRUCTION. This is the operator-gating made mechanical. 447// ============================================================================================================ 448func pub_policy_allows(policy: *u8, sha: *u8, approval_dir: *u8) -> i64 { 449 if pub_streq(policy, "internal" as *u8) == 1 { return 1 } // internal lane: no approval needed 450 let apath: *u8 = sys_mmap(700); pub_join(approval_dir, sha, apath) 451 if pub_exists(apath) == 1 { return 1 } // outward: approved iff the operator-ok token exists 452 return 0 // outward + unapproved -> HELD (fail-closed) 453} 454// the operator approves a specific artifact (by content sha) out-of-band: create approval_dir/<sha>. 455func pub_approve(sha: *u8, approval_dir: *u8) -> i64 { 456 let apath: *u8 = sys_mmap(700); pub_join(approval_dir, sha, apath) 457 let fd: i64 = sys_openat_wr(apath, 0x1a4); if fd < 0 { return 0 } 458 sys_close(fd); return 1 459} 460 461// GOVERNED production loop = pub_run_full + the R6 policy gate enforced IN the loop. An OUTWARD request is HELD 462// (left PENDING, not published) until the operator approves its exact artifact; internal requests proceed. This 463// is the full pipeline a real outward publish runs through -- operator-gating by construction, not by promise. 464func pub_run_governed(qpath: *u8, ledpath: *u8, stageroot: *u8, liveroot: *u8, lockres: *u8, approval_dir: *u8) -> i64 { 465 let lenp: *i64 = sys_mmap(8) as *i64 466 let data: *u8 = sys_read_file(qpath, lenp) 467 if (data as i64) == 0 { return 0 } 468 let n: i64 = lenp[0] 469 let st: *u8 = sys_mmap(64) 470 let sha: *u8 = sys_mmap(256) 471 let src: *u8 = sys_mmap(512) 472 let dest: *u8 = sys_mmap(256) 473 let site: *u8 = sys_mmap(256) 474 let policy: *u8 = sys_mmap(64) 475 var i: i64 = 0 476 var ls: i64 = 0 477 var published: i64 = 0 478 while i < n { 479 if data[i] == (10 as u8) { 480 let line: *u8 = ((data as i64) + ls) as *u8 481 let ll: i64 = i - ls 482 pub_field(line, ll, 0, st) 483 if pub_streq(st, "PENDING" as *u8) == 1 { 484 pub_field(line, ll, 1, site) 485 pub_field(line, ll, 3, sha) 486 pub_field(line, ll, 4, src) 487 pub_field(line, ll, 5, dest) 488 pub_field(line, ll, 6, policy) 489 if pub_policy_allows(policy, sha, approval_dir) == 1 { // R6: outward needs operator-ok 490 let lfd: i64 = fl_acquire(lockres, PUB_MAGIC_100000, 1) 491 let pr: i64 = pub_publish_one(sha, src, dest, site, stageroot, liveroot, ledpath) 492 fl_release(lfd) 493 if pr == 1 { published = published + 1 } 494 } 495 } 496 ls = i + 1 497 } 498 i = i + 1 499 } 500 return published 501} 502 503// ============================================================================================================ 504// R10 -- UN-STUCKABLE DRAIN (operator: "make sure the publisher cant get stuck again as a whole even if 505// somethings get stuck"). pub_run_governed publishes each item IN-PROCESS, so a single item that CRASHES 506// pub_publish_one -- a malformed queue field overflowing a fixed buffer, a pathological dest, a corrupt source -- 507// takes the WHOLE drain down, and every later item is stuck forever (head-of-line blocking = the stuck root cause). 508// pub_run_resilient FORKS a child per item: the child does ALL the risky work (extract the user-data fields, 509// policy-check, stage/verify/promote) and exits; the PARENT only reaps it and CONTINUES, no matter how the child 510// died. A crashed (signalled) or failed (exit 2) item is QUARANTINED to a dead-letter file -- with its RAW queue 511// line, so the parent never has to parse a hostile field -- for the autonomous Dr+Engineer self-heal 512// (nx_pub_selfheal) to root-cause. It can NEVER block the rest. pub_deploy's atomic promote already guarantees a 513// crashed child cannot leave a half-written live file. ADDITIVE: pub_run_governed is unchanged; callers opt in. 514// ============================================================================================================ 515func pub_dlcat(rec: *u8, o: i64, s: *u8) -> i64 { var w: i64=o; var i: i64=0; while s[i]!=(0 as u8){rec[w]=s[i];w=w+1;i=i+1} return w } 516func pub_dlnum(rec: *u8, o: i64, v: i64) -> i64 { var w: i64=o; var m: i64=v; if m==0{rec[w]=48 as u8;return w+1} let t:*u8=sys_mmap(24); var k:i64=0; while m>0{t[k]=(48+(m%10)) as u8;m=m/10;k=k+1} var j:i64=0; while j<k{rec[w]=t[k-1-j];w=w+1;j=j+1} return w } 517 518// quarantine one stuck item by its RAW queue line (no field parsing in the crash-proof parent) + a reason+detail. 519func pub_dl_raw(dlpath: *u8, reason: *u8, detail: i64, line: *u8, ll: i64) -> i64 { 520 let rec: *u8 = sys_mmap(PUB_REC_CAP) 521 var o: i64 = 0 522 o = pub_dlcat(rec, o, "STUCK" as *u8); rec[o]=9 as u8; o=o+1 523 o = pub_dlcat(rec, o, reason); rec[o]=9 as u8; o=o+1 524 o = pub_dlnum(rec, o, detail); rec[o]=9 as u8; o=o+1 525 var k: i64 = 0 526 while k < ll { if o < PUB_REC_CAP - 2 { rec[o]=line[k]; o=o+1 } k=k+1 } 527 rec[o]=10 as u8; o=o+1; rec[o]=0 as u8 528 fa_appendz(dlpath, rec, PUB_REC_CAP) 529 return 1 530} 531 532// UN-STUCKABLE governed drain. outcounts[0..4] = published, held(outward-unapproved), failed, crashed, skipped. 533// Returns #published. NO single item can halt the loop -- each is published in its own process. 534func pub_run_resilient(qpath: *u8, ledpath: *u8, stageroot: *u8, liveroot: *u8, lockres: *u8, approval_dir: *u8, dlpath: *u8, outcounts: *i64) -> i64 { 535 outcounts[0]=0; outcounts[1]=0; outcounts[2]=0; outcounts[3]=0; outcounts[4]=0 536 let dlt: i64 = sys_openat_wr(dlpath, 0x1a4); if dlt >= 0 { sys_close(dlt) } // fresh dead-letter for THIS pass (no accumulation -> the self-heal never re-acts on stale records) 537 let lenp: *i64 = sys_mmap(8) as *i64 538 let data: *u8 = sys_read_file(qpath, lenp) 539 if (data as i64) == 0 { return 0 } 540 let n: i64 = lenp[0] 541 let st: *u8 = sys_mmap(64) 542 var i: i64 = 0; var ls: i64 = 0 543 while i < n { 544 if data[i] == (10 as u8) { 545 let line: *u8 = ((data as i64) + ls) as *u8 546 let ll: i64 = i - ls 547 if ll > 0 { 548 pub_field(line, ll, 0, st) // status only (machine-written, short) 549 if pub_streq(st, "PENDING" as *u8) == 1 { 550 let lfd: i64 = fl_acquire(lockres, PUB_MAGIC_100000, 1) 551 let pid: i64 = sys_fork() 552 if pid == 0 { 553 // CHILD: every hostile/heavy operation is isolated here. 554 let sha: *u8 = sys_mmap(256); let src: *u8 = sys_mmap(512); let dest: *u8 = sys_mmap(256) 555 let site: *u8 = sys_mmap(256); let policy: *u8 = sys_mmap(64) 556 pub_field(line, ll, 1, site); pub_field(line, ll, 3, sha); pub_field(line, ll, 4, src) 557 pub_field(line, ll, 5, dest); pub_field(line, ll, 6, policy) 558 if pub_policy_allows(policy, sha, approval_dir) == 0 { sys_exit(3) } // outward unapproved -> HELD 559 if pub_led_has(ledpath, sha, dest) == 1 { sys_exit(1) } // already published (this exact sha) -> SKIP 560 let cur: *u8 = sys_mmap(72) // STALE-DUP guard: if the source's CURRENT 561 if pub_sha_file(src, cur) == 1 { if pub_led_has(ledpath, cur, dest) == 1 { sys_exit(1) } } // content is already live at dest, the queued (stale) sha is just log cruft -> SKIP cleanly, do not fail/quarantine 562 let pr: i64 = pub_publish_one(sha, src, dest, site, stageroot, liveroot, ledpath) 563 if pr == 1 { sys_exit(0) } // PUBLISHED 564 sys_exit(2) // FAILED (verify/copy/promote) 565 } 566 let stx: *i64 = sys_mmap(16) as *i64; stx[0] = 0 567 sys_wait4(pid, stx, 0) 568 fl_release(lfd) 569 let raw: i64 = stx[0] 570 let sig: i64 = raw & 0x7f 571 if sig != 0 { 572 outcounts[3] = outcounts[3] + 1 573 pub_dl_raw(dlpath, "CRASH" as *u8, sig, line, ll) 574 } else { 575 let code: i64 = (raw >> 8) & 0xff 576 if code == 0 { outcounts[0] = outcounts[0] + 1 } 577 else { if code == 1 { outcounts[4] = outcounts[4] + 1 } 578 else { if code == 3 { outcounts[1] = outcounts[1] + 1 } 579 else { outcounts[2] = outcounts[2] + 1; pub_dl_raw(dlpath, "FAIL" as *u8, code, line, ll) } } } 580 } 581 } 582 } 583 ls = i + 1 584 } 585 i = i + 1 586 } 587 return outcounts[0] 588} 589 590// ============================================================================================================ 591// R11 -- AUTONOMOUS Dr+ENGINEER SELF-HEAL over the dead-letter (operator: "flag the dr and engineer to partner on 592// fixing the root causes of the stuck autonomously and automatically"). The ENGINEER re-diagnoses each quarantined 593// item AGAINST THE LIVE FILESYSTEM (grounded, not guessed -- rule #4): a CRASH = a publisher-code bug on that input; 594// a FAIL with a missing source = the artifact moved/was deleted; a FAIL whose source no longer hashes to the 595// submitted sha = the artifact changed after submit (TOCTOU); otherwise a transient deploy error. The DOCTOR then 596// assigns the remedy: a code-bug is FLAGGED to the engineer (and stays quarantined so it can't crash again); a 597// missing/changed source is FLAGGED to the owning workstream to re-stage/re-submit; a transient error is left to 598// RETRY on the next idempotent drain pass. Output is a structured report the two roles act on -- automatic, no human. 599// ============================================================================================================ 600func pub_sh_cause(reason: *u8, sha: *u8, src: *u8, ledpath: *u8, dest: *u8) -> i64 { 601 if pub_streq(reason, "CRASH" as *u8) == 1 { return 1 } // PUBLISHER-BUG (code crashed on this input) 602 if pub_exists(src) == 0 { return 2 } // SRC-MISSING 603 let h: *u8 = sys_mmap(72) 604 if pub_sha_file(src, h) == 1 { if pub_streq(h, sha) == 0 { // current content differs from the QUEUED sha 605 if pub_led_has(ledpath, h, dest) == 1 { return 5 } // ALREADY-LIVE: current content already published to dest -> stale dup (prune, do NOT republish) 606 return 3 // ARTIFACT-CHANGED: current content not yet live -> republish 607 } } 608 return 4 // DEPLOY-ERROR (sha matches but failed -> transient retry) 609} 610func pub_sh_cause_name(c: i64) -> *u8 { if c==1 { return "PUBLISHER-BUG" as *u8 } if c==2 { return "SRC-MISSING" as *u8 } if c==3 { return "ARTIFACT-CHANGED" as *u8 } if c==5 { return "ALREADY-LIVE" as *u8 } return "DEPLOY-ERROR" as *u8 } 611func pub_sh_action(c: i64) -> *u8 { if c==1 { return "FLAG-ENGINEER" as *u8 } if c==2 { return "FLAG-OWNER-RESTAGE" as *u8 } if c==3 { return "FLAG-OWNER-RESUBMIT" as *u8 } if c==5 { return "PRUNE-STALE-DUP" as *u8 } return "RETRY-NEXT-PASS" as *u8 } 612 613// process every STUCK record in the dead-letter -> diagnose + remedy, append to reportpath. returns #processed. 614// dead-letter layout (pub_dl_raw): STUCK<TAB>reason<TAB>detail<TAB>PENDING<TAB>site<TAB>req<TAB>sha<TAB>src<TAB>dest<TAB>policy 615// DOCTOR auto-remedy: an INTERNAL artifact that merely CHANGED since submit is re-queued with its CURRENT sha (the 616// owning ws's clear intent to publish the current bytes) -- BOUNDED to once per (sha,dest) via resub_led so it can 617// NEVER loop; OUTWARD changed/everything-else is FLAGGED (outward still needs operator approval, by construction). 618// requeue_path==0 disables auto-resubmit (pure diagnosis, e.g. a dry-run). 619func pub_selfheal(dlpath: *u8, reportpath: *u8, requeue_path: *u8, resub_led: *u8, ledpath: *u8) -> i64 { 620 let lenp: *i64 = sys_mmap(8) as *i64 621 let data: *u8 = sys_read_file(dlpath, lenp) 622 if (data as i64) == 0 { return 0 } 623 let n: i64 = lenp[0] 624 let st: *u8 = sys_mmap(64); let reason: *u8 = sys_mmap(64); let sha: *u8 = sys_mmap(256) 625 let src: *u8 = sys_mmap(512); let dest: *u8 = sys_mmap(256); let policy: *u8 = sys_mmap(64) 626 let site: *u8 = sys_mmap(256); let req: *u8 = sys_mmap(256) 627 var i: i64 = 0; var ls: i64 = 0; var processed: i64 = 0 628 while i < n { 629 if data[i] == (10 as u8) { 630 let line: *u8 = ((data as i64) + ls) as *u8 631 let ll: i64 = i - ls 632 if ll > 0 { 633 pub_field(line, ll, 0, st) 634 if pub_streq(st, "STUCK" as *u8) == 1 { 635 pub_field(line, ll, 1, reason) 636 pub_field(line, ll, 6, sha); pub_field(line, ll, 7, src); pub_field(line, ll, 8, dest) 637 let cause: i64 = pub_sh_cause(reason, sha, src, ledpath, dest) 638 var action: *u8 = pub_sh_action(cause) 639 if cause == 3 { // ARTIFACT-CHANGED (genuinely not-yet-live) 640 pub_field(line, ll, 9, policy) 641 if (requeue_path as i64) != 0 { if pub_streq(policy, "internal" as *u8) == 1 { 642 if pub_led_has(resub_led, sha, dest) == 1 { action = "ALREADY-RESUBMITTED" as *u8 } 643 else { 644 pub_field(line, ll, 4, site); pub_field(line, ll, 5, req) 645 pub_submit_to(requeue_path, src, dest, site, req, "internal" as *u8) // re-queue with the CURRENT sha 646 pub_record_ledger(resub_led, sha, dest, site) // bound: never resubmit this stale (sha,dest) again 647 action = "AUTO-RESUBMITTED" as *u8 648 } 649 } } 650 } 651 let rec: *u8 = sys_mmap(PUB_REC_CAP); var o: i64 = 0 652 o = pub_dlcat(rec, o, pub_sh_cause_name(cause)); rec[o]=9 as u8; o=o+1 653 o = pub_dlcat(rec, o, action); rec[o]=9 as u8; o=o+1 654 o = pub_dlcat(rec, o, dest); rec[o]=9 as u8; o=o+1 655 o = pub_dlcat(rec, o, sha) 656 rec[o]=10 as u8; o=o+1; rec[o]=0 as u8 657 fa_appendz(reportpath, rec, PUB_REC_CAP) 658 processed = processed + 1 659 } 660 } 661 ls = i + 1 662 } 663 i = i + 1 664 } 665 return processed 666} 667 668// ============================================================================================================ 669// R9 -- POST-DEPLOY HTTP SMOKE TEST + HEALTH-GATED AUTO-ROLLBACK. pub_deploy proves the staged BYTES hash to the 670// approved sha; it CANNOT prove the live URL actually SERVES them. That blind spot is exactly the sites.elf class 671// of failure: the deploy "succeeded" on disk while the service did not serve (down / wedged / wrong path). pub_smoke 672// does a REAL loopback HTTP GET of the served path and verifies the SERVED body hashes to the approved sha; 673// pub_health_gate auto-rolls-back to the last-good live if the smoke fails -> the publisher never leaves a broken 674// URL live AND never falsely reports a publish that the world can't actually fetch. Sovereign client (our own 675// socket syscalls; mirrors nx_pub_serve_gate's cg_get with a read-to-close loop so the body sha is exact). 676// ============================================================================================================ 677func pub_nap_ms(ms: i64) -> i64 { let ts: *i64 = sys_mmap(16) as *i64; ts[0]=0; ts[1]=ms*PUB_MAGIC_1000000; __syscall(35, ts as i64, 0, 0, 0, 0, 0); return 0 } 678 679// sha256(data[0..len)) -> 64 lowercase hex chars into outhex (NUL-terminated). byte-range twin of pub_sha_file. 680func pub_hash_bytes(data: *u8, len: i64, outhex: *u8) -> i64 { 681 let dig: *u8 = sys_mmap(32) 682 sha256_digest(data, len, dig) 683 var i: i64 = 0 684 while i < 32 { 685 let b: i64 = dig[i] & 0xff 686 outhex[i*2] = pub_hexd((b >> 4) & 0xf) as u8 687 outhex[i*2 + 1] = pub_hexd(b & 0xf) as u8 688 i = i + 1 689 } 690 outhex[64] = 0 as u8 691 return 1 692} 693// offset of the HTTP body (just past the CRLFCRLF header terminator) in resp[0..n), or -1 if not found. 694func pub_body_off(resp: *u8, n: i64) -> i64 { 695 var i: i64 = 0 696 while i + 3 < n { 697 if resp[i]==(13 as u8) { if resp[i+1]==(10 as u8) { if resp[i+2]==(13 as u8) { if resp[i+3]==(10 as u8) { return i + 4 } } } } 698 i = i + 1 699 } 700 return 0 - 1 701} 702// sovereign loopback HTTP/1.0 client: connect 127.0.0.1:port (retry until the server is up), GET /<path>, read the 703// FULL response (loop until the server closes / RCVTIMEO). returns bytes read, or -1 if the server never answered. 704func pub_http_get(port: i64, path: *u8, resp: *u8, cap: i64) -> i64 { 705 var tries: i64 = 0 706 while tries < 80 { 707 let fd: i64 = sys_socket(2, 1, 0) 708 if fd >= 0 { 709 let tv: *u8 = sys_mmap(16); tv[0]=2 as u8; var tz: i64=1; while tz<16 { tv[tz]=0 as u8; tz=tz+1 } // 2s 710 sys_setsockopt(fd, 1, 20, tv, 16) // SO_RCVTIMEO -> sys_read can't block forever 711 let addr: *u8 = sys_mmap(16) 712 addr[0]=2 as u8; addr[1]=0 as u8; addr[2]=((port>>8)&0xff) as u8; addr[3]=(port&0xff) as u8 713 addr[4]=127 as u8; addr[5]=0 as u8; addr[6]=0 as u8; addr[7]=1 as u8 714 var z: i64=8; while z<16 { addr[z]=0 as u8; z=z+1 } 715 if nx_connect_bounded(fd, addr, 16, NX_CONN_DEFAULT_MS) == 0 { 716 let r: *u8 = sys_mmap(512); var o: i64=0 717 o = fa_cat(r, o, "GET /" as *u8); o = fa_cat(r, o, path); o = fa_cat(r, o, " HTTP/1.0\r\nConnection: close\r\n\r\n" as *u8) 718 sys_write(fd, r, o) 719 var got: i64 = 0 720 var done: i64 = 0 721 while done == 0 { 722 let rd: i64 = sys_read(fd, ((resp as i64)+got) as *u8, cap-got) 723 if rd <= 0 { done = 1 } else { got = got + rd; if got >= cap { done = 1 } } 724 } 725 sys_close(fd) 726 return got 727 } 728 sys_close(fd) 729 } 730 pub_nap_ms(20) 731 tries = tries + 1 732 } 733 return 0 - 1 734} 735// THE POST-DEPLOY SMOKE TEST: GET the served path; pass iff status is 200 AND the served body hashes to expect_sha. 736// returns 1 = the live URL truly serves the approved artifact, 0 = it does not (no answer / non-200 / wrong bytes). 737func pub_smoke(port: i64, urlpath: *u8, expect_sha: *u8) -> i64 { 738 let resp: *u8 = sys_mmap(PUB_MAGIC_262144) 739 let n: i64 = pub_http_get(port, urlpath, resp, PUB_MAGIC_262144) 740 if n <= 0 { return 0 } // server down / wedged -> serve failure 741 if pub_substr(resp, n, "200 OK" as *u8) == 0 { return 0 } // non-200 (e.g. 404 wrong path) -> serve failure 742 let bo: i64 = pub_body_off(resp, n) 743 if bo < 0 { return 0 } 744 let h: *u8 = sys_mmap(72) 745 pub_hash_bytes(((resp as i64)+bo) as *u8, n - bo, h) 746 return pub_streq(h, expect_sha) // served body must hash to the approved artifact 747} 748// HEALTH GATE: after a promote, confirm the live URL serves the approved bytes; if not, AUTO-ROLLBACK to last-good. 749// returns 1 = healthy (smoke passed), 0 = unhealthy (smoke failed -> rolled back; the URL is not left broken). 750func pub_health_gate(expect_sha: *u8, livepath: *u8, port: i64, urlpath: *u8) -> i64 { 751 if pub_smoke(port, urlpath, expect_sha) == 1 { return 1 } 752 pub_rollback(livepath) 753 return 0 754} 755// THE SAFE DEPLOY: stage -> verify(sha) -> backup-prev -> atomic-promote (pub_deploy), THEN post-deploy HTTP smoke 756// at the live URL; if the served result doesn't match, auto-rollback. returns 1 = PUBLISHED + served-verified, 757// 0 = REJECTED (pre-promote verify failed, OR the live URL didn't serve it -> rolled back), <0 = copy error. 758func pub_deploy_smoke(expect_sha: *u8, src: *u8, stagepath: *u8, livepath: *u8, port: i64, urlpath: *u8) -> i64 { 759 let d: i64 = pub_deploy(expect_sha, src, stagepath, livepath) 760 if d != 1 { return d } // pre-promote verify failed/error: live untouched 761 return pub_health_gate(expect_sha, livepath, port, urlpath) // 1 = healthy, 0 = unhealthy (rolled back) 762} 763 764// ============================================================================================================ 765// R10 -- OBSERVABILITY: STATUS (what is queued / published / ready / held) + DRY-RUN (plan a run, NO side effects). 766// Both are READ-ONLY over the queue + ledger. dry-run is the operator's "what will this do?" before a real publish: 767// it computes the EXACT set pub_run_governed would publish without writing live or appending the ledger. 768// ============================================================================================================ 769// number of records (lines) in the ledger = things PUBLISHED so far. 770func pub_count_ledger(ledpath: *u8) -> i64 { 771 let lenp: *i64 = sys_mmap(8) as *i64 772 let data: *u8 = sys_read_file(ledpath, lenp) 773 if (data as i64)==0 { return 0 } 774 let n: i64 = lenp[0] 775 var i: i64=0; var c: i64=0 776 while i<n { if data[i]==(10 as u8) { c=c+1 } i=i+1 } 777 return c 778} 779// THE PLAN PREDICATE (shared by dry-run; mirrors the wet pub_run_governed decision): a PENDING request WOULD be 780// published iff policy allows (internal, or outward+approved) AND it is not already in the ledger. Fills out[]: 781// out[0]=total PENDING, out[1]=ready(would publish), out[2]=held(policy denied), out[3]=idempotent-skip(in ledger). 782func pub_plan(qpath: *u8, ledpath: *u8, approval_dir: *u8, out: *i64) -> i64 { 783 out[0]=0; out[1]=0; out[2]=0; out[3]=0 784 let lenp: *i64 = sys_mmap(8) as *i64 785 let data: *u8 = sys_read_file(qpath, lenp) 786 if (data as i64)==0 { return 0 } 787 let n: i64 = lenp[0] 788 let st: *u8 = sys_mmap(64); let sha: *u8 = sys_mmap(256); let dest: *u8 = sys_mmap(256); let policy: *u8 = sys_mmap(64) 789 var i: i64=0; var ls: i64=0 790 while i<n { 791 if data[i]==(10 as u8) { 792 let line: *u8 = ((data as i64)+ls) as *u8 793 let ll: i64 = i-ls 794 pub_field(line, ll, 0, st) 795 if pub_streq(st, "PENDING" as *u8)==1 { 796 out[0]=out[0]+1 797 pub_field(line, ll, 3, sha) 798 pub_field(line, ll, 5, dest) 799 pub_field(line, ll, 6, policy) 800 if pub_policy_allows(policy, sha, approval_dir)==1 { 801 if pub_led_has(ledpath, sha, dest)==1 { out[3]=out[3]+1 } else { out[1]=out[1]+1 } 802 } else { out[2]=out[2]+1 } 803 } 804 ls=i+1 805 } 806 i=i+1 807 } 808 return out[1] 809} 810// DRY-RUN: how many requests a real pub_run_governed WOULD publish now, with ZERO side effects (no live write, no 811// ledger append). Equals the wet run's published count (artifacts were sha-verified at submit). out[] = full plan. 812func pub_dryrun(qpath: *u8, ledpath: *u8, approval_dir: *u8, out: *i64) -> i64 { 813 return pub_plan(qpath, ledpath, approval_dir, out) 814} 815// STATUS snapshot. out[0]=PENDING requests, out[1]=PUBLISHED(ledger records), out[2]=ready, out[3]=held, 816// out[4]=idempotent-already-published. (Pure read; the live dashboard is this data, formatted by the caller.) 817func pub_status(qpath: *u8, ledpath: *u8, approval_dir: *u8, out: *i64) -> i64 { 818 let p: *i64 = sys_mmap(64) as *i64 819 pub_plan(qpath, ledpath, approval_dir, p) 820 out[0]=p[0]; out[2]=p[1]; out[3]=p[2]; out[4]=p[3] 821 out[1]=pub_count_ledger(ledpath) 822 return 0 823} 824 825// ============================================================================================================ 826// R11 -- AUDIT QUERY (provenance/history lookups over the append-only ledger) + CHANGELOG (release notes). All 827// READ-ONLY: the ledger IS the source of truth for what was published, when-ordered, with what content sha. 828// ============================================================================================================ 829// is `dest` currently published? returns 1 + the LATEST sha into out_sha (ledger is append-only, last match wins), 830// else 0 (out_sha untouched). This is the "what is live at this path, and from which artifact?" provenance query. 831func pub_audit_query(ledpath: *u8, dest: *u8, out_sha: *u8) -> i64 { 832 let lenp: *i64 = sys_mmap(8) as *i64 833 let data: *u8 = sys_read_file(ledpath, lenp) 834 if (data as i64)==0 { return 0 } 835 let n: i64 = lenp[0] 836 let f0: *u8 = sys_mmap(256); let f1: *u8 = sys_mmap(256) 837 var i: i64=0; var ls: i64=0; var found: i64=0 838 while i<n { 839 if data[i]==(10 as u8) { 840 let line: *u8 = ((data as i64)+ls) as *u8 841 pub_field(line, i-ls, 0, f0) 842 pub_field(line, i-ls, 1, f1) 843 if pub_streq(f1, dest)==1 { 844 var k: i64=0; while f0[k]!=(0 as u8){ out_sha[k]=f0[k]; k=k+1 } out_sha[k]=0 as u8 845 found=1 846 } 847 ls=i+1 848 } 849 i=i+1 850 } 851 return found 852} 853// how many releases recorded for `site` (field2). audit aggregate. 854func pub_query_count_site(ledpath: *u8, site: *u8) -> i64 { 855 let lenp: *i64 = sys_mmap(8) as *i64 856 let data: *u8 = sys_read_file(ledpath, lenp) 857 if (data as i64)==0 { return 0 } 858 let n: i64 = lenp[0] 859 let f2: *u8 = sys_mmap(256) 860 var i: i64=0; var ls: i64=0; var c: i64=0 861 while i<n { 862 if data[i]==(10 as u8) { 863 let line: *u8 = ((data as i64)+ls) as *u8 864 pub_field(line, i-ls, 2, f2) 865 if pub_streq(f2, site)==1 { c=c+1 } 866 ls=i+1 867 } 868 i=i+1 869 } 870 return c 871} 872// parse a leading decimal int from a NUL-terminated string (ignores non-digits). 873func pub_atoi(s: *u8) -> i64 { var v: i64=0; var i: i64=0; while s[i]!=(0 as u8){ let c: i64=s[i] as i64; if c>=48 { if c<=57 { v=v*10+(c-48) } } i=i+1 } return v } 874 875// record a ledger event with an EXPLICIT outcome + timestamp + lead (used by tests/recovery to log non-PUBLISHED 876// outcomes; the live path uses pub_record_ledger = PUBLISHED + now()). record = sha dest site outcome pub_ts lead. 877func pub_record_outcome(ledpath: *u8, sha: *u8, dest: *u8, site: *u8, outcome: *u8, ts: i64, lead: i64) -> i64 { 878 let rec: *u8 = sys_mmap(PUB_REC_CAP) 879 var o: i64 = 0 880 o = fa_cat(rec, o, sha); rec[o]=9 as u8; o=o+1 881 o = fa_cat(rec, o, dest); rec[o]=9 as u8; o=o+1 882 o = fa_cat(rec, o, site); rec[o]=9 as u8; o=o+1 883 o = fa_cat(rec, o, outcome); rec[o]=9 as u8; o=o+1 884 o = fa_catn(rec, o, ts); rec[o]=9 as u8; o=o+1 885 o = fa_catn(rec, o, lead) 886 rec[o] = 0 as u8 887 return fa_appendz(ledpath, rec, PUB_REC_CAP) 888} 889 890// ============================================================================================================ 891// R12 -- DORA METRICS (the release-engineering yardstick) computed from the ledger event-log + deploy NOTIFY. 892// The ledger records sha dest site outcome pub_ts lead_sec, so the publisher can compute the four DORA metrics: 893// out[0]=deploys out[1]=successes out[2]=failures out[3]=change_fail_permille out[4]=span_sec 894// out[5]=deploys_per_ksec out[6]=avg_MTTR_sec(resolved failures) out[7]=resolved_failures out[8]=avg_lead_sec 895// MTTR pairs each failure with the NEXT later success for the SAME dest (the recovery). change-fail-rate and 896// frequency are live now; lead-time is computed but reads 0 on live records until submit-ts is plumbed (v2). 897// ============================================================================================================ 898func pub_dora(ledpath: *u8, out: *i64) -> i64 { 899 var z: i64=0; while z<9 { out[z]=0; z=z+1 } 900 let lenp: *i64 = sys_mmap(8) as *i64 901 let data: *u8 = sys_read_file(ledpath, lenp) 902 if (data as i64)==0 { return 0 } 903 let n: i64 = lenp[0] 904 let oc: *u8 = sys_mmap(64); let de: *u8 = sys_mmap(256); let tsf: *u8 = sys_mmap(64); let ldf: *u8 = sys_mmap(64) 905 let oc2: *u8 = sys_mmap(64); let de2: *u8 = sys_mmap(256); let ts2f: *u8 = sys_mmap(64) 906 var mints: i64=0; var maxts: i64=0; var havets: i64=0 907 var deploys: i64=0; var succ: i64=0; var fail: i64=0 908 var lead_sum: i64=0; var mttr_sum: i64=0; var mttr_cnt: i64=0 909 var i: i64=0; var ls: i64=0 910 while i<n { 911 if data[i]==(10 as u8) { 912 let line: *u8 = ((data as i64)+ls) as *u8 913 let ll: i64 = i-ls 914 pub_field(line, ll, 3, oc) 915 pub_field(line, ll, 4, tsf); let ts: i64 = pub_atoi(tsf) 916 deploys = deploys + 1 917 if havets==0 { mints=ts; maxts=ts; havets=1 } else { if ts<mints {mints=ts} if ts>maxts {maxts=ts} } 918 if pub_streq(oc, "PUBLISHED" as *u8)==1 { 919 succ=succ+1 920 pub_field(line, ll, 5, ldf); lead_sum = lead_sum + pub_atoi(ldf) 921 } else { 922 fail=fail+1 923 pub_field(line, ll, 1, de) 924 var best: i64=0; var found: i64=0 925 var j: i64=0; var js: i64=0 926 while j<n { 927 if data[j]==(10 as u8) { 928 let l2: *u8 = ((data as i64)+js) as *u8 929 let ll2: i64 = j-js 930 pub_field(l2, ll2, 3, oc2) 931 if pub_streq(oc2, "PUBLISHED" as *u8)==1 { 932 pub_field(l2, ll2, 1, de2) 933 if pub_streq(de2, de)==1 { 934 pub_field(l2, ll2, 4, ts2f); let ts2: i64 = pub_atoi(ts2f) 935 if ts2 > ts { if found==0 { best=ts2; found=1 } else { if ts2<best { best=ts2 } } } 936 } 937 } 938 js=j+1 939 } 940 j=j+1 941 } 942 if found==1 { mttr_sum = mttr_sum + (best - ts); mttr_cnt = mttr_cnt + 1 } 943 } 944 ls=i+1 945 } 946 i=i+1 947 } 948 out[0]=deploys; out[1]=succ; out[2]=fail 949 if deploys>0 { out[3] = fail*1000/deploys } 950 out[4] = maxts - mints 951 if out[4] > 0 { out[5] = deploys*1000/out[4] } 952 out[6] = 0; if mttr_cnt>0 { out[6] = mttr_sum/mttr_cnt } 953 out[7] = mttr_cnt 954 out[8] = 0; if succ>0 { out[8] = lead_sum/succ } 955 return deploys 956} 957 958// DEPLOY NOTIFICATION: append a framed event to a notify channel (a file daemons/operators watch -- the sovereign 959// equivalent of an alert webhook). One atomic framed line: kind<TAB>dest<TAB>sha<TAB>ts. returns the append result. 960func pub_notify(notifypath: *u8, kind: *u8, dest: *u8, sha: *u8) -> i64 { 961 let rec: *u8 = sys_mmap(PUB_REC_CAP) 962 var o: i64 = 0 963 o = fa_cat(rec, o, kind); rec[o]=9 as u8; o=o+1 964 o = fa_cat(rec, o, dest); rec[o]=9 as u8; o=o+1 965 o = fa_cat(rec, o, sha); rec[o]=9 as u8; o=o+1 966 o = fa_catn(rec, o, sys_now_realtime_sec()) 967 rec[o] = 0 as u8 968 return fa_appendz(notifypath, rec, PUB_REC_CAP) 969} 970 971// CHANGELOG / release notes: project the ledger into human-readable "dest sha site" lines into out (NUL-terminated). 972// returns the byte length. Bounded by cap (stops appending if a line would overflow). Pure read + format. 973func pub_changelog(ledpath: *u8, out: *u8, cap: i64) -> i64 { 974 let lenp: *i64 = sys_mmap(8) as *i64 975 let data: *u8 = sys_read_file(ledpath, lenp) 976 if (data as i64)==0 { out[0]=0 as u8; return 0 } 977 let n: i64 = lenp[0] 978 let f0: *u8 = sys_mmap(256); let f1: *u8 = sys_mmap(256); let f2: *u8 = sys_mmap(256) 979 var i: i64=0; var ls: i64=0; var o: i64=0 980 while i<n { 981 if data[i]==(10 as u8) { 982 let line: *u8 = ((data as i64)+ls) as *u8 983 pub_field(line, i-ls, 1, f1) // dest 984 pub_field(line, i-ls, 0, f0) // sha 985 pub_field(line, i-ls, 2, f2) // site 986 if o + 320 < cap { 987 o = fa_cat(out, o, f1); out[o]=32 as u8; o=o+1 988 o = fa_cat(out, o, f0); out[o]=32 as u8; o=o+1 989 o = fa_cat(out, o, f2); out[o]=10 as u8; o=o+1 990 } 991 ls=i+1 992 } 993 i=i+1 994 } 995 out[o]=0 as u8 996 return o 997} 998 999// ============================================================================================================ 1000// R13 -- GOVERNANCE II: N-of-M multi-approver QUORUM (beyond R6's single operator-ok) + release SCHEDULE 1001// (deploy window + a FREEZE override). Both file-based, sovereign, fail-closed. 1002// ============================================================================================================ 1003// path of the per-artifact approvers file: <approval_dir>/<sha>.approvers (one distinct approver per line). 1004func pub_approvers_path(approval_dir: *u8, sha: *u8, out: *u8) -> i64 { 1005 let tmp: *u8 = sys_mmap(700); pub_join(approval_dir, sha, tmp) 1006 pub_pcat(tmp, ".approvers" as *u8, out) 1007 return 0 1008} 1009// 1 iff a whole line == needle exists in the file. 1010func pub_has_line(path: *u8, needle: *u8) -> i64 { 1011 let lenp: *i64 = sys_mmap(8) as *i64 1012 let data: *u8 = sys_read_file(path, lenp) 1013 if (data as i64)==0 { return 0 } 1014 let n: i64 = lenp[0] 1015 let f: *u8 = sys_mmap(256) 1016 var i: i64=0; var ls: i64=0 1017 while i<n { 1018 if data[i]==(10 as u8) { 1019 let line: *u8 = ((data as i64)+ls) as *u8 1020 pub_field(line, i-ls, 0, f) 1021 if pub_streq(f, needle)==1 { return 1 } 1022 ls=i+1 1023 } 1024 i=i+1 1025 } 1026 return 0 1027} 1028// record an approval by a named approver for an artifact (DEDUP: the same approver counts once). returns 1 if newly 1029// recorded, 0 if this approver already approved. 1030func pub_approve_quorum(approval_dir: *u8, sha: *u8, approver: *u8) -> i64 { 1031 let p: *u8 = sys_mmap(700); pub_approvers_path(approval_dir, sha, p) 1032 if pub_has_line(p, approver)==1 { return 0 } 1033 let rec: *u8 = sys_mmap(256); var o: i64=0; o=fa_cat(rec, o, approver); rec[o]=0 as u8 1034 fa_appendz(p, rec, 256) 1035 return 1 1036} 1037// 1 iff at least `need` DISTINCT approvers have approved the artifact (N-of-M). fail-closed (no file -> 0). 1038func pub_quorum_met(approval_dir: *u8, sha: *u8, need: i64) -> i64 { 1039 let p: *u8 = sys_mmap(700); pub_approvers_path(approval_dir, sha, p) 1040 let lenp: *i64 = sys_mmap(8) as *i64 1041 let data: *u8 = sys_read_file(p, lenp) 1042 if (data as i64)==0 { return 0 } 1043 let n: i64 = lenp[0] 1044 var i: i64=0; var c: i64=0 1045 while i<n { if data[i]==(10 as u8) { c=c+1 } i=i+1 } 1046 if c >= need { return 1 } 1047 return 0 1048} 1049// 1 iff a freeze flag file is present (deploys frozen). 1050func pub_frozen(freeze_path: *u8) -> i64 { return pub_exists(freeze_path) } 1051// release SCHEDULE: allow a deploy iff NOT frozen AND now is within [win_start, win_end]. fail-closed; freeze wins. 1052func pub_schedule_allows(now: i64, win_start: i64, win_end: i64, freeze_path: *u8) -> i64 { 1053 if pub_exists(freeze_path)==1 { return 0 } 1054 if now < win_start { return 0 } 1055 if now > win_end { return 0 } 1056 return 1 1057} 1058 1059// ============================================================================================================ 1060// R14 -- PROGRESSIVE DELIVERY: BLUE-GREEN (two materialized slots + zero-copy instant atomic flip) and CANARY 1061// (a separate cohort slot, served-smoke-gated before full promotion -> a bad version reaches 0% of main). 1062// ============================================================================================================ 1063// path of a color slot: <slotroot>/<dest>.<color> (e.g. page.html.blue). 1064func pub_bg_cpath(slotroot: *u8, dest: *u8, color: *u8, out: *u8) -> i64 { 1065 var o: i64 = pub_join(slotroot, dest, out) 1066 out[o]=46 as u8; o=o+1 1067 var i: i64=0; while color[i]!=(0 as u8){ out[o]=color[i]; o=o+1; i=i+1 } 1068 out[o]=0 as u8 1069 return o 1070} 1071// materialize a color slot from src + verify its bytes against expect_sha. returns 1 ok, 0 sha-mismatch, <0 copy err. 1072func pub_blue_green_stage(slotroot: *u8, dest: *u8, color: *u8, src: *u8, expect_sha: *u8) -> i64 { 1073 let cp: *u8 = sys_mmap(700); pub_bg_cpath(slotroot, dest, color, cp) 1074 if pub_copy(src, cp) < 0 { return 0 - 1 } 1075 if pub_sha_match(cp, expect_sha)==0 { return 0 } 1076 return 1 1077} 1078// THE FLIP: atomically repoint the active path <slotroot>/<dest> to the given color via a relative symlink + rename 1079// (rename is atomic -> a reader sees old-or-new, never broken). ZERO-COPY: the color files are never rewritten; the 1080// flip (and flip-back, for instant rollback) is an O(1) pointer swap. returns 1, or <0 on rename error. 1081func pub_blue_green_flip(slotroot: *u8, dest: *u8, color: *u8) -> i64 { 1082 let tgt: *u8 = sys_mmap(700); var o: i64=0; var i: i64=0 // relative target "<dest>.<color>" 1083 while dest[i]!=(0 as u8){ tgt[o]=dest[i]; o=o+1; i=i+1 } tgt[o]=46 as u8; o=o+1 1084 i=0; while color[i]!=(0 as u8){ tgt[o]=color[i]; o=o+1; i=i+1 } tgt[o]=0 as u8 1085 let active: *u8 = sys_mmap(700); pub_join(slotroot, dest, active) 1086 let tmp: *u8 = sys_mmap(700); pub_pcat(active, ".flip" as *u8, tmp) 1087 __syscall(87, tmp as i64, 0, 0, 0, 0, 0) // unlink any stale tmp link 1088 __syscall(88, tgt as i64, tmp as i64, 0, 0, 0, 0) // symlink(target, tmp) [x86_64 symlink=88] 1089 if pub_rename(tmp, active) != 0 { return 0 - 2 } // atomic replace -> instant flip 1090 return 1 1091} 1092// CANARY rollout: stage the new version to a SEPARATE canary slot, run `cohort` served-smoke checks against the 1093// canary URL, and promote to main ONLY if every check passes; otherwise ABORT -> main is never touched (a bad 1094// version reaches 0% of main). The smoke is the SERVED-result gate (catches disk-OK-but-URL-bad, not just bytes). 1095// returns 1 promoted, 0 aborted (canary unhealthy; main untouched), <0 stage error. urlbase = the served dest path. 1096func pub_canary_rollout(expect_sha: *u8, src: *u8, slotroot: *u8, dest: *u8, urlbase: *u8, port: i64, cohort: i64) -> i64 { 1097 let cp: *u8 = sys_mmap(700); pub_bg_cpath(slotroot, dest, "canary" as *u8, cp) 1098 if pub_copy(src, cp) < 0 { return 0 - 1 } // stage to the canary slot 1099 let curl: *u8 = sys_mmap(700); var o: i64=0; var i: i64=0 // canary URL = "<urlbase>.canary" 1100 while urlbase[i]!=(0 as u8){ curl[o]=urlbase[i]; o=o+1; i=i+1 } curl[o]=46 as u8; o=o+1 1101 let cc: *u8 = "canary" as *u8; i=0; while cc[i]!=(0 as u8){ curl[o]=cc[i]; o=o+1; i=i+1 } curl[o]=0 as u8 1102 var k: i64=0 1103 while k < cohort { 1104 if pub_smoke(port, curl, expect_sha)==0 { return 0 } // canary unhealthy -> ABORT, main untouched 1105 k=k+1 1106 } 1107 let mp: *u8 = sys_mmap(700); pub_join(slotroot, dest, mp) 1108 if pub_promote_atomic(cp, mp) < 0 { return 0 - 2 } // healthy -> full rollout (atomic) 1109 return 1 1110} 1111 1112// ============================================================================================================ 1113// R15 -- MULTI-ENV PROMOTE-CHAIN (dev->stage->prod), MULTI-TARGET FAN-OUT, and FEATURE FLAGS (decouple deploy 1114// from release). roots/targets are passed as a *i64 array of string pointers (roots[i] = an env/target root path). 1115// ============================================================================================================ 1116// promote an artifact through an ORDERED chain of env roots; each env stages+verifies+promotes before the next. 1117// returns the number of envs reached (== nroots if it reached prod; < nroots if it stopped at a failed verify -> 1118// the later envs (incl prod) are NEVER touched = fail-closed ordered promotion). 1119func pub_promote_chain(expect_sha: *u8, src: *u8, dest: *u8, roots: *i64, nroots: i64, stageroot: *u8) -> i64 { 1120 var i: i64 = 0 1121 while i < nroots { 1122 let envroot: *u8 = roots[i] as *u8 1123 let stagep: *u8 = sys_mmap(700); pub_join(stageroot, dest, stagep) 1124 let livep: *u8 = sys_mmap(700); pub_join(envroot, dest, livep) 1125 if pub_deploy(expect_sha, src, stagep, livep) != 1 { return i } // stopped at env i; envs >= i untouched 1126 i = i + 1 1127 } 1128 return nroots 1129} 1130// fan out one artifact to N targets ALL-OR-NOTHING: stage+verify ONCE, and only if it verifies do we atomically 1131// promote to each target -> no target ever receives unverified bytes (fail-closed). returns #targets promoted. 1132func pub_fanout(expect_sha: *u8, src: *u8, dest: *u8, targets: *i64, ntargets: i64, stageroot: *u8) -> i64 { 1133 let stagep: *u8 = sys_mmap(700); pub_join(stageroot, dest, stagep) 1134 if pub_copy(src, stagep) < 0 { return 0 - 1 } 1135 if pub_sha_match(stagep, expect_sha) == 0 { return 0 } // fail-closed: NO target gets bad bytes 1136 var i: i64 = 0; var done: i64 = 0 1137 while i < ntargets { 1138 let troot: *u8 = targets[i] as *u8 1139 let livep: *u8 = sys_mmap(700); pub_join(troot, dest, livep) 1140 if pub_promote_atomic(stagep, livep) >= 0 { done = done + 1 } 1141 i = i + 1 1142 } 1143 return done 1144} 1145// FEATURE FLAGS: a flag store decouples DEPLOY (artifact shipped) from RELEASE (flag on). Append-only (last wins). 1146func pub_flag_set(store: *u8, name: *u8, val: i64) -> i64 { 1147 let rec: *u8 = sys_mmap(256); var o: i64=0 1148 o = fa_cat(rec, o, name); rec[o]=9 as u8; o=o+1 1149 o = fa_catn(rec, o, val); rec[o]=0 as u8 1150 return fa_appendz(store, rec, 256) 1151} 1152// read a flag: the LAST recorded value for `name`, or 0 (OFF) if never set (fail-safe default = off). 1153func pub_flag_get(store: *u8, name: *u8) -> i64 { 1154 let lenp: *i64 = sys_mmap(8) as *i64 1155 let data: *u8 = sys_read_file(store, lenp) 1156 if (data as i64)==0 { return 0 } 1157 let n: i64 = lenp[0] 1158 let f0: *u8 = sys_mmap(128); let f1: *u8 = sys_mmap(64) 1159 var i: i64=0; var ls: i64=0; var val: i64=0 1160 while i<n { 1161 if data[i]==(10 as u8) { 1162 let line: *u8 = ((data as i64)+ls) as *u8 1163 pub_field(line, i-ls, 0, f0) 1164 if pub_streq(f0, name)==1 { pub_field(line, i-ls, 1, f1); val = pub_atoi(f1) } 1165 ls=i+1 1166 } 1167 i=i+1 1168 } 1169 return val 1170} 1171 1172// ============================================================================================================ 1173// R16 -- ROLLING update (incremental, halt-on-failure), artifact RETENTION/GC (never-brick), bounded RETRY. 1174// ============================================================================================================ 1175// update instances ONE AT A TIME; verify each; STOP at the first failure (the remaining instances are never touched 1176// -> a bad rollout is halted mid-roll, blast-limited). returns the number of instances successfully updated. 1177func pub_rolling(expect_sha: *u8, src: *u8, dest: *u8, targets: *i64, ntargets: i64, stageroot: *u8) -> i64 { 1178 var i: i64 = 0 1179 while i < ntargets { 1180 let troot: *u8 = targets[i] as *u8 1181 let stagep: *u8 = sys_mmap(700); pub_join(stageroot, dest, stagep) 1182 let livep: *u8 = sys_mmap(700); pub_join(troot, dest, livep) 1183 if pub_deploy(expect_sha, src, stagep, livep) != 1 { return i } // halt: instances >= i untouched 1184 i = i + 1 1185 } 1186 return ntargets 1187} 1188// RETENTION/GC: remove the publisher's TRANSIENT leftovers for a live path (.tmp/.flip/.rbk). It NEVER removes the 1189// live file or its .prev (the rollback target) -> never-brick #26 by construction. returns 1. 1190func pub_retain(livepath: *u8) -> i64 { 1191 let tmp: *u8 = sys_mmap(700); pub_pcat(livepath, ".tmp" as *u8, tmp); __syscall(87, tmp as i64, 0, 0, 0, 0, 0) 1192 let flip: *u8 = sys_mmap(700); pub_pcat(livepath, ".flip" as *u8, flip); __syscall(87, flip as i64, 0, 0, 0, 0, 0) 1193 let rbk: *u8 = sys_mmap(700); pub_pcat(livepath, ".rbk" as *u8, rbk); __syscall(87, rbk as i64, 0, 0, 0, 0, 0) 1194 return 1 1195} 1196// bounded RETRY with growing backoff: attempt up to maxtries; the op "succeeds" on attempt #succeed_at. returns the 1197// winning attempt (1..maxtries), or 0 if exhausted (GIVES UP -- bounded, never an infinite loop). graceful-degradation. 1198func pub_retry(succeed_at: i64, maxtries: i64, base_backoff_ms: i64) -> i64 { 1199 var k: i64 = 1 1200 while k <= maxtries { 1201 if k >= succeed_at { return k } 1202 pub_nap_ms(base_backoff_ms * k) // linear backoff before the next attempt 1203 k = k + 1 1204 } 1205 return 0 1206} 1207 1208// ============================================================================================================ 1209// R17 -- request PRIORITY lanes (field7 of the queue record) + per-environment concurrency groups (LOCKGROUP). 1210// ============================================================================================================ 1211// submit with an explicit priority (field7). Higher = more urgent. (pub_submit_to records carry no field7 = pri 0.) 1212func pub_submit_pri(qpath: *u8, src: *u8, dest: *u8, site: *u8, requester: *u8, policy: *u8, pri: i64) -> i64 { 1213 let hex: *u8 = sys_mmap(72) 1214 if pub_sha_file(src, hex) == 0 { return 0 - 9 } 1215 let rec: *u8 = sys_mmap(PUB_REC_CAP) 1216 var o: i64 = pub_build_rec(rec, site, requester, hex, src, dest, policy) // 7 fields, rec[o]=0 1217 rec[o]=9 as u8; o=o+1 1218 o = fa_catn(rec, o, pri); rec[o]=0 as u8 // field7 = priority 1219 return fa_appendz(qpath, rec, PUB_REC_CAP) 1220} 1221// pick the highest-priority PENDING request: returns its priority (>=0), writes its dest into out_dest; -1 if none. 1222func pub_priority_pick(qpath: *u8, out_dest: *u8) -> i64 { 1223 out_dest[0] = 0 as u8 1224 let lenp: *i64 = sys_mmap(8) as *i64 1225 let data: *u8 = sys_read_file(qpath, lenp) 1226 if (data as i64)==0 { return 0 - 1 } 1227 let n: i64 = lenp[0] 1228 let st: *u8 = sys_mmap(64); let dest: *u8 = sys_mmap(256); let prif: *u8 = sys_mmap(64) 1229 var i: i64=0; var ls: i64=0; var best: i64 = 0 - 1 1230 while i<n { 1231 if data[i]==(10 as u8) { 1232 let line: *u8 = ((data as i64)+ls) as *u8 1233 let ll: i64 = i-ls 1234 pub_field(line, ll, 0, st) 1235 if pub_streq(st, "PENDING" as *u8)==1 { 1236 pub_field(line, ll, 7, prif) 1237 let pri: i64 = pub_atoi(prif) 1238 if pri > best { 1239 best = pri 1240 pub_field(line, ll, 5, dest) 1241 var k: i64=0; while dest[k]!=(0 as u8){ out_dest[k]=dest[k]; k=k+1 } out_dest[k]=0 as u8 1242 } 1243 } 1244 ls=i+1 1245 } 1246 i=i+1 1247 } 1248 return best 1249} 1250// LOCKGROUP: derive a per-site lock resource so DIFFERENT sites publish in parallel while the SAME site serializes. 1251func pub_lockgroup_res(site: *u8, out: *u8) -> i64 { 1252 var o: i64 = 0; let p: *u8 = "publish:" as *u8 1253 while p[o]!=(0 as u8){ out[o]=p[o]; o=o+1 } 1254 var i: i64=0; while site[i]!=(0 as u8){ out[o]=site[i]; o=o+1; i=i+1 } 1255 out[o]=0 as u8 1256 return o 1257} 1258// acquire the per-site publish lock (returns the fl_acquire fd); release with pub_lockgroup_release. 1259func pub_lockgroup_acquire(site: *u8) -> i64 { 1260 let res: *u8 = sys_mmap(320); pub_lockgroup_res(site, res) 1261 return fl_acquire(res, PUB_MAGIC_100000, 1) 1262} 1263func pub_lockgroup_release(fd: i64) -> i64 { return fl_release(fd) } 1264 1265// ============================================================================================================ 1266// R18 -- PUBLIC-DOMAIN WIRING (pub_dns): the publisher EMITS a stable domain->endpoint mapping for hosting to apply 1267// (DNS A / stable reverse-proxy), so going public is NOT a fragile daemon-swap. The publisher owns the EMISSION + 1268// a stable internal endpoint; hosting APPLIES the DNS record (coordinated). config = one parseable directive line. 1269// ============================================================================================================ 1270func pub_dns_config(domain: *u8, host: *u8, port: i64, out: *u8) -> i64 { 1271 var o: i64 = 0 1272 o = fa_cat(out, o, "publish-endpoint domain=" as *u8); o = fa_cat(out, o, domain) 1273 o = fa_cat(out, o, " host=" as *u8); o = fa_cat(out, o, host) 1274 o = fa_cat(out, o, " port=" as *u8); o = fa_catn(out, o, port) 1275 o = fa_cat(out, o, " proto=https" as *u8) 1276 out[o] = 0 as u8 1277 return o 1278} 1279// persist the mapping (idempotent overwrite) for hosting to apply. returns 1. 1280func pub_dns_emit(domain: *u8, host: *u8, port: i64, path: *u8) -> i64 { 1281 let buf: *u8 = sys_mmap(512); let n: i64 = pub_dns_config(domain, host, port, buf) 1282 let fd: i64 = sys_openat_wr(path, 0x1a4); if fd<0 { return 0 } 1283 sys_write(fd, buf, n); sys_close(fd) 1284 return 1 1285} 1286 1287// ============================================================================================================ 1288// R19 -- CONTINUOUS DRAIN (the daemon loop): repeatedly run the GOVERNED pipeline so the publisher keeps the live 1289// queue drained as workstreams submit. Each cycle is idempotent + serialized (pub_run_governed), so a daemon is 1290// just this loop with poll-sleep. pub_run_drain is the BOUNDED form (stops when a cycle publishes 0 = drained, or 1291// after max_cycles) -- gateable; a real daemon passes a large/poll cap. returns total published across cycles. 1292// ============================================================================================================ 1293func pub_run_drain(qpath: *u8, ledpath: *u8, stageroot: *u8, liveroot: *u8, lockres: *u8, approval_dir: *u8, max_cycles: i64, sleep_ms: i64) -> i64 { 1294 var total: i64 = 0 1295 var c: i64 = 0 1296 while c < max_cycles { 1297 let n: i64 = pub_run_governed(qpath, ledpath, stageroot, liveroot, lockres, approval_dir) 1298 total = total + n 1299 if n == 0 { return total } // queue drained this cycle (a daemon would poll-sleep and re-check) 1300 c = c + 1 1301 if sleep_ms > 0 { pub_nap_ms(sleep_ms) } 1302 } 1303 return total 1304} 1305 1306// ============================================================================================================ 1307// R20 -- CALL-AWARE no-bypass audit. The comment-aware audit still over-flags STRING-LITERAL mentions (e.g. an 1308// HTML page that prints "<code>nx_aw_push</code>" in its body). A real bypass is a CALL: the symbol immediately 1309// followed by '('. This strips // comments AND matches only "symbol(" -> the TRUE direct-caller count. 1310// ============================================================================================================ 1311func pub_forbidden_call(code: *u8, n: i64) -> i64 { 1312 if pub_substr(code, n, "nx_aw_send(" as *u8)==1 { return 1 } 1313 if pub_substr(code, n, "nx_aw_push(" as *u8)==1 { return 1 } 1314 if pub_substr(code, n, "pub_deploy(" as *u8)==1 { return 1 } 1315 if pub_substr(code, n, "pub_promote_atomic(" as *u8)==1 { return 1 } 1316 if pub_substr(code, n, "pub_rollback(" as *u8)==1 { return 1 } 1317 if pub_substr(code, n, "pub_blue_green_flip(" as *u8)==1 { return 1 } 1318 if pub_substr(code, n, "pub_canary_rollout(" as *u8)==1 { return 1 } 1319 if pub_substr(code, n, "pub_record_ledger(" as *u8)==1 { return 1 } 1320 if pub_substr(code, n, "pub_record_outcome(" as *u8)==1 { return 1 } 1321 return 0 1322} 1323func pub_audit_call_strict(path: *u8, allowlisted: i64) -> i64 { 1324 if allowlisted == 1 { return 0 } 1325 let lenp: *i64 = sys_mmap(8) as *i64 1326 let data: *u8 = sys_read_file(path, lenp) 1327 if (data as i64)==0 { return 0 } 1328 let n: i64 = lenp[0] 1329 let code: *u8 = sys_mmap(n + 16) 1330 var i: i64=0; var o: i64=0; var incomment: i64=0 1331 while i < n { 1332 let c: i64 = data[i] & 0xff 1333 if c == 10 { incomment=0; code[o]=10 as u8; o=o+1 } 1334 else { 1335 if incomment == 0 { 1336 if c == 47 { if i+1 < n { if (data[i+1] & 0xff) == 47 { incomment = 1 } } } 1337 if incomment == 0 { code[o]=c as u8; o=o+1 } 1338 } 1339 } 1340 i = i + 1 1341 } 1342 return pub_forbidden_call(code, o) 1343} 1344 1345// ============================================================================================================ 1346// R21 -- BEST-PRACTICE CONTINUOUS DAEMON (researched + cited: knowledge/fetched/dmn_*.raw). Operator: "run as we add 1347// things, not start/stop". The sovereign researcher (nx_dmn_research_fetch, 13/13 sources) determined the practice: 1348// · SUPERVISED auto-restart, not manual start/stop (systemd/runit "supervision") -> the supervisor runs+restarts it; 1349// · CRASH-ONLY (dmn_b_crashonly): safe to kill+restart anytime; recover BY restart -> our drain is idempotent; 1350// · EVENT-DRIVEN via inotify (dmn_c_inotify): act as work ARRIVES, not fixed polling (poll-timeout as the fallback); 1351// · WATCHDOG/HEARTBEAT (dmn_d_*): emit a heartbeat so a HANG (the wedge) is detected, not just a crash; 1352// · GRACEFUL stop (dmn_e_*): on a stop signal, finish the current drain + exit cleanly. 1353// pub_daemon_serve is the loop; the pieces are individually gated. The SUPERVISOR is the hosting workstream's 1354// (hostop_supervise emits the command); this daemon is supervision-COMPATIBLE by being crash-only + heartbeat + graceful. 1355// ============================================================================================================ 1356// LIVENESS: write the current epoch to the heartbeat file (a watchdog reads it to detect a hang). returns the epoch. 1357func pub_daemon_heartbeat(hbpath: *u8) -> i64 { 1358 let now: i64 = sys_now_realtime_sec() 1359 let buf: *u8 = sys_mmap(24); let o: i64 = fa_catn(buf, 0, now); buf[o]=0 as u8 1360 let fd: i64 = sys_openat_wr(hbpath, 0x1a4); if fd < 0 { return 0 - 1 } 1361 sys_write(fd, buf, o); sys_close(fd) 1362 return now 1363} 1364// WATCHDOG view: seconds since the last heartbeat (now - hb); -1 if no heartbeat. A supervisor restarts if age > limit. 1365func pub_daemon_hb_age(hbpath: *u8, now: i64) -> i64 { 1366 let lenp: *i64 = sys_mmap(8) as *i64 1367 let d: *u8 = sys_read_file(hbpath, lenp) 1368 if (d as i64) == 0 { return 0 - 1 } 1369 return now - pub_atoi(d) 1370} 1371// EVENT-DRIVEN: inotify-watch a directory (queue dir) for writes/creates/moves. returns the inotify fd, or <0. 1372func pub_daemon_watch_init(dirpath: *u8) -> i64 { 1373 let infd: i64 = __syscall(294, 0, 0, 0, 0, 0, 0) // inotify_init1(0) 1374 if infd < 0 { return infd } 1375 __syscall(254, infd, dirpath as i64, 0x18a, 0, 0, 0) // add_watch: IN_MODIFY|IN_CLOSE_WRITE|IN_MOVED_TO|IN_CREATE 1376 return infd 1377} 1378// wait for a watched change OR timeout_ms (poll fallback). returns 1 if a change arrived (events drained), 0 on timeout. 1379func pub_daemon_wait(infd: i64, timeout_ms: i64) -> i64 { 1380 let pfd: *u8 = sys_mmap(16) 1381 pfd[0]=(infd & 0xff) as u8; pfd[1]=((infd>>8)&0xff) as u8; pfd[2]=((infd>>16)&0xff) as u8; pfd[3]=((infd>>24)&0xff) as u8 1382 pfd[4]=1 as u8; pfd[5]=0 as u8; pfd[6]=0 as u8; pfd[7]=0 as u8 // events=POLLIN 1383 let r: i64 = __syscall(7, pfd as i64, 1, timeout_ms, 0, 0, 0) // poll(fds,1,timeout_ms) 1384 if r <= 0 { return 0 } // timeout/err -> no change 1385 let buf: *u8 = sys_mmap(PUB_MAGIC_4096); sys_read(infd, buf, PUB_MAGIC_4096) // drain events 1386 return 1 1387} 1388// GRACEFUL: a stop is requested iff the stop-flag file exists (a SIGTERM handler or supervisor creates it). 1389func pub_daemon_should_stop(stopflag: *u8) -> i64 { return pub_exists(stopflag) } 1390// THE DAEMON LOOP: crash-only idempotent drain, event-driven (inotify), heartbeat liveness, graceful stop. max_cycles 1391// large = effectively continuous (the supervisor restarts on death); bounded = gateable. returns total published. 1392func pub_daemon_serve(qpath: *u8, ledpath: *u8, stageroot: *u8, liveroot: *u8, lockres: *u8, approval: *u8, watchdir: *u8, hbpath: *u8, stopflag: *u8, max_cycles: i64, poll_ms: i64) -> i64 { 1393 let infd: i64 = pub_daemon_watch_init(watchdir) 1394 var cycles: i64 = 0; var total: i64 = 0 1395 while cycles < max_cycles { 1396 if pub_daemon_should_stop(stopflag) == 1 { return total } // graceful stop 1397 total = total + pub_run_governed(qpath, ledpath, stageroot, liveroot, lockres, approval) // crash-only idempotent drain 1398 pub_daemon_heartbeat(hbpath) // liveness 1399 if pub_daemon_should_stop(stopflag) == 1 { return total } 1400 if infd >= 0 { pub_daemon_wait(infd, poll_ms) } // event-driven wait (act as work arrives) 1401 cycles = cycles + 1 1402 } 1403 return total 1404}