code wiki / _hdl_build / nx_wd_core.nx

nx_wd_core.nx source

↩ module page · 440 lines · 16519 B

1// nx_wd_core.nx -- DISPATCH-ACT CORE (mainless): the Warden's attempt loop 2// over the assignment queue (X-Q-003 rung 1; spec 2026-06-11-sclass-exceed- 3// backlog.md ADDENDUM Q3). RACI: Warden verb = ATTEMPT/route. This core 4// owns NO priority (PM's w column), NO sequencing policy (an_pick is the 5// Conductor's, imported), NO done-judging (nx_reconcile owns DONE flips on 6// MARK evidence -- this core RUNS reconcile and READS the queue back). 7// 8// THE BEAT (wd_beat), bounded to <=1 raise + <=1 attempt per call: 9// pick = an_pick (highest-w runnable TODO) 10// pick has ||EXEC=<organ> recipe -> ATTEMPT: lane-build+run the organ 11// (deadline-guarded, hang-proof), run nx_reconcile, re-read the queue; 12// row DONE -> ASSIGNRESULT verdict=GREEN 13// row !DONE -> flip row RED (fail-loud, no livelock) + verdict=RED 14// pick has no recipe -> RAISE: flip row TODO->NOVEL (tutor batch picks it 15// up -- "a RAISED-HAND row instead of a silent stall") AND still 16// attempt the best EXEC-covered runnable row so the beat does work. 17// Rung 2 (filed as its own queue row): covered-SHAPE routing via the warden 18// pattern classifier -> emitter lanes; this rung covers the EXEC-recipe class 19// (the X-EX-001 convention) only, and ASSIGNRESULT route= says which. 20// 21// Trust boundary (defensive at boundary law): EXEC basenames come from a 22// hand-curated TSV but are validated anyway -- [a-z0-9_] only, 1..63 chars, 23// so a recipe can never path-escape the lane's source resolution. 24// Queue rewrites change line length (TODO->NOVEL grows, TODO->RED shrinks); 25// sys_openat_wr has no O_TRUNC, so shrink pads trailing '\n' bytes -- an_load 26// and the line-walkers all skip empty lines (verified against their parsers). 27// license_tier: ORIGINAL 28 29import "nx_syscalls.nx" 30import "nx_itoa_lib.nx" // shared MSB-first emitter (zero-alloc) 31import "nx_assign_core.nx" 32import "nx_guarded_run.nx" 33const WD_MAGIC_1048576: i64 = 1048576 34const WD_MAGIC_1048575: i64 = 1048575 35const WD_MAGIC_4096: i64 = 4096 36const WD_MAGIC_4095: i64 = 4095 37 38const WD_DEADLINE_DEFAULT: i64 = 600000 // ms; overridden by work_dispatcher.conf exec_deadline_ms= 39const WD_EXECCAP: i64 = 64 40 41// wcx block: wcx[0]=queue path wcx[1]=results log path wcx[2]=lane elf path 42// wcx[3]=reconcile elf path wcx[4]=deadline ms wcx[5]=open results fd 43// wcx[6]=auto-builder elf path (the SPEC route: X-Q-006 rung "rows that BUILD") 44func wd_newwcx(qp: *u8, respath: *u8, lane: *u8, rec: *u8, ab: *u8, dl: i64) -> *i64 { 45 let w: *i64 = sys_mmap(64) as *i64 46 w[0] = qp as i64 47 w[1] = respath as i64 48 w[2] = lane as i64 49 w[3] = rec as i64 50 w[4] = dl 51 w[5] = 0 - 1 52 w[6] = ab as i64 53 return w 54} 55 56func wd_w(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 } 57// MIGRATED to the shared emitter (debt 1785563586). The old body mmapped a scratch buffer 58// per call and never freed it. At PAGE granularity that is 4096B leaked PER CALL -- the 59// defect that took 28.5GB of a 36GB host in nx_ts_lumadiff (2MB input, ~3.66M calls). 60// nxi_* is MSB-first, allocates NOTHING, and emits identical bytes including the sign. 61func wd_wn(fd: i64, v: i64) -> i64 { nxi_fd(fd, v); return 0 } 62 63func wd_both(wcx: *i64, s: *u8) -> i64 { 64 wd_w(1, s) 65 let fd: i64 = wcx[5] 66 if fd >= 0 { wd_w(fd, s) } 67 return 0 68} 69 70func wd_bothn(wcx: *i64, v: i64) -> i64 { 71 wd_wn(1, v) 72 let fd: i64 = wcx[5] 73 if fd >= 0 { wd_wn(fd, v) } 74 return 0 75} 76 77// pattern-at: does buf[i..] start with pat (pl bytes)? (rc_at shape) 78func wd_at(buf: *u8, n: i64, i: i64, pat: *u8, pl: i64) -> i64 { 79 if i + pl > n { return 0 } 80 var k: i64 = 0 81 while k < pl { if buf[i + k] != pat[k] { return 0 } k = k + 1 } 82 return 1 83} 84 85// extract ||EXEC=<basename> from a gate cell into out (cap WD_EXECCAP). 86// returns 1 valid recipe, 0 none-or-invalid. Charset law: [a-z0-9_] only. 87func wd_exec_name(gate: *u8, out: *u8) -> i64 { 88 var gl: i64 = 0 89 while gate[gl] != (0 as u8) { gl = gl + 1 } 90 var i: i64 = 0 91 var at: i64 = 0 - 1 92 while i < gl { 93 if wd_at(gate, gl, i, "||EXEC=" as *u8, 7) == 1 { at = i + 7; i = gl } else { i = i + 1 } 94 } 95 if at < 0 { return 0 } 96 var k: i64 = 0 97 var go: i64 = 1 98 while go == 1 { 99 let ch: i64 = gate[at + k] as i64 100 var stop: i64 = 0 101 if ch == 0 { stop = 1 } 102 if ch == 9 { stop = 1 } 103 if ch == 124 { stop = 1 } 104 if stop == 1 { go = 0 } else { 105 var okc: i64 = 0 106 if ch >= 97 { if ch <= 122 { okc = 1 } } 107 if ch >= 48 { if ch <= 57 { okc = 1 } } 108 if ch == 95 { okc = 1 } 109 if okc == 0 { return 0 } 110 if k >= WD_EXECCAP - 1 { return 0 } 111 out[k] = ch as u8 112 k = k + 1 113 } 114 } 115 if k == 0 { return 0 } 116 out[k] = 0 as u8 117 return 1 118} 119 120const WD_SPECCAP: i64 = 192 121 122// extract ||SPEC=<specfile> from a gate cell into out (cap WD_SPECCAP). 123// returns 1 valid, 0 none-or-invalid. Trust boundary: the path must live 124// under knowledge/specs/ (no traversal -- ".." rejected), charset 125// [a-z0-9_/.-] only, so a row can never route the builder outside the tree. 126func wd_spec_name(gate: *u8, out: *u8) -> i64 { 127 var gl: i64 = 0 128 while gate[gl] != (0 as u8) { gl = gl + 1 } 129 var i: i64 = 0 130 var at: i64 = 0 - 1 131 while i < gl { 132 if wd_at(gate, gl, i, "||SPEC=" as *u8, 7) == 1 { at = i + 7; i = gl } else { i = i + 1 } 133 } 134 if at < 0 { return 0 } 135 var k: i64 = 0 136 var go: i64 = 1 137 while go == 1 { 138 let ch: i64 = gate[at + k] as i64 139 var stop: i64 = 0 140 if ch == 0 { stop = 1 } 141 if ch == 9 { stop = 1 } 142 if ch == 124 { stop = 1 } 143 if stop == 1 { go = 0 } else { 144 var okc: i64 = 0 145 if ch >= 97 { if ch <= 122 { okc = 1 } } 146 if ch >= 48 { if ch <= 57 { okc = 1 } } 147 if ch == 95 { okc = 1 } 148 if ch == 47 { okc = 1 } 149 if ch == 46 { okc = 1 } 150 if ch == 45 { okc = 1 } 151 if okc == 0 { return 0 } 152 if k >= WD_SPECCAP - 1 { return 0 } 153 out[k] = ch as u8 154 k = k + 1 155 } 156 } 157 if k == 0 { return 0 } 158 out[k] = 0 as u8 159 if wd_at(out, k, 0, "knowledge/specs/" as *u8, 16) != 1 { return 0 } 160 var j: i64 = 0 161 while j + 1 < k { 162 if out[j] == (46 as u8) { if out[j + 1] == (46 as u8) { return 0 } } 163 j = j + 1 164 } 165 return 1 166} 167 168// is row r covered (carries a valid EXEC recipe or SPEC build)? 169func wd_covered(cx: *i64, r: i64) -> i64 { 170 let tmp: *u8 = sys_mmap(WD_SPECCAP) 171 if wd_exec_name(an_gate_at(cx, r), tmp) == 1 { return 1 } 172 if wd_spec_name(an_gate_at(cx, r), tmp) == 1 { return 1 } 173 return 0 174} 175 176// rewrite the queue file flipping row <id>'s status field (field index 5) to 177// newst. Whole-file read -> patch into a second buffer -> write back; if the 178// patched file is SHORTER, pad with '\n' (no O_TRUNC in the syscall wrapper; 179// empty lines are invisible to every queue parser). Returns 1 flipped, 0 not. 180func wd_flip_status(qp: *u8, id: *u8, newst: *u8) -> i64 { 181 let buf: *u8 = sys_mmap(WD_MAGIC_1048576) 182 let fd: i64 = sys_openat_rd(qp) 183 if fd < 0 { return 0 } 184 var n: i64 = 0 185 var r: i64 = sys_read(fd, buf, WD_MAGIC_1048575) 186 while r > 0 { n = n + r; r = sys_read(fd, buf + n, WD_MAGIC_1048575 - n) } 187 sys_close(fd) 188 var idl: i64 = 0 189 while id[idl] != (0 as u8) { idl = idl + 1 } 190 var nsl: i64 = 0 191 while newst[nsl] != (0 as u8) { nsl = nsl + 1 } 192 let out: *u8 = sys_mmap(WD_MAGIC_1048576 + 64) 193 var o: i64 = 0 194 var hit: i64 = 0 195 var ls: i64 = 0 196 var i: i64 = 0 197 while i <= n { 198 var eol: i64 = 0 199 if i == n { eol = 1 } else { if buf[i] == (10 as u8) { eol = 1 } } 200 if eol == 1 { 201 var mrow: i64 = 0 202 if wd_at(buf, n, ls, id, idl) == 1 { 203 if ls + idl < n { if buf[ls + idl] == (9 as u8) { mrow = 1 } } 204 } 205 if mrow == 1 { 206 if hit == 0 { 207 hit = 1 208 // copy fields 0..4 verbatim (5 tabs), swap field 5, copy rest 209 var tabs: i64 = 0 210 var j: i64 = ls 211 while tabs < 5 { 212 if j >= i { tabs = 5 } else { 213 out[o] = buf[j] 214 if buf[j] == (9 as u8) { tabs = tabs + 1 } 215 o = o + 1 216 j = j + 1 217 } 218 } 219 var k: i64 = 0 220 while k < nsl { out[o] = newst[k]; o = o + 1; k = k + 1 } 221 // skip the old status field content 222 var sk: i64 = 1 223 while sk == 1 { 224 if j >= i { sk = 0 } else { 225 if buf[j] == (9 as u8) { sk = 0 } else { j = j + 1 } 226 } 227 } 228 while j < i { out[o] = buf[j]; o = o + 1; j = j + 1 } 229 } else { 230 var j2: i64 = ls 231 while j2 < i { out[o] = buf[j2]; o = o + 1; j2 = j2 + 1 } 232 } 233 } else { 234 var j3: i64 = ls 235 while j3 < i { out[o] = buf[j3]; o = o + 1; j3 = j3 + 1 } 236 } 237 if i < n { out[o] = 10 as u8; o = o + 1 } 238 ls = i + 1 239 } 240 i = i + 1 241 } 242 if hit == 0 { return 0 } 243 while o < n { out[o] = 10 as u8; o = o + 1 } 244 let wf: i64 = sys_openat_wr(qp, 0x1a4) 245 if wf < 0 { return 0 } 246 var off: i64 = 0 247 while off < o { let w2: i64 = sys_write(wf, out + off, o - off); if w2 <= 0 { off = o } else { off = off + w2 } } 248 sys_close(wf) 249 return 1 250} 251 252// the best runnable TODO row that is COVERED (EXEC recipe or SPEC build): 253// an_pick variant -- highest w, deps DONE. -1 if none. 254func wd_pick_covered(cx: *i64) -> i64 { 255 let wv: *i64 = cx[3] as *i64 256 let st: *i64 = cx[4] as *i64 257 let sz: *i64 = cx[5] as *i64 258 var best: i64 = 0 - 1 259 var r: i64 = 0 260 while r < cx[0] { 261 if st[r] == 84 { 262 if wd_covered(cx, r) == 1 { 263 if an_deps_done(cx, r) == 1 { 264 var take: i64 = 0 265 if best < 0 { take = 1 } else { 266 if wv[r] > wv[best] { take = 1 } 267 if wv[r] == wv[best] { if sz[r] < sz[best] { take = 1 } } 268 } 269 if take == 1 { best = r } 270 } 271 } 272 } 273 r = r + 1 274 } 275 return best 276} 277 278// spawn elf with ONE argument under the wcx deadline (hang-proof; composes 279// nx_guarded_run -- SIGKILL reap, rc=124 timeout convention). 280func wd_spawn2(wcx: *i64, elf: *u8, a1: *u8) -> i64 { 281 let argv: *i64 = sys_mmap(32) as *i64 282 argv[0] = elf as i64 283 argv[1] = a1 as i64 284 argv[2] = 0 285 let envp: *i64 = sys_mmap(32) as *i64 286 envp[0] = "PATH=/usr/bin:/bin" as *u8 as i64 287 envp[1] = 0 288 let neg: i64 = 0 - 1 289 return nx_guarded_run(elf, argv, envp, wcx[4], neg, neg) 290} 291 292// one ASSIGNRESULT row (stdout + results log): the attempt audit trail. 293func wd_result(wcx: *i64, id: *u8, route: *u8, verdict: *u8, rc: i64) -> i64 { 294 wd_both(wcx, "ASSIGNRESULT id=" as *u8) 295 wd_both(wcx, id) 296 wd_both(wcx, " route=" as *u8) 297 wd_both(wcx, route) 298 wd_both(wcx, " verdict=" as *u8) 299 wd_both(wcx, verdict) 300 wd_both(wcx, " rc=" as *u8) 301 wd_bothn(wcx, rc) 302 wd_both(wcx, " epoch=" as *u8) 303 wd_bothn(wcx, sys_now_realtime_sec()) 304 wd_both(wcx, "\n" as *u8) 305 return 0 306} 307 308// ATTEMPT one covered row end to end: run <elf a1> (the route's act), then 309// the status-keeper (nx_reconcile), then re-read the queue. Returns 0 GREEN, 310// 1 RED. Judgment is EVIDENCE ONLY -- the row is GREEN iff reconcile flipped 311// it DONE on its own MARK evaluation. An act that exits 0 but never turns 312// its marker green is a LIAR and goes RED. 313func wd_attempt(wcx: *i64, id: *u8, elf: *u8, a1: *u8, route: *u8) -> i64 { 314 let qp: *u8 = wcx[0] as *u8 315 let echk: i64 = sys_openat_rd(elf) 316 if echk < 0 { 317 wd_result(wcx, id, route, "RED-act-elf-absent" as *u8, 127) 318 return 1 319 } 320 sys_close(echk) 321 let rc_run: i64 = wd_spawn2(wcx, elf, a1) 322 let chk: i64 = sys_openat_rd(wcx[3] as *u8) 323 if chk < 0 { 324 wd_result(wcx, id, route, "RED-reconcile-elf-absent" as *u8, rc_run) 325 return 1 326 } 327 sys_close(chk) 328 wd_spawn2(wcx, wcx[3] as *u8, qp) 329 let cx2: *i64 = an_newcx() 330 let rows: i64 = an_load(qp, cx2) 331 if rows <= 0 { 332 wd_result(wcx, id, route, "RED-queue-reload-failed" as *u8, rc_run) 333 return 1 334 } 335 let r2: i64 = an_find(cx2, id) 336 if r2 >= 0 { 337 let st: *i64 = cx2[4] as *i64 338 if st[r2] == 68 { 339 wd_result(wcx, id, route, "GREEN" as *u8, rc_run) 340 return 0 341 } 342 } 343 wd_flip_status(qp, id, "RED" as *u8) 344 wd_result(wcx, id, route, "RED" as *u8, rc_run) 345 return 1 346} 347 348// route one covered row by its kind: EXEC -> the durable lane rebuilds+runs 349// the recipe organ; SPEC -> the durable auto-builder authors+gates the 350// module from the spec file (classifier-routed emitter lanes: rows that 351// BUILD). Returns wd_attempt's verdict; 1 if the row turned out uncovered 352// (caller bug -- fail loud). 353func wd_route_attempt(wcx: *i64, cx: *i64, r: i64) -> i64 { 354 let idbuf: *u8 = sys_mmap(64) 355 let pid: *u8 = an_id_at(cx, r) 356 var ci: i64 = 0 357 while pid[ci] != (0 as u8) { idbuf[ci] = pid[ci]; ci = ci + 1 } 358 idbuf[ci] = 0 as u8 359 let arg: *u8 = sys_mmap(WD_SPECCAP) 360 if wd_exec_name(an_gate_at(cx, r), arg) == 1 { 361 return wd_attempt(wcx, idbuf, wcx[2] as *u8, arg, "EXEC" as *u8) 362 } 363 if wd_spec_name(an_gate_at(cx, r), arg) == 1 { 364 return wd_attempt(wcx, idbuf, wcx[6] as *u8, arg, "SPEC" as *u8) 365 } 366 wd_result(wcx, idbuf, "NONE" as *u8, "RED-uncovered-routed" as *u8, 0) 367 return 1 368} 369 370// THE BEAT. Returns 0 healthy (work done, raised, or idle), 1 attempt RED, 371// 101 queue missing. Bounded: <=1 raise + <=1 attempt per call. 372func wd_beat(wcx: *i64) -> i64 { 373 let qp: *u8 = wcx[0] as *u8 374 let cx: *i64 = an_newcx() 375 let rows: i64 = an_load(qp, cx) 376 if rows <= 0 { 377 wd_w(1, "ASSIGNRESULT id=NONE route=NONE verdict=RED-queue-missing\n" as *u8) 378 return 101 379 } 380 let lfd: i64 = sys_openat_append(wcx[1] as *u8, 0x1a4) 381 wcx[5] = lfd 382 var bad: i64 = 0 383 let p: i64 = an_pick(cx) 384 if p < 0 { 385 wd_result(wcx, "NONE-RUNNABLE" as *u8, "NONE" as *u8, "IDLE" as *u8, 0) 386 } else { 387 if wd_covered(cx, p) == 1 { 388 bad = wd_route_attempt(wcx, cx, p) 389 } else { 390 let idbuf: *u8 = sys_mmap(64) 391 let pid: *u8 = an_id_at(cx, p) 392 var ci: i64 = 0 393 while pid[ci] != (0 as u8) { idbuf[ci] = pid[ci]; ci = ci + 1 } 394 idbuf[ci] = 0 as u8 395 wd_flip_status(qp, idbuf, "NOVEL" as *u8) 396 wd_result(wcx, idbuf, "NOVEL" as *u8, "RAISED" as *u8, 0) 397 let pe: i64 = wd_pick_covered(cx) 398 if pe >= 0 { bad = wd_route_attempt(wcx, cx, pe) } 399 } 400 } 401 if lfd >= 0 { sys_close(lfd) } 402 return bad 403} 404 405// deadline from knowledge/registry/work_dispatcher.conf (exec_deadline_ms=N); 406// bootstrap default when the conf or key is absent (config-hierarchy law). 407func wd_conf_deadline(path: *u8) -> i64 { 408 let buf: *u8 = sys_mmap(WD_MAGIC_4096) 409 let fd: i64 = sys_openat_rd(path) 410 if fd < 0 { return WD_DEADLINE_DEFAULT } 411 var n: i64 = 0 412 var r: i64 = sys_read(fd, buf, WD_MAGIC_4095) 413 while r > 0 { n = n + r; r = sys_read(fd, buf + n, WD_MAGIC_4095 - n) } 414 sys_close(fd) 415 let key: *u8 = "exec_deadline_ms=" as *u8 416 var i: i64 = 0 417 var at: i64 = 0 - 1 418 while i < n { 419 if wd_at(buf, n, i, key, 17) == 1 { at = i + 17; i = n } else { i = i + 1 } 420 } 421 if at < 0 { return WD_DEADLINE_DEFAULT } 422 var v: i64 = 0 423 var any: i64 = 0 424 var go: i64 = 1 425 while go == 1 { 426 if at >= n { go = 0 } else { 427 let ch: i64 = buf[at] as i64 428 if ch >= 48 { 429 if ch <= 57 { 430 v = v * 10 + (ch - 48) 431 any = 1 432 at = at + 1 433 } else { go = 0 } 434 } else { go = 0 } 435 } 436 } 437 if any == 0 { return WD_DEADLINE_DEFAULT } 438 if v < 1000 { return WD_DEADLINE_DEFAULT } 439 return v 440}