code wiki / _hdl_build / nx_classifier_sync.nx

nx_classifier_sync.nx source

↩ module page · 141 lines · 5841 B

1// nx_classifier_sync.nx -- the AUDITOR's pattern-census DRIFT GATE. The library grows from BOTH ends 2// (this arc added shapes 6-10's emitters; a concurrent arc added 11-14: MATH_KERNEL/WIRE_TLV/ 3// STRUCT_WALK/IO_CONTRACT) -- and the classifier + library census silently fell behind (pl_n_patterns 4// stuck at 10 while emit6-9 ship shape 14). This gate makes that class of skew IMPOSSIBLE to miss: 5// it scans runtime/_hdl_build for nx_pattern_emit*.nx sources, parses each header's "(shape N" claim 6// (the EMITTERS are the ground truth -- they exist and gate; the census is derived), and fails unless 7// (a) pl_n_patterns() >= max shape claimed by any emitter (the library census is current) 8// (b) plc_max_covered() >= max shape claimed (every shape has a classifier route) 9// Verdict line appends to knowledge/status/classifier_sync.log -- pulse-able like every gate. 10// RACI: AUDITOR verb (detect the skew); the Builder fixes it by adding rows. license_tier: ORIGINAL 11import "nx_pattern_classify.nx" 12import "nx_itoa_lib.nx" // shared MSB-first emitter (zero-alloc) 13import "nx_syscalls.nx" 14const K_MAGIC_1200: i64 = 1200 15const K_MAGIC_65536: i64 = 65536 16 17func cs_w(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 } 18// MIGRATED to the shared emitter (debt 1785563586). The old body mmapped a scratch buffer 19// per call and never freed it. At PAGE granularity that is 4096B leaked PER CALL -- the 20// defect that took 28.5GB of a 36GB host in nx_ts_lumadiff (2MB input, ~3.66M calls). 21// nxi_* is MSB-first, allocates NOTHING, and emits identical bytes including the sign. 22func cs_wn(fd: i64, v: i64) -> i64 { nxi_fd(fd, v); return 0 } 23func cs_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 } dst[off+i]=0 as u8; return off+i } 24 25// does name match nx_pattern_emit*.nx? (prefix + .nx suffix) 26func cs_is_emit(name: *u8) -> i64 { 27 let pre: *u8 = "nx_pattern_emit" as *u8 28 var i: i64 = 0 29 while pre[i] != (0 as u8) { 30 if name[i] != pre[i] { return 0 } 31 i = i + 1 32 } 33 var n: i64 = i 34 while name[n] != (0 as u8) { n = n + 1 } 35 if n < i + 3 { return 0 } 36 if name[n-3] != (46 as u8) { return 0 } 37 if name[n-2] != (110 as u8) { return 0 } 38 if name[n-1] != (120 as u8) { return 0 } 39 return 1 40} 41 42// parse the max "(shape N" claim in a file's first 1200 bytes (the header doc is the claim site) 43func cs_shape_claim(path: *u8) -> i64 { 44 let lenp: *i64 = sys_mmap(16) as *i64 45 let b: *u8 = sys_read_file(path, lenp) 46 var n: i64 = lenp[0] 47 if n <= 0 { return 0 } 48 if n > K_MAGIC_1200 { n = K_MAGIC_1200 } 49 let m: *u8 = "(shape " as *u8 50 var best: i64 = 0 51 var i: i64 = 0 52 while i < n { 53 var k: i64 = 0 54 var hit: i64 = 1 55 while m[k] != (0 as u8) { 56 if i + k >= n { hit = 0 } 57 if hit == 1 { if b[i+k] != m[k] { hit = 0 } } 58 k = k + 1 59 } 60 if hit == 1 { 61 var v: i64 = 0 62 var j: i64 = i + k 63 while j < n { 64 let c: i64 = b[j] as i64 65 if c < 48 { j = n } 66 if j < n { if c > 57 { j = n } } 67 if j < n { v = v * 10 + (c - 48); j = j + 1 } 68 } 69 if v > best { best = v } 70 } 71 i = i + 1 72 } 73 return best 74} 75 76// scan runtime/_hdl_build for emitter sources; return the MAX shape any emitter claims 77func cs_max_emitter_shape() -> i64 { 78 let dfd: i64 = sys_openat_rd("runtime/_hdl_build" as *u8) 79 if dfd < 0 { return 0 - 1 } 80 let buf: *u8 = sys_mmap(K_MAGIC_65536) 81 var best: i64 = 0 82 var more: i64 = 1 83 while more == 1 { 84 let nb: i64 = sys_getdents64(dfd, buf, K_MAGIC_65536) 85 if nb <= 0 { more = 0 } 86 var off: i64 = 0 87 while off < nb { 88 let rec: *u8 = (buf as i64 + off) as *u8 89 let nm: *u8 = dirent_name(rec) 90 if cs_is_emit(nm) == 1 { 91 let p: *u8 = sys_mmap(512) 92 var o: i64 = cs_cat(p, 0, "runtime/_hdl_build/" as *u8) 93 o = cs_cat(p, o, nm) 94 let v: i64 = cs_shape_claim(p) 95 if v > best { best = v } 96 } 97 off = off + dirent_reclen(rec) 98 } 99 } 100 sys_close(dfd) 101 return best 102} 103 104// the gate: emitters are ground truth; census + classifier must cover them. out[0]=max emitter shape, 105// out[1]=pl_n_patterns, out[2]=plc_max_covered. Returns 1 GREEN / 0 RED. 106func cs_gate(out: *i64) -> i64 { 107 out[0] = cs_max_emitter_shape() 108 out[1] = pl_n_patterns() 109 out[2] = plc_max_covered() 110 if out[0] <= 0 { return 0 } 111 var ok: i64 = 1 112 if out[1] < out[0] { ok = 0 } 113 if out[2] < out[0] { ok = 0 } 114 return ok 115} 116 117func cs_report(out: *i64, green: i64) -> i64 { 118 let fd: i64 = sys_openat_append("knowledge/status/classifier_sync.log" as *u8, 0x1a4) 119 if fd < 0 { return 0 } 120 cs_w(fd, "CLSYNC max_emitter_shape=" as *u8); cs_wn(fd, out[0]) 121 cs_w(fd, " library_census=" as *u8); cs_wn(fd, out[1]) 122 cs_w(fd, " classifier_covered=" as *u8); cs_wn(fd, out[2]) 123 cs_w(fd, " epoch=" as *u8); cs_wn(fd, sys_now_realtime_sec()) 124 if green == 1 { cs_w(fd, " verdict=GREEN\n" as *u8) } 125 if green != 1 { cs_w(fd, " verdict=RED(census-behind-emitters)\n" as *u8) } 126 sys_close(fd) 127 return 1 128} 129 130func main() -> i64 { 131 let out: *i64 = sys_mmap(32) as *i64 132 let green: i64 = cs_gate(out) 133 cs_report(out, green) 134 cs_w(1, "CLSYNC max_emitter_shape=" as *u8); cs_wn(1, out[0]) 135 cs_w(1, " library_census=" as *u8); cs_wn(1, out[1]) 136 cs_w(1, " classifier_covered=" as *u8); cs_wn(1, out[2]) 137 if green == 1 { cs_w(1, " verdict=GREEN\n" as *u8); sys_exit(0) } 138 cs_w(1, " verdict=RED(census-behind-emitters)\n" as *u8) 139 sys_exit(1) 140 return 1 141}