code wiki / _hdl_build / nx_capgraph_derive_lib.nx

nx_capgraph_derive_lib.nx source

↩ module page · 508 lines · 16730 B

1// nx_capgraph_derive_lib.nx -- pure core for nx_capgraph_derive: level thresholds, row parsing, 2// the progress-rail snapshot compare, and the history reader. 3// 4// SPLIT OUT 2026-07-31 for the SAME reason as nx_capgraph_edges_lib: these helpers sat beside a main() 5// and were therefore unreachable from any gate, which pinned the progress rail at level 2 (WORKS) on 6// this system's own ladder. Gating the edges organ but not this one would have been applying the 7// standard selectively -- exactly the kind of convenient inconsistency this arc exists to catch. 8// license_tier: ORIGINAL No hw writes (Rule 26). 9import "nx_capgraph_lib.nx" 10import "nx_tool_run.nx" 11 12const CD2_CAP: i64 = 262144 13const CD2_ELF: *u8 = "/volume1/homes/elderwesto/nishihost/nx_sota_status.elf" as *u8 14const CD2_EDGES: *u8 = "knowledge/status/capgraph_edges.conf" as *u8 15 16const CD2_HIST: *u8 = "knowledge/status/capgraph_history.jrnl" as *u8 17const CD2_SBMAX: i64 = 16384 18const CD2_AX_COVER: i64 = 0 19const CD2_AX_EVID: i64 = 1 20const CD2_AX_FRONTIER: i64 = 2 21 22func cd2_match(buf: *u8, at: i64, end: i64, pat: *u8) -> i64 { 23 var k: i64 = 0 24 var ok: i64 = 1 25 var done: i64 = 0 26 while done == 0 { 27 let pc: i64 = pat[k] as i64 28 if pc == 0 { done = 1 } 29 else { 30 if at + k >= end { ok = 0 } 31 else { if buf[at + k] as i64 != pc { ok = 0 } } 32 if ok == 0 { done = 1 } 33 else { k = k + 1 } 34 } 35 } 36 return ok 37} 38 39func cd2_find(buf: *u8, ls: i64, le: i64, pat: *u8) -> i64 { 40 var j: i64 = ls 41 var hit: i64 = 0 - 1 42 while j < le { 43 if cd2_match(buf, j, le, pat) == 1 { 44 hit = j 45 j = le 46 } else { j = j + 1 } 47 } 48 return hit 49} 50 51func cd2_num(buf: *u8, at: i64, end: i64) -> i64 { 52 var v: i64 = 0 53 var i: i64 = at 54 var any: i64 = 0 55 var done: i64 = 0 56 while done == 0 { 57 if i >= end { done = 1 } 58 else { 59 let c: i64 = buf[i] as i64 60 if c < 48 { done = 1 } 61 else { 62 if c > 57 { done = 1 } 63 else { 64 v = v * 10 + (c - 48) 65 any = 1 66 i = i + 1 67 } 68 } 69 } 70 } 71 if any == 0 { return CG_UNMEASURED } 72 return v 73} 74 75// The flat permil becomes an ORDINAL level. Thresholds are declared here as named boundaries so the 76// conversion is auditable; the level is then capped by evidence (L6) at cg_set, which is what actually 77// stops a big coverage claim from reading as progress. 78func cd2_cov_level(permil: i64) -> i64 { 79 if permil == CG_UNMEASURED { return CG_UNMEASURED } 80 if permil < 200 { return 0 } 81 if permil < 400 { return 1 } 82 if permil < 600 { return 2 } 83 if permil < 800 { return 3 } 84 if permil < 950 { return 4 } 85 return 5 86} 87 88func cd2_gap_level(gaps: i64) -> i64 { 89 if gaps == CG_UNMEASURED { return CG_UNMEASURED } 90 if gaps <= 0 { return 5 } 91 var d: i64 = gaps / 3 92 if d > 5 { d = 5 } 93 return 5 - d 94} 95 96// ---- THE PROGRESS RAIL ---- 97// Ordinal levels make a level-up COUNTABLE, but counting requires a record. Without a time series the 98// graph can only ever answer "where are we", never "did we move" -- and the operator asked for the 99// second. This appends ONE row per ACTUAL CHANGE (content-idempotent, the nx_debt pattern): re-running 100// on an unchanged graph appends nothing, so the journal is a history of MOVEMENT, not of invocations. 101// A rail that grows on every run would drown the signal it exists to carry. 102static cd2_sb: *u8 103static cd2_sn: i64 104 105func cd2_sput(s: *u8) { 106 var i: i64 = 0 107 while s[i] != (0 as u8) { 108 if cd2_sn < CD2_SBMAX - 2 { 109 cd2_sb[cd2_sn] = s[i] 110 cd2_sn = cd2_sn + 1 111 } 112 i = i + 1 113 } 114 cd2_sb[cd2_sn] = 0 as u8 115} 116 117func cd2_sputi(x: i64) { 118 let b: *u8 = sys_mmap(64) as *u8 119 var v: i64 = x 120 var neg: i64 = 0 121 if v < 0 { 122 neg = 1 123 v = 0 - v 124 } 125 var i: i64 = 40 126 if v == 0 { 127 i = i - 1 128 b[i] = 48 as u8 129 } 130 while v > 0 { 131 let d: i64 = v - (v / 10) * 10 132 i = i - 1 133 b[i] = (d + 48) as u8 134 v = v / 10 135 } 136 if neg == 1 { 137 i = i - 1 138 b[i] = 45 as u8 139 } 140 b[40] = 0 as u8 141 cd2_sput(((b as i64) + i) as *u8) 142} 143 144func cd2_is_infra(s: *u8) -> i64 { 145 if s[0] != (105 as u8) { return 0 } 146 if s[1] != (110 as u8) { return 0 } 147 if s[2] != (102 as u8) { return 0 } 148 if s[3] != (114 as u8) { return 0 } 149 if s[4] != (97 as u8) { return 0 } 150 if s[5] != (58 as u8) { return 0 } 151 return 1 152} 153 154func cd2_name_of(buf: *u8, ls: i64, le: i64, dst: *u8) -> i64 { 155 var start: i64 = ls 156 var found: i64 = 0 157 var scan: i64 = ls 158 while scan < le { 159 if found == 0 { 160 if buf[scan] != (32 as u8) { 161 start = scan 162 found = 1 163 } 164 } 165 scan = scan + 1 166 } 167 if found == 0 { return 0 } 168 var w: i64 = 0 169 var q: i64 = start 170 var done: i64 = 0 171 while done == 0 { 172 if q >= le { done = 1 } 173 else { 174 if buf[q] == (32 as u8) { done = 1 } 175 else { 176 if w < CG_NAMEW - 1 { 177 dst[w] = buf[q] 178 w = w + 1 179 } 180 q = q + 1 181 } 182 } 183 } 184 dst[w] = 0 as u8 185 return w 186} 187 188// ---- READING the rail. Recording movement is only half a progress system; a journal nobody can read 189// is a log, not an instrument. This diffs the last two rows and names what MOVED, in both directions -- 190// a level going DOWN is the more important signal, because it means something that used to hold no 191// longer does, and a report that only ever shows gains is a cheerleader, not a ruler. 192const CD2_MAXPAIR: i64 = 512 193const CD2_PW: i64 = 48 194static cd2_pn: *u8 195static cd2_pv: *i64 196static cd2_np: i64 197static cd2_cn: *u8 198static cd2_cv: *i64 199static cd2_nc: i64 200 201func cd2_parse_row(buf: *u8, s: i64, e: i64) { 202 cd2_np = 0 203 var i: i64 = s 204 while i < e { 205 let c: i64 = buf[i] as i64 206 var adv: i64 = 1 207 if c == 32 { adv = 1 } 208 else { 209 if c == 9 { adv = 1 } 210 else { 211 var j: i64 = i 212 var eqp: i64 = 0 - 1 213 var done: i64 = 0 214 while done == 0 { 215 if j >= e { done = 1 } 216 else { 217 let cj: i64 = buf[j] as i64 218 if cj == 32 { done = 1 } 219 else { 220 if cj == 9 { done = 1 } 221 else { 222 if cj == 61 { 223 if eqp < 0 { eqp = j } 224 } 225 j = j + 1 226 } 227 } 228 } 229 } 230 if eqp > 0 { 231 if cd2_np < CD2_MAXPAIR { 232 var w: i64 = 0 233 var k: i64 = i 234 while k < eqp { 235 if w < CD2_PW - 1 { 236 let dst: *u8 = ((cd2_pn as i64) + cd2_np * CD2_PW + w) as *u8 237 dst[0] = buf[k] 238 w = w + 1 239 } 240 k = k + 1 241 } 242 let term: *u8 = ((cd2_pn as i64) + cd2_np * CD2_PW + w) as *u8 243 term[0] = 0 as u8 244 var v: i64 = 0 245 var neg: i64 = 0 246 var m: i64 = eqp + 1 247 if m < j { 248 if buf[m] == (45 as u8) { 249 neg = 1 250 m = m + 1 251 } 252 } 253 while m < j { 254 let cm: i64 = buf[m] as i64 255 if cm >= 48 { 256 if cm <= 57 { v = v * 10 + (cm - 48) } 257 } 258 m = m + 1 259 } 260 if neg == 1 { v = 0 - v } 261 cd2_pv[cd2_np] = v 262 cd2_np = cd2_np + 1 263 } 264 } 265 if j > i { adv = j - i } 266 } 267 } 268 i = i + adv 269 } 270} 271 272func cd2_prev_lookup(nm: *u8) -> i64 { 273 var i: i64 = 0 274 var hit: i64 = 0 - 999 275 while i < cd2_np { 276 if cg_streq(((cd2_pn as i64) + i * CD2_PW) as *u8, nm) == 1 { 277 hit = cd2_pv[i] 278 i = cd2_np 279 } else { i = i + 1 } 280 } 281 return hit 282} 283 284func cd2_progress() -> i64 { 285 cd2_pn = sys_mmap(CD2_MAXPAIR * CD2_PW + 64) as *u8 286 cd2_pv = sys_mmap(CD2_MAXPAIR * 8 + 64) as *i64 287 cd2_cn = sys_mmap(CD2_MAXPAIR * CD2_PW + 64) as *u8 288 cd2_cv = sys_mmap(CD2_MAXPAIR * 8 + 64) as *i64 289 let hl: *i64 = sys_mmap(16) as *i64 290 let hb: *u8 = sys_read_file(CD2_HIST, hl) 291 let hn: i64 = hl[0] 292 cax_puts("=== NX-CAPGRAPH PROGRESS: what MOVED between the last two recorded states ===\n" as *u8) 293 if hn <= 0 { 294 cax_puts("no history yet -- run nx_capgraph_derive once to record a baseline.\n" as *u8) 295 return 0 296 } 297 let l2: i64 = cd2_last_row_start(hb, hn) 298 let l1: i64 = cd2_prev_row_start(hb, hn) 299 if l1 < 0 { 300 cax_puts("only ONE recorded state -- a baseline, no movement to report yet.\n" as *u8) 301 cax_puts("This is the honest answer: progress needs two points, and there is one.\n" as *u8) 302 return 0 303 } 304 var e1: i64 = l2 - 1 305 var e2: i64 = hn 306 cd2_parse_row(hb, l2, e2) 307 cd2_nc = cd2_np 308 var c: i64 = 0 309 while c < cd2_nc { 310 var w: i64 = 0 311 let src: *u8 = ((cd2_pn as i64) + c * CD2_PW) as *u8 312 while src[w] != (0 as u8) { 313 let d: *u8 = ((cd2_cn as i64) + c * CD2_PW + w) as *u8 314 d[0] = src[w] 315 w = w + 1 316 } 317 let t: *u8 = ((cd2_cn as i64) + c * CD2_PW + w) as *u8 318 t[0] = 0 as u8 319 cd2_cv[c] = cd2_pv[c] 320 c = c + 1 321 } 322 cd2_parse_row(hb, l1, e1) 323 324 var up: i64 = 0 325 var down: i64 = 0 326 var newn: i64 = 0 327 var i: i64 = 0 328 while i < cd2_nc { 329 let nm: *u8 = ((cd2_cn as i64) + i * CD2_PW) as *u8 330 let now: i64 = cd2_cv[i] 331 let was: i64 = cd2_prev_lookup(nm) 332 if was == (0 - 999) { 333 cax_puts(" NEW " as *u8) 334 cax_puts(nm) 335 cax_puts(" = " as *u8) 336 cax_puti(now) 337 cax_puts("\n" as *u8) 338 newn = newn + 1 339 } else { 340 if now > was { 341 cax_puts(" UP " as *u8) 342 cax_puts(nm) 343 cax_puts(" " as *u8) 344 cax_puti(was) 345 cax_puts(" -> " as *u8) 346 cax_puti(now) 347 cax_puts("\n" as *u8) 348 up = up + 1 349 } 350 if now < was { 351 cax_puts(" DOWN " as *u8) 352 cax_puts(nm) 353 cax_puts(" " as *u8) 354 cax_puti(was) 355 cax_puts(" -> " as *u8) 356 cax_puti(now) 357 cax_puts(" <- REGRESSION\n" as *u8) 358 down = down + 1 359 } 360 } 361 i = i + 1 362 } 363 cax_puts("\n" as *u8) 364 cax_kv("advanced" as *u8, up) 365 cax_kv("REGRESSED" as *u8, down) 366 cax_kv("new_nodes" as *u8, newn) 367 cax_puts("\n" as *u8) 368 if up == 0 { 369 if down == 0 { 370 if newn == 0 { cax_puts("no level changed between the last two states (structure moved, levels did not).\n" as *u8) } 371 } 372 } 373 if down > 0 { 374 cax_puts("⚠a DOWN is the signal that matters: something that used to hold no longer does.\n" as *u8) 375 } 376 return 0 377} 378 379// ROW-BOUNDARY DECISIONS, extracted for the same reason as cd2_last_row_matches: `progress` diffs the 380// LAST TWO rows, so if these pick the wrong pair it silently reports the wrong movement -- and an 381// off-by-one here is invisible in a live run, which only ever exercises whatever shape the journal 382// happens to have that day. Trailing-newline handling is the trap: a file ending in \n must NOT be read 383// as having an extra empty final row. 384// cd2_last_row_start: byte offset where the final non-empty row begins, or -1 if there is none. 385func cd2_last_row_start(hb: *u8, hn: i64) -> i64 { 386 if hn <= 0 { return 0 - 1 } 387 var lstart: i64 = 0 388 var k: i64 = 0 389 while k < hn { 390 if hb[k] == (10 as u8) { 391 if k + 1 < hn { lstart = k + 1 } 392 } 393 k = k + 1 394 } 395 return lstart 396} 397 398// cd2_prev_row_start: offset of the row BEFORE the last one, or -1 when fewer than two rows exist. 399func cd2_prev_row_start(hb: *u8, hn: i64) -> i64 { 400 let last: i64 = cd2_last_row_start(hb, hn) 401 if last <= 0 { return 0 - 1 } 402 var prev: i64 = 0 403 var k: i64 = 0 404 while k < last - 1 { 405 if hb[k] == (10 as u8) { 406 if k + 1 < last { prev = k + 1 } 407 } 408 k = k + 1 409 } 410 return prev 411} 412 413// THE DECISION THE WHOLE RAIL TURNS ON: does the LAST journal row already carry exactly this state? 414// If this says yes when it should say no, real movement is silently DROPPED. If it says no when it 415// should say yes, the journal fills with duplicate rows and progress reports phantom changes. It was 416// the one piece of the rail with no standing tooth, so it is now a PURE function -- extracted solely 417// to make it gate-reachable. Compares the state field (after the epoch TAB) of the final line. 418// Returns 1 = identical (do not append) · 0 = differs, or unreadable. 419func cd2_last_row_matches(hb: *u8, hn: i64, st: *u8, stn: i64) -> i64 { 420 if hn <= 0 { return 0 } 421 let lstart: i64 = cd2_last_row_start(hb, hn) 422 if lstart < 0 { return 0 } 423 var tab: i64 = lstart 424 var found: i64 = 0 425 var t: i64 = lstart 426 while t < hn { 427 if found == 0 { 428 if hb[t] == (9 as u8) { 429 tab = t + 1 430 found = 1 431 } 432 } 433 t = t + 1 434 } 435 if found == 0 { return 0 } 436 var m: i64 = 1 437 var q: i64 = 0 438 while q < stn { 439 if tab + q >= hn { m = 0 } 440 else { if hb[tab + q] != st[q] { m = 0 } } 441 q = q + 1 442 } 443 // A stored PREFIX must not read as equal: the byte after the compared span has to END the line. 444 // Without this, a shorter recorded state would swallow every longer one and the rail would go deaf. 445 if tab + stn < hn { 446 if hb[tab + stn] != (10 as u8) { m = 0 } 447 } 448 return m 449} 450 451// Append one row IFF the graph state differs from the last recorded row. 452// returns 1 = movement recorded · 0 = unchanged (nothing appended) · -1 = write failed 453func cd2_snapshot(edges: i64) -> i64 { 454 cd2_sn = 0 455 cd2_sput("nodes=" as *u8) 456 cd2_sputi(cg_nn) 457 cd2_sput(" edges=" as *u8) 458 cd2_sputi(edges) 459 // Record BOTH the effective level and the node's OWN level. 460 // Measured 2026-08-01: `instrument` earned executable evidence (own 0->3 GATED) and the rail showed 461 // NOTHING, because L4 correctly capped its EFFECTIVE level at 0 behind an unevidenced prerequisite. 462 // A rail that records only the capped figure tells a lane that did real work that nothing happened -- 463 // ★★★UNDER A WEAKEST-PATH RULE, PROGRESS AND ITS VISIBILITY ARE DIFFERENT THINGS, so record both: 464 // `<name>` is what the graph can currently deliver, `<name>#own` is what that node itself earned. 465 var i: i64 = 0 466 while i < cg_nn { 467 cd2_sput(" " as *u8) 468 cd2_sput(cg_node_name(i)) 469 cd2_sput("=" as *u8) 470 cd2_sputi(cg_effective(i)) 471 cd2_sput(" " as *u8) 472 cd2_sput(cg_node_name(i)) 473 cd2_sput("#own=" as *u8) 474 cd2_sputi(cg_own[i]) 475 i = i + 1 476 } 477 478 let hl: *i64 = sys_mmap(16) as *i64 479 let hb: *u8 = sys_read_file(CD2_HIST, hl) 480 let hn: i64 = hl[0] 481 let same: i64 = cd2_last_row_matches(hb, hn, cd2_sb, cd2_sn) 482 if same == 1 { return 0 } 483 484 let ts: *i64 = sys_mmap(32) as *i64 485 sys_clock_gettime_real(ts) 486 let fd: i64 = sys_openat_append(CD2_HIST, 0x1A4) 487 if fd < 0 { return 0 - 1 } 488 let eb: *u8 = sys_mmap(64) as *u8 489 var v: i64 = ts[0] 490 var bi: i64 = 40 491 if v == 0 { 492 bi = bi - 1 493 eb[bi] = 48 as u8 494 } 495 while v > 0 { 496 let d: i64 = v - (v / 10) * 10 497 bi = bi - 1 498 eb[bi] = (d + 48) as u8 499 v = v / 10 500 } 501 sys_write(fd, ((eb as i64) + bi) as *u8, 40 - bi) 502 sys_write(fd, "\t" as *u8, 1) 503 sys_write(fd, cd2_sb, cd2_sn) 504 sys_write(fd, "\n" as *u8, 1) 505 sys_close(fd) 506 return 1 507} 508