code wiki / _hdl_build / nx_ws_board_gate.nx

nx_ws_board_gate.nx source

↩ module page · 304 lines · 13859 B

1// nx_ws_board_gate.nx -- THE REFEREE for WMS rung M2 (the live status board). 2// 3// Proves nx_ws_board DERIVES the correct per-empire/per-stream view from the WMS-R1 4// registry, AND that it is NEVER silently wrong -- the four mandatory negative controls 5// prove the detector can actually SEE failure (no-false-green): 6// 7// HERMETIC fixtures (controlled, NOT production claims): 8// prefix wsboard- : ws:empires = E-A,E-B,E-C ; ws:ids = B-1..B-4 ; 4 complete streams 9// B-1 E-A DONE / B-2 E-A ACTIVE / B-3 E-B BLOCKED / B-4 E-C DONE 10// prefix wsboard2- : ws:ids lists B2-1 + B2-LOST, but ws:B2-LOST is NEVER committed 11// (the lost-segment fault, twin of registry-gate T5). 12// 13// POSITIVE (all must hold for GREEN): 14// T1 enumerate-exact : wb_board_p(wsboard-, refpath=0) returns empires=3. 15// T2 per-empire counts EXACT : E-A streams=2 done=1 active=1 blocked=0 ; 16// E-B streams=1 blocked=1 ; E-C streams=1 done=1. 17// T3 summary EXACT : total=4 done=2 active=1 blocked=1. 18// T4 clean-reflog overlay : a /tmp reflog of good ledger_append records (flagged=0) 19// -> wb_board_p(..., refpath=good) returns >=0 (accepted). 20// 21// NEGATIVE CONTROLS (a GREEN with no working neg-control is INVALID): 22// N1 unregistered-absent : ws_get_p(wsboard-, ws:B-NEVER) == WS_UNKNOWN(-1) AND 23// "B-NEVER" appears in ZERO board empire rows. 24// N2 torn-reflog REJECTED : a /tmp reflog = good records + one raw line MISSING the 25// " END" sentinel -> wb_board_p(..., refpath=torn) == -3 26// (rejected, NOT silently rendered). >=0 => RED. 27// N3 incomplete-registry REJECTED : wb_board_p(wsboard2-, 0) == -1 (lost segment -> 28// board refuses). >=0 => RED. 29// N4 detector-sees-difference : N2's -3 and T4's >=0 are DIFFERENT return values on 30// contrasting inputs (proves the guard is not a constant). 31// 32// GREEN only if T1..T4 AND N1..N4 all hold. Evidence rows + verdict go to 33// knowledge/status/ws_board_gate.log via the MANDATORY fa_appendz one-buffer-one-locked- 34// write discipline (eat-own-dogfood); fixture /tmp reflogs use epoch+pid-suffixed names 35// so concurrent gate runs never collide. Exit 0 GREEN / 1 RED. 36// Sovereign: imports only the WMS stack + nx_syscalls (no gcc). license_tier: ORIGINAL 37import "nx_ws_board.nx" 38import "nx_workstream_store.nx" 39import "nx_ws_ledger.nx" 40import "nx_framed_append.nx" 41import "nx_seg_store.nx" 42import "nx_syscalls.nx" 43 44const WBG_LOG: *u8 = "knowledge/status/ws_board_gate.log" 45const WBG_PREFIX: *u8 = "knowledge/store/wsboard-" 46const WBG_PREFIX2: *u8 = "knowledge/store/wsboard2-" 47const WBG_RECCAP: i64 = 512 48 49func wbg_len(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n } 50 51func wbg_streq(a: *u8, b: *u8) -> i64 { 52 var i: i64 = 0 53 while a[i] != (0 as u8) { if a[i] != b[i] { return 0 } i = i + 1 } 54 if b[i] != (0 as u8) { return 0 } 55 return 1 56} 57 58// 1 if store value for key under `prefix` byte-equals val (idempotent seed helper). 59func wbg_streq_store(prefix: *u8, key: *u8, val: *u8) -> i64 { 60 let pq: *i64 = sys_mmap(16) as *i64 61 let lq: *i64 = sys_mmap(16) as *i64 62 if ss_get(prefix, key, pq, lq) != 1 { return 0 } 63 let b: *u8 = pq[0] as *u8 64 let n: i64 = lq[0] 65 let vl: i64 = wbg_len(val) 66 if n != vl { return 0 } 67 var i: i64 = 0 68 while i < n { if b[i] != val[i] { return 0 } i = i + 1 } 69 return 1 70} 71 72// commit one (key,val) into `prefix`, idempotent (wrg_seed_one idiom). 73func wbg_seed_one(prefix: *u8, key: *u8, val: *u8) -> i64 { 74 if wbg_streq_store(prefix, key, val) == 1 { return 1 } 75 let w: *i64 = ss_begin() 76 ss_add(w, 1, key, val, wbg_len(val)) 77 let segid: i64 = ws_seg_next(prefix) 78 return ss_commit(prefix, w, segid) 79} 80 81// find empire row e in rows[] whose empire-id == name; return its base index, or -1. 82func wbg_find(rows: *i64, ecount: i64, name: *u8) -> i64 { 83 var e: i64 = 0 84 while e < ecount { 85 let base: i64 = e * WB_ROWW 86 if wbg_streq(rows[base + 0] as *u8, name) == 1 { return base } 87 e = e + 1 88 } 89 return 0 - 1 90} 91 92// decimal of v into dst at off (for building the unique /tmp path suffix). 93func wbg_catn(dst: *u8, off: i64, v: i64) -> i64 { 94 var m: i64 = v; var o: i64 = off 95 if m < 0 { m = 0 - m } 96 let t: *u8 = sys_mmap(28); var k: i64 = 0 97 if m == 0 { t[0] = 48 as u8; k = 1 } 98 while m > 0 { t[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 } 99 var i: i64 = 0 100 while i < k { dst[o + i] = t[k - 1 - i]; i = i + 1 } 101 return o + k 102} 103func wbg_cat(dst: *u8, off: i64, s: *u8) -> i64 { 104 var i: i64 = 0 105 while s[i] != (0 as u8) { dst[off + i] = s[i]; i = i + 1 } 106 return off + i 107} 108 109// build a unique /tmp path = <stem><epoch>.<pid>.log into out (NUL-term). 110func wbg_tmppath(out: *u8, stem: *u8, epoch: i64, pid: i64) -> i64 { 111 var o: i64 = 0 112 o = wbg_cat(out, o, stem) 113 o = wbg_catn(out, o, epoch) 114 o = wbg_cat(out, o, "." as *u8) 115 o = wbg_catn(out, o, pid) 116 o = wbg_cat(out, o, ".log" as *u8) 117 out[o] = 0 as u8 118 return o 119} 120 121// MANDATORY WRITE DISCIPLINE: one PASS/FAIL row assembled into one buffer, ONE locked 122// fa_appendz (eat-own-dogfood). Also mirrored to stdout (terminal, uncontended). 123func wbg_row(name: *u8, pass: i64) -> i64 { 124 let buf: *u8 = sys_mmap(WBG_RECCAP + 16) 125 var o: i64 = 0 126 o = wbg_cat(buf, o, "WSB row=\x00" as *u8) 127 o = wbg_cat(buf, o, name) 128 if pass == 1 { o = wbg_cat(buf, o, " verdict=PASS\x00" as *u8) } else { o = wbg_cat(buf, o, " verdict=FAIL\x00" as *u8) } 129 buf[o] = 0 as u8 130 fa_appendz(WBG_LOG, buf, WBG_RECCAP) 131 // stdout mirror 132 sys_write(1, " \x00" as *u8, 2) 133 var n: i64 = 0; while name[n] != (0 as u8) { n = n + 1 } sys_write(1, name, n) 134 if pass == 1 { sys_write(1, " PASS\n\x00" as *u8, 6) } else { sys_write(1, " FAIL\n\x00" as *u8, 6) } 135 return 0 136} 137 138func main() -> i64 { 139 let epoch: i64 = sys_now_realtime_sec() 140 let pid: i64 = __syscall(39, 0, 0, 0, 0, 0, 0) 141 142 // ===== seed the HERMETIC complete store (idempotent / additive). ===== 143 wbg_seed_one(WBG_PREFIX, "ws:empires" as *u8, "E-A\tE-B\tE-C" as *u8) 144 wbg_seed_one(WBG_PREFIX, "ws:ids" as *u8, "B-1\tB-2\tB-3\tB-4" as *u8) 145 wbg_seed_one(WBG_PREFIX, "ws:B-1" as *u8, "B-1\tE-A\tDONE\t100\tmem\torgan\t-" as *u8) 146 wbg_seed_one(WBG_PREFIX, "ws:B-2" as *u8, "B-2\tE-A\tACTIVE\t200\tmem\torgan\t-" as *u8) 147 wbg_seed_one(WBG_PREFIX, "ws:B-3" as *u8, "B-3\tE-B\tBLOCKED\t300\tmem\torgan\t-" as *u8) 148 wbg_seed_one(WBG_PREFIX, "ws:B-4" as *u8, "B-4\tE-C\tDONE\t400\tmem\torgan\t-" as *u8) 149 150 // ===== seed the INCOMPLETE store (N3): ws:B2-LOST listed but never committed. ===== 151 wbg_seed_one(WBG_PREFIX2, "ws:empires" as *u8, "E-A\tE-B" as *u8) 152 wbg_seed_one(WBG_PREFIX2, "ws:ids" as *u8, "B2-1\tB2-LOST" as *u8) 153 wbg_seed_one(WBG_PREFIX2, "ws:B2-1" as *u8, "B2-1\tE-A\tDONE\t1\tmem\torgan\t-" as *u8) 154 // NOTE: ws:B2-LOST intentionally NOT seeded (the lost/torn segment). 155 156 let rows: *i64 = sys_mmap(8 * WB_MAXEMP * WB_ROWW) as *i64 157 let ec: *i64 = sys_mmap(16) as *i64 158 let sm: *i64 = sys_mmap(64) as *i64 159 160 // ---- T1: enumerate-exact (empires=3) ---- 161 let r1: i64 = wb_board_p(WBG_PREFIX, 0 as *u8, rows, WB_MAXEMP, ec, sm) 162 var t1: i64 = 0 163 if r1 == 3 { if ec[0] == 3 { t1 = 1 } } 164 165 // ---- T2: per-empire counts EXACT ---- 166 var t2: i64 = 0 167 let ba: i64 = wbg_find(rows, ec[0], "E-A" as *u8) 168 let bb: i64 = wbg_find(rows, ec[0], "E-B" as *u8) 169 let bc: i64 = wbg_find(rows, ec[0], "E-C" as *u8) 170 if ba >= 0 { if bb >= 0 { if bc >= 0 { 171 var ok2: i64 = 1 172 // E-A: streams=2 done=1 active=1 blocked=0 173 if rows[ba + 1] != 2 { ok2 = 0 } 174 if rows[ba + 2] != 1 { ok2 = 0 } 175 if rows[ba + 3] != 1 { ok2 = 0 } 176 if rows[ba + 4] != 0 { ok2 = 0 } 177 // E-B: streams=1 blocked=1 178 if rows[bb + 1] != 1 { ok2 = 0 } 179 if rows[bb + 4] != 1 { ok2 = 0 } 180 // E-C: streams=1 done=1 181 if rows[bc + 1] != 1 { ok2 = 0 } 182 if rows[bc + 2] != 1 { ok2 = 0 } 183 if ok2 == 1 { t2 = 1 } 184 } } } 185 186 // ---- T3: summary EXACT (total=4 done=2 active=1 blocked=1) ---- 187 var t3: i64 = 0 188 if sm[0] == 4 { if sm[1] == 2 { if sm[2] == 1 { if sm[3] == 1 { t3 = 1 } } } } 189 190 // ---- T4: clean-reflog overlay accepted (>=0) ---- 191 // build a unique /tmp good reflog with a few well-formed ledger_append records. 192 let goodp: *u8 = sys_mmap(256) 193 wbg_tmppath(goodp, "/tmp/wsb_good." as *u8, epoch, pid) 194 let g0: i64 = sys_openat_wr(goodp, 0x1a4) // truncate fresh 195 if g0 > 0 { sys_close(g0) } 196 var gi: i64 = 0 197 while gi < 5 { ledger_append(goodp, gi, 0, 1, 7, gi, gi); gi = gi + 1 } 198 let r4: i64 = wb_board_p(WBG_PREFIX, goodp, rows, WB_MAXEMP, ec, sm) 199 var t4: i64 = 0 200 if r4 >= 0 { t4 = 1 } 201 202 // ---- N1: unregistered-stream-absent ---- 203 // a never-registered id returns WS_UNKNOWN, AND "B-NEVER" appears in no empire row. 204 let pq: *i64 = sys_mmap(16) as *i64 205 let lq: *i64 = sys_mmap(16) as *i64 206 var n1: i64 = 0 207 if ws_get_p(WBG_PREFIX, "ws:B-NEVER" as *u8, pq, lq) == WS_UNKNOWN { 208 // re-render the board and scan every empire-id row for the token (must be 0 hits). 209 let r1b: i64 = wb_board_p(WBG_PREFIX, 0 as *u8, rows, WB_MAXEMP, ec, sm) 210 var hits: i64 = 0 211 var e: i64 = 0 212 while e < ec[0] { 213 let base: i64 = e * WB_ROWW 214 if wbg_streq(rows[base + 0] as *u8, "B-NEVER" as *u8) == 1 { hits = hits + 1 } 215 e = e + 1 216 } 217 if r1b == 3 { if hits == 0 { n1 = 1 } } 218 } 219 220 // ---- N2: torn/old reflog REJECTED (wb_board_p returns -3) ---- 221 let tornp: *u8 = sys_mmap(256) 222 wbg_tmppath(tornp, "/tmp/wsb_torn." as *u8, epoch, pid) 223 let t0: i64 = sys_openat_wr(tornp, 0x1a4) 224 if t0 > 0 { sys_close(t0) } 225 var ti: i64 = 0 226 while ti < 3 { ledger_append(tornp, ti, 0, 1, 7, ti, ti); ti = ti + 1 } 227 // append one raw line MISSING the " END" sentinel (the R2 gate's tamper idiom). 228 let tfd: i64 = sys_openat_append(tornp, 0x1a4) 229 if tfd > 0 { 230 sys_write(tfd, "WSX ws=0 old=1 new=2 actor=7 reason=9 ev=0 epoch=0 BROKEN\n\x00" as *u8, 58) 231 sys_close(tfd) 232 } 233 let rn2: i64 = wb_board_p(WBG_PREFIX, tornp, rows, WB_MAXEMP, ec, sm) 234 var n2: i64 = 0 235 if rn2 == WB_TORNREFLOG { n2 = 1 } // -3 : rejected (NOT silently rendered) 236 237 // ---- N3: incomplete-registry REJECTED (wb_board_p returns -1) ---- 238 let rn3: i64 = wb_board_p(WBG_PREFIX2, 0 as *u8, rows, WB_MAXEMP, ec, sm) 239 var n3: i64 = 0 240 if rn3 == WB_INCOMPLETE { n3 = 1 } // -1 : lost segment -> refuse 241 242 // ---- N4: detector-sees-difference (rn2 != r4 on contrasting reflog inputs) ---- 243 var n4: i64 = 0 244 if rn2 != r4 { if rn2 == WB_TORNREFLOG { if r4 >= 0 { n4 = 1 } } } 245 246 // ===== flat pass-tally ===== 247 var passes: i64 = 0 248 if t1 == 1 { passes = passes + 1 } 249 if t2 == 1 { passes = passes + 1 } 250 if t3 == 1 { passes = passes + 1 } 251 if t4 == 1 { passes = passes + 1 } 252 if n1 == 1 { passes = passes + 1 } 253 if n2 == 1 { passes = passes + 1 } 254 if n3 == 1 { passes = passes + 1 } 255 if n4 == 1 { passes = passes + 1 } 256 var green: i64 = 0 257 if passes == 8 { green = 1 } 258 259 sys_write(1, "WMS-M2 ws-board gate (derived view + 4 neg-controls)\n\x00" as *u8, 52) 260 wbg_row("T1-enumerate-exact \x00" as *u8, t1) 261 wbg_row("T2-per-empire-counts \x00" as *u8, t2) 262 wbg_row("T3-summary-exact \x00" as *u8, t3) 263 wbg_row("T4-clean-reflog-overlay \x00" as *u8, t4) 264 wbg_row("N1-unregistered-absent \x00" as *u8, n1) 265 wbg_row("N2-torn-reflog-rejected \x00" as *u8, n2) 266 wbg_row("N3-incomplete-rejected \x00" as *u8, n3) 267 wbg_row("N4-detector-sees-diff \x00" as *u8, n4) 268 269 // verdict line: one buffer, one locked atomic fa_appendz (eat-own-dogfood). 270 let vb: *u8 = sys_mmap(WBG_RECCAP + 16) 271 var o: i64 = 0 272 o = wbg_cat(vb, o, "WS-BOARD verdict=\x00" as *u8) 273 if green == 1 { o = wbg_cat(vb, o, "GREEN\x00" as *u8) } else { o = wbg_cat(vb, o, "RED\x00" as *u8) } 274 o = wbg_cat(vb, o, " passes=\x00" as *u8) 275 o = wbg_catn(vb, o, passes) 276 o = wbg_cat(vb, o, "/8 t1=\x00" as *u8); o = wbg_catn(vb, o, t1) 277 o = wbg_cat(vb, o, " t2=\x00" as *u8); o = wbg_catn(vb, o, t2) 278 o = wbg_cat(vb, o, " t3=\x00" as *u8); o = wbg_catn(vb, o, t3) 279 o = wbg_cat(vb, o, " t4=\x00" as *u8); o = wbg_catn(vb, o, t4) 280 o = wbg_cat(vb, o, " n1=\x00" as *u8); o = wbg_catn(vb, o, n1) 281 o = wbg_cat(vb, o, " n2=\x00" as *u8); o = wbg_catn(vb, o, n2) 282 o = wbg_cat(vb, o, " n3=\x00" as *u8); o = wbg_catn(vb, o, n3) 283 o = wbg_cat(vb, o, " n4=\x00" as *u8); o = wbg_catn(vb, o, n4) 284 if green == 0 { 285 o = wbg_cat(vb, o, " reason=\x00" as *u8) 286 if t1 == 0 { o = wbg_cat(vb, o, "enumerate-wrong \x00" as *u8) } 287 if t2 == 0 { o = wbg_cat(vb, o, "per-empire-counts-wrong \x00" as *u8) } 288 if t3 == 0 { o = wbg_cat(vb, o, "summary-wrong \x00" as *u8) } 289 if t4 == 0 { o = wbg_cat(vb, o, "clean-reflog-rejected \x00" as *u8) } 290 if n1 == 0 { o = wbg_cat(vb, o, "unregistered-appeared \x00" as *u8) } 291 if n2 == 0 { o = wbg_cat(vb, o, "torn-reflog-silently-rendered \x00" as *u8) } 292 if n3 == 0 { o = wbg_cat(vb, o, "incomplete-registry-rendered \x00" as *u8) } 293 if n4 == 0 { o = wbg_cat(vb, o, "detector-blind \x00" as *u8) } 294 } 295 o = wbg_cat(vb, o, " END\x00" as *u8) 296 vb[o] = 0 as u8 297 fa_appendz(WBG_LOG, vb, WBG_RECCAP) 298 // stdout verdict 299 sys_write(1, vb, o) 300 sys_write(1, "\n\x00" as *u8, 1) 301 302 if green == 1 { return 0 } 303 return 1 304}