code wiki / _hdl_build / nx_bless_compiler.nx
nx_bless_compiler.nx source
↩ module page · 297 lines · 14216 B
1// nx_bless_compiler.nx -- TEAM-OWNED self-deploy for the sovereign compiler
2// (GAME arc G2, operator: "keep building the team to handle this
3// autonomously"). The whole win-win-win update gate from
4// [[project-pm-plan-maintainer-winwinwin-2026-06-05]] mechanized:
5//
6// 1. BUILD the candidate SOVEREIGNLY: current _offc compiler compiles
7// runtime/nx_compile_x86.nx (retry-guarded), nxasm_x86_main assembles.
8// nxasm crash/refusal -> REFUSE "BLOCKED-BY-G1" (today's state: the
9// 2.4MB-.s capacity segfault). NO gcc anywhere on this path.
10// 2. MEASURE: nx_game_gate runs twice -- candidate vs live _offc.
11// Verdict is DATA (fails counts), not opinion.
12// 3. BLESS only if candidate is STRICTLY better (fewer fails). The live
13// compiler is backed up to _offc/nx_cc_sovereign.elf.bak first.
14// 4. POST-VERIFY: gate the freshly blessed _offc; if it does not match the
15// candidate's measurement, ROLL BACK from the .bak and re-verify.
16// 5. The gate-loop daemon is STOPPED before measuring and RESTARTED after
17// (two concurrent gates corrupt each other's /tmp artifacts -- learned
18// live 2026-06-09).
19//
20// Exit: 0 blessed+verified, 1 refused (candidate not better), 2 blocked at
21// build (G1), 3 rolled back (post-verify mismatch), 4 internal error.
22// license_tier: ORIGINAL
23import "nx_pm_review_log.nx"
24import "nx_itoa_lib.nx" // shared MSB-first emitter (zero-alloc)
25import "nx_syscalls.nx"
26const BC_MAGIC_65536: i64 = 65536
27const BC_MAGIC_4095: i64 = 4095
28const BC_MAGIC_4096: i64 = 4096
29
30const BC_MIN_ASM_BYTES: i64 = 128
31const BC_MAX_RETRIES: i64 = 12
32
33func bc_puts(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } sys_write(1, s, n); return 0 }
34// MIGRATED to the shared emitter (debt 1785563586). The old body mmapped a scratch buffer
35// per call and never freed it. At PAGE granularity that is 4096B leaked PER CALL -- the
36// defect that took 28.5GB of a 36GB host in nx_ts_lumadiff (2MB input, ~3.66M calls).
37// nxi_* is MSB-first, allocates NOTHING, and emits identical bytes including the sign.
38func bc_putn(v: i64) -> i64 { nxi_out(v); return 0 }
39func bc_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 }
40func bc_cat_n(dst: *u8, off: i64, v: i64) -> i64 {
41 var o: i64 = off
42 var m: i64 = v
43 if m < 0 { dst[o] = 45; o = o + 1; m = 0 - m }
44 let t: *u8 = sys_mmap(28)
45 var k: i64 = 0
46 if m == 0 { t[0] = 48; k = 1 }
47 while m > 0 { t[k] = 48 + (m % 10); m = m / 10; k = k + 1 }
48 var i: i64 = 0
49 while i < k { dst[o+i] = t[k-1-i]; i = i + 1 }
50 return o + k
51}
52
53func bc_run(path: *u8, argv: *i64, envp: *i64, redir_out: i64, redir_err: i64) -> i64 {
54 let pid: i64 = sys_fork()
55 if pid == 0 {
56 if redir_out >= 0 { sys_dup3(redir_out, 1, 0) }
57 if redir_err >= 0 { sys_dup3(redir_err, 2, 0) }
58 sys_execve(path, argv, envp)
59 sys_exit(127)
60 }
61 let st: *i64 = sys_mmap(16) as *i64
62 sys_wait4(pid, st, 0)
63 let sig: i64 = st[0] & 0x7f
64 if sig != 0 { return 128 + sig }
65 return (st[0] >> 8) & 0xff
66}
67
68func bc_run1(path: *u8, arg1: *u8, envp: *i64, devnull: i64) -> i64 {
69 let argv: *i64 = sys_mmap(32) as *i64
70 argv[0] = path as i64; argv[1] = arg1 as i64; argv[2] = 0
71 return bc_run(path, argv, envp, devnull, devnull)
72}
73
74func bc_filesize(path: *u8) -> i64 {
75 let fd: i64 = sys_openat_rd(path)
76 if fd < 0 { return 0 - 1 }
77 let buf: *u8 = sys_mmap(BC_MAGIC_65536)
78 var total: i64 = 0
79 var n: i64 = sys_read(fd, buf, BC_MAGIC_65536)
80 while n > 0 { total = total + n; n = sys_read(fd, buf, BC_MAGIC_65536) }
81 sys_close(fd)
82 return total
83}
84
85// copy src -> dst with mode 0755 (the dst is an executable tool)
86func bc_copy(src: *u8, dst: *u8) -> i64 {
87 let in_fd: i64 = sys_openat_rd(src)
88 if in_fd < 0 { return 0 - 1 }
89 let out_fd: i64 = sys_openat_wr(dst, 0x1ed)
90 if out_fd < 0 { sys_close(in_fd); return 0 - 1 }
91 let buf: *u8 = sys_mmap(BC_MAGIC_65536)
92 var n: i64 = sys_read(in_fd, buf, BC_MAGIC_65536)
93 while n > 0 {
94 sys_write(out_fd, buf, n)
95 n = sys_read(in_fd, buf, BC_MAGIC_65536)
96 }
97 sys_close(in_fd)
98 sys_close(out_fd)
99 return 0
100}
101
102func bc_read_pidfile(path: *u8) -> i64 {
103 let len_p: *i64 = sys_mmap(8) as *i64
104 let buf: *u8 = sys_read_file(path, len_p)
105 if (buf as i64) == 0 { return 0 - 1 }
106 let n: i64 = len_p[0]
107 var v: i64 = 0
108 var any: i64 = 0
109 var i: i64 = 0
110 while i < n {
111 let c: i64 = buf[i] as i64
112 if c >= 48 { if c <= 57 { v = v * 10 + (c - 48); any = 1 } }
113 i = i + 1
114 }
115 if any == 0 { return 0 - 1 }
116 return v
117}
118
119// substring search in buf[0,n)
120func bc_substr(buf: *u8, n: i64, needle: *u8) -> i64 {
121 var nl: i64 = 0
122 while needle[nl] != (0 as u8) { nl = nl + 1 }
123 if nl == 0 { return 1 }
124 var i: i64 = 0
125 while i + nl <= n {
126 var k: i64 = 0
127 var ok: i64 = 1
128 while k < nl { if buf[i+k] != needle[k] { ok = 0; k = nl } else { k = k + 1 } }
129 if ok == 1 { return 1 }
130 i = i + 1
131 }
132 return 0
133}
134
135// 1 iff the LAST line of knowledge/status/cc_equiv_gate.log carries selfhost=1 + verdict=GREEN
136// (the most recent cc_equiv run's summary). Used as the pre-deploy guard's verdict reader.
137func bc_equiv_green() -> i64 {
138 let fd: i64 = sys_openat_rd("knowledge/status/cc_equiv_gate.log" as *u8)
139 if fd < 0 { return 0 }
140 let sz: i64 = sys_lseek(fd, 0, 2)
141 var off: i64 = 0
142 if sz > BC_MAGIC_4095 { off = sz - BC_MAGIC_4095 }
143 sys_lseek(fd, off, 0)
144 let buf: *u8 = sys_mmap(BC_MAGIC_4096)
145 var n: i64 = 0
146 var r: i64 = sys_read(fd, buf, BC_MAGIC_4095)
147 while r > 0 { n = n + r; if n >= BC_MAGIC_4095 { r = 0 } else { r = sys_read(fd, buf + n, BC_MAGIC_4095 - n) } }
148 sys_close(fd)
149 var s: i64 = n
150 if s > 0 { if buf[s-1] == (10 as u8) { s = s - 1 } }
151 var ls: i64 = s
152 while ls > 0 { if buf[ls-1] == (10 as u8) { ls = 0 - ls } else { ls = ls - 1 } }
153 if ls < 0 { ls = 0 - ls }
154 let len: i64 = s - ls
155 if len <= 0 { return 0 }
156 if bc_substr(buf + ls, len, "selfhost=1" as *u8) == 1 { if bc_substr(buf + ls, len, "verdict=GREEN" as *u8) == 1 { return 1 } }
157 return 0
158}
159
160func main(argc: i64, argv: *i64) -> i64 {
161 // NEUTRAL mode (opt-in, argv[1]=="NEUTRAL"): bless a behavior-NEUTRAL capability fix (e.g. the
162 // flock syscall-map fix, X-SYSXLATE-FLOCK) on NO-REGRESSION (b_fails <= a_fails) instead of the
163 // default STRICTLY-better (b_fails < a_fails). Default (no arg) is UNCHANGED so the daemon's
164 // automatic bless still requires a genuine improvement.
165 var allow_equal: i64 = 0
166 if argc >= 2 {
167 let av: *u8 = argv[1] as *u8
168 if av[0] == (78 as u8) { if av[1] == (69 as u8) { if av[2] == (85 as u8) { allow_equal = 1 } } }
169 }
170 let envp: *i64 = sys_mmap(8*4) as *i64
171 envp[0] = "PATH=/usr/bin:/bin" as *u8 as i64; envp[1] = 0
172 let devnull: i64 = sys_openat_wr("/dev/null" as *u8, 0x1a4)
173 let live: *u8 = "_offc/nx_cc_sovereign.elf" as *u8
174 let bak: *u8 = "_offc/nx_cc_sovereign.elf.bak" as *u8
175 let cand_s: *u8 = "/tmp/nx_cc_candidate.s" as *u8
176 let cand: *u8 = "/tmp/nx_cc_candidate.elf" as *u8
177 let gate: *u8 = "/tmp/nx_game_gate.sov.elf" as *u8
178
179 // ---- 1. sovereign build of the candidate ----
180 bc_puts("[bless] building candidate: " as *u8); bc_puts(live); bc_puts(" -> nx_compile_x86.nx -> nxasm\n" as *u8)
181 var asmbytes: i64 = 0
182 var tries: i64 = 0
183 while tries < BC_MAX_RETRIES {
184 let sfd: i64 = sys_openat_wr(cand_s, 0x1a4)
185 let cc: *i64 = sys_mmap(8*4) as *i64
186 cc[0] = live as i64; cc[1] = "runtime/nx_compile_x86.nx" as *u8 as i64; cc[2] = 0
187 let rc_c: i64 = bc_run(live, cc, envp, sfd, devnull)
188 sys_close(sfd)
189 asmbytes = bc_filesize(cand_s)
190 if rc_c == 0 { if asmbytes > BC_MIN_ASM_BYTES { tries = BC_MAX_RETRIES } }
191 if tries != BC_MAX_RETRIES { tries = tries + 1 }
192 }
193 if asmbytes <= BC_MIN_ASM_BYTES {
194 bc_puts("[bless] REFUSED: candidate compile produced no usable .s\n" as *u8)
195 return 2
196 }
197 let asm_tool: *u8 = "_offc/nxasm_x86_main.elf" as *u8
198 let aa: *i64 = sys_mmap(8*4) as *i64
199 aa[0] = asm_tool as i64; aa[1] = cand_s as i64; aa[2] = cand as i64; aa[3] = 0
200 let rc_a: i64 = bc_run(asm_tool, aa, envp, devnull, devnull)
201 if rc_a != 0 {
202 bc_puts("[bless] REFUSED: BLOCKED-BY-G1 -- nxasm rc=" as *u8); bc_putn(rc_a)
203 bc_puts(" on the " as *u8); bc_putn(asmbytes)
204 bc_puts("B candidate .s (capacity bug; see GAME arc G1). _offc UNTOUCHED.\n" as *u8)
205 let pm: i64 = pm_open("/tmp/nishi_pm_review.log" as *u8)
206 pm_gap(pm, "toolchain/x86" as *u8, "BLOCKED" as *u8, "compiler self-deploy blocked by G1" as *u8, "nx_bless_compiler: candidate .s built fine but nxasm failed (capacity/encoding); the parser-fixed compiler still cannot be sovereignly blessed; fix GAME-G1 then re-run nx_bless_compiler" as *u8)
207 sys_close(pm)
208 return 2
209 }
210
211 // ---- 1b. pause the gate-loop daemon (concurrent gates corrupt artifacts) ----
212 let loop_pid: i64 = bc_read_pidfile("/tmp/nishi_game_gate_loop.pid" as *u8)
213 if loop_pid > 0 {
214 nx_kill(loop_pid, 15)
215 bc_puts("[bless] paused gate-loop daemon pid=" as *u8); bc_putn(loop_pid); bc_puts("\n" as *u8)
216 }
217
218 // ---- 2. measure: candidate vs live ----
219 let b_fails: i64 = bc_run1(gate, cand, envp, devnull)
220 let a_fails: i64 = bc_run1(gate, 0 as *u8, envp, devnull)
221 bc_puts("[bless] gate: candidate fails=" as *u8); bc_putn(b_fails)
222 bc_puts(" live fails=" as *u8); bc_putn(a_fails); bc_puts("\n" as *u8)
223
224 var verdict: i64 = 4
225 var should_bless: i64 = 0
226 if b_fails < a_fails { should_bless = 1 }
227 if allow_equal == 1 { if b_fails == a_fails { should_bless = 1 } }
228 if allow_equal == 1 { bc_puts("[bless] NEUTRAL mode: blessing on NO-REGRESSION (b_fails <= a_fails)\n" as *u8) }
229 if should_bless == 1 {
230 // ---- 2b. PRE-DEPLOY EQUIV GUARD (runs ONLY when a bless is imminent, so it never slows a
231 // refused attempt): the candidate must be byte-behavior-equivalent to the baseline on the
232 // corpus AND self-host -- this catches the deref-cast / gen3 regression CLASS that
233 // nx_game_gate cannot. Point the equiv-gate's default challenger (/tmp/cc_challenger.elf) at
234 // our candidate, run it, require GREEN; a RED REFUSES the bless so a regressing compiler can
235 // never go live. (Folds in nx_cc_promote's equiv validation -> nx_cc_promote can retire.) ----
236 bc_copy(cand, "/tmp/cc_challenger.elf" as *u8)
237 let eg: *i64 = sys_mmap(8*4) as *i64
238 eg[0] = "./_offc/nx_sov_build_run.elf" as *u8 as i64
239 eg[1] = "nx_cc_equiv_gate" as *u8 as i64
240 eg[2] = 0
241 bc_run("./_offc/nx_sov_build_run.elf" as *u8, eg, envp, devnull, devnull)
242 let eq_green: i64 = bc_equiv_green()
243 bc_puts("[bless] cc_equiv guard (corpus+self-host) green=" as *u8); bc_putn(eq_green); bc_puts("\n" as *u8)
244 if eq_green == 0 {
245 bc_puts("[bless] REFUSED: cc_equiv NOT GREEN -- deref-cast/gen3 guard; _offc UNTOUCHED\n" as *u8)
246 let pmq: i64 = pm_open("/tmp/nishi_pm_review.log" as *u8)
247 pm_gap(pmq, "toolchain/x86" as *u8, "BLOCKED" as *u8, "bless equiv-guard RED" as *u8, "nx_bless_compiler: candidate failed nx_cc_equiv_gate (corpus/self-host differential) -> refused to bless; investigate the compiler-source regression before re-bless" as *u8)
248 sys_close(pmq)
249 verdict = 2
250 }
251 if eq_green == 1 {
252 // ---- 3. bless with backup ----
253 let rc_bak: i64 = bc_copy(live, bak)
254 if rc_bak < 0 { bc_puts("[bless] ERROR: backup copy failed; ABORT (no bless)\n" as *u8); verdict = 4 }
255 if rc_bak >= 0 {
256 let rc_bls: i64 = bc_copy(cand, live)
257 if rc_bls < 0 { bc_puts("[bless] ERROR: bless copy failed\n" as *u8); verdict = 4 }
258 if rc_bls >= 0 {
259 // ---- 4. post-verify the blessed live tool ----
260 let c_fails: i64 = bc_run1(gate, 0 as *u8, envp, devnull)
261 bc_puts("[bless] post-verify: blessed-live fails=" as *u8); bc_putn(c_fails)
262 bc_puts(" (need ==" as *u8); bc_putn(b_fails); bc_puts(")\n" as *u8)
263 if c_fails == b_fails {
264 bc_puts("[bless] BLESSED + VERIFIED\n" as *u8)
265 let pm2: i64 = pm_open("/tmp/nishi_pm_review.log" as *u8)
266 pm_deliverable(pm2, "toolchain/x86" as *u8, "compiler-blessed" as *u8, "nx_bless_compiler: candidate gated strictly better than live, blessed to _offc/nx_cc_sovereign.elf (backup at .bak), post-verify matched; GAME-G2 satisfied by the team" as *u8)
267 sys_close(pm2)
268 verdict = 0
269 }
270 if c_fails != b_fails {
271 bc_copy(bak, live)
272 let r_fails: i64 = bc_run1(gate, 0 as *u8, envp, devnull)
273 bc_puts("[bless] POST-VERIFY MISMATCH -> ROLLED BACK; live fails now=" as *u8); bc_putn(r_fails); bc_puts("\n" as *u8)
274 let pm3: i64 = pm_open("/tmp/nishi_pm_review.log" as *u8)
275 pm_gap(pm3, "toolchain/x86" as *u8, "NEEDS-FIX" as *u8, "bless post-verify mismatch" as *u8, "nx_bless_compiler: blessed tool gated differently than the candidate binary (nondeterminism or copy fault); ROLLED BACK from .bak; investigate before re-bless" as *u8)
276 sys_close(pm3)
277 verdict = 3
278 }
279 }
280 }
281 }
282 }
283 if should_bless == 0 {
284 bc_puts("[bless] REFUSED: candidate not better (neutral mode allows ==); _offc UNTOUCHED\n" as *u8)
285 verdict = 1
286 }
287
288 // ---- 5. restart the gate-loop daemon ----
289 let loop_elf: *u8 = "/tmp/nx_gate_loop.sov.elf" as *u8
290 let chk: i64 = sys_openat_rd(loop_elf)
291 if chk >= 0 {
292 sys_close(chk)
293 bc_run1(loop_elf, 0 as *u8, envp, devnull)
294 bc_puts("[bless] gate-loop daemon restarted\n" as *u8)
295 }
296 return verdict
297}