code wiki / _hdl_build / nx_plotgen_gate.nx
nx_plotgen_gate.nx source
↩ module page · 201 lines · 8570 B
1// nx_plotgen_gate.nx -- CERTIFICATION of nx_plotgen (gamebench hard GAP; the operator's "our own plot generator").
2// T1 STRUCTURAL VALIDITY -- every choice target is in range, forward-only (acyclic), endings marked
3// T2 ★SOLVABILITY ACROSS 200 SEEDS -- the graph is WALKED with the real sv_choose from nx_story_vm and must
4// reach an ending every time. This is the unwinnable-quest killer, proven by execution not inspection.
5// T3 NO DEAD ENDS -- every non-ending node offers at least one choice
6// T4 DETERMINISM -- same seed -> byte-identical plot (a story is reproducible from its seed)
7// T5 VARIETY -- different seeds -> materially different plots (not one template)
8// T6 GATES ARE REAL -- generated plots actually contain flag-gated choices; without this, solvability
9// would be trivially satisfied by emitting an ungated linear chain
10// T7 ★ANTI-VACUITY -- a gated choice is GENUINELY BLOCKED when its flag is missing. Proves the gating is
11// enforced rather than decorative, and that T2 passes on merit rather than because nothing gates.
12// T8 composes: runs on nx_story_vm and the plot DATA round-trips through nx_gamesave
13// license_tier: ORIGINAL expect_exit: 0
14import "nx_syscalls.nx"
15import "nx_plotgen.nx"
16import "nx_gamesave.nx"
17
18func pw(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 }
19func pn(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
29func main() -> i64 {
30 pw("=== nx_plotgen_gate: can the generator emit a plot that is always winnable? ===\n\n")
31 var pass: i64 = 0
32 var checks: i64 = 0
33 let N: i64 = 24
34 let CH: i64 = N*SV_NCH
35
36 let tg: *i64 = sys_mmap(CH*8) as *i64
37 let rq: *i64 = sys_mmap(CH*8) as *i64
38 let sf: *i64 = sys_mmap(CH*8) as *i64
39 let ie: *i64 = sys_mmap(N*8) as *i64
40
41 // ---------- T1 structural validity ----------
42 checks = checks + 1
43 let gated0: i64 = pg_gen(tg, rq, sf, ie, N, 20260720)
44 var bad: i64 = 0
45 var backward: i64 = 0
46 var i: i64 = 0
47 while i < N {
48 var c: i64 = 0
49 while c < SV_NCH {
50 let t: i64 = tg[i*SV_NCH + c]
51 if t != 0-1 {
52 if t < 0 { bad = bad + 1 }
53 if t >= N { bad = bad + 1 }
54 if t <= i { backward = backward + 1 } // forward-only => acyclic => always terminates
55 }
56 c = c + 1
57 }
58 i = i + 1
59 }
60 if bad==0 { if backward==0 { if ie[N-1]==1 {
61 pw("T1 GREEN structural: all targets in range, forward-only (acyclic), ending marked at node ")
62 pn(N-1); pw("\n"); pass=pass+1
63 } } }
64 if bad>0 { pw("T1 RED "); pn(bad); pw(" out-of-range targets\n") }
65 if bad==0 { if backward>0 { pw("T1 RED "); pn(backward); pw(" backward edges -- graph may cycle\n") } }
66
67 // ---------- T2 solvability across 200 seeds ----------
68 checks = checks + 1
69 var solved: i64 = 0
70 var trials: i64 = 0
71 var totalgated: i64 = 0
72 var s: i64 = 1
73 while s <= 200 {
74 totalgated = totalgated + pg_gen(tg, rq, sf, ie, N, s*7919)
75 let endnode: i64 = pg_walk(tg, rq, sf, ie, N, N*4)
76 if endnode >= 0 { if sv_is_end(ie, endnode)==1 { solved = solved + 1 } }
77 trials = trials + 1
78 s = s + 1
79 }
80 if solved==trials {
81 pw("T2 GREEN solvability: "); pn(solved); pw("/"); pn(trials)
82 pw(" generated plots WALKED to an ending via the real sv_choose (0 unwinnable), ")
83 pn(totalgated); pw(" gated choices total\n"); pass=pass+1
84 } else {
85 pw("T2 RED "); pn(trials-solved); pw("/"); pn(trials); pw(" plots were UNWINNABLE\n")
86 }
87
88 // ---------- T3 no dead ends ----------
89 checks = checks + 1
90 pg_gen(tg, rq, sf, ie, N, 4242)
91 var dead: i64 = 0
92 i = 0
93 while i < N {
94 if ie[i]==0 {
95 var any: i64 = 0
96 var c: i64 = 0
97 while c < SV_NCH { if tg[i*SV_NCH + c] != 0-1 { any = 1 } c = c + 1 }
98 if any==0 { dead = dead + 1 }
99 }
100 i = i + 1
101 }
102 if dead==0 {
103 pw("T3 GREEN no dead ends: every non-ending node offers at least one choice\n"); pass=pass+1
104 } else { pw("T3 RED "); pn(dead); pw(" dead-end nodes\n") }
105
106 // ---------- T4 determinism ----------
107 checks = checks + 1
108 let tg2: *i64 = sys_mmap(CH*8) as *i64
109 let rq2: *i64 = sys_mmap(CH*8) as *i64
110 let sf2: *i64 = sys_mmap(CH*8) as *i64
111 let ie2: *i64 = sys_mmap(N*8) as *i64
112 pg_gen(tg, rq, sf, ie, N, 31337)
113 pg_gen(tg2, rq2, sf2, ie2, N, 31337)
114 var det: i64 = 1
115 i = 0
116 while i < CH {
117 if tg[i]!=tg2[i] { det=0 }
118 if rq[i]!=rq2[i] { det=0 }
119 if sf[i]!=sf2[i] { det=0 }
120 i = i + 1
121 }
122 i = 0
123 while i < N { if ie[i]!=ie2[i] { det=0 } i=i+1 }
124 if det==1 {
125 pw("T4 GREEN deterministic: seed 31337 twice -> identical plot (a story is reproducible from its seed)\n")
126 pass=pass+1
127 } else { pw("T4 RED same seed produced different plots\n") }
128
129 // ---------- T5 variety ----------
130 checks = checks + 1
131 pg_gen(tg2, rq2, sf2, ie2, N, 90210)
132 var diff: i64 = 0
133 i = 0
134 while i < CH { if tg[i]!=tg2[i] { diff = diff + 1 } i=i+1 }
135 if diff > 8 {
136 pw("T5 GREEN variety: a different seed changed "); pn(diff)
137 pw(" of "); pn(CH); pw(" choice slots -- not one template\n"); pass=pass+1
138 } else { pw("T5 RED seeds barely differ ("); pn(diff); pw(" slots) -- generator is a template\n") }
139
140 // ---------- T6 gates are real ----------
141 checks = checks + 1
142 pg_gen(tg, rq, sf, ie, N, 555)
143 var ngate: i64 = 0
144 i = 0
145 while i < CH { if rq[i] > 0 { ngate = ngate + 1 } i=i+1 }
146 if ngate > 0 {
147 pw("T6 GREEN gates are real: "); pn(ngate)
148 pw(" flag-gated choices in this plot -- solvability is not trivially satisfied by a linear chain\n")
149 pass=pass+1
150 } else { pw("T6 RED no gated choices generated -- T2 would be vacuous\n") }
151
152 // ---------- T7 anti-vacuity: a gate genuinely BLOCKS ----------
153 checks = checks + 1
154 // find a gated choice and try it with EMPTY flags -- sv_choose must refuse it
155 var gi: i64 = 0-1
156 i = 0
157 while i < CH { if rq[i] > 0 { if gi < 0 { gi = i } } i=i+1 }
158 var t7: i64 = 0
159 if gi >= 0 {
160 let node: i64 = gi / SV_NCH
161 let cho: i64 = gi % SV_NCH
162 let flags: *i64 = sys_mmap(8) as *i64
163 flags[0] = 0 // no flags raised
164 let blocked: i64 = sv_choose(tg, rq, sf, node, cho, flags)
165 flags[0] = rq[gi] // exactly the required bits
166 let allowed: i64 = sv_choose(tg, rq, sf, node, cho, flags)
167 if blocked == 0-1 { if allowed >= 0 { t7 = 1 } }
168 if t7==1 {
169 pw("T7 GREEN anti-vacuity: gated choice at node "); pn(node); pw(" REFUSED without its flag (-1) and ")
170 pw("ALLOWED with it (-> node "); pn(allowed); pw(") -- gating is enforced, not decorative\n")
171 pass=pass+1
172 } else {
173 pw("T7 RED gate not enforced: blocked="); pn(blocked); pw(" allowed="); pn(allowed); pw("\n")
174 }
175 } else { pw("T7 RED no gated choice found to test\n") }
176
177 // ---------- T8 composes: story_vm execution + gamesave round-trip ----------
178 checks = checks + 1
179 let PP: *u8 = "knowledge/nx_plotgen_story.sav" as *u8
180 sys_unlinkat(PP)
181 pg_gen(tg, rq, sf, ie, N, 777001)
182 let endn: i64 = pg_walk(tg, rq, sf, ie, N, N*4)
183 let wrote: i64 = gs_save(PP, 70707, tg, CH, 1784580000)
184 let rd: *i64 = sys_mmap(CH*8) as *i64
185 let got: i64 = gs_load(PP, rd, CH, 0 as *i64)
186 var t8: i64 = 1
187 if got != CH { t8 = 0 }
188 if wrote <= 0 { t8 = 0 }
189 if endn < 0 { t8 = 0 }
190 i = 0
191 while i < CH { if rd[i]!=tg[i] { t8=0 } i=i+1 }
192 if t8==1 {
193 pw("T8 GREEN composes: plot ran on nx_story_vm to ending node "); pn(endn)
194 pw(" and its graph round-tripped through nx_gamesave ("); pn(wrote); pw("B)\n"); pass=pass+1
195 } else { pw("T8 RED compose failed: end="); pn(endn); pw(" rc="); pn(got); pw("\n") }
196
197 pw("\n=== nx_plotgen_gate "); pn(pass); pw("/"); pn(checks)
198 if pass == checks { pw(" verdict=GREEN ===\n"); return 0 }
199 pw(" RED ===\n")
200 return 1
201}