code wiki / _hdl_build / nx_triage_gate.nx
nx_triage_gate.nx source
↩ module page · 204 lines · 12139 B
1// nx_triage_gate.nx -- the KAT for the triage organ itself (evidence doctrine: live-proven is not
2// gate-proven; the instrument that grades the system must itself be re-runnable-graded).
3// World-state INDEPENDENT -- synthetic conf fixtures, fixture log in /tmp (argv overrides added to
4// nx_system_triage for exactly this), so the gate passes/fails on the INSTRUMENT, not on whether
5// today's system happens to be healthy:
6// row 1 DETECT: conf naming a nonexistent organ (UNRECOVERABLE) + nonexistent daemon (DOWN) +
7// impossible disk budget (DISK-LOW) -> triage MUST exit 1 + log verdict=ATTENTION
8// row 2 GREEN: conf naming only nx_system_triage itself (always present when running) + 1GB
9// budget -> triage MUST exit 0 + log verdict=GREEN
10// row 3 GRACE (CR5): stale evidence + G window + journaled RECENT boot -> RECOVER (rc=2),
11// graced=1 -- a crash the team already measured is recovering, not wedged
12// row 4 WEDGED (CR5): same staleness, boot journal ANCIENT -> stays ATTENTION (rc=1)
13// row 5 G-OFF (CR5): no G row + recent boot -> still ATTENTION (grace is opt-in, data-driven)
14// Durable TRIAGE-GATE line -> knowledge/status/triage_gate.log; exit 0 iff all rows hold.
15// Sovereign (syscalls only, no .sh). license_tier: ORIGINAL
16import "nx_syscalls.nx"
17import "nx_gate_verdict.nx"
18func _p(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 { 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 }
20func _fp(fd: i64, s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(fd,s,n); return 0 }
21func _fn(fd: i64, v: i64) -> i64 { let bb: *u8=sys_mmap(28); var m: i64=v; if m<0{m=0-m;sys_write(fd,"-" 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(fd,bb,k); return 0 }
22func tg_len(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n }
23func tg_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 }
24func tg_numcat(dst: *u8, off: i64, v: i64) -> i64 {
25 let t: *u8 = sys_mmap(28)
26 var m: i64 = v
27 var k: i64 = 0
28 if m == 0 { t[0] = 48; k = 1 }
29 while m > 0 { t[k] = 48 + (m % 10); m = m / 10; k = k + 1 }
30 var o: i64 = off
31 while k > 0 { k = k - 1; dst[o] = t[k]; o = o + 1 }
32 return o
33}
34func tg_read_all(path: *u8, buf: *u8, cap: i64) -> i64 {
35 let fd: i64 = sys_openat_rd(path)
36 if fd < 0 { return 0 }
37 var n: i64 = 0
38 var go: i64 = 1
39 while go == 1 { let base: i64 = buf as i64; let r: i64 = sys_read(fd, (base + n) as *u8, cap - n); if r <= 0 { go = 0 } else { n = n + r } if n >= cap { go = 0 } }
40 sys_close(fd)
41 return n
42}
43func tg_contains(hay: *u8, n: i64, pat: *u8) -> i64 {
44 let pl: i64 = tg_len(pat)
45 if pl == 0 { return 0 }
46 var i: i64 = 0
47 while i + pl <= n {
48 var k: i64 = 0
49 var hit: i64 = 1
50 while k < pl { if hay[i+k] != pat[k] { hit = 0; k = pl } else { k = k + 1 } }
51 if hit == 1 { return 1 }
52 i = i + 1
53 }
54 return 0
55}
56func tg_write_file(path: *u8, content: *u8) -> i64 {
57 let fd: i64 = sys_openat_wr(path, 0x1a4)
58 if fd < 0 { return 0 - 1 }
59 sys_write(fd, content, tg_len(content))
60 sys_close(fd)
61 return 0
62}
63// fork+exec elf with up to 2 extra args, stdout+stderr muted; returns exit code (128+sig on crash)
64func tg_run(elf: *u8, a1: *u8, a2: *u8) -> i64 {
65 let pid: i64 = sys_fork()
66 if pid == 0 {
67 let argv: *i64 = sys_mmap(64) as *i64
68 argv[0] = elf as i64
69 var i: i64 = 1
70 if (a1 as i64) != 0 { argv[i] = a1 as i64; i = i + 1 }
71 if (a2 as i64) != 0 { argv[i] = a2 as i64; i = i + 1 }
72 argv[i] = 0
73 let envp: *i64 = sys_mmap(16) as *i64; envp[0] = 0
74 let dn: i64 = sys_openat_wr("/dev/null" as *u8, 0x1a4)
75 if dn >= 0 { sys_dup3(dn, 1, 0); sys_dup3(dn, 2, 0) }
76 sys_execve(elf, argv, envp)
77 sys_exit(127)
78 }
79 let st: *i64 = sys_mmap(16) as *i64
80 sys_wait4(pid, st, 0)
81 let sig: i64 = st[0] & 0x7f
82 if sig != 0 { return 128 + sig }
83 return (st[0] >> 8) & 0xff
84}
85// 4-arg variant for the CR5 rows (conf, log, beat-log, boot-journal overrides)
86func tg_run4(elf: *u8, a1: *u8, a2: *u8, a3: *u8, a4: *u8) -> i64 {
87 let pid: i64 = sys_fork()
88 if pid == 0 {
89 let argv: *i64 = sys_mmap(64) as *i64
90 argv[0] = elf as i64
91 argv[1] = a1 as i64
92 argv[2] = a2 as i64
93 argv[3] = a3 as i64
94 argv[4] = a4 as i64
95 argv[5] = 0
96 let envp: *i64 = sys_mmap(16) as *i64; envp[0] = 0
97 let dn: i64 = sys_openat_wr("/dev/null" as *u8, 0x1a4)
98 if dn >= 0 { sys_dup3(dn, 1, 0); sys_dup3(dn, 2, 0) }
99 sys_execve(elf, argv, envp)
100 sys_exit(127)
101 }
102 let st: *i64 = sys_mmap(16) as *i64
103 sys_wait4(pid, st, 0)
104 let sig: i64 = st[0] & 0x7f
105 if sig != 0 { return 128 + sig }
106 return (st[0] >> 8) & 0xff
107}
108func main() -> i64 {
109 _p("=== TRIAGE GATE: the situational-awareness instrument is itself gate-proven (KAT fixtures) ===\n" as *u8)
110 let triage: *u8 = "buildroot/_build/nx_system_triage.sov.elf" as *u8
111 // ensure the instrument exists (post-reboot: rebuild via the durable runner)
112 let probe: i64 = sys_openat_rd(triage)
113 if probe >= 0 { sys_close(probe) }
114 else {
115 _p(" instrument missing -> rebuilding via durable runner\n" as *u8)
116 tg_run("_offc/nx_sov_build_run.elf" as *u8, "nx_system_triage" as *u8, 0 as *u8)
117 }
118 // row 1 DETECT: everything in this conf is broken on purpose (incl. an EXPIRED evidence log)
119 tg_write_file("/tmp/_tg_stale.log" as *u8, "X epoch=5 verdict=ANCIENT\n" as *u8)
120 tg_write_file("/tmp/_tg_bad.conf" as *u8, "E _tg_no_such_organ S\nD _tg_no_such_daemon\nT 999999\nF 1 /tmp/_tg_stale.log\nR 127.0.0.1 1\n" as *u8)
121 let lb: *u8 = sys_mmap(65536)
122 tg_write_file("/tmp/_tg.log" as *u8, "" as *u8)
123 let rc1: i64 = tg_run(triage, "/tmp/_tg_bad.conf" as *u8, "/tmp/_tg.log" as *u8)
124 let n1: i64 = tg_read_all("/tmp/_tg.log" as *u8, lb, 65520)
125 var ok1: i64 = 0
126 if rc1 == 1 { if tg_contains(lb, n1, "verdict=ATTENTION" as *u8) == 1 { ok1 = 1 } }
127 _p(" [1] detect (dead organ + dead daemon + impossible disk budget -> ATTENTION): " as *u8)
128 if ok1 == 1 { _p("PASS\n" as *u8) } else { _p("FAIL rc=" as *u8); _pn(rc1); _p("\n" as *u8) }
129 // row 2 GREEN: only obligations that always hold while the instrument runs
130 // (fresh-evidence fixture stamped with NOW so the F path is exercised on the green side too)
131 let ffd: i64 = sys_openat_wr("/tmp/_tg_fresh.log" as *u8, 0x1a4)
132 if ffd >= 0 { _fp(ffd, "X epoch=" as *u8); _fn(ffd, sys_now_realtime_sec()); _fp(ffd, " verdict=NOW\n" as *u8); sys_close(ffd) }
133 tg_write_file("/tmp/_tg_good.conf" as *u8, "E nx_system_triage S\nT 1\nF 999999 /tmp/_tg_fresh.log\n" as *u8)
134 tg_write_file("/tmp/_tg.log" as *u8, "" as *u8)
135 let rc2: i64 = tg_run(triage, "/tmp/_tg_good.conf" as *u8, "/tmp/_tg.log" as *u8)
136 let n2: i64 = tg_read_all("/tmp/_tg.log" as *u8, lb, 65520)
137 var ok2: i64 = 0
138 if rc2 == 0 { if tg_contains(lb, n2, "verdict=GREEN" as *u8) == 1 { ok2 = 1 } }
139 _p(" [2] green path (satisfiable conf -> GREEN): " as *u8)
140 if ok2 == 1 { _p("PASS\n" as *u8) } else { _p("FAIL rc=" as *u8); _pn(rc2); _p("\n" as *u8) }
141 // row 3 GRACE (CR5): stale evidence + G window + journaled RECENT boot -> RECOVER
142 let jb2: *u8 = sys_mmap(256)
143 var jo: i64 = 0
144 jo = tg_cat(jb2, jo, "BOOT boot_epoch=" as *u8)
145 jo = tg_numcat(jb2, jo, sys_now_realtime_sec() - 10)
146 jo = tg_cat(jb2, jo, " revive_epoch=0 dark_gap=42\n" as *u8); jb2[jo] = 0 as u8
147 tg_write_file("/tmp/_tg_journal.log" as *u8, jb2)
148 tg_write_file("/tmp/_tg_grace.conf" as *u8, "E nx_system_triage S\nT 1\nG 60\nF 1 /tmp/_tg_stale.log\n" as *u8)
149 tg_write_file("/tmp/_tg.log" as *u8, "" as *u8)
150 let rc3: i64 = tg_run4(triage, "/tmp/_tg_grace.conf" as *u8, "/tmp/_tg.log" as *u8, "/tmp/_tg_nobeat.log" as *u8, "/tmp/_tg_journal.log" as *u8)
151 let n3: i64 = tg_read_all("/tmp/_tg.log" as *u8, lb, 65520)
152 var ok3: i64 = 0
153 if rc3 == 2 { if tg_contains(lb, n3, "verdict=RECOVER" as *u8) == 1 { if tg_contains(lb, n3, "graced=1" as *u8) == 1 { ok3 = 1 } } }
154 _p(" [3] boot-grace (stale evidence + recent journaled boot -> RECOVER): " as *u8)
155 if ok3 == 1 { _p("PASS\n" as *u8) } else { _p("FAIL rc=" as *u8); _pn(rc3); _p("\n" as *u8) }
156 // row 4 WEDGED (CR5): same staleness, ANCIENT boot journal -> stays ATTENTION
157 tg_write_file("/tmp/_tg_journal.log" as *u8, "BOOT boot_epoch=5 revive_epoch=0 dark_gap=0\n" as *u8)
158 tg_write_file("/tmp/_tg.log" as *u8, "" as *u8)
159 let rc4: i64 = tg_run4(triage, "/tmp/_tg_grace.conf" as *u8, "/tmp/_tg.log" as *u8, "/tmp/_tg_nobeat.log" as *u8, "/tmp/_tg_journal.log" as *u8)
160 let n4: i64 = tg_read_all("/tmp/_tg.log" as *u8, lb, 65520)
161 var ok4: i64 = 0
162 if rc4 == 1 { if tg_contains(lb, n4, "verdict=ATTENTION" as *u8) == 1 { if tg_contains(lb, n4, "graced=0" as *u8) == 1 { ok4 = 1 } } }
163 _p(" [4] wedged-stays-red (stale + ancient boot -> ATTENTION): " as *u8)
164 if ok4 == 1 { _p("PASS\n" as *u8) } else { _p("FAIL rc=" as *u8); _pn(rc4); _p("\n" as *u8) }
165 // row 5 G-OFF (CR5): no G row -> recent boot grants NO grace (opt-in, data-driven)
166 jo = 0
167 jo = tg_cat(jb2, jo, "BOOT boot_epoch=" as *u8)
168 jo = tg_numcat(jb2, jo, sys_now_realtime_sec() - 10)
169 jo = tg_cat(jb2, jo, " revive_epoch=0 dark_gap=42\n" as *u8); jb2[jo] = 0 as u8
170 tg_write_file("/tmp/_tg_journal.log" as *u8, jb2)
171 tg_write_file("/tmp/_tg_goff.conf" as *u8, "E nx_system_triage S\nT 1\nF 1 /tmp/_tg_stale.log\n" as *u8)
172 tg_write_file("/tmp/_tg.log" as *u8, "" as *u8)
173 let rc5: i64 = tg_run4(triage, "/tmp/_tg_goff.conf" as *u8, "/tmp/_tg.log" as *u8, "/tmp/_tg_nobeat.log" as *u8, "/tmp/_tg_journal.log" as *u8)
174 let n5: i64 = tg_read_all("/tmp/_tg.log" as *u8, lb, 65520)
175 var ok5: i64 = 0
176 if rc5 == 1 { if tg_contains(lb, n5, "verdict=ATTENTION" as *u8) == 1 { ok5 = 1 } }
177 _p(" [5] grace-off-by-default (no G row -> ATTENTION even with recent boot): " as *u8)
178 if ok5 == 1 { _p("PASS\n" as *u8) } else { _p("FAIL rc=" as *u8); _pn(rc5); _p("\n" as *u8) }
179 // durable verdict
180 let total: i64 = ok1 + ok2 + ok3 + ok4 + ok5
181 let lfd: i64 = sys_openat_append("knowledge/status/triage_gate.log" as *u8, 0x1a4)
182 if lfd >= 0 {
183 _fp(lfd, "TRIAGE-GATE epoch=" as *u8); _fn(lfd, sys_now_realtime_sec())
184 _fp(lfd, " detect=" as *u8); _fn(lfd, ok1)
185 _fp(lfd, " green=" as *u8); _fn(lfd, ok2)
186 _fp(lfd, " grace=" as *u8); _fn(lfd, ok3)
187 _fp(lfd, " wedged=" as *u8); _fn(lfd, ok4)
188 _fp(lfd, " goff=" as *u8); _fn(lfd, ok5)
189 if total == 5 { _fp(lfd, " verdict=PASS\n" as *u8) } else { _fp(lfd, " verdict=FAIL\n" as *u8) }
190 sys_close(lfd)
191 }
192 if total == 5 { _p(" TRIAGE GATE: PASS (detects breakage, certifies health, AND grades crashes crash-aware)\n" as *u8) }
193 else { _p(" TRIAGE GATE: FAIL (the instrument itself is broken -- fix before trusting any TRIAGE line)\n" as *u8) }
194 // MIGRATED onto nx_gate_verdict by hand (D001). No helper renames were needed -- this gate names
195 // its locals _p/_fp/tg_*, so there was no collision with the base class. The five ok1..ok5 checks
196 // above are untouched, so the PASS/FAIL vector cannot change; only the hand-rolled exit is
197 // replaced, so /api/gate_run can now READ the outcome instead of inferring it.
198 let ctr__dry: *i64 = gv_ctr()
199 ctr__dry[0] = total
200 ctr__dry[1] = 5
201 let rc__dry: i64 = gv_verdict("TRIAGE-GATE" as *u8, ctr__dry, "teeth unchanged; verdict emission migrated onto the shared base class" as *u8)
202 sys_exit(rc__dry)
203 return rc__dry
204}