code wiki / _hdl_build / nx_buildq.nx

nx_buildq.nx source

↩ module page · 337 lines · 17927 B

1// nx_buildq.nx -- QUEUE A BUILD FOR THE NEXT OPENING instead of re-issuing it by hand. 2// 3// WHY. `/api/build` under load answers REFUSED-LOAD: "NOTHING IS QUEUED for you anywhere -- re-issue it 4// yourself once the load clears" -- and nx_build_admit's own header says its QUEUE verdict was DESIGNED to 5// be absorbed by nx_orchestrate's wait-for-opening queue. Nothing ever wired the two: the queue had no 6// predicate for headroom, and nothing seeded a build row. Measured 2026-08-18: five REFUSED-LOAD 7// re-issues by hand in one session while the toolchain rung shipped -- a human acting as the retry loop. 8// 9// WHAT (composition, no new mechanism): one call seeds 10// plan-build-<target>- : 1 <TAB> nx_sov_build_run <TAB> <target> <TAB> --build-only 11// deployq- : BQ-<target> | title | headroom:[floor:max] | queued | build-<target> | note 12// nx_orchestrate (the */5 poller) evaluates `headroom:` by forking nx_build_admit and FIRES the plan via 13// nx_plan_run when the box GRANTS -- so the compile lands in buildroot/_build/<target>.sov.elf on the 14// first pass after the opening, its rc + output snippet in planrun-build-<target>-, no human in the loop. 15// The build itself still runs through nx_sov_build_run, so admission, lease, cache, canon and every other 16// guard the build lane already has apply unchanged. Promotion is NOT queued here (a promote is a 17// deliberate act with a digest); read the planrun result, then promote. 18// 19// DL9 (deploy, 2026-09-02) bq_dedupe_target: the queue was MEASURED idempotent by id (231 rows, 231 distinct 20// ids, nx_store_put re-puts by id), so a second `add` of one target replaces the row rather than doubling it 21// -- and this organ now SAYS so (ALREADY-QUEUED) instead of printing a second QUEUED receipt that read like 22// a second row. The half of the rung that was genuinely open is CLOSE: a build that succeeds by another 23// door (a sync /api/build, a hand nx_sov_build_run) left the queued row alive, so the poller rebuilt the 24// same source on its next opening. `close <target> [rc]` marks the row closed with the reason, in place, 25// by id; the poller fires only `queued` rows, so a closed row can never fire. Nothing to close is a named 26// NO-ROW, never an error: a caller in a build lane must not fail because nobody had queued it. 27// 28// nx_buildq add <target> [floor_mb] [max_centiload] [--store <elf>] [--queue <prefix>] [--plan <prefix>] 29// nx_buildq close <target> [rc] [--store <elf>] [--queue <prefix>] 30// 31// Both writes go through nx_store_put (THE plane write verb, provenanced, revision-logged) -- forked, 32// never re-implemented. Fails CLOSED and LOUD: a refused seed prints the verb's own answer and exits 4. 33// The --store/--queue/--plan overrides exist for the gate (fixture planes under /tmp); production callers 34// never pass them. 35// license_tier: ORIGINAL No hw writes (Rule 26). expect_exit: 0 36import "nx_tool_run.nx" 37import "nx_syscalls.nx" 38 39const BQ_STORE_PUT_DEFAULT: *u8 = "/volume1/homes/elderwesto/nishihost/nx_store_put.elf" 40const BQ_PLAN_PREFIX_DEFAULT: *u8 = "knowledge/store/plan-build-" 41const BQ_QUEUE_PREFIX_DEFAULT: *u8 = "knowledge/store/deployq-" 42const BQ_ACTOR: *u8 = "nx_buildq" 43const BQ_STATUS_QUEUED: *u8 = "queued" 44const BQ_STATUS_CLOSED: *u8 = "closed" 45const BQ_CAP: i64 = 65536 46const BQ_LOAD_CAP: i64 = 1048576 // a whole-plane load: 231 rows measured at ~74 KB; 1 MiB holds 14x and the brim is announced 47const BQ_PATHCAP: i64 = 512 48const BQ_NOTECAP: i64 = 1024 49const BQ_ROW_FIELDS: i64 = 6 // id title precond status plan note 50const BQ_TAB: i64 = 9 51const BQ_NL: i64 = 10 52const BQ_EXIT_USAGE: i64 = 2 53const BQ_EXIT_REFUSED: i64 = 4 54// NO deadline on the store verb: nx_store_put serialises whole-store writers and under contention a 55// single put MEASURED ~90 s (2026-08-18). A 30 s box here killed a legitimate in-flight write and 56// reported REFUSED -- the verb owns its own locking and its own answer; this organ only relays it. 57 58func bq_w(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } sys_write(1, s, n); return 0 } 59func bq_wn(v: i64) -> i64 { 60 let t: *u8 = sys_mmap(32); var m: i64 = v; var neg: i64 = 0 61 if m < 0 { neg = 1; m = 0 - m } 62 let d: *u8 = sys_mmap(32); var k: i64 = 0 63 if m == 0 { d[0] = 48 as u8; k = 1 } 64 while m > 0 { d[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 } 65 var o: i64 = 0 66 if neg == 1 { t[0] = 45 as u8; o = 1 } 67 var i: i64 = 0 68 while i < k { t[o] = d[k - 1 - i]; o = o + 1; i = i + 1 } 69 sys_write(1, t, o) 70 return 0 71} 72func bq_len(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n } 73func bq_streq(a: *u8, b: *u8) -> i64 { 74 var i: i64 = 0 75 while a[i] != (0 as u8) { if a[i] != b[i] { return 0 } i = i + 1 } 76 if b[i] != (0 as u8) { return 0 } 77 return 1 78} 79func bq_cat(dst: *u8, o: i64, s: *u8) -> i64 { var i: i64 = 0; var p: i64 = o; while s[i] != (0 as u8) { if p < BQ_PATHCAP - 1 { dst[p] = s[i]; p = p + 1 } i = i + 1 } dst[p] = 0 as u8; return p } 80func bq_catn(dst: *u8, o: i64, cap: i64, s: *u8) -> i64 { var i: i64 = 0; var p: i64 = o; while s[i] != (0 as u8) { if p < cap - 1 { dst[p] = s[i]; p = p + 1 } i = i + 1 } dst[p] = 0 as u8; return p } 81func bq_catnum(dst: *u8, o: i64, cap: i64, v: i64) -> i64 { 82 let d: *u8 = sys_mmap(32); var m: i64 = v; var k: i64 = 0 83 if m < 0 { m = 0 } 84 if m == 0 { d[0] = 48 as u8; k = 1 } 85 while m > 0 { d[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 } 86 var p: i64 = o 87 var i: i64 = 0 88 while i < k { if p < cap - 1 { dst[p] = d[k - 1 - i]; p = p + 1 } i = i + 1 } 89 dst[p] = 0 as u8 90 return p 91} 92// a target name is a bare organ basename: [A-Za-z0-9_] only, so it can never smuggle a path or a tab 93// into a plane row or a plan step (the same sanitizer shape /api/build applies). 94func bq_safe(s: *u8) -> i64 { 95 var i: i64 = 0 96 if s[0] == (0 as u8) { return 0 } 97 while s[i] != (0 as u8) { 98 let c: i64 = s[i] as i64 99 var ok: i64 = 0 100 if c >= 48 { if c <= 57 { ok = 1 } } 101 if c >= 65 { if c <= 90 { ok = 1 } } 102 if c >= 97 { if c <= 122 { ok = 1 } } 103 if c == 95 { ok = 1 } 104 if ok == 0 { return 0 } 105 i = i + 1 106 } 107 return 1 108} 109func bq_digits(s: *u8) -> i64 { 110 var i: i64 = 0 111 if s[0] == (0 as u8) { return 0 } 112 while s[i] != (0 as u8) { let c: i64 = s[i] as i64; if c < 48 { return 0 } if c > 57 { return 0 } i = i + 1 } 113 return 1 114} 115// fork nx_store_put with argv (null-terminated array), echo its answer, return its exit code 116func bq_put(store: *u8, av: *i64) -> i64 { 117 let out: *u8 = sys_mmap(BQ_CAP) 118 let olen: *i64 = sys_mmap(16) as *i64 119 let rc: i64 = tr_run_capture(store, av, out, BQ_CAP, olen) 120 if olen[0] > 0 { sys_write(1, out, olen[0]) } 121 return rc 122} 123// fork `nx_store_put <prefix> load`; the whole plane dump lands in buf (announces a brim, never trims silently) 124func bq_load(store: *u8, prefix: *u8, buf: *u8, cap: i64) -> i64 { 125 let av: *i64 = sys_mmap(8 * 4) as *i64 126 av[0] = store as i64 127 av[1] = prefix as i64 128 av[2] = "load" as *u8 as i64 129 av[3] = 0 130 let olen: *i64 = sys_mmap(16) as *i64 131 let rc: i64 = tr_run_capture(store, av, buf, cap, olen) 132 if rc != 0 { return 0 - 1 } 133 var n: i64 = olen[0] 134 if n < 0 { n = 0 } 135 if n >= cap - 1 { bq_w("BUILDQ BRIM: the plane load filled the capture; rows past the brim were NOT scanned\n" as *u8); n = cap - 1 } 136 buf[n] = 0 as u8 137 return n 138} 139// DL9 bq_dedupe_target: the row for <target> in a plane dump. Fills fields[0..5] (id title precond status plan 140// note, each NUL-terminated in its own BQ_NOTECAP cell) and returns 1 when a row with id BQ-<target> exists, 141// 0 when none does. A pure function of the dump text, so a tooth can drive it without a store. 142func bq_dedupe_target(dump: *u8, n: i64, target: *u8, fields: *u8) -> i64 { 143 let want: *u8 = sys_mmap(BQ_PATHCAP) 144 var wl: i64 = bq_cat(want, 0, "BQ-" as *u8) 145 wl = bq_cat(want, wl, target) 146 var i: i64 = 0 147 while i < n { 148 // one line [i, e) 149 var e: i64 = i 150 var scan: i64 = 1 151 while scan == 1 { if e >= n { scan = 0 } else { if (dump[e] as i64) == BQ_NL { scan = 0 } else { e = e + 1 } } } 152 // the id is the first tab-delimited field; it must equal want EXACTLY (BQ-x must not match BQ-xy) 153 var t: i64 = i 154 var s2: i64 = 1 155 while s2 == 1 { if t >= e { s2 = 0 } else { if (dump[t] as i64) == BQ_TAB { s2 = 0 } else { t = t + 1 } } } 156 var same: i64 = 0 157 if t - i == wl { 158 same = 1 159 var k: i64 = 0 160 while k < wl { if dump[i + k] != want[k] { same = 0 } k = k + 1 } 161 } 162 if same == 1 { 163 var f: i64 = 0 164 var s: i64 = i 165 var p: i64 = i 166 var go: i64 = 1 167 while go == 1 { 168 var cut: i64 = 0 169 if p >= e { cut = 1 } else { if (dump[p] as i64) == BQ_TAB { cut = 1 } } 170 if cut == 1 { 171 if f < BQ_ROW_FIELDS { 172 let cell: *u8 = ((fields as i64) + f * BQ_NOTECAP) as *u8 173 var c: i64 = 0 174 var q: i64 = s 175 while q < p { if c < BQ_NOTECAP - 1 { cell[c] = dump[q]; c = c + 1 } q = q + 1 } 176 cell[c] = 0 as u8 177 f = f + 1 178 } 179 s = p + 1 180 if p >= e { go = 0 } 181 } 182 p = p + 1 183 } 184 while f < BQ_ROW_FIELDS { let cz: *u8 = ((fields as i64) + f * BQ_NOTECAP) as *u8; cz[0] = 0 as u8; f = f + 1 } 185 return 1 186 } 187 i = e + 1 188 } 189 return 0 190} 191func bq_field(fields: *u8, k: i64) -> *u8 { return ((fields as i64) + k * BQ_NOTECAP) as *u8 } 192 193func bq_usage() -> i64 { 194 bq_w("usage: nx_buildq add <target> [floor_mb] [max_centiload] [--store <elf>] [--queue <prefix>] [--plan <prefix>] | close <target> [rc] [--store <elf>] [--queue <prefix>]\n" as *u8) 195 sys_exit(BQ_EXIT_USAGE) 196 return BQ_EXIT_USAGE 197} 198 199func main(argc: i64, argv: *i64) -> i64 { 200 if argc < 3 { return bq_usage() } 201 let verb: *u8 = argv[1] as *u8 202 var is_add: i64 = 0 203 var is_close: i64 = 0 204 if bq_streq(verb, "add" as *u8) == 1 { is_add = 1 } 205 if bq_streq(verb, "close" as *u8) == 1 { is_close = 1 } 206 if is_add + is_close == 0 { return bq_usage() } 207 let target: *u8 = argv[2] as *u8 208 if bq_safe(target) == 0 { bq_w("BUILDQ REFUSED: target must be a bare organ basename [A-Za-z0-9_]\n" as *u8); sys_exit(BQ_EXIT_REFUSED); return BQ_EXIT_REFUSED } 209 // positional numerics, then flags (the gate's fixture overrides; production never passes them) 210 var store: *u8 = BQ_STORE_PUT_DEFAULT 211 var qpfx: *u8 = BQ_QUEUE_PREFIX_DEFAULT 212 var ppfx0: *u8 = BQ_PLAN_PREFIX_DEFAULT 213 var floor: *u8 = "" as *u8 214 var maxl: *u8 = "" as *u8 215 var rcs: *u8 = "" as *u8 216 var npos: i64 = 0 217 var ai: i64 = 3 218 while ai < argc { 219 let a: *u8 = argv[ai] as *u8 220 var used: i64 = 0 221 if bq_streq(a, "--store" as *u8) == 1 { if ai + 1 < argc { store = argv[ai + 1] as *u8; ai = ai + 1 } used = 1 } 222 if bq_streq(a, "--queue" as *u8) == 1 { if ai + 1 < argc { qpfx = argv[ai + 1] as *u8; ai = ai + 1 } used = 1 } 223 if bq_streq(a, "--plan" as *u8) == 1 { if ai + 1 < argc { ppfx0 = argv[ai + 1] as *u8; ai = ai + 1 } used = 1 } 224 if used == 0 { 225 if bq_digits(a) == 0 { bq_w("BUILDQ REFUSED: numeric argument must be decimal digits: " as *u8); bq_w(a); bq_w("\n" as *u8); sys_exit(BQ_EXIT_REFUSED); return BQ_EXIT_REFUSED } 226 if is_add == 1 { if npos == 0 { floor = a } else { if npos == 1 { maxl = a } } } 227 if is_close == 1 { if npos == 0 { rcs = a } } 228 npos = npos + 1 229 } 230 ai = ai + 1 231 } 232 let rid: *u8 = sys_mmap(BQ_PATHCAP) 233 var r: i64 = bq_cat(rid, 0, "BQ-" as *u8) 234 r = bq_cat(rid, r, target) 235 236 if is_close == 1 { 237 // ---- close: mark the queued row closed, in place, by id -- never invent a row to close ---- 238 let dump: *u8 = sys_mmap(BQ_LOAD_CAP) 239 let n: i64 = bq_load(store, qpfx, dump, BQ_LOAD_CAP) 240 if n < 0 { bq_w("BUILDQ REFUSED: the plane could not be loaded (see the verb's answer above)\n" as *u8); sys_exit(BQ_EXIT_REFUSED); return BQ_EXIT_REFUSED } 241 let fields: *u8 = sys_mmap(BQ_ROW_FIELDS * BQ_NOTECAP) 242 if bq_dedupe_target(dump, n, target, fields) == 0 { 243 bq_w("BUILDQ CLOSE NO-ROW id=" as *u8); bq_w(rid); bq_w(" -- nothing was queued for this target; nothing to close (not an error: a build lane must not fail because nobody queued it)\n" as *u8) 244 return 0 245 } 246 let st: *u8 = bq_field(fields, 3) 247 if bq_streq(st, BQ_STATUS_QUEUED) == 0 { 248 bq_w("BUILDQ CLOSE NOT-QUEUED id=" as *u8); bq_w(rid); bq_w(" status=" as *u8); bq_w(st); bq_w(" -- only a queued row is closed; a fired or closed row is left as its own record\n" as *u8) 249 return 0 250 } 251 let note: *u8 = sys_mmap(BQ_NOTECAP) 252 var no: i64 = bq_catn(note, 0, BQ_NOTECAP, "closed by nx_buildq close: a build of " as *u8) 253 no = bq_catn(note, no, BQ_NOTECAP, target) 254 no = bq_catn(note, no, BQ_NOTECAP, " succeeded by another door" as *u8) 255 if rcs[0] != (0 as u8) { no = bq_catn(note, no, BQ_NOTECAP, " rc=" as *u8); no = bq_catn(note, no, BQ_NOTECAP, rcs) } 256 no = bq_catn(note, no, BQ_NOTECAP, " at epoch " as *u8) 257 no = bq_catnum(note, no, BQ_NOTECAP, sys_now_realtime_sec()) 258 no = bq_catn(note, no, BQ_NOTECAP, "; the queued row would have rebuilt the same source on the next opening (DL9 bq_dedupe_target)" as *u8) 259 let av: *i64 = sys_mmap(8 * 12) as *i64 260 av[0] = store as i64 261 av[1] = qpfx as i64 262 av[2] = "put" as *u8 as i64 263 av[3] = BQ_ACTOR as i64 264 av[4] = rid as i64 265 av[5] = bq_field(fields, 1) as i64 266 av[6] = bq_field(fields, 2) as i64 267 av[7] = BQ_STATUS_CLOSED as i64 268 av[8] = bq_field(fields, 4) as i64 269 av[9] = note as i64 270 av[10] = 0 271 bq_w("BUILDQ close " as *u8); bq_w(rid); bq_w(" queued -> closed\n" as *u8) 272 let rcc: i64 = bq_put(store, av) 273 if rcc != 0 { bq_w("BUILDQ REFUSED: close re-put failed (see the verb's answer above)\n" as *u8); sys_exit(BQ_EXIT_REFUSED); return BQ_EXIT_REFUSED } 274 bq_w("BUILDQ CLOSED id=" as *u8); bq_w(rid); bq_w(" -- the poller fires only queued rows, so this one can never fire\n" as *u8) 275 return 0 276 } 277 278 // ---- add ---- 279 // DL9: say what the plane already holds before re-putting. A queued row for this target is REPLACED by id 280 // (the measured idempotence), and the receipt names it so a second QUEUED line never reads as a second row. 281 let dump0: *u8 = sys_mmap(BQ_LOAD_CAP) 282 let n0: i64 = bq_load(store, qpfx, dump0, BQ_LOAD_CAP) 283 if n0 >= 0 { 284 let f0: *u8 = sys_mmap(BQ_ROW_FIELDS * BQ_NOTECAP) 285 if bq_dedupe_target(dump0, n0, target, f0) == 1 { 286 bq_w("BUILDQ ALREADY-QUEUED id=" as *u8); bq_w(rid); bq_w(" status=" as *u8); bq_w(bq_field(f0, 3)); bq_w(" -- one row per target by id; this add REPLACES it, it does not add a second\n" as *u8) 287 } 288 } 289 // 1. the plan: one step, the sovereign build runner in build-only mode 290 let ppfx: *u8 = sys_mmap(BQ_PATHCAP) 291 var o: i64 = bq_cat(ppfx, 0, ppfx0) 292 o = bq_cat(ppfx, o, target) 293 o = bq_cat(ppfx, o, "-" as *u8) 294 let av1: *i64 = sys_mmap(8 * 10) as *i64 295 av1[0] = store as i64 296 av1[1] = ppfx as i64 297 av1[2] = "put" as *u8 as i64 298 av1[3] = BQ_ACTOR as i64 299 av1[4] = "1" as *u8 as i64 300 av1[5] = "nx_sov_build_run" as *u8 as i64 301 av1[6] = target as i64 302 av1[7] = "--build-only" as *u8 as i64 303 av1[8] = 0 304 bq_w("BUILDQ plan " as *u8); bq_w(ppfx); bq_w(" <- 1 nx_sov_build_run " as *u8); bq_w(target); bq_w(" --build-only\n" as *u8) 305 let rc1: i64 = bq_put(store, av1) 306 if rc1 != 0 { bq_w("BUILDQ REFUSED: plan seed failed (see the verb's answer above)\n" as *u8); sys_exit(BQ_EXIT_REFUSED); return BQ_EXIT_REFUSED } 307 308 // 2. the queue row: precondition headroom:[floor[:max]], plan build-<target> 309 let pre: *u8 = sys_mmap(BQ_PATHCAP) 310 var q: i64 = bq_cat(pre, 0, "headroom:" as *u8) 311 if floor[0] != (0 as u8) { q = bq_cat(pre, q, floor) } 312 if maxl[0] != (0 as u8) { q = bq_cat(pre, q, ":" as *u8); q = bq_cat(pre, q, maxl) } 313 let planid: *u8 = sys_mmap(BQ_PATHCAP) 314 var pl: i64 = bq_cat(planid, 0, "build-" as *u8) 315 pl = bq_cat(planid, pl, target) 316 let title: *u8 = sys_mmap(BQ_PATHCAP) 317 var t: i64 = bq_cat(title, 0, "queued build of " as *u8) 318 t = bq_cat(title, t, target) 319 t = bq_cat(title, t, " (fires on the first poller pass with build headroom)" as *u8) 320 let av2: *i64 = sys_mmap(8 * 12) as *i64 321 av2[0] = store as i64 322 av2[1] = qpfx as i64 323 av2[2] = "put" as *u8 as i64 324 av2[3] = BQ_ACTOR as i64 325 av2[4] = rid as i64 326 av2[5] = title as i64 327 av2[6] = pre as i64 328 av2[7] = BQ_STATUS_QUEUED as i64 329 av2[8] = planid as i64 330 av2[9] = "seeded by nx_buildq; result lands in knowledge/store/planrun-build-<target>-; promote deliberately afterwards; a build that succeeds by another door closes this row (nx_buildq close)" as *u8 as i64 331 av2[10] = 0 332 bq_w("BUILDQ queue " as *u8); bq_w(rid); bq_w(" precond=" as *u8); bq_w(pre); bq_w(" plan=" as *u8); bq_w(planid); bq_w("\n" as *u8) 333 let rc2: i64 = bq_put(store, av2) 334 if rc2 != 0 { bq_w("BUILDQ REFUSED: queue seed failed (see the verb's answer above)\n" as *u8); sys_exit(BQ_EXIT_REFUSED); return BQ_EXIT_REFUSED } 335 bq_w("BUILDQ QUEUED id=" as *u8); bq_w(rid); bq_w(" -- nx_orchestrate fires it on its next pass with headroom; read knowledge/store/planrun-build-" as *u8); bq_w(target); bq_w("- for the result\n" as *u8) 336 return 0 337}