code wiki / _hdl_build / nx_capsweep_lib.nx

nx_capsweep_lib.nx source

↩ module page · 221 lines · 9819 B

1// nx_capsweep_lib.nx -- CR1 of /compare/capregistry: THE WHOLE-REGISTRY LIFECYCLE JOIN. 2// 3// THE DEFECT THIS CLOSES, MEASURED 2026-08-28 in a single session: three censuses of the SAME estate 4// returned three different denominators -- nx_wirecensus 2048 promoted artifacts, nx_execsurface 2418 5// organs, nx_artifactdrift 1295 registry rows. Every one of those partitions RECONCILES INTERNALLY and 6// every one is correct about its own subject, so NOTHING LOOKS WRONG -- and yet no reader can state how 7// many distinct units the estate has, because nothing joins them PER UNIT. 8// 9// WHAT THIS IS NOT: a fourth census. It collects nothing and it walks no directory. It JOINS artifacts the 10// existing censuses have already written, so it cannot disagree with them about anything except the join. 11// If it ever grows a collector, that is the moment it becomes a rival ruler and stops being trustworthy. 12// 13// COMPOSED, NEVER RE-IMPLEMENTED: wc_read, wc_read_tail, wc_parse_registered, wc_parse_authorised, 14// wc_parse_invoked, wc_has and wc_elflen all come from nx_wirecensus_lib. There is exactly ONE parser for 15// the allowlist, the consent ledger and the actlog in this estate, and it is not this file. 16 17import "nx_syscalls.nx" 18import "nx_wirecensus_lib.nx" 19 20// The unit table. execsurface.tsv enumerated 2418 organs when this was written; 8192 is 3.4x headroom and 21// overflow is ANNOUNCED through trunc rather than absorbed. A cap that fills in silence is the defect this 22// whole board exists to find, so this one may not have it. 23const CS_MAXU: i64 = 8192 24const CS_TAB: i64 = 9 25const CS_NL: i64 = 10 26const CS_HASH: i64 = 35 27const CS_DASH: i64 = 45 28const CS_SURF_FIELD: i64 = 7 // column index of first_surface in execsurface.tsv, read from its emitter 29 30// Surface codes, derived from column 7 of execsurface.tsv. 31const CS_S_NONE: i64 = 0 32const CS_S_CLOCK: i64 = 1 33const CS_S_CRON: i64 = 2 34const CS_S_DAEMON: i64 = 3 35const CS_S_ROSTER: i64 = 4 36const CS_S_ACTLOG: i64 = 5 37const CS_S_FORK: i64 = 6 38const CS_S_REF: i64 = 7 39const CS_S_UNKNOWN: i64 = 8 40 41// Lifecycle stage bits, so one row carries the whole chain rather than four booleans a reader must recombine. 42const CS_B_SURFACE: i64 = 1 43const CS_B_REGISTERED: i64 = 2 44const CS_B_AUTHORISED: i64 = 4 45const CS_B_INVOKED: i64 = 8 46 47// Add-if-absent into a CALLER-SIZED table. 48// THIS DELIBERATELY DOES NOT COMPOSE wc_add, and the reason is the point of the organ: wc_add is hard-capped 49// at WC_MAXT = 2048 while the surface census enumerates 2418 organs, so composing it would have silently 50// dropped 370 units -- the exact silent-cap defect this board was written to expose. Here the cap is a 51// PARAMETER and every rejected row increments trunc, which the caller must print. 52func cs_add(names: *u8, lens: *i64, cnt: i64, cap: i64, p: *u8, l: i64, trunc: *i64) -> i64 { 53 if l <= 0 { return cnt } 54 if l >= WC_NAMEMAX { return cnt } 55 if wc_has(names, lens, cnt, p, l) == 1 { return cnt } 56 if cnt >= cap { trunc[0] = trunc[0] + 1; return cnt } 57 let base: i64 = cnt * WC_NAMEMAX 58 var k: i64 = 0 59 while k < l { names[base + k] = p[k]; k = k + 1 } 60 names[base + l] = 0 as u8 61 lens[cnt] = l 62 return cnt + 1 63} 64 65// Field-boundary scan with a SEPARATE cursor and a clean return, never a clobbered index. A loop that exits 66// by overwriting the cursor it is meant to report destroys its own answer; this estate wrote that eol-scan 67// defect four times in one day, so it is not written a fifth time here. 68func cs_field_end(buf: *u8, s: i64, lim: i64) -> i64 { 69 var j: i64 = s 70 while j < lim { 71 if buf[j] == (CS_TAB as u8) { return j } 72 j = j + 1 73 } 74 return lim 75} 76 77// Start offset of field <want> on the line [ls, lim). 78func cs_field_start(buf: *u8, ls: i64, lim: i64, want: i64) -> i64 { 79 var fs: i64 = ls 80 var f: i64 = 0 81 while f < want { 82 let fe: i64 = cs_field_end(buf, fs, lim) 83 if fe < lim { fs = fe + 1 } else { fs = lim } 84 f = f + 1 85 } 86 return fs 87} 88 89// first_surface token -> code. Two bytes are required because clock and cron share their first. 90func cs_surf_code(buf: *u8, s: i64, e: i64) -> i64 { 91 if e <= s { return CS_S_NONE } 92 if buf[s] == (CS_DASH as u8) { return CS_S_NONE } 93 if e - s < 2 { return CS_S_UNKNOWN } 94 let c0: i64 = buf[s] as i64 95 let c1: i64 = buf[s + 1] as i64 96 if c0 == 100 { return CS_S_DAEMON } 97 if c0 == 97 { return CS_S_ACTLOG } 98 if c0 == 102 { return CS_S_FORK } 99 if c0 == 99 { 100 if c1 == 108 { return CS_S_CLOCK } 101 if c1 == 114 { return CS_S_CRON } 102 return CS_S_UNKNOWN 103 } 104 if c0 == 114 { 105 if c1 == 111 { return CS_S_ROSTER } 106 if c1 == 101 { return CS_S_REF } 107 return CS_S_UNKNOWN 108 } 109 return CS_S_UNKNOWN 110} 111 112// Column 0 (name) and column 7 (first_surface) of every non-comment line of execsurface.tsv. 113// The trailing footer line begins with the comment byte and is SKIPPED here: it carries the census's own 114// organs= total, and it is read SEPARATELY by cs_footer_num so the two numbers can be COMPARED instead of 115// one silently standing in for the other. 116func cs_parse_surface(buf: *u8, n: i64, names: *u8, lens: *i64, surf: *i64, cap: i64, trunc: *i64) -> i64 { 117 var cnt: i64 = 0 118 var ls: i64 = 0 119 var i: i64 = 0 120 while i <= n { 121 var eol: i64 = 0 122 if i == n { eol = 1 } 123 else { if buf[i] == (CS_NL as u8) { eol = 1 } } 124 if eol == 1 { 125 if i > ls { 126 if buf[ls] != (CS_HASH as u8) { 127 let e0: i64 = cs_field_end(buf, ls, i) 128 let raw: *u8 = ((buf as i64) + ls) as *u8 129 let l0: i64 = wc_elflen(raw, e0 - ls) 130 let before: i64 = cnt 131 cnt = cs_add(names, lens, cnt, cap, raw, l0, trunc) 132 if cnt > before { 133 let fs: i64 = cs_field_start(buf, ls, i, CS_SURF_FIELD) 134 surf[cnt - 1] = cs_surf_code(buf, fs, i) 135 } 136 } 137 } 138 ls = i + 1 139 } 140 i = i + 1 141 } 142 return cnt 143} 144 145// Read the integer that follows <key> on the footer line, or -1 when it is absent. 146// -1 IS A THIRD STATE ON PURPOSE: a missing footer must read UNKNOWN, never zero, because a zero here would 147// make the reconciliation appear to balance against a total nobody published. 148func cs_footer_num(buf: *u8, n: i64, key: *u8) -> i64 { 149 var klen: i64 = 0 150 while key[klen] != (0 as u8) { klen = klen + 1 } 151 var i: i64 = 0 152 while i + klen <= n { 153 var k: i64 = 0 154 var same: i64 = 1 155 while k < klen { 156 if buf[i + k] != key[k] { same = 0; k = klen } else { k = k + 1 } 157 } 158 if same == 1 { 159 var j: i64 = i + klen 160 var v: i64 = 0 161 var got: i64 = 0 162 while j < n { 163 let c: i64 = buf[j] as i64 164 if c >= 48 { 165 if c <= 57 { v = v * 10 + (c - 48); got = 1; j = j + 1 } 166 else { j = n } 167 } else { j = n } 168 } 169 if got == 1 { return v } 170 return 0 - 1 171 } 172 i = i + 1 173 } 174 return 0 - 1 175} 176 177// The lifecycle bitmask for one unit. 178func cs_stage_bits(has_surface: i64, reg: i64, auth: i64, inv: i64) -> i64 { 179 var b: i64 = 0 180 if has_surface == 1 { b = b + CS_B_SURFACE } 181 if reg == 1 { b = b + CS_B_REGISTERED } 182 if auth == 1 { b = b + CS_B_AUTHORISED } 183 if inv == 1 { b = b + CS_B_INVOKED } 184 return b 185} 186 187// WHY A RESIDUAL NEEDS A REASON, MEASURED 2026-08-28 THE HOUR THE WORKLIST FIRST EXISTED: the 126 names the 188// join could not match are NOT one class. Reading them found four causes with FOUR DIFFERENT REMEDIES -- 189// tools registered under an MCP name that is not an elf basename at all (not a defect), names whose artifact 190// is a STAGED .elf.new that was never promoted (registered and uncallable, worse than dark), names promoted 191// AFTER the spine snapshot was taken (the spine is behind, not the estate -- nx_capsweep appeared in its OWN 192// residual this way), and genuinely dark rows. ★NAME WHICH REASON: TWO CAUSES WITH OPPOSITE REMEDIES MUST 193// NOT SHARE ONE COUNTER, or the count sends its reader at the wrong work. 194// 195// PURE BY CONSTRUCTION: the two filesystem probes stay in the CALLER and this takes their results as 196// booleans, so the classifier is gate-testable without touching a filesystem and a mutation reaches it. 197const CS_R_STALE_SPINE: i64 = 1 198const CS_R_SCAFFOLD: i64 = 2 199const CS_R_NO_ARTIFACT: i64 = 3 200 201func cs_residual_reason(elf_exists: i64, new_exists: i64) -> i64 { 202 // ORDER IS LOAD-BEARING: a promoted artifact can also still have a stale .elf.new beside it, and that is 203 // a SPINE-FRESHNESS fact, not a scaffold. Testing scaffold first would misfile every such row. 204 if elf_exists == 1 { return CS_R_STALE_SPINE } 205 if new_exists == 1 { return CS_R_SCAFFOLD } 206 // DELIBERATELY NOT SPLIT INTO ALIAS-vs-DARK. Separating those needs the allowlist's elf column, which 207 // this organ does not parse, so the honest label is the one that names what was actually established: 208 // no artifact of that NAME exists. Guessing which of the two it is would be the confident-wrong answer. 209 return CS_R_NO_ARTIFACT 210} 211 212// THE PARTITION PREDICATE. The join publishes a unit count ONLY when every input population is accounted 213// for: units seen = units carried, and every registered name is either joined or counted as a residual. 214// A count whose parts do not sum is a leak, and this organ refuses to print one. 215func cs_partition_ok(units: i64, joined: i64, residual: i64) -> i64 { 216 if units < 0 { return 0 } 217 if joined < 0 { return 0 } 218 if residual < 0 { return 0 } 219 if joined + residual == units { return 1 } 220 return 0 221}