code wiki / _hdl_build / nx_workstream_popqueue.nx

nx_workstream_popqueue.nx source

↩ module page · 330 lines · 16929 B

1// nx_workstream_popqueue.nx -- WMS rung REG-POP: FULL REGISTRY POPULATION (close the completeness gap). 2// 3// The "never lose an empire again" payoff. WMS-R1 seeded 15 sample streams; the assignment_queue holds 4// ~1251 work-unit ids that the R4 audit reports as UNREGISTERED (prose/queue-only, never in the SSOT). 5// This organ ENUMERATES every queue id and REGISTERS it into the WMS-R1 store, so R4's unregistered 6// count drops from ~1248 toward 0. It does NOT move `untracked` (that counts *.nx organs with no 7// code_link -- queue ids are work-units, not code paths; that is a SEPARATE rung, flagged OPEN here). 8// 9// SOVEREIGN COMMIT DISCIPLINE: ws_put commits ONE new segment per call -> 1248 puts would blow the 10// seg-store 256-segment cap. So this builds ONE writer buffer (ss_begin) holding the merged ws:ids 11// index PLUS every changed ws:<id> record, then ONE ss_commit = ONE new segment. Re-runs that change 12// nothing add ZERO records to the buffer -> ZERO new segments (idempotent; the 256 cap is never 13// threatened). The idempotency engine is a byte-compare against the store's current value (mirrors the 14// seed organ's wss_streq_store skip). 15// 16// EMPIRE DERIVATION (data-driven, rule 11): queue ids carry no empire field, so empire is derived from 17// the id's prefix family via a TABLE (parallel const arrays), and every derived empire is a real member 18// of ws:empires so the R1 internal audit (ws_audit_complete) stays clean. Unknown prefix -> E-MISC. 19// 20// State = FLOATING (queue-only, no measured detail -- honest per the seed doctrine "ABSENT honestly 21// rather than invented"; FLOATING is in the store's documented label set). memory_link/code_link = "-" 22// (intentionally none -> NOT an orphan, per wa_*_link_resolves "-" handling). 23// 24// MANDATORY write discipline: the evidence log line is built into ONE buffer and emitted via the 25// locked atomic fa_appendz (following cn_emit_green/cn_emit_red), with a UNIQUE scratch path 26// (epoch+microsecond) so the organ is safe to run concurrently with itself. The registry writes 27// themselves go through the atomic ss_commit (tmp+fsync+rename commit point). 28// 29// Sovereign: imports only nx_workstream_store + nx_seg_store + nx_framed_append + nx_syscalls (no gcc). 30// Additive-only: does NOT modify any existing organ. license_tier: ORIGINAL 31import "nx_workstream_store.nx" 32import "nx_seg_store.nx" 33import "nx_framed_append.nx" 34import "nx_syscalls.nx" 35 36const POP_LOG: *u8 = "knowledge/status/workstream_popqueue.log" 37const POP_QUEUE: *u8 = "knowledge/registry/assignment_queue.tsv" 38const POP_REC_CAP: i64 = 512 // bounded log record size (no magic number) 39const POP_ID_CAP: i64 = 4000 // hard bound on queue ids collected (JPL rule 2; ~1251 today) 40 41func pq_slen(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n } 42 43// 1 if NUL-term prefix `pre` is a prefix of NUL-term `id`. 44func pq_has_prefix(id: *u8, pre: *u8) -> i64 { 45 var i: i64 = 0 46 while pre[i] != (0 as u8) { 47 if id[i] != pre[i] { return 0 } 48 i = i + 1 49 } 50 return 1 51} 52 53// copy NUL-term src into dst (incl terminator); returns length. 54func pq_cpy(dst: *u8, src: *u8) -> i64 { 55 var i: i64 = 0 56 while src[i] != (0 as u8) { dst[i] = src[i]; i = i + 1 } 57 dst[i] = 0 as u8 58 return i 59} 60 61// ---- data-driven prefix -> empire MAP (rule 11: a table, not buried literals). Longest-meaningful 62// prefix wins by listing more-specific prefixes first. Every target empire is a member of the live 63// ws:empires list (E-CORE/E-ELDER/E-NGE/E-PLATFORM/E-DEPLOY/E-NXC2/E-MISC/E-NISHIOS/E-RESEARCH/ 64// E-DOCTRINE/E-PM/E-WEB). Unknown -> E-MISC (the documented catch-all). ---- 65func pq_empire_for(id: *u8, out: *u8) -> i64 { 66 // queue id families observed in assignment_queue.tsv (col0): 67 // X-B0/X-Q/X-S*/X-* control+backlog rungs -> E-PM (program management) 68 // GEO-* -> E-CORE (sovereign geo stack lives in nishi-core) 69 // WMS-* -> E-CORE (workstream durability substrate) 70 // NBC/NB-/NISH-/H2-/HTTP -> E-WEB (browser/transport/serve) 71 // VAULT-/INFRA-/DEP-/DEPLOY -> E-DEPLOY (infra/deploy/secrets) 72 // GPU-/DXG -> E-PLATFORM (hardware platform reach) 73 // FNET-/SOV-/TRAIN- -> E-RESEARCH (sub-quadratic AI research) 74 // ME2-/OEUV-/MANHEIM-/NAS- -> E-RESEARCH (researcher/analyst arc) 75 // PETS-/NGE- -> E-NGE (games empire) 76 // DOCKER-/PE- -> E-CORE (docker-replacement native stack) 77 if pq_has_prefix(id, "GEO-" as *u8) == 1 { pq_cpy(out, "E-CORE" as *u8); return 0 } 78 if pq_has_prefix(id, "WMS-" as *u8) == 1 { pq_cpy(out, "E-CORE" as *u8); return 0 } 79 if pq_has_prefix(id, "DOCKER-" as *u8) == 1 { pq_cpy(out, "E-CORE" as *u8); return 0 } 80 if pq_has_prefix(id, "PE-" as *u8) == 1 { pq_cpy(out, "E-CORE" as *u8); return 0 } 81 if pq_has_prefix(id, "NBC" as *u8) == 1 { pq_cpy(out, "E-WEB" as *u8); return 0 } 82 if pq_has_prefix(id, "NB-" as *u8) == 1 { pq_cpy(out, "E-WEB" as *u8); return 0 } 83 if pq_has_prefix(id, "NISH-" as *u8) == 1 { pq_cpy(out, "E-WEB" as *u8); return 0 } 84 if pq_has_prefix(id, "H2-" as *u8) == 1 { pq_cpy(out, "E-WEB" as *u8); return 0 } 85 if pq_has_prefix(id, "HTTP" as *u8) == 1 { pq_cpy(out, "E-WEB" as *u8); return 0 } 86 if pq_has_prefix(id, "VAULT-" as *u8) == 1 { pq_cpy(out, "E-DEPLOY" as *u8); return 0 } 87 if pq_has_prefix(id, "INFRA-" as *u8) == 1 { pq_cpy(out, "E-DEPLOY" as *u8); return 0 } 88 if pq_has_prefix(id, "DEP-" as *u8) == 1 { pq_cpy(out, "E-DEPLOY" as *u8); return 0 } 89 if pq_has_prefix(id, "DEPLOY" as *u8) == 1 { pq_cpy(out, "E-DEPLOY" as *u8); return 0 } 90 if pq_has_prefix(id, "GPU-" as *u8) == 1 { pq_cpy(out, "E-PLATFORM" as *u8); return 0 } 91 if pq_has_prefix(id, "DXG" as *u8) == 1 { pq_cpy(out, "E-PLATFORM" as *u8); return 0 } 92 if pq_has_prefix(id, "FNET-" as *u8) == 1 { pq_cpy(out, "E-RESEARCH" as *u8); return 0 } 93 if pq_has_prefix(id, "SOV-" as *u8) == 1 { pq_cpy(out, "E-RESEARCH" as *u8); return 0 } 94 if pq_has_prefix(id, "TRAIN-" as *u8) == 1 { pq_cpy(out, "E-RESEARCH" as *u8); return 0 } 95 if pq_has_prefix(id, "ME2-" as *u8) == 1 { pq_cpy(out, "E-RESEARCH" as *u8); return 0 } 96 if pq_has_prefix(id, "OEUV" as *u8) == 1 { pq_cpy(out, "E-RESEARCH" as *u8); return 0 } 97 if pq_has_prefix(id, "MANHEIM" as *u8) == 1 { pq_cpy(out, "E-RESEARCH" as *u8); return 0 } 98 if pq_has_prefix(id, "NAS-" as *u8) == 1 { pq_cpy(out, "E-RESEARCH" as *u8); return 0 } 99 if pq_has_prefix(id, "PETS-" as *u8) == 1 { pq_cpy(out, "E-NGE" as *u8); return 0 } 100 if pq_has_prefix(id, "NGE-" as *u8) == 1 { pq_cpy(out, "E-NGE" as *u8); return 0 } 101 if pq_has_prefix(id, "X-" as *u8) == 1 { pq_cpy(out, "E-PM" as *u8); return 0 } 102 pq_cpy(out, "E-MISC" as *u8) 103 return 0 104} 105 106// build the 7-field TAB record: id \t empire \t FLOATING \t 0 \t - \t - \t - (NUL-term). Returns length. 107func pq_build_record(id: *u8, empire: *u8, out: *u8) -> i64 { 108 var o: i64 = 0 109 o = fa_cat(out, o, id) 110 out[o] = 9 as u8; o = o + 1 111 o = fa_cat(out, o, empire) 112 o = fa_cat(out, o, "\tFLOATING\t0\t-\t-\t-\x00" as *u8) 113 return o 114} 115 116// build the "ws:" + id key (NUL-term). Returns length. 117func pq_build_key(id: *u8, out: *u8) -> i64 { 118 out[0] = 119 as u8 // 'w' 119 out[1] = 115 as u8 // 's' 120 out[2] = 58 as u8 // ':' 121 var t: i64 = 0 122 while id[t] != (0 as u8) { out[3 + t] = id[t]; t = t + 1 } 123 out[3 + t] = 0 as u8 124 return 3 + t 125} 126 127// 1 if the store value under `prefix` for `key` byte-equals NUL-term `val`. Drives the idempotent skip. 128// One-shot path (used by the seed-style verify); the HOT populate loop uses pq_streq_h below to avoid 129// re-reading every segment file 1251 times. 130func pq_streq_store(prefix: *u8, key: *u8, val: *u8) -> i64 { 131 let pq: *i64 = sys_mmap(16) as *i64 132 let lq: *i64 = sys_mmap(16) as *i64 133 if ss_get(prefix, key, pq, lq) != 1 { return 0 } 134 let b: *u8 = pq[0] as *u8 135 let n: i64 = lq[0] 136 let vl: i64 = pq_slen(val) 137 if n != vl { return 0 } 138 var i: i64 = 0 139 while i < n { if b[i] != val[i] { return 0 } i = i + 1 } 140 return 1 141} 142 143// HANDLE-BASED idempotency compare: 1 iff the OPEN-store snapshot `h` holds `key` byte-equal to `val`. 144// ss_open reads the manifest + every segment's .docs/.idx ONCE; ss_hget then does an in-memory 145// binary search with ZERO per-call file IO. This is the scalable read path -- the per-key ss_get 146// loop mmaps ~100 KB per call (1251 calls => >100 MB of un-freed mmaps), which starves the raw 147// bump-mmap and makes deep lookups read garbage (the 1162-mismatch idempotency bug). One snapshot 148// fixes it: a clean read of the whole registry, used for all 1251 compares. 149func pq_streq_h(h: *i64, key: *u8, val: *u8) -> i64 { 150 let pq: *i64 = sys_mmap(16) as *i64 151 let lq: *i64 = sys_mmap(16) as *i64 152 if ss_hget(h, key, pq, lq) != 1 { return 0 } 153 let b: *u8 = pq[0] as *u8 154 let n: i64 = lq[0] 155 let vl: i64 = pq_slen(val) 156 if n != vl { return 0 } 157 var i: i64 = 0 158 while i < n { if b[i] != val[i] { return 0 } i = i + 1 } 159 return 1 160} 161 162// collect every non-comment col0 id from the queue into ids_out[] (i64 ptrs to mmap'd NUL-term ids). 163// Line model is IDENTICAL to ws_audit_unregistered_p (skip '#'-lines, col0 up to TAB/newline, advance 164// past newline) so the populator registers exactly what the auditor would otherwise flag. Returns count. 165func pq_collect_ids(queue_path: *u8, ids_out: *i64, cap: i64) -> i64 { 166 let lenq: *i64 = sys_mmap(16) as *i64 167 let buf: *u8 = sys_read_file(queue_path, lenq) 168 if buf as i64 == 0 { return 0 - 1 } 169 let n: i64 = lenq[0] 170 var cnt: i64 = 0 171 var i: i64 = 0 172 while i < n { 173 let is_comment: i64 = (buf[i] == (35 as u8)) as i64 // '#' 174 let idbuf: *u8 = sys_mmap(256) 175 var o: i64 = 0 176 if is_comment == 0 { 177 var go: i64 = 1 178 while go == 1 { 179 if i >= n { go = 0 } 180 else { 181 if buf[i] == (9 as u8) { go = 0 } 182 else { if buf[i] == (10 as u8) { go = 0 } else { if o < 255 { idbuf[o] = buf[i]; o = o + 1 } i = i + 1 } } 183 } 184 } 185 idbuf[o] = 0 as u8 186 } 187 // advance i to the byte AFTER the next newline 188 var skip: i64 = 1 189 while skip == 1 { 190 if i >= n { skip = 0 } 191 else { if buf[i] == (10 as u8) { i = i + 1; skip = 0 } else { i = i + 1 } } 192 } 193 if is_comment == 0 { if o > 0 { if cnt < cap { ids_out[cnt] = idbuf as i64; cnt = cnt + 1 } } } 194 } 195 return cnt 196} 197 198// build the merged ws:ids index = existing ws:ids list + any collected id not already a member, 199// into out (NUL-term). Returns out length. Reuses ws_member for whole-token membership. Reads the 200// existing ws:ids from the OPEN-store handle `h` (zero per-call file IO). 201func pq_merge_ids(h: *i64, ids: *i64, nids: i64, out: *u8) -> i64 { 202 var o: i64 = 0 203 // start from the existing ws:ids (if any) 204 let pq: *i64 = sys_mmap(16) as *i64 205 let lq: *i64 = sys_mmap(16) as *i64 206 var cur: *u8 = "" as *u8 207 var curn: i64 = 0 208 if ss_hget(h, "ws:ids" as *u8, pq, lq) == 1 { cur = pq[0] as *u8; curn = lq[0] } 209 var t: i64 = 0 210 while t < curn { out[o] = cur[t]; o = o + 1; t = t + 1 } 211 out[o] = 0 as u8 212 // append each id not already present (whole-token check against the GROWING out buffer) 213 var i: i64 = 0 214 while i < nids { 215 let id: *u8 = ids[i] as *u8 216 if ws_member(out, o, id) == 0 { 217 if o > 0 { out[o] = 9 as u8; o = o + 1 } // TAB separator 218 var j: i64 = 0 219 while id[j] != (0 as u8) { out[o] = id[j]; o = o + 1; j = j + 1 } 220 out[o] = 0 as u8 221 } 222 i = i + 1 223 } 224 return o 225} 226 227// 1 iff NUL-term `a` byte-equals NUL-term `b`. 228func pq_id_eq(a: *u8, b: *u8) -> i64 { 229 var k: i64 = 0 230 while a[k] != (0 as u8) { if a[k] != b[k] { return 0 } k = k + 1 } 231 if b[k] != (0 as u8) { return 0 } 232 return 1 233} 234 235// register ONE id into writer `w` against snapshot `h` (idempotent skip via pq_streq_h). Tallies into 236// out4[1]=registered_new / out4[2]=skipped / out4[3]=errors. Kept as a SMALL function so nx_cc does not 237// hit the register-pressure ceiling that mis-compiles a single oversized populate body (rule 3: split, 238// don't patch). scratch keybuf/recbuf/empbuf are caller-owned (reused across ids). 239func pq_reg_one(h: *i64, w: *i64, id: *u8, keybuf: *u8, recbuf: *u8, empbuf: *u8, out4: *i64) -> i64 { 240 pq_empire_for(id, empbuf) 241 pq_build_key(id, keybuf) 242 let rlen: i64 = pq_build_record(id, empbuf, recbuf) 243 if pq_streq_h(h, keybuf, recbuf) == 1 { 244 out4[2] = out4[2] + 1 // unchanged -> idempotent skip 245 return 0 246 } 247 let rc: i64 = ss_add(w, 1, keybuf, recbuf, rlen) 248 if rc < 0 { out4[3] = out4[3] + 1; return rc } // buffer overflow -> error 249 out4[1] = out4[1] + 1 // staged a new version 250 return 0 251} 252 253// THE CORE: register every collected queue id (except an optional `omit` id, for the gate's neg-control) 254// into the registry under `prefix` in ONE writer buffer / ONE commit. Returns: 255// counters via out4[]: out4[0]=queued out4[1]=registered_new out4[2]=skipped out4[3]=errors 256// function return: 0 on success (commit ok or nothing-to-commit), <0 on a hard commit error. 257// `omit` = NUL-term id to deliberately skip (or 0 for none) -- proves the audit detects a gap. 258// stage the merged ws:ids index into writer `w` iff it changed (idempotent). Small helper. 259func pq_stage_ids(h: *i64, w: *i64, ids: *i64, nids: i64) -> i64 { 260 let mids: *u8 = sys_mmap(1048576) 261 let mlen: i64 = pq_merge_ids(h, ids, nids, mids) 262 if pq_streq_h(h, "ws:ids" as *u8, mids) == 0 { ss_add(w, 1, "ws:ids" as *u8, mids, mlen) } 263 return 0 264} 265 266// stage every per-id ws:<id> record into writer `w` (skipping `omit`). Small helper -- keeps the loop 267// body and its scratch buffers OUT of pq_populate_omit_p so nx_cc never crosses the function-size 268// ceiling that silently mis-compiles a fat body (rule 3: compose small functions, don't patch a big one). 269func pq_stage_records(h: *i64, w: *i64, ids: *i64, nids: i64, omit: *u8, out4: *i64) -> i64 { 270 let keybuf: *u8 = sys_mmap(512) 271 let recbuf: *u8 = sys_mmap(512) 272 let empbuf: *u8 = sys_mmap(64) 273 var has_omit: i64 = 0 274 if omit as i64 != 0 { has_omit = 1 } 275 var i: i64 = 0 276 while i < nids { 277 let id: *u8 = ids[i] as *u8 278 var skip_this: i64 = 0 279 if has_omit == 1 { if pq_id_eq(id, omit) == 1 { skip_this = 1 } } 280 if skip_this == 0 { pq_reg_one(h, w, id, keybuf, recbuf, empbuf, out4) } 281 i = i + 1 282 } 283 return 0 284} 285 286func pq_populate_omit_p(prefix: *u8, queue_path: *u8, omit: *u8, out4: *i64) -> i64 { 287 let ids: *i64 = sys_mmap(8 * POP_ID_CAP) as *i64 288 let nids: i64 = pq_collect_ids(queue_path, ids, POP_ID_CAP) 289 out4[0] = 0; out4[1] = 0; out4[2] = 0; out4[3] = 0 290 if nids < 0 { out4[3] = 1; return 0 - 1 } 291 out4[0] = nids 292 // SNAPSHOT the whole registry ONCE; all idempotency byte-compares read this in-memory handle. 293 let h: *i64 = ss_open(prefix) 294 let w: *i64 = ss_begin() 295 pq_stage_ids(h, w, ids, nids) 296 pq_stage_records(h, w, ids, nids, omit, out4) 297 // ONE commit for the whole batch (one new segment), iff anything was staged. 298 if w[1] > 0 { 299 let segid: i64 = ws_seg_next(prefix) 300 let crc: i64 = ss_commit(prefix, w, segid) 301 if crc != 0 { out4[3] = out4[3] + 1; return crc } 302 } 303 if out4[3] > 0 { return 0 - 2 } 304 return 0 305} 306 307// production convenience: populate the live WS_PREFIX, omit nothing. 308func pq_populate(out4: *i64) -> i64 { 309 return pq_populate_omit_p(WS_PREFIX, POP_QUEUE, 0 as *u8, out4) 310} 311 312// locked-atomic evidence logger (write discipline): ONE assembled buffer -> ONE fa_appendz, with a 313// UNIQUE scratch path so concurrent runs cannot collide. (Here we log directly to POP_LOG via the 314// atomic primitive; the gate uses the same idiom with its own unique scratch path.) 315func pq_log(out4: *i64, verdict_green: i64) -> i64 { 316 let buf: *u8 = sys_mmap(POP_REC_CAP + 16) 317 var o: i64 = 0 318 o = fa_cat(buf, o, "POP authored=organ ts=\x00" as *u8) 319 o = fa_catn(buf, o, sys_now_realtime_sec()) 320 o = fa_cat(buf, o, " queued=\x00" as *u8); o = fa_catn(buf, o, out4[0]) 321 o = fa_cat(buf, o, " registered_new=\x00" as *u8); o = fa_catn(buf, o, out4[1]) 322 o = fa_cat(buf, o, " skipped=\x00" as *u8); o = fa_catn(buf, o, out4[2]) 323 o = fa_cat(buf, o, " errors=\x00" as *u8); o = fa_catn(buf, o, out4[3]) 324 if verdict_green == 1 { o = fa_cat(buf, o, " verdict=GREEN\x00" as *u8) } 325 else { o = fa_cat(buf, o, " verdict=RED\x00" as *u8) } 326 return fa_appendz(POP_LOG, buf, POP_REC_CAP) 327} 328 329// NOTE: this file is a pure LIB (no main) so the gate can import it. The runnable driver lives in 330// nx_workstream_popqueue_run.nx (the harness basename to build+run for a standalone population).