code wiki / _hdl_build / nx_bootstrap_gate.nx
nx_bootstrap_gate.nx source
↩ module page · 161 lines · 8026 B
1// nx_bootstrap_gate.nx -- BOOTSTRAPPABILITY: can the sovereign toolchain still be rebuilt from this tree?
2//
3// WHY THIS EXISTS. On 2026-07-31 the answer was NO and nobody knew. ~170 sources -- including nxc.nx,
4// nxld.nx and nxasm_main.nx, i.e. the compiler, the linker and the assembler themselves -- imported
5// "../nxasm/<module>.nx", and the entire nxasm/ directory was ABSENT from the build root. Three
6// independent builds died identically with `nx_compile_x86: expand_imports failed`. The toolchain kept
7// WORKING, because it runs from prebuilt ELFs in _offc/, so nothing ever surfaced the gap: what was broken
8// was REBUILDING it, and a system that cannot rebuild its own compiler cannot ship a change to it.
9//
10// BOOTSTRAPPABILITY IS A TRACKED PROPERTY, NOT AN ASSUMPTION. This mirrors the reproducible-builds
11// bootstrapping discipline and the 2026 hermetic-build rule that a build is a PURE FUNCTION OF ITS
12// DECLARED INPUTS: an input that has silently vanished must fail LOUDLY at declaration time, not years
13// later when someone finally tries to rebuild. The fix restored the modules; THIS gate is what stops the
14// regression, because the fix without a tooth is just a good day.
15//
16// WHAT IT MEASURES (mechanical, no compilation -- so it finishes well inside the ~14.5s edge window that
17// KILLS any longer gate outright; measured that day: sync died at 14486ms and _async=1 at 14140ms with
18// deadline_ms=60000 ignored, and a self-recorded verdict never even got written because the process was
19// killed before reaching its own emit):
20// T1 the five recovered assembler/linker modules EXIST and are non-empty
21// T2 ZERO sources still reference the absent ../nxasm/ path (the exact regression shape)
22// T3 the toolchain trio's own sources are present and each declares at least one import
23// T4 NON-VACUITY: the same predicate applied to a name that cannot exist must REPORT MISSING,
24// proving the check can fail. A gate never observed to fail is not an instrument.
25//
26// license_tier: ORIGINAL No hw writes (Rule 26). expect_exit: 0
27import "nx_syscalls.nx"
28
29const BG_LOG: *u8 = "knowledge/status/bootstrap_gate.log"
30
31func bg_w(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 }
32func bg_n(v: i64) -> i64 {
33 let t: *u8 = sys_mmap(24); var m: i64=v; var k: i64=0
34 if m==0 { t[0]=48 as u8; sys_write(1,t,1); return 0 }
35 while m>0 { t[k]=(48+(m%10)) as u8; m=m/10; k=k+1 }
36 let b: *u8 = sys_mmap(24); var i: i64=0
37 while i<k { b[i]=t[k-1-i]; i=i+1 }
38 sys_write(1,b,k); return 0
39}
40
41// EXISTS-AND-NON-EMPTY. A zero-byte file is the failure mode a bare open() would call success, and an
42// empty module resolves as an import while defining nothing -- the silent shape this gate exists to catch.
43func bg_present(path: *u8) -> i64 {
44 let lenp: *i64 = sys_mmap(8) as *i64
45 lenp[0] = 0
46 let d: *u8 = sys_read_file(path, lenp)
47 if (d as i64) == 0 { return 0 }
48 if lenp[0] <= 0 { return 0 }
49 sys_munmap(d, lenp[0])
50 return 1
51}
52
53// Does this file's text contain `needle`? Used for the dangling-path check.
54func bg_contains(path: *u8, needle: *u8) -> i64 {
55 let lenp: *i64 = sys_mmap(8) as *i64
56 lenp[0] = 0
57 let d: *u8 = sys_read_file(path, lenp)
58 if (d as i64) == 0 { return 0 - 1 }
59 let n: i64 = lenp[0]
60 var nl: i64 = 0
61 while needle[nl] != (0 as u8) { nl = nl + 1 }
62 var i: i64 = 0
63 var hit: i64 = 0
64 while i + nl <= n {
65 var k: i64 = 0
66 var same: i64 = 1
67 while k < nl { if d[i+k] != needle[k] { same = 0; k = nl } else { k = k + 1 } }
68 if same == 1 { hit = 1; i = n }
69 i = i + 1
70 }
71 sys_munmap(d, n)
72 return hit
73}
74
75func main() -> i64 {
76 bg_w("=== nx_bootstrap_gate -- CAN THE SOVEREIGN TOOLCHAIN BE REBUILT FROM THIS TREE? ===\n" as *u8)
77 var pass: i64 = 0
78 var total: i64 = 0
79
80 // ---- T1: the recovered assembler/linker modules are present and non-empty ----
81 total = total + 1
82 var miss: i64 = 0
83 if bg_present("buildroot/runtime/nxasm_v2.nx" as *u8) == 0 { miss = miss + 1 }
84 if bg_present("buildroot/runtime/nxasm_x86.nx" as *u8) == 0 { miss = miss + 1 }
85 if bg_present("buildroot/runtime/nxasm_x86_enc.nx" as *u8) == 0 { miss = miss + 1 }
86 if bg_present("buildroot/runtime/elf_writer.nx" as *u8) == 0 { miss = miss + 1 }
87 if bg_present("buildroot/runtime/nxasm_arm64_enc.nx" as *u8) == 0 { miss = miss + 1 }
88 if miss == 0 { pass = pass + 1; bg_w(" T1 PASS all 5 assembler/linker modules present + non-empty\n" as *u8) }
89 else { bg_w(" T1 FAIL missing_or_empty="); bg_n(miss); bg_w(" -- the toolchain cannot rebuild; recover from nishi-core/nxc2/nxasm\n" as *u8) }
90
91 // ---- T2: no source still points at the ABSENT ../nxasm/ tree ----
92 // Checked on the toolchain trio itself, which is where the regression would bite first and hardest.
93 total = total + 1
94 var dangling: i64 = 0
95 if bg_contains("buildroot/runtime/nxc.nx" as *u8, "../nxasm/" as *u8) == 1 { dangling = dangling + 1 }
96 if bg_contains("buildroot/runtime/nxld.nx" as *u8, "../nxasm/" as *u8) == 1 { dangling = dangling + 1 }
97 if bg_contains("buildroot/runtime/nxasm_main.nx" as *u8, "../nxasm/" as *u8) == 1 { dangling = dangling + 1 }
98 if dangling == 0 { pass = pass + 1; bg_w(" T2 PASS toolchain trio has NO ../nxasm/ dangling imports\n" as *u8) }
99 else { bg_w(" T2 FAIL dangling_refs="); bg_n(dangling); bg_w(" -- buildroot/nxasm does NOT exist, so these targets cannot compile\n" as *u8) }
100
101 // ---- T3: the toolchain trio's own sources are present ----
102 total = total + 1
103 var tmiss: i64 = 0
104 if bg_present("buildroot/runtime/nxc.nx" as *u8) == 0 { tmiss = tmiss + 1 }
105 if bg_present("buildroot/runtime/nxld.nx" as *u8) == 0 { tmiss = tmiss + 1 }
106 if bg_present("buildroot/runtime/nxasm_main.nx" as *u8) == 0 { tmiss = tmiss + 1 }
107 if tmiss == 0 { pass = pass + 1; bg_w(" T3 PASS compiler + linker + assembler sources all present\n" as *u8) }
108 else { bg_w(" T3 FAIL missing_toolchain_sources="); bg_n(tmiss); bg_w("\n" as *u8) }
109
110 // ---- T4: NON-VACUITY -- the predicate must be able to say NO ----
111 total = total + 1
112 if bg_present("buildroot/runtime/_nx_bootstrap_absent_control.nx" as *u8) == 0 {
113 pass = pass + 1
114 bg_w(" T4 PASS non-vacuity: bg_present REPORTS MISSING for a file that cannot exist\n" as *u8)
115 } else { bg_w(" T4 FAIL non-vacuity: the control file exists, so T1/T3 prove nothing\n" as *u8) }
116
117 // ---- verdict, self-recorded LAST (a record written before the work it records is a false green) ----
118 sys_mkdir("knowledge" as *u8, 0x1ed)
119 sys_mkdir("knowledge/status" as *u8, 0x1ed)
120 let fd: i64 = sys_openat_wr(BG_LOG, 0x1a4)
121 if fd >= 0 {
122 let b: *u8 = sys_mmap(128)
123 var o: i64 = 0
124 let pre: *u8 = "BOOTSTRAP-GATE passed=" as *u8
125 var i: i64 = 0
126 while pre[i] != (0 as u8) { b[o]=pre[i]; o=o+1; i=i+1 }
127 b[o] = (48 + pass) as u8
128 o = o + 1
129 let mid: *u8 = " total=" as *u8
130 i = 0
131 while mid[i] != (0 as u8) { b[o]=mid[i]; o=o+1; i=i+1 }
132 b[o] = (48 + total) as u8
133 o = o + 1
134 let vv: *u8 = " verdict=" as *u8
135 i = 0
136 while vv[i] != (0 as u8) { b[o]=vv[i]; o=o+1; i=i+1 }
137 if pass == total {
138 let g: *u8 = "GREEN" as *u8
139 i = 0
140 while g[i] != (0 as u8) { b[o]=g[i]; o=o+1; i=i+1 }
141 } else {
142 let rr: *u8 = "RED" as *u8
143 i = 0
144 while rr[i] != (0 as u8) { b[o]=rr[i]; o=o+1; i=i+1 }
145 }
146 b[o] = 10 as u8
147 o = o + 1
148 sys_write(fd, b, o)
149 sys_close(fd)
150 }
151
152 bg_w("BOOTSTRAP-GATE "); bg_n(pass); bg_w("/"); bg_n(total)
153 if pass == total {
154 bg_w(" GREEN -- the toolchain can be rebuilt from this tree\n" as *u8)
155 sys_exit(0)
156 return 0
157 }
158 bg_w(" RED -- BOOTSTRAP BROKEN: the compiler cannot be rebuilt from source\n" as *u8)
159 sys_exit(1)
160 return 1
161}