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}