code wiki / _hdl_build / nx_gamehud_gate.nx

nx_gamehud_gate.nx source

↩ module page · 268 lines · 12020 B

1// nx_gamehud_gate.nx -- certification gate for nx_gamehud (gamebench capability 18 ui-menus-hud). 2// The bug classes each tooth exists to kill (every one shipped in a real engine somewhere): 3// T1 stale HUD -- HUD renders CACHED text instead of the live bound value 4// T2 impure render -- same state renders different pixels (kills replay/lockstep evidence) 5// T3 cursor clamp -- menu cursor clamps at the ends instead of wrapping (MUTATION TARGET) 6// T4 modal residue -- closing a menu does not restore the exact pre-menu frame 7// T5 out-of-bounds -- off-screen text/panel writes past the framebuffer (canary proves it can't) 8// T6 save amnesia -- HUD/menu state does not survive nx_gamesave round-trip (parts-compose tooth) 9// T7 nondeterminism -- the same nav script produces different selections/frames on a second run 10// T8 anti-vacuity -- guards that the equality teeth compared REAL ink and REAL distinct choices 11// (GX-9 law: a green gate that cannot fail is not evidence; T8 must stay GREEN under mutations) 12// license_tier: ORIGINAL expect_exit: 0 13import "nx_syscalls.nx" 14import "nx_gamehud.nx" 15import "nx_gamesave.nx" 16 17const W: i64 = 200 18const H: i64 = 120 19const FBN: i64 = 72000 // W*H*3 20const CAN: i64 = 64 // canary bytes past the fb 21const SCHEMA: i64 = 7411 22const INKMIN: i64 = 50 23 24func ww(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 } 25func wn(v: i64) -> i64 { 26 if v==0 { sys_write(1,"0" as *u8,1); return 0 } 27 var m: i64=v; if m<0 { sys_write(1,"-" as *u8,1); m=0-m } 28 let t: *u8=sys_mmap(32); var k: i64=0 29 while m>0 { t[k]=(48+(m%10)) as u8; m=m/10; k=k+1 } 30 let o: *u8=sys_mmap(32); var q: i64=k-1; var i: i64=0 31 while q>=0 { o[i]=t[q]; i=i+1; q=q-1 } 32 sys_write(1,o,i); return 0 33} 34func fbnew() -> *u8 { 35 let fb: *u8 = sys_mmap(FBN + CAN) 36 var i: i64 = 0 37 while i < FBN { fb[i] = 0 as u8; i = i + 1 } 38 var c: i64 = 0 39 while c < CAN { fb[FBN + c] = 0xA5 as u8; c = c + 1 } 40 return fb 41} 42func fbclear(fb: *u8) -> i64 { 43 var i: i64 = 0 44 while i < FBN { fb[i] = 0 as u8; i = i + 1 } 45 return 0 46} 47func fbdiff(a: *u8, b: *u8) -> i64 { 48 var d: i64 = 0 49 var i: i64 = 0 50 while i < FBN { if (a[i] & 0xff) != (b[i] & 0xff) { d = d + 1 } i = i + 1 } 51 return d 52} 53func canck(fb: *u8) -> i64 { 54 var bad: i64 = 0 55 var c: i64 = 0 56 while c < CAN { if (fb[FBN + c] & 0xff) != 0xA5 { bad = bad + 1 } c = c + 1 } 57 return bad 58} 59// the scripted nav run for T7/T8: returns sel0*1e9 + sel1*1e6 + nsel*1000 + distinct, and writes 60// final state ck to out[0], final frame ck to out[1] 61func navrun(font: *u8, labels: *i64, mlabels: *i64, out: *i64) -> i64 { 62 let g: *i64 = sys_mmap(GH_WORDS * 8) as *i64 63 gh_init(g, 4) 64 gh_slot_set(g, 0, 17) 65 gh_slot_set(g, 1, 3) 66 gh_slot_set(g, 2, 2) 67 gh_slot_set(g, 3, 9) 68 gh_menu_open(g, 4) 69 gh_menu_item(g, 0, 7, 100) 70 gh_menu_item(g, 1, 11, 200) 71 gh_menu_item(g, 2, 13, 300) 72 gh_menu_item(g, 3, 17, 400) 73 gh_menu_move(g, 5) // 0+5 wraps to 1 74 let s0: i64 = gh_menu_sel(g) // id 11, closes 75 gh_slot_set(g, 0, 17 + s0) // selection FEEDS BACK into the HUD (causal, not decorative) 76 gh_menu_open(g, 3) 77 gh_menu_item(g, 0, 21, 500) 78 gh_menu_item(g, 1, 23, 600) 79 gh_menu_item(g, 2, 29, 700) 80 gh_menu_move(g, 0 - 4) // 0-4 wraps to 2 81 let s1: i64 = gh_menu_sel(g) // id 29 82 gh_slot_set(g, 3, s1) 83 let fb: *u8 = fbnew() 84 gh_render(g, fb, W, H, font, labels, mlabels) 85 out[0] = gh_ck(g) 86 out[1] = gh_frame_ck(fb, W, H) 87 var distinct: i64 = 1 88 if s1 != s0 { distinct = 2 } 89 return s0 * 1000000000 + s1 * 1000000 + g[GH_F_NSEL] * 1000 + distinct 90} 91 92func main() -> i64 { 93 var pass: i64 = 0 94 let font: *u8 = font8x8_table() 95 let labels: *i64 = sys_mmap(16 * 8) as *i64 96 labels[0] = "HP" as i64 97 labels[1] = "LVL" as i64 98 labels[2] = "DEPTH" as i64 99 labels[3] = "KILLS" as i64 100 let mlabels: *i64 = sys_mmap(16 * 8) as *i64 101 mlabels[0] = "ration" as i64 102 mlabels[1] = "feast" as i64 103 mlabels[2] = "scroll" as i64 104 mlabels[3] = "potion" as i64 105 var i: i64 = 0 106 // 16-item labels for the T5 overflow menu reuse the 4 above cyclically 107 let biglab: *i64 = sys_mmap(16 * 8) as *i64 108 i = 0 109 while i < 16 { biglab[i] = mlabels[i % 4]; i = i + 1 } 110 111 ww("=== nx_gamehud_gate ===\n") 112 113 // ---------- T1 binding + non-vacuity: live values, not cached text ---------- 114 let g1: *i64 = sys_mmap(GH_WORDS * 8) as *i64 115 gh_init(g1, 4) 116 gh_slot_set(g1, 0, 17) 117 gh_slot_set(g1, 1, 3) 118 gh_slot_set(g1, 2, 2) 119 gh_slot_set(g1, 3, 9) 120 let fa: *u8 = fbnew() 121 gh_render(g1, fa, W, H, font, labels, mlabels) 122 let ink0: i64 = gh_ink(fa, W, H) 123 let cka: i64 = gh_frame_ck(fa, W, H) 124 gh_slot_set(g1, 0, 18) 125 let fB: *u8 = fbnew() 126 gh_render(g1, fB, W, H, font, labels, mlabels) 127 let ckb: i64 = gh_frame_ck(fB, W, H) 128 var t1: i64 = 0 129 if ink0 >= INKMIN { if cka != ckb { t1 = 1 } } 130 if t1 == 1 { 131 ww("T1 GREEN binding: ink "); wn(ink0); ww(" px, HP 17->18 moved the frame ck\n"); pass = pass + 1 132 } 133 if t1 == 0 { ww("T1 RED binding: ink="); wn(ink0); ww(" cka="); wn(cka); ww(" ckb="); wn(ckb); ww("\n") } 134 135 // ---------- T2 render purity: same state -> byte-identical pixels ---------- 136 let fc: *u8 = fbnew() 137 let fd: *u8 = fbnew() 138 gh_render(g1, fc, W, H, font, labels, mlabels) 139 gh_render(g1, fd, W, H, font, labels, mlabels) 140 let d2: i64 = fbdiff(fc, fd) 141 let ink2: i64 = gh_ink(fc, W, H) 142 var t2: i64 = 0 143 if d2 == 0 { if ink2 >= INKMIN { t2 = 1 } } 144 if t2 == 1 { ww("T2 GREEN purity: two renders byte-identical ("); wn(ink2); ww(" ink px)\n"); pass = pass + 1 } 145 if t2 == 0 { ww("T2 RED purity: diffs="); wn(d2); ww(" ink="); wn(ink2); ww("\n") } 146 147 // ---------- T3 wrap-around both directions + select id (MUTATION TARGET) ---------- 148 let g3: *i64 = sys_mmap(GH_WORDS * 8) as *i64 149 gh_init(g3, 1) 150 gh_menu_open(g3, 3) 151 gh_menu_item(g3, 0, 7, 0) 152 gh_menu_item(g3, 1, 11, 0) 153 gh_menu_item(g3, 2, 13, 0) 154 let w1: i64 = gh_menu_move(g3, 0 - 1) // 0 -> 2 (wrap down) 155 let w2: i64 = gh_menu_move(g3, 1) // 2 -> 0 (wrap up) 156 let w3: i64 = gh_menu_move(g3, 1) // 0 -> 1 157 let sid: i64 = gh_menu_sel(g3) // id 11 158 var t3: i64 = 0 159 if w1 == 2 { if w2 == 0 { if w3 == 1 { if sid == 11 { if g3[GH_F_MOPEN] == 0 { t3 = 1 } } } } } 160 if t3 == 1 { ww("T3 GREEN menu wrap: -1 from 0 -> 2, +1 -> 0, select under cursor = id 11, modal-closed\n"); pass = pass + 1 } 161 if t3 == 0 { ww("T3 RED wrap: w1="); wn(w1); ww(" w2="); wn(w2); ww(" w3="); wn(w3); ww(" sel="); wn(sid); ww("\n") } 162 163 // ---------- T4 modality: menu paints over, close restores the EXACT frame ---------- 164 let g4: *i64 = sys_mmap(GH_WORDS * 8) as *i64 165 gh_init(g4, 4) 166 gh_slot_set(g4, 0, 17) 167 gh_slot_set(g4, 1, 3) 168 gh_slot_set(g4, 2, 2) 169 gh_slot_set(g4, 3, 9) 170 let f4a: *u8 = fbnew() 171 gh_render(g4, f4a, W, H, font, labels, mlabels) 172 gh_menu_open(g4, 4) 173 gh_menu_item(g4, 0, 7, 100) 174 gh_menu_item(g4, 1, 11, 200) 175 gh_menu_item(g4, 2, 13, 300) 176 gh_menu_item(g4, 3, 17, 400) 177 let f4b: *u8 = fbnew() 178 gh_render(g4, f4b, W, H, font, labels, mlabels) 179 let dopen: i64 = fbdiff(f4a, f4b) 180 gh_menu_close(g4) 181 let f4c: *u8 = fbnew() 182 gh_render(g4, f4c, W, H, font, labels, mlabels) 183 let dclose: i64 = fbdiff(f4a, f4c) 184 var t4: i64 = 0 185 if dopen >= 100 { if dclose == 0 { t4 = 1 } } 186 if t4 == 1 { ww("T4 GREEN modality: open moved "); wn(dopen); ww(" bytes, close restored the exact frame\n"); pass = pass + 1 } 187 if t4 == 0 { ww("T4 RED modality: dopen="); wn(dopen); ww(" dclose="); wn(dclose); ww("\n") } 188 189 // ---------- T5 bounds: off-screen text + oversized panel cannot escape the fb ---------- 190 let g5: *i64 = sys_mmap(GH_WORDS * 8) as *i64 191 gh_init(g5, 4) 192 gh_slot_set(g5, 0, 1234567) // long number pushes the bar toward the right edge 193 gh_slot_set(g5, 1, 7654321) 194 gh_slot_set(g5, 2, 9999999) 195 gh_slot_set(g5, 3, 8888888) 196 gh_menu_open(g5, 16) // panel bottom = 14+4+160+2 = 180 > H=120 -> clipped 197 var mi: i64 = 0 198 while mi < 16 { gh_menu_item(g5, mi, 100 + mi, 1000000 + mi); mi = mi + 1 } 199 let f5: *u8 = fbnew() 200 gh_render(g5, f5, W, H, font, labels, biglab) 201 gh_text(f5, W, H, font, W - 5, H - 3, "overflow-right-bottom" as *u8) 202 gh_text(f5, W, H, font, 0 - 30, 0 - 30, "negative-origin" as *u8) 203 gh_numdraw(f5, W, H, font, W - 2, 4, 987654321) 204 let bad5: i64 = canck(f5) 205 let ink5: i64 = gh_ink(f5, W, H) 206 var t5: i64 = 0 207 if bad5 == 0 { if ink5 >= INKMIN { t5 = 1 } } 208 if t5 == 1 { ww("T5 GREEN bounds: oversized panel + edge/negative text, canary intact ("); wn(ink5); ww(" ink px)\n"); pass = pass + 1 } 209 if t5 == 0 { ww("T5 RED bounds: canary-bytes-hit="); wn(bad5); ww(" ink="); wn(ink5); ww("\n") } 210 211 // ---------- T6 save/load round-trip through nx_gamesave (parts-compose tooth) ---------- 212 let P: *u8 = "knowledge/nx_gamehud_t.sav" as *u8 213 sys_unlinkat(P) 214 let g6: *i64 = sys_mmap(GH_WORDS * 8) as *i64 215 gh_init(g6, 4) 216 gh_slot_set(g6, 0, 28) 217 gh_slot_set(g6, 1, 4) 218 gh_slot_set(g6, 2, 3) 219 gh_slot_set(g6, 3, 16) 220 gh_menu_open(g6, 4) 221 gh_menu_item(g6, 0, 7, 100) 222 gh_menu_item(g6, 1, 11, 200) 223 gh_menu_item(g6, 2, 13, 300) 224 gh_menu_item(g6, 3, 17, 400) 225 gh_menu_move(g6, 1) // cursor 1: cursor position must survive the save 226 let sr: i64 = gs_save(P, SCHEMA, g6, GH_NSV, 777001) 227 let g6b: *i64 = sys_mmap(GH_WORDS * 8) as *i64 228 let meta: *i64 = sys_mmap(8 * 8) as *i64 229 let lr: i64 = gs_load(P, g6b, GH_WORDS, meta) 230 let ck6a: i64 = gh_ck(g6) 231 let ck6b: i64 = gh_ck(g6b) 232 let f6a: *u8 = fbnew() 233 let f6b: *u8 = fbnew() 234 gh_render(g6, f6a, W, H, font, labels, mlabels) 235 gh_render(g6b, f6b, W, H, font, labels, mlabels) 236 let d6: i64 = fbdiff(f6a, f6b) 237 let ink6: i64 = gh_ink(f6a, W, H) 238 var t6: i64 = 0 239 let expw: i64 = GS_HDR + GH_NSV * 8 // gs_save returns TOTAL BYTES WRITTEN (header + payload) 240 if sr == expw { if lr == GH_NSV { if ck6a == ck6b { if d6 == 0 { if ink6 >= INKMIN { t6 = 1 } } } } } 241 if t6 == 1 { 242 ww("T6 GREEN save/load: state ck "); wn(ck6a); ww(" and render survive the round-trip (cursor kept)\n") 243 pass = pass + 1 244 } 245 if t6 == 0 { ww("T6 RED save/load: sr="); wn(sr); ww(" lr="); wn(lr); ww(" cka="); wn(ck6a); ww(" ckb="); wn(ck6b); ww(" d="); wn(d6); ww("\n") } 246 247 // ---------- T7 scripted determinism: same nav script twice from scratch ---------- 248 let o7a: *i64 = sys_mmap(4 * 8) as *i64 249 let o7b: *i64 = sys_mmap(4 * 8) as *i64 250 let r7a: i64 = navrun(font, labels, mlabels, o7a) 251 let r7b: i64 = navrun(font, labels, mlabels, o7b) 252 var t7: i64 = 0 253 if r7a == r7b { if o7a[0] == o7b[0] { if o7a[1] == o7b[1] { t7 = 1 } } } 254 if t7 == 1 { ww("T7 GREEN deterministic: nav script twice -> identical selections + state ck + frame ck ("); wn(o7a[0]); ww(")\n"); pass = pass + 1 } 255 if t7 == 0 { ww("T7 RED determinism: r7a="); wn(r7a); ww(" r7b="); wn(r7b); ww("\n") } 256 257 // ---------- T8 anti-vacuity: the compared things were REAL (stays GREEN under mutations) ---------- 258 let dist: i64 = r7a % 1000 259 let nsel: i64 = (r7a / 1000) % 1000 260 var t8: i64 = 0 261 if dist >= 2 { if nsel >= 2 { if ink0 >= INKMIN { if dopen >= 100 { t8 = 1 } } } } 262 if t8 == 1 { ww("T8 GREEN anti-vacuity: "); wn(nsel); ww(" selections, "); wn(dist); ww(" distinct ids, real ink both frames\n"); pass = pass + 1 } 263 if t8 == 0 { ww("T8 RED vacuous: distinct="); wn(dist); ww(" nsel="); wn(nsel); ww(" ink0="); wn(ink0); ww(" dopen="); wn(dopen); ww("\n") } 264 265 ww("nx_gamehud_gate: "); wn(pass); ww("/8\n") 266 if pass == 8 { return 0 } 267 return 1 268}