code wiki / (root) / nx_board_idref_gate.nx

nx_board_idref_gate.nx source

↩ module page · 361 lines · 18388 B

1// nx_board_idref_gate.nx -- THE COMPARE BOARD'S REFERENTIAL INTEGRITY REFEREE (2026-09-04). 2// 3// WHY THIS EXISTS, AND WHY IT IS A MECHANISM RATHER THAN ANOTHER LAW. On 2026-09-03 a seat appended a rung 4// as LN37 and four log rows as LN36 and BOTH ids were already taken by another lane the same day. It 5// journaled the finding, renumbered to LN41/LN42 after grepping for free ids, and wrote the durable remedy 6// in its own words: "the durable fix is a uniqueness tooth in the compare referee rather than a habit." 7// By 2026-09-04 LN41 AND LN42 had each collided AGAIN -- the renumbering itself landed on ids a third lane 8// had taken while it worked. That is the whole argument for this file: GREP-BEFORE-APPEND IS A HABIT, AND 9// A HABIT LOSES TO CONCURRENCY EVERY TIME. Only something in the path can hold this invariant. 10// 11// WHAT IT JUDGES. A .plan is a board, and a board's ids are its addresses. Three ways an address goes bad: 12// DUPID two rung rows share an id, so the ranker, a watch flip and a done-rule all attach to whichever 13// the reader matches first. Measured live: lang carried one LANDED and one OPEN rung under LN42, 14// which is the dangerous shape -- the board can report the open work as finished. 15// DANGLOG a log row is journaled against a rung id no rung row declares, so the worked plan a crashed 16// session is supposed to inherit points at nothing. 17// DANGMS a milestone lists a member rung that does not exist, so its cumulative estimate is over a set 18// the board cannot enumerate. 19// 20// IT RATCHETS RATHER THAN DEMANDING ZERO, AND THAT IS DELIBERATE. Real offenders already exist that belong 21// to other lanes, and a detector that is permanently RED is one everyone learns to ignore. The bar is 22// knowledge/status/board_idref.baseline; the gate goes RED only when the count RISES, and it TIGHTENS the 23// baseline when the count falls so a fix cannot be undone silently. EVERY OFFENDER IS NAMED IN THE OUTPUT 24// whatever the verdict, because a count without a worklist is not actionable. 25// 26// COMPOSES nx_rowparse_lib for pipe-delimited column extraction rather than hand-rolling a fourth copy of 27// that arithmetic, and gk_* for directory and file access. 28// license_tier: ORIGINAL. Reads the compare trees, writes only its own baseline. No hw writes (Rule 26). 29import "nx_syscalls.nx" 30import "nx_gate_verdict.nx" 31import "nx_gatekit_lib.nx" 32import "nx_rowparse_lib.nx" 33 34// A .plan is prose-heavy: the largest measured is ~131 KB, so 4 MB is thirty times the largest real board. 35// A file over this is REFUSED BY NAME and forces coverage_complete to 0 rather than being read in part -- 36// a partial board would under-report both duplicates and dangling references. 37const BI_FILECAP: i64 = 4194304 38const BI_NAMES: i64 = 262144 39const BI_NAMESTRIDE: i64 = 256 40const BI_MAXFILES: i64 = 512 41const BI_IDCAP: i64 = 32 42const BI_MAXIDS: i64 = 1024 43const BI_PATH: i64 = 1024 44const BI_OUT: i64 = 262144 45const BI_SPAN: i64 = 8 46const BI_BASEMAX: i64 = 64 47const BI_DIR_PRIMARY: *u8 = "buildroot/knowledge/compare/" 48const BI_DIR_SECONDARY: *u8 = "knowledge/compare/" 49const BI_BASELINE: *u8 = "knowledge/status/board_idref.baseline" 50const BI_FLD_KIND: i64 = 0 51const BI_FLD_RUNGID: i64 = 1 52const BI_FLD_LOGID: i64 = 2 53const BI_FLD_MSMEMBERS: i64 = 4 54const BI_COMMA: i64 = 44 55const BI_SPACE: i64 = 32 56const BI_CR: i64 = 13 57 58// store id `s` (len l) into slot table at index n; returns new n (silently refuses to overflow, and the 59// caller checks the cap so a full table becomes a NAMED refusal rather than a quiet undercount) 60func bi_put_id(tab: *u8, n: i64, b: *u8, s: i64, l: i64) -> i64 { 61 if n >= BI_MAXIDS { return n } 62 var len: i64 = l 63 if len > BI_IDCAP - 1 { len = BI_IDCAP - 1 } 64 var i: i64 = 0 65 while i < len { tab[n * BI_IDCAP + i] = b[s + i]; i = i + 1 } 66 tab[n * BI_IDCAP + len] = 0 as u8 67 return n + 1 68} 69func bi_id_at(tab: *u8, i: i64) -> *u8 { return (tab as i64 + i * BI_IDCAP) as *u8 } 70// TRIM A TRAILING CR OR SPACE FROM AN EXTRACTED ID. The compare tree has MIXED LINE ENDINGS -- measured 71// 2026-09-04, failmodes.plan is CRLF while performance.plan and enginelab.plan are LF -- and rp_le stops at 72// the newline, so on a CRLF board the carriage return rides along on whatever field ends the line. That made 73// the LAST member of every milestone on a CRLF board unresolvable and reported three declared rungs as 74// missing. The tell was that the offenders were FM5, FM8 and FM9: the last member of M1, M2 and M3 exactly. 75func bi_trim(b: *u8) -> i64 { 76 var n: i64 = 0 77 while b[n] != (0 as u8) { n = n + 1 } 78 while n > 0 { 79 let ch: i64 = b[n - 1] as i64 80 if ch == BI_CR { n = n - 1 } else { 81 if ch == BI_SPACE { n = n - 1 } else { b[n] = 0 as u8; return n } 82 } 83 } 84 b[0] = 0 as u8 85 return 0 86} 87// how many times does the id at slot `k` appear in the first `n` slots? 88func bi_count(tab: *u8, n: i64, k: i64) -> i64 { 89 var c: i64 = 0 90 var i: i64 = 0 91 while i < n { 92 if gk_streq(bi_id_at(tab, i), bi_id_at(tab, k)) == 1 { c = c + 1 } 93 i = i + 1 94 } 95 return c 96} 97func bi_has_id(tab: *u8, n: i64, want: *u8) -> i64 { 98 var i: i64 = 0 99 while i < n { 100 if gk_streq(bi_id_at(tab, i), want) == 1 { return 1 } 101 i = i + 1 102 } 103 return 0 104} 105// is this the FIRST slot holding this id? Used so a duplicate is reported ONCE per id, not once per copy. 106func bi_first(tab: *u8, k: i64) -> i64 { 107 var i: i64 = 0 108 while i < k { 109 if gk_streq(bi_id_at(tab, i), bi_id_at(tab, k)) == 1 { return 0 } 110 i = i + 1 111 } 112 return 1 113} 114 115func main(argc: i64, argv: **u8) -> i64 { 116 let ctr: *i64 = gv_ctr() 117 gv_head("NX-BOARD-IDREF-GATE" as *u8) 118 119 let names: *u8 = sys_mmap(BI_NAMES) 120 let fbuf: *u8 = sys_mmap(BI_FILECAP) 121 let rungs: *u8 = sys_mmap(BI_IDCAP * BI_MAXIDS) 122 let path: *u8 = sys_mmap(BI_PATH) 123 let idbuf: *u8 = sys_mmap(BI_IDCAP) 124 let out: *u8 = sys_mmap(BI_OUT) 125 let c: *i64 = sys_mmap(BI_SPAN * 2) as *i64 126 var o: i64 = 0 127 128 // BOTH compare trees are scanned, as SEPARATE roots rather than as an overlay. gk_dirscan's shadowdir 129 // argument means "skip a basename that also exists there", which is the right rule for resolving WHICH 130 // SOURCE COMPILES and exactly the wrong one here: a board present in both trees is two boards, and each 131 // one's ids must be judged on their own. Measured 2026-08-31: .plan is buildroot-owned and .gates is 132 // knowledge-owned, so neither root may be assumed to be the whole subject. 133 var nf: i64 = gk_dirscan_ext(BI_DIR_PRIMARY, 0 as *u8, names, BI_NAMESTRIDE, BI_MAXFILES, 0, ".plan" as *u8) 134 if nf < 0 { nf = 0 } 135 let nf2: i64 = gk_dirscan_ext(BI_DIR_SECONDARY, 0 as *u8, names, BI_NAMESTRIDE, BI_MAXFILES, nf, ".plan" as *u8) 136 if nf2 > nf { nf = nf2 } 137 var domains: i64 = 0 138 var rungrows: i64 = 0 139 var logrows: i64 = 0 140 var msrows: i64 = 0 141 var dupid: i64 = 0 142 var danglog: i64 = 0 143 var dangms: i64 = 0 144 var unread: i64 = 0 145 var oversize: i64 = 0 146 // HIGH-WATER MARK OF THE PER-FILE TABLE. The saturation control must compare the table against the 147 // largest SINGLE board, never against the fleet total: the table is refilled per board, so testing the 148 // sum makes the control fire as soon as the fleet is bigger than one board's capacity -- which it always 149 // is. Measured 2026-09-04: 1443 fleet rung rows against a 1024-slot per-board table produced exactly that 150 // false RED on the first live run. 151 var maxids: i64 = 0 152 153 var fi: i64 = 0 154 while fi < nf { 155 let nm: *u8 = (names as i64 + fi * BI_NAMESTRIDE) as *u8 156 // .plan only. gk_dirscan yields every entry, so the extension test is what scopes the subject. 157 if gk_ext_is(nm, ".plan" as *u8) == 1 { 158 // gk_dirscan_ext yields the FULL path already; joining a root onto it again would produce a 159 // doubled path that opens nothing and reports every board as unreadable. 160 rp_cstr(path, nm, 0, rp_slen(nm)) 161 let sz: i64 = gk_size(path) 162 if sz > BI_FILECAP { 163 oversize = oversize + 1 164 o = rp_put(out, o, "OVERSIZE ") 165 o = rp_put(out, o, nm) 166 o = rp_put(out, o, " <== NOT READ, so this board is UNJUDGED rather than clean\n") 167 } else { 168 let n: i64 = gk_read(path, fbuf, BI_FILECAP) 169 if n <= 0 { 170 unread = unread + 1 171 } else { 172 domains = domains + 1 173 // ---- PASS 1: every rung id declared by this board. 174 var nr: i64 = 0 175 var ls: i64 = 0 176 while ls < n { 177 let le: i64 = rp_le(fbuf, ls, n) 178 if le > ls { 179 if rp_col_pipe(fbuf, ls, le, BI_FLD_KIND, c) == 1 { 180 if rp_lit_eq(fbuf, c[0], c[1], "rung" as *u8) == 1 { 181 if rp_col_pipe(fbuf, ls, le, BI_FLD_RUNGID, c) == 1 { 182 nr = bi_put_id(rungs, nr, fbuf, c[0], c[1]) 183 rungrows = rungrows + 1 184 } 185 } 186 } 187 } 188 ls = le + 1 189 } 190 if nr > maxids { maxids = nr } 191 // ---- DUPID, reported once per id rather than once per copy. 192 var k: i64 = 0 193 while k < nr { 194 if bi_first(rungs, k) == 1 { 195 let cnt: i64 = bi_count(rungs, nr, k) 196 if cnt > 1 { 197 dupid = dupid + 1 198 o = rp_put(out, o, "DUPID ") 199 o = rp_put(out, o, nm) 200 o = rp_put(out, o, " id=") 201 o = rp_put(out, o, bi_id_at(rungs, k)) 202 o = rp_put(out, o, " copies=") 203 o = rp_putn(out, o, cnt) 204 o = rp_put(out, o, " <== the ranker, a watch flip and a done-rule attach to whichever copy is matched first\n") 205 } 206 } 207 k = k + 1 208 } 209 // ---- PASS 2: every reference must resolve to a declared rung id. 210 ls = 0 211 while ls < n { 212 let le: i64 = rp_le(fbuf, ls, n) 213 if le > ls { 214 if rp_col_pipe(fbuf, ls, le, BI_FLD_KIND, c) == 1 { 215 if rp_lit_eq(fbuf, c[0], c[1], "log" as *u8) == 1 { 216 logrows = logrows + 1 217 if rp_col_pipe(fbuf, ls, le, BI_FLD_LOGID, c) == 1 { 218 rp_cstr(idbuf, fbuf, c[0], c[1]) 219 bi_trim(idbuf) 220 if bi_has_id(rungs, nr, idbuf) == 0 { 221 danglog = danglog + 1 222 o = rp_put(out, o, "DANGLOG ") 223 o = rp_put(out, o, nm) 224 o = rp_put(out, o, " -> ") 225 o = rp_put(out, o, idbuf) 226 o = rp_put(out, o, " <== a journalled measurement addressed to a rung this board does not declare\n") 227 } 228 } 229 } 230 if rp_lit_eq(fbuf, c[0], c[1], "ms" as *u8) == 1 { 231 msrows = msrows + 1 232 if rp_col_pipe(fbuf, ls, le, BI_FLD_MSMEMBERS, c) == 1 { 233 // members are a comma list inside one field 234 var ms: i64 = c[0] 235 let me: i64 = c[0] + c[1] 236 while ms < me { 237 // MEMBERS ARE SEPARATED BY A COMMA *OR* A SPACE, AND BOTH ARE IN 238 // LIVE USE. Measured 2026-09-04: lang writes LN4,LN5,LN6 while 239 // performance writes PF2 PF11 and enginelab writes EL1 EL2. A 240 // comma-only split read every space-separated list as ONE token, 241 // which matched no rung and reported 17 dangling members on five 242 // boards whose rungs were all declared. That was a false-positive 243 // class in this detector, not a defect in those boards. 244 var mt: i64 = ms 245 while mt < me { 246 if (fbuf[mt] as i64) == BI_COMMA { break } 247 if (fbuf[mt] as i64) == BI_SPACE { break } 248 mt = mt + 1 249 } 250 if mt > ms { 251 rp_cstr(idbuf, fbuf, ms, mt - ms) 252 bi_trim(idbuf) 253 if bi_has_id(rungs, nr, idbuf) == 0 { 254 dangms = dangms + 1 255 o = rp_put(out, o, "DANGMS ") 256 o = rp_put(out, o, nm) 257 o = rp_put(out, o, " -> ") 258 o = rp_put(out, o, idbuf) 259 o = rp_put(out, o, " <== a milestone counts a member rung the board does not declare\n") 260 } 261 } 262 ms = mt + 1 263 } 264 } 265 } 266 } 267 } 268 ls = le + 1 269 } 270 } 271 } 272 } 273 fi = fi + 1 274 } 275 276 let offenders: i64 = dupid + danglog + dangms 277 o = rp_put(out, o, "ENVELOPE domains=") 278 o = rp_putn(out, o, domains) 279 o = rp_put(out, o, " rung_rows=") 280 o = rp_putn(out, o, rungrows) 281 o = rp_put(out, o, " log_rows=") 282 o = rp_putn(out, o, logrows) 283 o = rp_put(out, o, " ms_rows=") 284 o = rp_putn(out, o, msrows) 285 o = rp_put(out, o, " dupid=") 286 o = rp_putn(out, o, dupid) 287 o = rp_put(out, o, " danglog=") 288 o = rp_putn(out, o, danglog) 289 o = rp_put(out, o, " dangms=") 290 o = rp_putn(out, o, dangms) 291 o = rp_put(out, o, " offenders=") 292 o = rp_putn(out, o, offenders) 293 o = rp_put(out, o, " unreadable=") 294 o = rp_putn(out, o, unread) 295 o = rp_put(out, o, " oversize=") 296 o = rp_putn(out, o, oversize) 297 var complete: i64 = 1 298 if unread > 0 { complete = 0 } 299 if oversize > 0 { complete = 0 } 300 o = rp_put(out, o, " coverage_complete=") 301 o = rp_putn(out, o, complete) 302 o = rp_put(out, o, "\n") 303 sys_write(1, out, o) 304 305 // ---- THE RATCHET. Baseline absent means FIRST SIGHT: adopt the current count so the gate is 306 // non-breaking by construction, and say so, rather than going RED on every board at once. 307 let bb: *u8 = sys_mmap(BI_BASEMAX) 308 let bn: i64 = gk_read(BI_BASELINE, bb, BI_BASEMAX - 1) 309 var baseline: i64 = 0 - 1 310 if bn > 0 { 311 bb[bn] = 0 as u8 312 baseline = rp_num(bb, 0, bn) 313 } 314 var seeded: i64 = 0 315 if baseline < 0 { baseline = offenders; seeded = 1 } 316 317 gv_check("subject-population-non-empty" as *u8, (domains > 0) as i64, ctr) 318 gv_check("coverage-complete-no-unreadable-or-oversize-board" as *u8, complete, ctr) 319 gv_check_eq("offenders-did-not-rise-above-the-ratchet" as *u8, 320 (offenders > baseline) as i64, 0, ctr) 321 // NEG-CONTROL: the id table must not have silently filled, or a board's later rungs would be invisible 322 // and every reference to them would read as dangling -- a false positive that looks like a finding. 323 gv_check("neg-control-rung-id-table-did-not-saturate-on-the-largest-board" as *u8, 324 (maxids < BI_MAXIDS) as i64, ctr) 325 326 gv_values_head() 327 gv_kv("domains" as *u8, domains) 328 gv_kv("rung_rows" as *u8, rungrows) 329 gv_kv("log_rows" as *u8, logrows) 330 gv_kv("ms_rows" as *u8, msrows) 331 gv_kv("dupid" as *u8, dupid) 332 gv_kv("danglog" as *u8, danglog) 333 gv_kv("dangms" as *u8, dangms) 334 gv_kv("offenders" as *u8, offenders) 335 gv_kv("max_rungs_on_one_board" as *u8, maxids) 336 gv_kv("id_table_slots" as *u8, BI_MAXIDS) 337 gv_kv("baseline" as *u8, baseline) 338 gv_kv("baseline_seeded_this_run" as *u8, seeded) 339 340 // TIGHTEN ON A FALL, and only on a fall. A ratchet that rewrites its baseline on a RISE launders itself 341 // green, which is the defect this estate has bitten three times. 342 if offenders < baseline { 343 var t: i64 = 0 344 let tb: *u8 = sys_mmap(BI_BASEMAX) 345 t = rp_putn(tb, 0, offenders) 346 tb[t] = 10 as u8 347 tb[t + 1] = 0 as u8 348 gk_write(BI_BASELINE, tb) 349 } 350 if seeded == 1 { 351 var t2: i64 = 0 352 let tb2: *u8 = sys_mmap(BI_BASEMAX) 353 t2 = rp_putn(tb2, 0, offenders) 354 tb2[t2] = 10 as u8 355 tb2[t2 + 1] = 0 as u8 356 gk_write(BI_BASELINE, tb2) 357 } 358 359 return gv_verdict("BOARD-IDREF-GATE" as *u8, ctr, 360 "every rung id on every compare board is unique within its board, and every log row and milestone member resolves to a rung that board declares; the offender count is ratcheted so a rise is RED and a fall tightens the bar, and every offender is named above whatever the verdict") 361}