code wiki / _hdl_build / nx_buildq.nx
nx_buildq.nx
buildroot/runtime/_hdl_build/nx_buildq.nx
about
nx_buildq.nx -- QUEUE A BUILD FOR THE NEXT OPENING instead of re-issuing it by hand.
WHY. `/api/build` under load answers REFUSED-LOAD: "NOTHING IS QUEUED for you anywhere -- re-issue it
yourself once the load clears" -- and nx_build_admit's own header says its QUEUE verdict was DESIGNED to
be absorbed by nx_orchestrate's wait-for-opening queue. Nothing ever wired the two: the queue had no
predicate for headroom, and nothing seeded a build row. Measured 2026-08-18: five REFUSED-LOAD
re-issues by hand in one session while the toolchain rung shipped -- a human acting as the retry loop.
WHAT (composition, no new mechanism): one call seeds
plan-build-<target>- : 1 <TAB> nx_sov_build_run <TAB> <target> <TAB> --build-only
deployq- : BQ-<target> | title | headroom:[floor:max] | queued | build-<target> | note
nx_orchestrate (the */5 poller) evaluates `headroom:` by forking nx_build_admit and FIRES the plan via
nx_plan_run when the box GRANTS -- so the compile lands in buildroot/_build/<target>.sov.elf on the
first pass after the opening, its rc + output snippet in planrun-build-<target>-, no human in the loop.
The build itself still runs through nx_sov_build_run, so admission, lease, cache, canon and every other
guard the build lane already has apply unchanged. Promotion is NOT queued here (a promote is a
deliberate act with a digest); read the planrun result, then promote.
DL9 (deploy, 2026-09-02) bq_dedupe_target: the queue was MEASURED idempotent by id (231 rows, 231 distinct
ids, nx_store_put re-puts by id), so a second `add` of one target replaces the row rather than doubling it
-- and this organ now SAYS so (ALREADY-QUEUED) instead of printing a second QUEUED receipt that read like
a second row. The half of the rung that was genuinely open is CLOSE: a build that succeeds by another
door (a sync /api/build, a hand nx_sov_build_run) left the queued row alive, so the poller rebuilt the
same source on its next opening. `close <target> [rc]` marks the row closed with the reason, in place,
by id; the poller fires only `queued` rows, so a closed row can never fire. Nothing to close is a named
NO-ROW, never an error: a caller in a build lane must not fail because nobody had queued it.
nx_buildq add <target> [floor_mb] [max_centiload] [--store <elf>] [--queue <prefix>] [--plan <prefix>]
nx_buildq close <target> [rc] [--store <elf>] [--queue <prefix>]
Both writes go through nx_store_put (THE plane write verb, provenanced, revision-logged) -- forked,
never re-implemented. Fails CLOSED and LOUD: a refused seed prints the verb's own answer and exits 4.
The --store/--queue/--plan overrides exist for the gate (fixture planes under /tmp); production callers
never pass them.
license_tier: ORIGINAL No hw writes (Rule 26). expect_exit: 0
dependencies 2 imports · 0 importers
imports: nx_tool_run.nxnx_syscalls.nx
imported by: nobody (leaf or entry point)
call flow from main pre-order; caps 40 nodes / depth 6 declared; ↻ = already shown
structs
| none |
consts
| 39 | const BQ_STORE_PUT_DEFAULT: *u8 = "/volume1/homes/elderwesto/nishihost/nx_store_put.elf" |
| 40 | const BQ_PLAN_PREFIX_DEFAULT: *u8 = "knowledge/store/plan-build-" |
| 41 | const BQ_QUEUE_PREFIX_DEFAULT: *u8 = "knowledge/store/deployq-" |
| 42 | const BQ_ACTOR: *u8 = "nx_buildq" |
| 43 | const BQ_STATUS_QUEUED: *u8 = "queued" |
| 44 | const BQ_STATUS_CLOSED: *u8 = "closed" |
| 45 | const BQ_CAP: i64 = 65536 |
| 46 | const BQ_LOAD_CAP: i64 = 1048576 // a whole-plane load: 231 rows measured at ~74 KB; 1 MiB holds 14x and the brim is announced |
| 47 | const BQ_PATHCAP: i64 = 512 |
| 48 | const BQ_NOTECAP: i64 = 1024 |
| 49 | const BQ_ROW_FIELDS: i64 = 6 // id title precond status plan note |
| 50 | const BQ_TAB: i64 = 9 |
| 51 | const BQ_NL: i64 = 10 |
| 52 | const BQ_EXIT_USAGE: i64 = 2 |
| 53 | const BQ_EXIT_REFUSED: i64 = 4 |
functions
| 58 | func 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 } |
| 59 | func bq_wn(v: i64) -> i64 |
| 72 | func bq_len(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n } |
| 73 | func bq_streq(a: *u8, b: *u8) -> i64 called by 1: main |
| 79 | func 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 } |
| 80 | func 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 } called by 1: main |
| 81 | func bq_catnum(dst: *u8, o: i64, cap: i64, v: i64) -> i64 |
| 94 | func bq_safe(s: *u8) -> i64 called by 1: main |
| 109 | func bq_digits(s: *u8) -> i64 called by 1: main |
| 116 | func bq_put(store: *u8, av: *i64) -> i64 |
| 124 | func bq_load(store: *u8, prefix: *u8, buf: *u8, cap: i64) -> i64 |
| 142 | func bq_dedupe_target(dump: *u8, n: i64, target: *u8, fields: *u8) -> i64 |
| 191 | func bq_field(fields: *u8, k: i64) -> *u8 { return ((fields as i64) + k * BQ_NOTECAP) as *u8 } called by 1: main |
| 193 | func bq_usage() -> i64 |
| 199 | func main(argc: i64, argv: *i64) -> i64 |