code wiki / _hdl_build / nx_gate_triage.nx
nx_gate_triage.nx source
↩ module page · 213 lines · 9314 B
1// nx_gate_triage.nx -- TEAM-OWNED failure LOCALIZER for the game gate
2// (operator: "keep building the team to handle this autonomously").
3// Mechanizes the oracle-differential diagnosis ladder Claude ran by hand on
4// 2026-06-09 (the tictactoe draw-detect hunt): for every gated module, build
5// the SAME compiler-emitted .s twice -- once with the sovereign assembler,
6// once with gcc (ORACLE USE ONLY, per the C-is-for-benchmarking law; gcc
7// never lands on a deploy path here) -- run both, and classify:
8//
9// PASS : sovereign build exits 0
10// ASM-GAP : nxasm refuses the .s (encoding gap) or crashes
11// TOOLCHAIN-NXASM : sovereign build fails BUT gcc build of the SAME .s
12// passes -> the assembler mis-encoded something
13// COMPILER-OR-SOURCE : BOTH builds fail the same way -> the .s itself is
14// wrong (compiler bug) or the module's source is
15// COMPILE-FAIL : no usable .s after retries
16//
17// One TRIAGE line per module -> stdout + /tmp/nishi_game_gate_triage.log.
18// The sentinel forks this automatically on REGRESSION, so a red beat arrives
19// pre-localized: the Engineer reads WHERE the bug lives, not just that one
20// exists. Usage: nx_gate_triage.elf [compiler] (default _offc, repo root).
21//
22// license_tier: ORIGINAL Reuses the gg_ spine from nx_game_gate.
23import "nx_syscalls.nx"
24const GT_MAGIC_4096: i64 = 4096
25
26const GT_MIN_ASM_BYTES: i64 = 128
27const GT_MAX_RETRIES: i64 = 12
28
29func gt_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 }
30func gt_cat_n(dst: *u8, off: i64, v: i64) -> i64 {
31 var o: i64 = off
32 var m: i64 = v
33 if m < 0 { dst[o] = 45; o = o + 1; m = 0 - m }
34 let t: *u8 = sys_mmap(28)
35 var k: i64 = 0
36 if m == 0 { t[0] = 48; k = 1 }
37 while m > 0 { t[k] = 48 + (m % 10); m = m / 10; k = k + 1 }
38 var i: i64 = 0
39 while i < k { dst[o+i] = t[k-1-i]; i = i + 1 }
40 return o + k
41}
42
43func gt_run(path: *u8, argv: *i64, envp: *i64, redir_out: i64, redir_err: i64) -> i64 {
44 let pid: i64 = sys_fork()
45 if pid == 0 {
46 if redir_out >= 0 { sys_dup3(redir_out, 1, 0) }
47 if redir_err >= 0 { sys_dup3(redir_err, 2, 0) }
48 sys_execve(path, argv, envp)
49 sys_exit(127)
50 }
51 let st: *i64 = sys_mmap(16) as *i64
52 sys_wait4(pid, st, 0)
53 let sig: i64 = st[0] & 0x7f
54 if sig != 0 { return 128 + sig }
55 return (st[0] >> 8) & 0xff
56}
57
58func gt_filesize(path: *u8) -> i64 {
59 let fd: i64 = sys_openat_rd(path)
60 if fd < 0 { return 0 }
61 let buf: *u8 = sys_mmap(GT_MAGIC_4096)
62 var total: i64 = 0
63 var n: i64 = sys_read(fd, buf, GT_MAGIC_4096)
64 while n > 0 { total = total + n; n = sys_read(fd, buf, GT_MAGIC_4096) }
65 sys_close(fd)
66 return total
67}
68
69// Same module list as nx_game_gate (keep in sync; gate owns the canon).
70func gt_module(i: i64) -> *u8 {
71 if i == 0 { return "nx_term_kat" as *u8 }
72 if i == 1 { return "nx_tictactoe_test" as *u8 }
73 if i == 2 { return "nx_checkers_test" as *u8 }
74 if i == 3 { return "nx_raycast_voxel_test" as *u8 }
75 if i == 4 { return "nx_game_engine_compose_test" as *u8 }
76 if i == 5 { return "nx_game_runtime_compose_test" as *u8 }
77 if i == 6 { return "nx_fab_slice_test" as *u8 }
78 if i == 7 { return "nx_text_render_test" as *u8 }
79 if i == 8 { return "nx_html_render_test" as *u8 }
80 if i == 9 { return "nx_render_target_match_test" as *u8 }
81 if i == 10 { return "nx_perceptual_render_test" as *u8 }
82 if i == 11 { return "nx_pitwall_render_test" as *u8 }
83 if i == 12 { return "nx_math_games_test" as *u8 }
84 if i == 13 { return "nx_actor_role_game_logic_test" as *u8 }
85 if i == 14 { return "nx_user_sim_games" as *u8 }
86 if i == 15 { return "nx_worldgen_refine" as *u8 }
87 if i == 16 { return "nx_visual_novel_test" as *u8 }
88 return 0 as *u8
89}
90
91// classification codes
92const GT_PASS: i64 = 0
93const GT_ASM_GAP: i64 = 1
94const GT_TOOLCHAIN_NXASM: i64 = 2
95const GT_COMPILER_OR_SOURCE: i64 = 3
96const GT_COMPILE_FAIL: i64 = 4
97
98func gt_triage_one(name: *u8, compiler: *u8, envp: *i64, devnull: i64, sov_exit: *i64, ora_exit: *i64) -> i64 {
99 let src: *u8 = sys_mmap(512)
100 var o: i64 = 0
101 o = gt_cat(src, o, "runtime/_hdl_build/" as *u8); o = gt_cat(src, o, name); o = gt_cat(src, o, ".nx" as *u8); src[o] = 0 as u8
102 let chk: i64 = sys_openat_rd(src)
103 if chk < 0 {
104 o = 0
105 o = gt_cat(src, o, "runtime/" as *u8); o = gt_cat(src, o, name); o = gt_cat(src, o, ".nx" as *u8); src[o] = 0 as u8
106 }
107 if chk >= 0 { sys_close(chk) }
108
109 let spath: *u8 = sys_mmap(256); o = 0
110 o = gt_cat(spath, o, "/tmp/" as *u8); o = gt_cat(spath, o, name); o = gt_cat(spath, o, ".tri.s" as *u8); spath[o] = 0 as u8
111 let sovelf: *u8 = sys_mmap(256); o = 0
112 o = gt_cat(sovelf, o, "/tmp/" as *u8); o = gt_cat(sovelf, o, name); o = gt_cat(sovelf, o, ".tri.sov" as *u8); sovelf[o] = 0 as u8
113 let oraelf: *u8 = sys_mmap(256); o = 0
114 o = gt_cat(oraelf, o, "/tmp/" as *u8); o = gt_cat(oraelf, o, name); o = gt_cat(oraelf, o, ".tri.ora" as *u8); oraelf[o] = 0 as u8
115
116 // compile (retry guard)
117 var asmbytes: i64 = 0
118 var tries: i64 = 0
119 while tries < GT_MAX_RETRIES {
120 let sfd: i64 = sys_openat_wr(spath, 0x1a4)
121 let cc: *i64 = sys_mmap(8*4) as *i64
122 cc[0] = compiler as i64; cc[1] = src as i64; cc[2] = 0
123 let rc_c: i64 = gt_run(compiler, cc, envp, sfd, devnull)
124 sys_close(sfd)
125 asmbytes = gt_filesize(spath)
126 if rc_c == 0 { if asmbytes > GT_MIN_ASM_BYTES { tries = GT_MAX_RETRIES } }
127 if tries != GT_MAX_RETRIES { tries = tries + 1 }
128 }
129 if asmbytes <= GT_MIN_ASM_BYTES { return GT_COMPILE_FAIL }
130
131 // lane A: sovereign assembler
132 let asm_tool: *u8 = "_offc/nxasm_x86_main.elf" as *u8
133 let aa: *i64 = sys_mmap(8*4) as *i64
134 aa[0] = asm_tool as i64; aa[1] = spath as i64; aa[2] = sovelf as i64; aa[3] = 0
135 let rc_a: i64 = gt_run(asm_tool, aa, envp, devnull, devnull)
136 if rc_a != 0 { return GT_ASM_GAP }
137 let rr: *i64 = sys_mmap(8*4) as *i64
138 rr[0] = sovelf as i64; rr[1] = 0
139 let rc_sov: i64 = gt_run(sovelf, rr, envp, devnull, devnull)
140 sov_exit[0] = rc_sov
141 if rc_sov == 0 { return GT_PASS }
142
143 // lane B: gcc ORACLE of the SAME .s (diagnosis only, never a deploy path)
144 let gcc_path: *u8 = "/usr/bin/gcc" as *u8
145 let ga: *i64 = sys_mmap(8*8) as *i64
146 ga[0] = gcc_path as i64
147 ga[1] = "-no-pie" as *u8 as i64
148 ga[2] = "-nostartfiles" as *u8 as i64
149 ga[3] = "-o" as *u8 as i64
150 ga[4] = oraelf as i64
151 ga[5] = spath as i64
152 ga[6] = 0
153 let rc_g: i64 = gt_run(gcc_path, ga, envp, devnull, devnull)
154 if rc_g != 0 { return GT_COMPILER_OR_SOURCE } // .s gcc won't even assemble -> emitted asm broken
155 let rr2: *i64 = sys_mmap(8*4) as *i64
156 rr2[0] = oraelf as i64; rr2[1] = 0
157 let rc_ora: i64 = gt_run(oraelf, rr2, envp, devnull, devnull)
158 ora_exit[0] = rc_ora
159 if rc_ora == 0 { return GT_TOOLCHAIN_NXASM }
160 return GT_COMPILER_OR_SOURCE
161}
162
163func gt_report(logfd: i64, name: *u8, cls: i64, sov: i64, ora: i64, ts: i64) -> i64 {
164 let line: *u8 = sys_mmap(512)
165 var o: i64 = 0
166 o = gt_cat(line, o, "TRIAGE ts=" as *u8)
167 o = gt_cat_n(line, o, ts)
168 o = gt_cat(line, o, " module=" as *u8)
169 o = gt_cat(line, o, name)
170 o = gt_cat(line, o, " class=" as *u8)
171 if cls == GT_PASS { o = gt_cat(line, o, "PASS" as *u8) }
172 if cls == GT_ASM_GAP { o = gt_cat(line, o, "ASM-GAP (nxasm refuses/crashes on the .s)" as *u8) }
173 if cls == GT_TOOLCHAIN_NXASM { o = gt_cat(line, o, "TOOLCHAIN-NXASM (gcc build of SAME .s passes; assembler mis-encodes)" as *u8) }
174 if cls == GT_COMPILER_OR_SOURCE { o = gt_cat(line, o, "COMPILER-OR-SOURCE (both lanes fail; the .s itself is wrong)" as *u8) }
175 if cls == GT_COMPILE_FAIL { o = gt_cat(line, o, "COMPILE-FAIL (no usable .s)" as *u8) }
176 if cls != GT_PASS {
177 o = gt_cat(line, o, " sov-exit=" as *u8)
178 o = gt_cat_n(line, o, sov)
179 o = gt_cat(line, o, " oracle-exit=" as *u8)
180 o = gt_cat_n(line, o, ora)
181 }
182 o = gt_cat(line, o, "\n" as *u8)
183 sys_write(1, line, o)
184 if logfd >= 0 { sys_write(logfd, line, o) }
185 return 0
186}
187
188func main(argc: i64, argv: *i64) -> i64 {
189 var compiler: *u8 = "_offc/nx_cc_sovereign.elf" as *u8
190 if argc >= 2 { compiler = argv[1] as *u8 }
191 let envp: *i64 = sys_mmap(8*4) as *i64
192 envp[0] = "PATH=/usr/bin:/bin" as *u8 as i64; envp[1] = 0
193 let devnull: i64 = sys_openat_wr("/dev/null" as *u8, 0x1a4)
194 let logfd: i64 = sys_openat_append("/tmp/nishi_game_gate_triage.log" as *u8, 0x1a4)
195 let ts: i64 = sys_now_realtime_sec()
196
197 var nonpass: i64 = 0
198 var i: i64 = 0
199 var name: *u8 = gt_module(0)
200 while name != (0 as *u8) {
201 let sov_exit: *i64 = sys_mmap(8) as *i64
202 let ora_exit: *i64 = sys_mmap(8) as *i64
203 sov_exit[0] = 0 - 1
204 ora_exit[0] = 0 - 1
205 let cls: i64 = gt_triage_one(name, compiler, envp, devnull, sov_exit, ora_exit)
206 gt_report(logfd, name, cls, sov_exit[0], ora_exit[0], ts)
207 if cls != GT_PASS { nonpass = nonpass + 1 }
208 i = i + 1
209 name = gt_module(i)
210 }
211 if logfd >= 0 { sys_close(logfd) }
212 return nonpass
213}