code wiki / (root) / nx_autograde_gate.nx

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}