nx_autograde_gate.nx source
↩ module page · 314 lines · 14737 B
1// nx_autograde_gate.nx -- THE AUTONOMOUS TARGET GRADER (operator 2026-07-15: "we should get to autonomous
2// grading so that compare works ... not self-driven by you or AI but just part of the nishi ecosystem that
3// it's analyzing targets we set like gcc exceed and handling them with manual triggering via mcp and apis").
4//
5// The problem it kills: grading driven by Claude (hand-editing matrices, eyeballing benches) is navel-gazing.
6// This organ makes grading the ECOSYSTEM'S OWN job: it reads knowledge/autograde_targets.reg (the goals WE set
7// -- data, operator-editable), then for each target MEASURES IT ITSELF -- either forks the bench fresh and parses
8// its stdout, or grades the ecosystem's persisted ledger -- and emits MET / NOT-MET / UNMEASURED. It is manually
9// triggerable (a workstream fires it via MCP/API). No Claude in the measurement loop.
10//
11// LOAD-BEARING ANTI-NAVEL-GAZING PROPERTY (by construction, gate-proven): a target with NO wired measurement
12// grades UNMEASURED -- it can NEVER be reported MET without a real number. The grader measures reality; it
13// cannot rubber-stamp a goal. And it must DISTINGUISH a met target from a not-met one (both present in the seed
14// set), proving it grades the actual value, not a fixed verdict.
15// T1 registry parsed (>=3 targets read as DATA)
16// T2 measured >=2 targets with a REAL number (not everything unmeasured)
17// T3 DISTINGUISHES reality: at least one MET and one NOT-MET (grades the value, does not rubber-stamp)
18// T4 ANTI-NAVEL-GAZING: the unwired target (no ledger) grades UNMEASURED, NOT met -- no measurement => no credit
19// T5 AUTONOMOUS FRESH RUN: the fork target actually executed (captured real stdout bytes), not asserted
20// T6 PERSISTED graded verdicts to a durable autograde ledger (living trend)
21// expect_exit: 0 license_tier: ORIGINAL
22import "nx_tool_run.nx"
23import "nx_gate_verdict.nx"
24
25func w(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } sys_write(1, s, n); return 0 }
26func wn(v: i64) -> i64 {
27 var m: i64 = v
28 if m < 0 { w("-" as *u8); m = 0 - m }
29 let t: *u8 = sys_mmap(24)
30 var k: i64 = 0
31 if m == 0 { t[0] = 48 as u8; k = 1 }
32 while m > 0 { t[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 }
33 let o: *u8 = sys_mmap(24)
34 var i: i64 = 0
35 while i < k { o[i] = t[k - 1 - i]; i = i + 1 }
36 sys_write(1, o, k)
37 return 0
38}
39func slen(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n }
40
41// compare null-terminated a to null-terminated b -> 1 if equal
42func streq(a: *u8, b: *u8) -> i64 {
43 var i: i64 = 0
44 var go: i64 = 1
45 var res: i64 = 1
46 while go == 1 {
47 let ca: i64 = a[i] as i64
48 let cb: i64 = b[i] as i64
49 if ca != cb { res = 0; go = 0 }
50 else { if ca == 0 { go = 0 } else { i = i + 1 } }
51 }
52 return res
53}
54
55// extract the k-th '|'-delimited field of line[ls,le) into dst (null-terminated). returns field length.
56func fext(line: *u8, ls: i64, le: i64, k: i64, dst: *u8, dcap: i64) -> i64 {
57 var fi: i64 = 0
58 var i: i64 = ls
59 while fi < k {
60 var atend: i64 = 0
61 while atend == 0 {
62 if i >= le { atend = 1 }
63 else { if line[i] == (124 as u8) { atend = 1 } else { i = i + 1 } }
64 }
65 if i < le { i = i + 1 }
66 fi = fi + 1
67 }
68 var j: i64 = 0
69 var done: i64 = 0
70 while done == 0 {
71 if i >= le { done = 1 }
72 else { if line[i] == (124 as u8) { done = 1 }
73 else { if j >= dcap - 1 { done = 1 }
74 else { dst[j] = line[i]; j = j + 1; i = i + 1 } } }
75 }
76 dst[j] = 0 as u8
77 return j
78}
79
80// find the START index of the LAST occurrence of needle in hay[0,hn). -1 if absent.
81func find_last(hay: *u8, hn: i64, needle: *u8) -> i64 {
82 let m: i64 = slen(needle)
83 if m == 0 { return 0 - 1 }
84 var last: i64 = 0 - 1
85 var i: i64 = 0
86 while i + m <= hn {
87 var j: i64 = 0
88 var ok: i64 = 1
89 while j < m { if hay[i+j] != needle[j] { ok = 0; j = m } else { j = j + 1 } }
90 if ok == 1 { last = i }
91 i = i + 1
92 }
93 return last
94}
95
96// parse an integer at-or-just-after p in hay[0,hn): skips up to 12 non-digit/non-'-' chars, then reads [-]digits.
97// returns -999999 (sentinel) if no number found.
98func pint_at(hay: *u8, hn: i64, p: i64) -> i64 {
99 var i: i64 = p
100 var guard: i64 = 0
101 var found: i64 = 0
102 while found == 0 {
103 if i >= hn { return 0 - 999999 }
104 if guard >= 12 { return 0 - 999999 }
105 let c: i64 = hay[i] as i64
106 if c == 45 { found = 1 }
107 else { if c >= 48 { if c <= 57 { found = 1 } else { i = i + 1; guard = guard + 1 } } else { i = i + 1; guard = guard + 1 } }
108 }
109 var neg: i64 = 0
110 if (hay[i] as i64) == 45 { neg = 1; i = i + 1 }
111 var v: i64 = 0
112 var any: i64 = 0
113 var go: i64 = 1
114 while go == 1 {
115 if i >= hn { go = 0 }
116 else {
117 let d: i64 = hay[i] as i64
118 if d >= 48 { if d <= 57 { v = v * 10 + (d - 48); any = 1; i = i + 1 } else { go = 0 } }
119 else { go = 0 }
120 }
121 }
122 if any == 0 { return 0 - 999999 }
123 if neg == 1 { return 0 - v }
124 return v
125}
126
127// append literal to buf at off; return new off
128func bcat(buf: *u8, off: i64, s: *u8) -> i64 { var i: i64 = 0; while s[i] != (0 as u8) { buf[off+i] = s[i]; i = i + 1 } return off + i }
129func bcatn(buf: *u8, off: i64, v: i64) -> i64 {
130 var m: i64 = v; var o: i64 = off
131 if m < 0 { buf[o] = 45 as u8; o = o + 1; m = 0 - m }
132 let t: *u8 = sys_mmap(24); var k: i64 = 0
133 if m == 0 { t[0] = 48 as u8; k = 1 }
134 while m > 0 { t[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 }
135 var j: i64 = k - 1
136 while j >= 0 { buf[o] = t[j]; o = o + 1; j = j - 1 }
137 return o
138}
139
140func main() -> i64 {
141 // ---- accumulators declared at TOP (scope-slot discipline) ----
142 var ntot: i64 = 0
143 var nmeas: i64 = 0
144 var nmet: i64 = 0
145 var nnotmet: i64 = 0
146 var nunmeas: i64 = 0
147 var met_seen: i64 = 0
148 var notmet_seen: i64 = 0
149 var forkbytes: i64 = 0
150 var exgcc_verdict: i64 = 0 - 1
151 var recoff: i64 = 0
152
153 w("=== NX-AUTOGRADE -- autonomous target grader (the ecosystem measures the goals WE set; no Claude in the loop) ===\n" as *u8)
154 let ts: i64 = sys_now_realtime_sec()
155
156 // read the target registry (DATA -- operator-editable goals)
157 let rlen: *i64 = sys_mmap(8) as *i64
158 let reg: *u8 = sys_read_file("knowledge/autograde_targets.reg" as *u8, rlen)
159 if (reg as i64) == 0 { w(" FATAL: cannot read knowledge/autograde_targets.reg\n" as *u8); return 2 }
160 let rn: i64 = rlen[0]
161 w(" target registry read: " as *u8); wn(rn); w(" bytes\n\n" as *u8)
162
163 // per-target field buffers (reused each line) + the ledger accumulator
164 let name: *u8 = sys_mmap(64)
165 let mode: *u8 = sys_mmap(16)
166 let src: *u8 = sys_mmap(320)
167 let tok: *u8 = sys_mmap(48)
168 let cmp: *u8 = sys_mmap(8)
169 let thrs: *u8 = sys_mmap(24)
170 let out: *u8 = sys_mmap(1048576)
171 let olen: *i64 = sys_mmap(8) as *i64
172 let recs: *u8 = sys_mmap(65536)
173
174 w(" TARGET MODE VALUE GOAL VERDICT\n" as *u8)
175 w(" ---------------------- ------ --------- ------------- -------\n" as *u8)
176
177 // iterate lines
178 var ls: i64 = 0
179 while ls < rn {
180 // find line end
181 var le: i64 = ls
182 var f: i64 = 0
183 while f == 0 { if le >= rn { f = 1 } else { if reg[le] == (10 as u8) { f = 1 } else { le = le + 1 } } }
184 // process non-comment, non-trivial lines
185 var skip: i64 = 0
186 if le <= ls + 2 { skip = 1 }
187 if skip == 0 { if reg[ls] == (35 as u8) { skip = 1 } }
188 if skip == 0 {
189 fext(reg, ls, le, 0, name, 64)
190 fext(reg, ls, le, 1, mode, 16)
191 fext(reg, ls, le, 2, src, 320)
192 fext(reg, ls, le, 3, tok, 48)
193 fext(reg, ls, le, 4, cmp, 8)
194 fext(reg, ls, le, 5, thrs, 24)
195 let thr: i64 = pint_at(thrs, slen(thrs), 0)
196
197 // ---- MEASURE (autonomous: run fresh, or read the persisted ledger) ----
198 var value: i64 = 0 - 999999
199 var didfork: i64 = 0
200 if streq(mode, "fork" as *u8) == 1 {
201 let av: *i64 = sys_mmap(64) as *i64
202 av[0] = "_offc/nx_sov_build_run.elf" as *u8 as i64
203 av[1] = src as i64
204 av[2] = 0
205 olen[0] = 0
206 tr_run_capture("_offc/nx_sov_build_run.elf" as *u8, av, out, 1048576, olen)
207 let cb: i64 = olen[0]
208 didfork = 1
209 if cb > forkbytes { forkbytes = cb }
210 let ti: i64 = find_last(out, cb, tok)
211 if ti >= 0 { value = pint_at(out, cb, ti + slen(tok)) }
212 }
213 else {
214 let hlen: *i64 = sys_mmap(8) as *i64
215 let hist: *u8 = sys_read_file(src, hlen)
216 if (hist as i64) != 0 {
217 let hn: i64 = hlen[0]
218 let ti: i64 = find_last(hist, hn, tok)
219 if ti >= 0 { value = pint_at(hist, hn, ti + slen(tok)) }
220 }
221 }
222
223 // ---- GRADE ---- verdict: 0=UNMEASURED 1=MET 2=NOT-MET
224 var verdict: i64 = 0
225 if value != (0 - 999999) {
226 nmeas = nmeas + 1
227 if streq(cmp, "ge" as *u8) == 1 { if value >= thr { verdict = 1 } else { verdict = 2 } }
228 else { if value <= thr { verdict = 1 } else { verdict = 2 } }
229 }
230 ntot = ntot + 1
231 if verdict == 1 { nmet = nmet + 1; met_seen = 1 }
232 if verdict == 2 { nnotmet = nnotmet + 1; notmet_seen = 1 }
233 if verdict == 0 { nunmeas = nunmeas + 1 }
234 if streq(name, "exceed-gcc-scalar" as *u8) == 1 { exgcc_verdict = verdict }
235
236 // ---- print row ----
237 w(" " as *u8)
238 var pi: i64 = 0
239 var pnul: i64 = 0
240 while pi < 22 { if pnul == 0 { if name[pi] != (0 as u8) { sys_write(1, (name as i64 + pi) as *u8, 1) } else { pnul = 1; w(" " as *u8) } } else { w(" " as *u8) } pi = pi + 1 }
241 w(" " as *u8)
242 var mi: i64 = 0
243 var mnul: i64 = 0
244 while mi < 6 { if mnul == 0 { if mode[mi] != (0 as u8) { sys_write(1, (mode as i64 + mi) as *u8, 1) } else { mnul = 1; w(" " as *u8) } } else { w(" " as *u8) } mi = mi + 1 }
245 w(" " as *u8)
246 if value != (0 - 999999) { wn(value); w(" " as *u8) } else { w("-- " as *u8) }
247 w(" " as *u8); w(cmp); w(" " as *u8); wn(thr); w(" " as *u8)
248 if verdict == 1 { w(" MET\n" as *u8) }
249 else { if verdict == 2 { w(" NOT-MET\n" as *u8) } else { w(" UNMEASURED\n" as *u8) } }
250
251 // ---- persist a graded record (living) ----
252 recoff = bcat(recs, recoff, "AGL ts=" as *u8); recoff = bcatn(recs, recoff, ts)
253 recoff = bcat(recs, recoff, " name=" as *u8); recoff = bcat(recs, recoff, name)
254 recoff = bcat(recs, recoff, " value=" as *u8)
255 if value != (0 - 999999) { recoff = bcatn(recs, recoff, value) } else { recoff = bcat(recs, recoff, "NA" as *u8) }
256 recoff = bcat(recs, recoff, " goal=" as *u8); recoff = bcat(recs, recoff, cmp); recoff = bcatn(recs, recoff, thr)
257 recoff = bcat(recs, recoff, " verdict=" as *u8)
258 if verdict == 1 { recoff = bcat(recs, recoff, "MET" as *u8) }
259 else { if verdict == 2 { recoff = bcat(recs, recoff, "NOTMET" as *u8) } else { recoff = bcat(recs, recoff, "UNMEAS" as *u8) } }
260 recs[recoff] = 10 as u8; recoff = recoff + 1
261 }
262 ls = le + 1
263 }
264
265 // ---- summary ----
266 w("\n AUTONOMOUS GRADE SUMMARY: " as *u8)
267 wn(ntot); w(" targets | " as *u8); wn(nmet); w(" MET | " as *u8); wn(nnotmet); w(" NOT-MET | " as *u8); wn(nunmeas); w(" UNMEASURED\n" as *u8)
268 w(" (measured " as *u8); wn(nmeas); w(" targets by RUNNING/READING the ecosystem itself -- not Claude's opinion)\n\n" as *u8)
269
270 // ---- persist to durable autograde ledger ----
271 let path: *u8 = "/home/elderwesto/nx_stage/autograde_ledger.log" as *u8
272 let olb: *i64 = sys_mmap(8) as *i64
273 let old: *u8 = sys_read_file(path, olb)
274 let full: *u8 = sys_mmap(262144)
275 var wo: i64 = 0
276 if (old as i64) != 0 { var z: i64 = 0; while z < olb[0] { full[wo] = old[z]; wo = wo + 1; z = z + 1 } }
277 var z2: i64 = 0; while z2 < recoff { full[wo] = recs[z2]; wo = wo + 1; z2 = z2 + 1 }
278 let fd: i64 = sys_openat_wr(path, 0x1a4)
279 var wrote: i64 = 0
280 if fd >= 0 { wrote = sys_write(fd, full, wo); sys_close(fd) }
281
282 // ---- teeth ----
283 var pass: i64 = 0
284 var ttl: i64 = 0
285 ttl = ttl + 1
286 w(" T1 registry parsed as DATA (>=3 targets): " as *u8)
287 if ntot >= 3 { pass = pass + 1; w("PASS (" as *u8); wn(ntot); w(")\n" as *u8) } else { w("FAIL\n" as *u8) }
288 ttl = ttl + 1
289 w(" T2 measured >=2 targets with a REAL number: " as *u8)
290 if nmeas >= 2 { pass = pass + 1; w("PASS (" as *u8); wn(nmeas); w(")\n" as *u8) } else { w("FAIL\n" as *u8) }
291 ttl = ttl + 1
292 w(" T3 DISTINGUISHES reality (>=1 MET and >=1 NOT-MET -- grades the value, no rubber-stamp): " as *u8)
293 if met_seen == 1 { if notmet_seen == 1 { pass = pass + 1; w("PASS\n" as *u8) } else { w("FAIL\n" as *u8) } } else { w("FAIL\n" as *u8) }
294 ttl = ttl + 1
295 w(" T4 ANTI-NAVEL-GAZING (unwired exceed-gcc target => UNMEASURED, not MET): " as *u8)
296 if exgcc_verdict == 0 { pass = pass + 1; w("PASS (no measurement => no credit)\n" as *u8) } else { w("FAIL (a goal was credited without a real number!)\n" as *u8) }
297 ttl = ttl + 1
298 w(" T5 AUTONOMOUS FRESH RUN (fork target executed, captured real stdout): " as *u8)
299 if forkbytes > 0 { pass = pass + 1; w("PASS (" as *u8); wn(forkbytes); w("B captured)\n" as *u8) } else { w("FAIL\n" as *u8) }
300 ttl = ttl + 1
301 w(" T6 PERSISTED graded verdicts to durable autograde ledger (living): " as *u8)
302 if wrote > 0 { pass = pass + 1; w("PASS (" as *u8); wn(wrote); w("B)\n" as *u8) } else { w("FAIL\n" as *u8) }
303
304 w("NX-AUTOGRADE-GATE passed " as *u8); wn(pass); w("/" as *u8); wn(ttl)
305 // MIGRATED onto nx_gate_verdict by nx_gate_dry_apply (D001, minimal form): every check
306 // row above is untouched, so the PASS/FAIL vector cannot change; only the hand-rolled
307 // verdict emission is replaced by the ONE shared base class. Proven by nx_gate_migrate verify.
308 let ctr__dry: *i64 = gv_ctr()
309 ctr__dry[0] = pass
310 ctr__dry[1] = ttl
311 let rc__dry: i64 = gv_verdict("AUTOGRADE-GATE" as *u8, ctr__dry, "autonomous grading: the ecosystem measures the goals we set -- MET/NOT-MET/UNMEASURED, no rubber-stamp)" as *u8)
312 sys_exit(rc__dry)
313 return rc__dry
314}