code wiki / _hdl_build / nx_game_gate.nx
nx_game_gate.nx source
↩ module page · 220 lines · 9708 B
1// nx_game_gate.nx -- TEAM-OWNED re-runnable evidence gate for the game-engine
2// substrate (operator: "keep building the team to build this"). Builds and
3// runs every game-substrate test module through the SOVEREIGN pipeline
4// (nx_cc -> nxasm_x86_main -> run, no gcc/sh) and emits one structured
5// verdict line per module, judged by RAW wait4 status (signal-aware), so the
6// grade can never come from a lying $? channel (see
7// feedback-wsl-exit-code-judging-2026-06-09) nor from LLM assertion (see
8// feedback-evidence-driven-live-grading). Appends every line to
9// /tmp/nishi_game_gate.log so grades are LIVE + auditable.
10//
11// Usage:
12// nx_game_gate.elf # compiler = _offc/nx_cc_sovereign.elf
13// nx_game_gate.elf /path/to/nx_cc.elf # explicit compiler (e.g. a candidate
14// # build under test, or the gcc-linked
15// # oracle scaffold while the nxasm
16// # capacity fix is pending)
17// Run from the nxc2 repo root (paths are root-relative like nx_sov_build_run).
18// Exit code = number of FAILED modules (0 = substrate green).
19//
20// license_tier: ORIGINAL Reuses the _run spine from nx_sov_build_run.
21import "nx_syscalls.nx"
22
23const GG_MIN_ASM_BYTES: i64 = 128
24const GG_MAX_RETRIES: i64 = 12
25
26func gg_puts(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } sys_write(1, s, n); return 0 }
27func gg_putn(v: i64) -> i64 { let bb: *u8 = sys_mmap(28); var m: i64=v; if m<0 {m=0-m;sys_write(1,"-" as *u8,1)}; let t: *u8 = sys_mmap(28); var k: i64=0; if m==0 {t[0]=48;k=1}; while m>0 {t[k]=48+(m%10); m=m/10; k=k+1}; var i: i64=0; while i<k {bb[i]=t[k-1-i]; i=i+1}; sys_write(1, bb, k); return 0 }
28
29// append NUL-terminated s into dst at off; return new offset (no NUL written)
30func gg_cat(dst: *u8, off: i64, s: *u8) -> i64 { var i: i64 = 0; while s[i] != (0 as u8) { dst[off+i] = s[i]; i = i + 1 } return off + i }
31
32// append decimal v into dst at off; return new offset
33func gg_cat_n(dst: *u8, off: i64, v: i64) -> i64 {
34 var o: i64 = off
35 var m: i64 = v
36 if m < 0 { dst[o] = 45; o = o + 1; m = 0 - m }
37 let t: *u8 = sys_mmap(28)
38 var k: i64 = 0
39 if m == 0 { t[0] = 48; k = 1 }
40 while m > 0 { t[k] = 48 + (m % 10); m = m / 10; k = k + 1 }
41 var i: i64 = 0
42 while i < k { dst[o+i] = t[k-1-i]; i = i + 1 }
43 return o + k
44}
45
46// fork/execve/wait4; returns WEXITSTATUS, or 128+signal on signal death
47// (signal-aware per the nx_sov_build_run 2026-06-09 fix -- a segfaulted
48// tool must NEVER decode as success).
49func gg_run(path: *u8, argv: *i64, envp: *i64, redir_out: i64, redir_err: i64) -> i64 {
50 let pid: i64 = sys_fork()
51 if pid == 0 {
52 if redir_out >= 0 { sys_dup3(redir_out, 1, 0) }
53 if redir_err >= 0 { sys_dup3(redir_err, 2, 0) }
54 sys_execve(path, argv, envp)
55 sys_exit(127)
56 }
57 let st: *i64 = sys_mmap(16) as *i64
58 sys_wait4(pid, st, 0)
59 let sig: i64 = st[0] & 0x7f
60 if sig != 0 { return 128 + sig }
61 return (st[0] >> 8) & 0xff
62}
63
64func gg_filesize(path: *u8) -> i64 {
65 let fd: i64 = sys_openat_rd(path)
66 if fd < 0 { return 0 }
67 let buf: *u8 = sys_mmap(4096)
68 var total: i64 = 0
69 var n: i64 = sys_read(fd, buf, 4096)
70 while n > 0 { total = total + n; n = sys_read(fd, buf, 4096) }
71 sys_close(fd)
72 return total
73}
74
75// The gated module list. Index -> module basename; 0-pointer past the end.
76// KAT first: if the compiler itself regressed the terminator bug class,
77// every later verdict is suspect -- surface that immediately.
78func gg_module(i: i64) -> *u8 {
79 if i == 0 { return "nx_term_kat" as *u8 }
80 if i == 1 { return "nx_tictactoe_test" as *u8 }
81 if i == 2 { return "nx_checkers_test" as *u8 }
82 if i == 3 { return "nx_raycast_voxel_test" as *u8 }
83 if i == 4 { return "nx_game_engine_compose_test" as *u8 }
84 if i == 5 { return "nx_game_runtime_compose_test" as *u8 }
85 if i == 6 { return "nx_fab_slice_test" as *u8 }
86 if i == 7 { return "nx_text_render_test" as *u8 }
87 if i == 8 { return "nx_html_render_test" as *u8 }
88 if i == 9 { return "nx_render_target_match_test" as *u8 }
89 if i == 10 { return "nx_perceptual_render_test" as *u8 }
90 if i == 11 { return "nx_pitwall_render_test" as *u8 }
91 if i == 12 { return "nx_math_games_test" as *u8 }
92 if i == 13 { return "nx_actor_role_game_logic_test" as *u8 }
93 if i == 14 { return "nx_user_sim_games" as *u8 }
94 if i == 15 { return "nx_worldgen_refine" as *u8 }
95 if i == 16 { return "nx_visual_novel_test" as *u8 }
96 if i == 17 { return "nx_procgen_signature_test" as *u8 }
97 if i == 18 { return "nx_scene_contract_test" as *u8 }
98 if i == 19 { return "nx_procgen_biome_test" as *u8 }
99 if i == 20 { return "nx_procgen_features_test" as *u8 }
100 if i == 21 { return "nx_procgen_water_test" as *u8 }
101 if i == 22 { return "nx_worldgen_tuner_test" as *u8 }
102 return 0 as *u8
103}
104
105// Build + run ONE module through the sovereign pipeline. Returns the run
106// verdict code: 0 = PASS; 1..127 = module's own failing assertion exit;
107// 128+sig = signal death; 1001 = compile-fail; 1002 = assemble-fail.
108func gg_gate_one(name: *u8, compiler: *u8, envp: *i64, devnull: i64) -> i64 {
109 // resolve source: runtime/_hdl_build/<name>.nx, else runtime/<name>.nx
110 let src: *u8 = sys_mmap(512)
111 var o: i64 = 0
112 o = gg_cat(src, o, "runtime/_hdl_build/" as *u8); o = gg_cat(src, o, name); o = gg_cat(src, o, ".nx" as *u8); src[o] = 0 as u8
113 let chk: i64 = sys_openat_rd(src)
114 if chk < 0 {
115 o = 0
116 o = gg_cat(src, o, "runtime/" as *u8); o = gg_cat(src, o, name); o = gg_cat(src, o, ".nx" as *u8); src[o] = 0 as u8
117 }
118 if chk >= 0 { sys_close(chk) }
119
120 let spath: *u8 = sys_mmap(256); o = 0
121 o = gg_cat(spath, o, "/tmp/" as *u8); o = gg_cat(spath, o, name); o = gg_cat(spath, o, ".gg.s" as *u8); spath[o] = 0 as u8
122 let elfpath: *u8 = sys_mmap(256); o = 0
123 o = gg_cat(elfpath, o, "/tmp/" as *u8); o = gg_cat(elfpath, o, name); o = gg_cat(elfpath, o, ".gg.elf" as *u8); elfpath[o] = 0 as u8
124
125 // compile with recompile-retry (known compiler empty-.s nondeterminism)
126 var asmbytes: i64 = 0
127 var tries: i64 = 0
128 while tries < GG_MAX_RETRIES {
129 let sfd: i64 = sys_openat_wr(spath, 0x1a4)
130 let cc: *i64 = sys_mmap(8*4) as *i64
131 cc[0] = compiler as i64; cc[1] = src as i64; cc[2] = 0
132 let rc_c: i64 = gg_run(compiler, cc, envp, sfd, devnull)
133 sys_close(sfd)
134 asmbytes = gg_filesize(spath)
135 if rc_c == 0 { if asmbytes > GG_MIN_ASM_BYTES { tries = GG_MAX_RETRIES } }
136 if tries != GG_MAX_RETRIES { tries = tries + 1 }
137 }
138 if asmbytes <= GG_MIN_ASM_BYTES { return 1001 }
139
140 // assemble + link with the sovereign assembler (NO gcc)
141 let asm_tool: *u8 = "_offc/nxasm_x86_main.elf" as *u8
142 let aa: *i64 = sys_mmap(8*4) as *i64
143 aa[0] = asm_tool as i64; aa[1] = spath as i64; aa[2] = elfpath as i64; aa[3] = 0
144 let rc_a: i64 = gg_run(asm_tool, aa, envp, 0 - 1, 0 - 1)
145 if rc_a != 0 { return 1002 }
146
147 // run; mute the module's own stdout (verdict = exit status, not prose)
148 let rr: *i64 = sys_mmap(8*4) as *i64
149 rr[0] = elfpath as i64; rr[1] = 0
150 return gg_run(elfpath, rr, envp, devnull, devnull)
151}
152
153// Emit one verdict line to stdout AND append it to the gate log.
154func gg_report(logfd: i64, name: *u8, code: i64, ts: i64) -> i64 {
155 let line: *u8 = sys_mmap(512)
156 var o: i64 = 0
157 o = gg_cat(line, o, "GAMEGATE ts=" as *u8)
158 o = gg_cat_n(line, o, ts)
159 o = gg_cat(line, o, " module=" as *u8)
160 o = gg_cat(line, o, name)
161 o = gg_cat(line, o, " verdict=" as *u8)
162 if code == 0 { o = gg_cat(line, o, "PASS" as *u8) }
163 if code == 1001 { o = gg_cat(line, o, "COMPILE-FAIL" as *u8) }
164 if code == 1002 { o = gg_cat(line, o, "ASM-FAIL" as *u8) }
165 if code != 0 {
166 if code != 1001 {
167 if code != 1002 {
168 if code > 128 {
169 o = gg_cat(line, o, "SIGNAL sig=" as *u8)
170 o = gg_cat_n(line, o, code - 128)
171 } else {
172 o = gg_cat(line, o, "FAIL exit=" as *u8)
173 o = gg_cat_n(line, o, code)
174 }
175 }
176 }
177 }
178 o = gg_cat(line, o, "\n" as *u8)
179 sys_write(1, line, o)
180 if logfd >= 0 { sys_write(logfd, line, o) }
181 return 0
182}
183
184func main(argc: i64, argv: *i64) -> i64 {
185 var compiler: *u8 = "_offc/nx_cc_sovereign.elf" as *u8
186 if argc >= 2 { compiler = argv[1] as *u8 }
187
188 let envp: *i64 = sys_mmap(8*4) as *i64
189 envp[0] = "PATH=/usr/bin:/bin" as *u8 as i64; envp[1] = 0
190 let devnull: i64 = sys_openat_wr("/dev/null" as *u8, 0x1a4)
191 let logfd: i64 = sys_openat_append("/tmp/nishi_game_gate.log" as *u8, 0x1a4)
192 let ts: i64 = sys_now_realtime_sec()
193
194 gg_puts("GAMEGATE BEGIN compiler=" as *u8); gg_puts(compiler); gg_puts("\n" as *u8)
195
196 var fails: i64 = 0
197 var i: i64 = 0
198 var name: *u8 = gg_module(0)
199 while name != (0 as *u8) {
200 let code: i64 = gg_gate_one(name, compiler, envp, devnull)
201 gg_report(logfd, name, code, ts)
202 if code != 0 { fails = fails + 1 }
203 i = i + 1
204 name = gg_module(i)
205 }
206
207 let sline: *u8 = sys_mmap(256)
208 var o: i64 = 0
209 o = gg_cat(sline, o, "GAMEGATE SUMMARY ts=" as *u8)
210 o = gg_cat_n(sline, o, ts)
211 o = gg_cat(sline, o, " modules=" as *u8)
212 o = gg_cat_n(sline, o, i)
213 o = gg_cat(sline, o, " fails=" as *u8)
214 o = gg_cat_n(sline, o, fails)
215 o = gg_cat(sline, o, "\n" as *u8)
216 sys_write(1, sline, o)
217 if logfd >= 0 { sys_write(logfd, sline, o) }
218 if logfd >= 0 { sys_close(logfd) }
219 return fails
220}