code wiki / _hdl_build / nx_gamesave_gate.nx

nx_gamesave_gate.nx source

↩ module page · 196 lines · 8510 B

1// nx_gamesave_gate.nx -- CERTIFICATION of the nx_gamesave part (gamebench gap-queue rank 1). 2// A save/load part is only worth composing if the ugly cases are PROVEN, so the teeth are the failure 3// modes that actually ruin players' runs: 4// T1 round-trip fidelity -- every field returns exactly, metadata intact 5// T2 BIT-EXACT re-save -- save->load->save is byte-identical (the determinism exceed, persisted) 6// T3 corruption REFUSED -- one flipped payload byte -> CHECKSUM-CORRUPT, never partial state 7// T4 truncation REFUSED -- a chopped file -> SHORT-TRUNCATED, not a misparse 8// T5 future-version REFUSED -- a newer format is rejected, not silently misread 9// T6 additive-only (rule 13) -- saving over a slot banks the PRIOR BYTES as .prev, verified by content 10// T7 atomic -- no .tmp residue survives a save 11// T8 ANTI-VACUITY -- after all those refusals, a clean save/load must STILL SUCCEED. 12// Without T8 a loader that simply refused everything would score 7/7. This is the tooth that makes 13// the refusal teeth mean something. 14// license_tier: ORIGINAL expect_exit: 0 15import "nx_syscalls.nx" 16import "nx_gamesave.nx" 17 18func tw(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 } 19func tn(v: i64) -> i64 { 20 if v==0 { sys_write(1,"0" as *u8,1); return 0 } 21 var m: i64=v; if m<0 { sys_write(1,"-" as *u8,1); m=0-m } 22 let t: *u8=sys_mmap(32); var k: i64=0 23 while m>0 { t[k]=(48+(m%10)) as u8; m=m/10; k=k+1 } 24 let o: *u8=sys_mmap(32); var q: i64=k-1; var i: i64=0 25 while q>=0 { o[i]=t[q]; i=i+1; q=q-1 } 26 sys_write(1,o,i); return 0 27} 28// raw whole-file write (used only to FABRICATE damaged saves for the refusal teeth) 29func rawwrite(path: *u8, b: *u8, n: i64) -> i64 { 30 let fd: i64 = sys_openat_wr(path, 0x1a4) 31 if fd < 0 { return 0-1 } 32 let w: i64 = sys_write(fd, b, n) 33 sys_fsync(fd); sys_close(fd) 34 return w 35} 36func filebytes(path: *u8, outlen: *i64) -> *u8 { 37 outlen[0]=0 38 return sys_read_file(path, outlen) 39} 40func samebytes(a: *u8, an: i64, b: *u8, bn: i64) -> i64 { 41 if an != bn { return 0 } 42 var i: i64=0 43 while i<an { if a[i]!=b[i] { return 0 } i=i+1 } 44 return 1 45} 46 47func main() -> i64 { 48 tw("=== nx_gamesave_gate: is the save/load part safe to compose into every game? ===\n\n") 49 var pass: i64 = 0 50 var checks: i64 = 0 51 52 let P: *u8 = "knowledge/nx_gamesave_t.sav" as *u8 53 let P2: *u8 = "knowledge/nx_gamesave_t2.sav" as *u8 54 let PB: *u8 = "knowledge/nx_gamesave_bad.sav" as *u8 55 let PP: *u8 = "knowledge/nx_gamesave_t.sav.prev" as *u8 56 let PT: *u8 = "knowledge/nx_gamesave_t.sav.tmp" as *u8 57 // start clean so a stale artifact can never fake a pass 58 sys_unlinkat(P); sys_unlinkat(P2); sys_unlinkat(PB); sys_unlinkat(PP); sys_unlinkat(PT) 59 60 let NF: i64 = 12 61 let st: *i64 = sys_mmap(NF*8) as *i64 62 st[0]=1; st[1]=0-42; st[2]=999999; st[3]=0; st[4]=7; st[5]=123456789 63 st[6]=0-1; st[7]=64; st[8]=2026; st[9]=0-987654321; st[10]=5; st[11]=100 64 let SCHEMA: i64 = 4711 65 let WHEN: i64 = 1784577000 66 67 // ---------- T1 round-trip fidelity ---------- 68 checks = checks + 1 69 let wrote: i64 = gs_save(P, SCHEMA, st, NF, WHEN) 70 let back: *i64 = sys_mmap(NF*8) as *i64 71 let meta: *i64 = sys_mmap(3*8) as *i64 72 let got: i64 = gs_load(P, back, NF, meta) 73 var same: i64 = 1 74 var i: i64 = 0 75 while i<NF { if back[i]!=st[i] { same=0 } i=i+1 } 76 if wrote > 0 { if got==NF { if same==1 { if meta[0]==SCHEMA { if meta[1]==WHEN { 77 tw("T1 GREEN round-trip: "); tn(NF); tw(" fields exact, schema+timestamp intact, bytes="); tn(wrote); tw("\n") 78 pass = pass + 1 79 } } } } } 80 if pass==0 { 81 tw("T1 RED round-trip failed wrote="); tn(wrote); tw(" got="); tn(got); tw(" fields_equal="); tn(same); tw("\n") 82 } 83 84 // ---------- T2 BIT-EXACT re-save ---------- 85 checks = checks + 1 86 gs_save(P2, meta[0], back, got, meta[1]) 87 let l1: *i64 = sys_mmap(8) as *i64 88 let l2: *i64 = sys_mmap(8) as *i64 89 let b1: *u8 = filebytes(P, l1) 90 let b2: *u8 = filebytes(P2, l2) 91 var bitexact: i64 = 0 92 if (b1 as i64)!=0 { if (b2 as i64)!=0 { bitexact = samebytes(b1,l1[0],b2,l2[0]) } } 93 if bitexact==1 { 94 tw("T2 GREEN bit-exact re-save: save->load->save byte-identical ("); tn(l1[0]); tw("B) -- deterministic persistence\n") 95 pass = pass + 1 96 } else { 97 tw("T2 RED re-save differs: "); tn(l1[0]); tw("B vs "); tn(l2[0]); tw("B\n") 98 } 99 100 // ---------- T3 corruption REFUSED ---------- 101 checks = checks + 1 102 let lc: *i64 = sys_mmap(8) as *i64 103 let cb: *u8 = filebytes(P, lc) 104 var t3: i64 = 0 105 if (cb as i64)!=0 { 106 cb[GS_HDR+3] = (cb[GS_HDR+3] ^ 1) as u8 // flip ONE bit of payload 107 rawwrite(PB, cb, lc[0]) 108 let r: i64 = gs_load(PB, back, NF, 0 as *i64) 109 if r==GS_E_CKSUM { t3=1 } 110 if t3==1 { 111 tw("T3 GREEN corruption refused: 1 flipped payload bit -> "); tw(gs_errname(r)); tw(" (no partial state returned)\n") 112 pass = pass + 1 113 } else { 114 tw("T3 RED corrupted save was NOT refused, rc="); tn(r); tw("\n") 115 } 116 } 117 118 // ---------- T4 truncation REFUSED ---------- 119 checks = checks + 1 120 let lt: *i64 = sys_mmap(8) as *i64 121 let tb: *u8 = filebytes(P, lt) 122 if (tb as i64)!=0 { 123 rawwrite(PB, tb, lt[0]-8) // lose the last field 124 let r4: i64 = gs_load(PB, back, NF, 0 as *i64) 125 if r4==GS_E_SHORT { 126 tw("T4 GREEN truncation refused: short file -> "); tw(gs_errname(r4)); tw("\n") 127 pass = pass + 1 128 } else { 129 tw("T4 RED truncated save was NOT refused, rc="); tn(r4); tw("\n") 130 } 131 } 132 133 // ---------- T5 future-version REFUSED ---------- 134 checks = checks + 1 135 let lv: *i64 = sys_mmap(8) as *i64 136 let vb: *u8 = filebytes(P, lv) 137 if (vb as i64)!=0 { 138 vb[8] = (GS_FMT_VER + 1) as u8 // pretend a newer writer made it 139 rawwrite(PB, vb, lv[0]) 140 let r5: i64 = gs_load(PB, back, NF, 0 as *i64) 141 if r5==GS_E_VERSION { 142 tw("T5 GREEN future-version refused: fmt_ver="); tn(GS_FMT_VER+1); tw(" -> "); tw(gs_errname(r5)); tw("\n") 143 pass = pass + 1 144 } else { 145 tw("T5 RED future-version save was NOT refused, rc="); tn(r5); tw("\n") 146 } 147 } 148 149 // ---------- T6 additive-only: prior bytes banked as .prev ---------- 150 checks = checks + 1 151 let lorig: *i64 = sys_mmap(8) as *i64 152 let borig: *u8 = filebytes(P, lorig) // snapshot BEFORE the overwrite 153 st[0] = 424242 // materially different state 154 gs_save(P, SCHEMA, st, NF, WHEN+60) 155 let lprev: *i64 = sys_mmap(8) as *i64 156 let bprev: *u8 = filebytes(PP, lprev) 157 var t6: i64 = 0 158 if (bprev as i64)!=0 { if (borig as i64)!=0 { t6 = samebytes(borig,lorig[0],bprev,lprev[0]) } } 159 if t6==1 { 160 tw("T6 GREEN additive-only: overwriting a slot banked the PRIOR BYTES to .prev ("); tn(lprev[0]); tw("B, content-verified)\n") 161 pass = pass + 1 162 } else { 163 tw("T6 RED prior save was destroyed or .prev content differs -- rule 13 violation\n") 164 } 165 166 // ---------- T7 atomic: no .tmp residue ---------- 167 checks = checks + 1 168 let ltmp: *i64 = sys_mmap(8) as *i64 169 ltmp[0]=0 170 let btmp: *u8 = sys_read_file(PT, ltmp) 171 if (btmp as i64)==0 { 172 tw("T7 GREEN atomic: no .tmp residue after save (readers never see a torn file)\n") 173 pass = pass + 1 174 } else { 175 tw("T7 RED .tmp residue survived the save\n") 176 } 177 178 // ---------- T8 ANTI-VACUITY: a good save must STILL load ---------- 179 checks = checks + 1 180 let fresh: *i64 = sys_mmap(NF*8) as *i64 181 let r8: i64 = gs_load(P, fresh, NF, 0 as *i64) 182 var t8: i64 = 0 183 if r8==NF { if fresh[0]==424242 { t8=1 } } 184 if t8==1 { 185 tw("T8 GREEN anti-vacuity: a VALID save still loads (rc="); tn(r8); tw(", field0=424242) -- the refusals above are selective, not blanket\n") 186 pass = pass + 1 187 } else { 188 tw("T8 RED a valid save failed to load, rc="); tn(r8); tw(" -- the loader refuses everything, T3-T5 are vacuous\n") 189 } 190 191 sys_unlinkat(P2); sys_unlinkat(PB) 192 tw("\n=== nx_gamesave_gate "); tn(pass); tw("/"); tn(checks) 193 if pass == checks { tw(" GREEN ===\n"); return 0 } 194 tw(" RED ===\n") 195 return 1 196}