code wiki / _hdl_build / nx_assign_core.nx

nx_assign_core.nx source

↩ module page · 336 lines · 12237 B

1// nx_assign_core.nx -- DISPATCH CORE (mainless): parse assignment_queue.tsv 2// and answer the three questions the team loop needs every beat: 3// 1. an_pick(...) -- the next assignment: highest w, status TODO, all 4// deps DONE; ties -> smaller size, then file order. 5// (w is ADVISORY -- Claude's viewpoint column.) 6// 2. an_top_blocker(...)-- the STRUCTURAL view: the open row with the most 7// direct dependents (the dep graph's own opinion of 8// "largest blocker"). Where structure and w 9// disagree, the caller prints VIEWPOINT-DISCREPANCY 10// -- the operator reviews the diff, nobody hides it. 11// 3. an_novel(...) -- raised hands: NOVEL rows are the tutor queue (the 12// only work that costs Claude tokens; batching them 13// is the token-efficiency lever). 14// Queue grammar: knowledge/registry/assignment_queue.tsv -- 9 tab fields: 15// id rung w size owner status deps gate title ('#' lines skipped) 16// status by FIRST BYTE: T=TODO G=GEN N=NOVEL W=WIP D=DONE R=RED. 17// license_tier: ORIGINAL 18 19import "nx_syscalls.nx" 20const AN_MAGIC_1048576: i64 = 1048576 21const AN_MAGIC_1048575: i64 = 1048575 22 23const AN_MAX_ROWS: i64 = 1024 24const AN_IDCAP: i64 = 32 25const AN_DEPCAP: i64 = 128 26 27// context block layout (caller mmaps 1 block, passes everywhere): 28// cx[0]=nrows cx[1]=ids arena ptr cx[2]=deps arena ptr 29// cx[3]=w[] ptr cx[4]=status[] ptr cx[5]=sizerank[] ptr cx[6]=depcount[] ptr 30func an_newcx() -> *i64 { 31 let cx: *i64 = sys_mmap(128) as *i64 32 cx[0] = 0 33 cx[1] = sys_mmap(AN_MAX_ROWS * AN_IDCAP) as i64 34 cx[2] = sys_mmap(AN_MAX_ROWS * AN_DEPCAP) as i64 35 cx[3] = sys_mmap(AN_MAX_ROWS * 8) as i64 36 cx[4] = sys_mmap(AN_MAX_ROWS * 8) as i64 37 cx[5] = sys_mmap(AN_MAX_ROWS * 8) as i64 38 cx[6] = sys_mmap(AN_MAX_ROWS * 8) as i64 39 cx[7] = sys_mmap(AN_MAX_ROWS * 192) as i64 // gate cells (incl ||MARK ||EXEC suffixes) 40 cx[8] = sys_mmap(AN_MAX_ROWS * 128) as i64 // titles 41 return cx 42} 43 44func an_gate_at(cx: *i64, r: i64) -> *u8 { 45 return ((cx[7]) + r * 192) as *u8 46} 47 48func an_title_at(cx: *i64, r: i64) -> *u8 { 49 return ((cx[8]) + r * 128) as *u8 50} 51 52func an_id_at(cx: *i64, r: i64) -> *u8 { 53 return ((cx[1]) + r * AN_IDCAP) as *u8 54} 55 56func an_deps_at(cx: *i64, r: i64) -> *u8 { 57 return ((cx[2]) + r * AN_DEPCAP) as *u8 58} 59 60func an_streq(a: *u8, b: *u8) -> i64 { 61 var i: i64 = 0 62 var go: i64 = 1 63 while go == 1 { 64 if a[i] != b[i] { return 0 } 65 if a[i] == (0 as u8) { return 1 } 66 i = i + 1 67 if i >= 64 { go = 0 } 68 } 69 return 1 70} 71 72// parse the queue file into the context; returns row count (0 = fail-loud) 73func an_load(path: *u8, cx: *i64) -> i64 { 74 let buf: *u8 = sys_mmap(AN_MAGIC_1048576) 75 let fd: i64 = sys_openat_rd(path) 76 if fd < 0 { return 0 } 77 var n: i64 = 0 78 var r: i64 = sys_read(fd, buf, AN_MAGIC_1048575) 79 while r > 0 { n = n + r; r = sys_read(fd, buf + n, AN_MAGIC_1048575 - n) } 80 sys_close(fd) 81 let wv: *i64 = cx[3] as *i64 82 let st: *i64 = cx[4] as *i64 83 let sz: *i64 = cx[5] as *i64 84 var rows: i64 = 0 85 var i: i64 = 0 86 while i < n { 87 if buf[i] == (35 as u8) { 88 // comment: skip past the newline 89 var sk: i64 = 1 90 while sk == 1 { 91 if i >= n { sk = 0 } else { 92 if buf[i] == (10 as u8) { sk = 0 } 93 i = i + 1 94 } 95 } 96 } else { 97 // parse 9 tab fields; capture 0=id 2=w 3=size 5=status 6=deps 98 var f: i64 = 0 99 var fs: i64 = i 100 var idok: i64 = 0 101 while f < 9 { 102 var fe: i64 = fs 103 var scan: i64 = 1 104 while scan == 1 { 105 if fe >= n { scan = 0 } else { 106 if buf[fe] == (9 as u8) { scan = 0 } else { 107 if buf[fe] == (10 as u8) { scan = 0 } else { fe = fe + 1 } 108 } 109 } 110 } 111 let flen: i64 = fe - fs 112 if f == 0 { 113 if flen > 0 { 114 if flen < AN_IDCAP { 115 let dst: *u8 = an_id_at(cx, rows) 116 var k: i64 = 0 117 while k < flen { dst[k] = buf[fs + k]; k = k + 1 } 118 dst[flen] = 0 as u8 119 idok = 1 120 } 121 } 122 } 123 if f == 2 { 124 var v: i64 = 0 125 var q: i64 = fs 126 while q < fe { 127 if buf[q] >= (48 as u8) { if buf[q] <= (57 as u8) { v = v * 10 + ((buf[q] as i64) - 48) } } 128 q = q + 1 129 } 130 wv[rows] = v 131 } 132 if f == 3 { 133 var srk: i64 = 3 134 if flen > 0 { 135 if buf[fs] == (83 as u8) { srk = 0 } // S 136 if buf[fs] == (77 as u8) { srk = 1 } // M 137 if buf[fs] == (76 as u8) { srk = 2 } // L 138 } 139 sz[rows] = srk 140 } 141 if f == 5 { 142 var sc: i64 = 0 143 if flen > 0 { sc = buf[fs] as i64 } 144 // GRAMMAR FIX (2026-06-13): status was keyed by FIRST BYTE, so a CUSTOM 145 // status starting 'D' (e.g. "DAEMON-SIL") was misread as DONE by every 146 // consumer (an_pick, an_deps_done, capability ladder) -- a floating 147 // foundation under the whole queue. Only the exact word "DONE" is DONE; 148 // a D-prefixed non-DONE status -> '?' (63) sentinel (not DONE, not any 149 // active status). Surgical: changes ONLY D-prefixed non-DONE rows; every 150 // standard status (T/G/N/W/D/R/V) keeps its first-byte code unchanged. 151 if sc == 68 { 152 var isdone: i64 = 1 153 if flen != 4 { isdone = 0 } else { 154 if buf[fs+1] != (79 as u8) { isdone = 0 } // O 155 if buf[fs+2] != (78 as u8) { isdone = 0 } // N 156 if buf[fs+3] != (69 as u8) { isdone = 0 } // E 157 } 158 if isdone == 0 { sc = 63 } 159 } 160 st[rows] = sc // canonical status byte ('?'=63 for D-non-DONE) 161 } 162 if f == 6 { 163 let dd: *u8 = an_deps_at(cx, rows) 164 var k2: i64 = 0 165 while k2 < flen { if k2 < AN_DEPCAP - 1 { dd[k2] = buf[fs + k2] } k2 = k2 + 1 } 166 var dl: i64 = flen 167 if dl > AN_DEPCAP - 1 { dl = AN_DEPCAP - 1 } 168 dd[dl] = 0 as u8 169 } 170 if f == 7 { 171 let gg: *u8 = an_gate_at(cx, rows) 172 var k3: i64 = 0 173 while k3 < flen { if k3 < 191 { gg[k3] = buf[fs + k3] } k3 = k3 + 1 } 174 var gl: i64 = flen 175 if gl > 191 { gl = 191 } 176 gg[gl] = 0 as u8 177 } 178 if f == 8 { 179 let tt: *u8 = an_title_at(cx, rows) 180 var k4: i64 = 0 181 while k4 < flen { if k4 < 127 { tt[k4] = buf[fs + k4] } k4 = k4 + 1 } 182 var tl: i64 = flen 183 if tl > 127 { tl = 127 } 184 tt[tl] = 0 as u8 185 } 186 fs = fe + 1 187 if fe < n { if buf[fe] == (10 as u8) { f = 9; fs = fe + 1 } } 188 f = f + 1 189 if fs > n { f = 9 } 190 } 191 // advance i to fs (start of next line) 192 i = fs 193 if idok == 1 { 194 if rows < AN_MAX_ROWS - 1 { rows = rows + 1 } 195 } 196 } 197 } 198 cx[0] = rows 199 return rows 200} 201 202// find row index by id; -1 if absent 203func an_find(cx: *i64, id: *u8) -> i64 { 204 var r: i64 = 0 205 while r < cx[0] { 206 if an_streq(an_id_at(cx, r), id) == 1 { return r } 207 r = r + 1 208 } 209 return 0 - 1 210} 211 212// are all deps of row r DONE? deps "-" = yes; unknown dep id = NO (blocked loud) 213func an_deps_done(cx: *i64, r: i64) -> i64 { 214 let dd: *u8 = an_deps_at(cx, r) 215 if dd[0] == (45 as u8) { if dd[1] == (0 as u8) { return 1 } } 216 let st: *i64 = cx[4] as *i64 217 let tok: *u8 = sys_mmap(AN_IDCAP) 218 var i: i64 = 0 219 var k: i64 = 0 220 var go: i64 = 1 221 while go == 1 { 222 let ch: i64 = dd[i] as i64 223 var fin: i64 = 0 224 if ch == 0 { fin = 1 } 225 if ch == 44 { fin = 1 } 226 if fin == 1 { 227 if k > 0 { 228 tok[k] = 0 as u8 229 let dr: i64 = an_find(cx, tok) 230 if dr < 0 { return 0 } 231 if st[dr] != 68 { return 0 } // 'D' 232 k = 0 233 } 234 if ch == 0 { go = 0 } 235 } else { 236 if k < AN_IDCAP - 1 { tok[k] = ch as u8; k = k + 1 } 237 } 238 i = i + 1 239 } 240 return 1 241} 242 243// the pick: highest w TODO with deps done; ties smaller size then file order. 244// returns row idx or -1. 245func an_pick(cx: *i64) -> i64 { 246 let wv: *i64 = cx[3] as *i64 247 let st: *i64 = cx[4] as *i64 248 let sz: *i64 = cx[5] as *i64 249 var best: i64 = 0 - 1 250 var r: i64 = 0 251 while r < cx[0] { 252 if st[r] == 84 { // 'T' 253 if an_deps_done(cx, r) == 1 { 254 var take: i64 = 0 255 if best < 0 { take = 1 } else { 256 if wv[r] > wv[best] { take = 1 } 257 if wv[r] == wv[best] { if sz[r] < sz[best] { take = 1 } } 258 } 259 if take == 1 { best = r } 260 } 261 } 262 r = r + 1 263 } 264 return best 265} 266 267// structural view: count direct dependents of every OPEN row; returns the 268// open row idx with the most dependents (-1 if none have any). 269func an_top_blocker(cx: *i64) -> i64 { 270 let st: *i64 = cx[4] as *i64 271 let dc: *i64 = cx[6] as *i64 272 var r: i64 = 0 273 while r < cx[0] { dc[r] = 0; r = r + 1 } 274 let tok: *u8 = sys_mmap(AN_IDCAP) 275 r = 0 276 while r < cx[0] { 277 let dd: *u8 = an_deps_at(cx, r) 278 var i: i64 = 0 279 var k: i64 = 0 280 var go: i64 = 1 281 while go == 1 { 282 let ch: i64 = dd[i] as i64 283 var fin: i64 = 0 284 if ch == 0 { fin = 1 } 285 if ch == 44 { fin = 1 } 286 if fin == 1 { 287 if k > 0 { 288 tok[k] = 0 as u8 289 if tok[0] != (45 as u8) { 290 let dr: i64 = an_find(cx, tok) 291 if dr >= 0 { dc[dr] = dc[dr] + 1 } 292 } 293 k = 0 294 } 295 if ch == 0 { go = 0 } 296 } else { 297 if k < AN_IDCAP - 1 { tok[k] = ch as u8; k = k + 1 } 298 } 299 i = i + 1 300 } 301 r = r + 1 302 } 303 var best: i64 = 0 - 1 304 r = 0 305 while r < cx[0] { 306 var open: i64 = 0 307 if st[r] == 84 { open = 1 } // TODO 308 if st[r] == 78 { open = 1 } // NOVEL 309 if st[r] == 87 { open = 1 } // WIP 310 if open == 1 { 311 if dc[r] > 0 { 312 var take: i64 = 0 313 if best < 0 { take = 1 } else { if dc[r] > dc[best] { take = 1 } } 314 if take == 1 { best = r } 315 } 316 } 317 r = r + 1 318 } 319 return best 320} 321 322// raised hands: count NOVEL rows; first NOVEL idx into out[0] (-1 if none) 323func an_novel(cx: *i64, out: *i64) -> i64 { 324 let st: *i64 = cx[4] as *i64 325 out[0] = 0 - 1 326 var cnt: i64 = 0 327 var r: i64 = 0 328 while r < cx[0] { 329 if st[r] == 78 { 330 if out[0] < 0 { out[0] = r } 331 cnt = cnt + 1 332 } 333 r = r + 1 334 } 335 return cnt 336}