code wiki / _hdl_build / nx_idiomcensus.nx

nx_idiomcensus.nx source

↩ module page · 276 lines · 13000 B

1// nx_idiomcensus.nx -- WHAT COUNTER IDIOM DOES THE SKIP-IDIOM FAMILY ACTUALLY USE? 2// nx_gate_dry_apply SKIPs a large family because it cannot recognise how the gate counts pass/total, and 3// the remedy proposed for it has been "write a recogniser" -- for a shape distribution nobody has measured. 4// ★DIAGNOSE THE POPULATION BEFORE BUILDING THE GENERAL MACHINE. A recogniser written against the one shape 5// somebody happened to eyeball is a recogniser for n=1. 6// 7// ★SUBJECT MATCHES CLAIM. It censuses EXACTLY the gates dry_apply classed SKIP-IDIOM, read from the 8// NEWEST generation of knowledge/status/drysweep.log -- not "all gates", which is a different population 9// wearing the same name. drysweep.log is APPEND-ONLY across runs: reading every generation double-counts 10// (the identical defect already found and fixed in nx_adoptsweep), so the newest block is isolated first. 11// 12// ★UNKNOWN IS ITS OWN BUCKET and the partition is PRINTED AND CHECKED TO SUM. A shape that falls into a 13// known bucket because nothing matched is the number somebody then plans against. 14// ★MARKER TALLIES ARE NON-EXCLUSIVE AND LABELLED AS SUCH, separately from the exclusive partition -- two 15// different questions ("how many gates contain X" vs "what IS this gate") must never share a counter. 16// 17// nx_idiomcensus [max] [logpath] [dir] 18// exit: 0 censused | 2 usage | 3 NO-CONCLUSION (log unreadable / no SKIP-IDIOM rows / partition disagrees) 19// license_tier: ORIGINAL No hw writes (Rule 26). 20import "nx_syscalls.nx" 21import "nx_artifact_root.nx" 22 23const IC_DIR: *u8 = "buildroot/runtime/_hdl_build" 24const IC_LOG: *u8 = "knowledge/status/drysweep.log" 25const IC_LOGCAP: i64 = 4194304 26const IC_SRCCAP: i64 = 524288 27const IC_NAMECAP: i64 = 512 28const IC_SETCAP: i64 = 262144 29const IC_MAXN: i64 = 4096 30 31func ic_puts(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 } 32func ic_n(v: i64) -> i64 { 33 if v == 0 { sys_write(1, "0" as *u8, 1); return 0 } 34 var m: i64 = v 35 if m < 0 { sys_write(1, "-" as *u8, 1); m = 0 - m } 36 let t: *u8 = sys_mmap(32); var k: i64 = 0 37 while m > 0 { t[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 } 38 let o: *u8 = sys_mmap(32); var i: i64 = 0 39 while i < k { o[i] = t[k-1-i]; i = i + 1 } 40 sys_write(1, o, k) 41 return 0 42} 43func ic_row(label: *u8, v: i64) -> i64 { ic_puts(" " as *u8); ic_puts(label); ic_puts("=" as *u8); ic_n(v); ic_puts("\n" as *u8); return 0 } 44 45// plain bounded substring scan. Returns index or -1. 46// ⚠separate cursor + explicit flag: a loop that exits by clobbering its own index destroys the position 47// it was searching for. That bug was written 4x in one day in this estate; it is not written here. 48func ic_find(buf: *u8, n: i64, pat: *u8, from: i64) -> i64 { 49 var pl: i64 = 0 50 while pat[pl] != (0 as u8) { pl = pl + 1 } 51 if pl == 0 { return 0 - 1 } 52 var i: i64 = from 53 var hit: i64 = 0 - 1 54 while i + pl <= n { 55 var k: i64 = 0 56 var ok: i64 = 1 57 while k < pl { if buf[i+k] != pat[k] { ok = 0; k = pl } else { k = k + 1 } } 58 if ok == 1 { hit = i; i = n + pl } else { i = i + 1 } 59 } 60 return hit 61} 62func ic_has(buf: *u8, n: i64, pat: *u8) -> i64 { if ic_find(buf, n, pat, 0) >= 0 { return 1 } return 0 } 63 64func ic_rfind(buf: *u8, n: i64, pat: *u8) -> i64 { 65 var at: i64 = 0 - 1 66 var cur: i64 = 0 67 var go: i64 = 1 68 while go == 1 { 69 let h: i64 = ic_find(buf, n, pat, cur) 70 if h < 0 { go = 0 } else { at = h; cur = h + 1 } 71 } 72 return at 73} 74 75// ★★★★★★STRIP // COMMENTS BEFORE CLASSIFYING. Found by this organ's OWN bite proof: a fixture written 76// to match NOTHING carried the sentence "no var pass, no var ok, no fails" in its header comment and was 77// duly filed as var_pass_only. A SCANNER THAT DOES NOT SKIP COMMENTS MEASURES THE DOCUMENTATION, NOT THE 78// CODE -- and in THIS estate, where every organ carries a large prose header that often NAMES the very 79// idioms being censused, that is not a corner case, it is the common case. The first published run of 80// this organ (415 / 849) was contaminated by exactly this and had to be re-measured. 81// ⚠IMPRECISION ACCEPTED AND STATED: a `//` inside a string literal is also stripped. Gate sources 82// effectively never contain one, and erring this way UNDER-counts markers rather than inventing them, 83// so it fails toward UNKNOWN (an honest bucket) rather than toward a confident wrong shape. 84// ⚠Separate cursor + explicit done flag: no loop here exits by clobbering its own index. 85func ic_strip(buf: *u8, n: i64) -> i64 { 86 var r: i64 = 0 87 var w: i64 = 0 88 while r < n { 89 var isc: i64 = 0 90 if buf[r] == (47 as u8) { if r + 1 < n { if buf[r+1] == (47 as u8) { isc = 1 } } } 91 if isc == 1 { 92 var done: i64 = 0 93 while done == 0 { 94 if r >= n { done = 1 } else { 95 if buf[r] == (10 as u8) { done = 1 } else { r = r + 1 } 96 } 97 } 98 } else { 99 buf[w] = buf[r] 100 w = w + 1 101 r = r + 1 102 } 103 } 104 return w 105} 106 107func ic_read(path: *u8, buf: *u8, cap: i64) -> i64 { 108 let fd: i64 = sys_openat_rd(path) 109 if fd < 0 { return 0 - 1 } 110 let n: i64 = sys_read(fd, buf, cap) 111 sys_close(fd) 112 return n 113} 114 115func main(argc: i64, argv: *i64) -> i64 { 116 var maxn: i64 = IC_MAXN 117 if argc >= 2 { 118 var i0: i64 = 0 119 var v: i64 = 0 120 let a1: *u8 = argv[1] as *u8 121 while a1[i0] != (0 as u8) { let c: i64 = a1[i0] as i64; if c >= 48 { if c <= 57 { v = v*10 + (c-48) } } i0 = i0 + 1 } 122 if v > 0 { maxn = v } 123 } 124 // ★ONE CENSUS, ANY CLASS. The NOANCHOR family needs exactly this measurement with a different filter; 125 // a second organ would be a second silently-diverging judge of the same log (the duplicate-ruler defect). 126 // Pass the FULL token, e.g. class=SKIP-NOANCHOR. 127 var cls: *u8 = "class=SKIP-IDIOM" 128 if argc >= 3 { cls = argv[2] as *u8 } 129 var logp: *u8 = IC_LOG 130 if argc >= 4 { logp = argv[3] as *u8 } 131 var dir: *u8 = IC_DIR 132 if argc >= 5 { dir = argv[4] as *u8 } 133 134 let lbuf: *u8 = sys_mmap(IC_LOGCAP) 135 let ln: i64 = ic_read(logp, lbuf, IC_LOGCAP) 136 if ln <= 0 { 137 ic_puts("nx_idiomcensus: drysweep log unreadable or empty -- NO CONCLUSION (an absent input is not an empty population)\n" as *u8) 138 sys_exit(3); return 3 139 } 140 // ★★★★★★THE BANNER MUST NAME THE CLASS IT ACTUALLY MEASURED, NOT THE ONE IT WAS FIRST WRITTEN FOR. 141 // v1 hardcoded "SKIP-IDIOM" here; run with class=SKIP-NOANCHOR it printed a NOANCHOR distribution under 142 // an IDIOM heading. A REPORT THAT MISNAMES ITS OWN SUBJECT IS HOW A CORRECT NUMBER BECOMES A WRONG 143 // CLAIM SIX MONTHS LATER -- and it costs one line to make impossible. 144 ic_puts("=== nx_idiomcensus -- counter shapes of the " as *u8); ic_puts(cls); ic_puts(" family (subject = dry_apply's own classification) ===\n" as *u8) 145 ic_row("log_bytes" as *u8, ln) 146 ic_puts(" class_filter=" as *u8); ic_puts(cls); ic_puts("\n" as *u8) 147 if ln == IC_LOGCAP { ic_puts(" LOG HIT THE READ CAP -- this census is PARTIAL and says so rather than reporting a truncated total as a total\n" as *u8) } 148 149 var gstart: i64 = 0 150 let lastTotal: i64 = ic_rfind(lbuf, ln, "DRYSWEEP-TOTAL" as *u8) 151 if lastTotal > 0 { 152 let prevTotal: i64 = ic_rfind(lbuf, lastTotal, "DRYSWEEP-TOTAL" as *u8) 153 if prevTotal >= 0 { gstart = prevTotal } else { gstart = 0 } 154 } 155 ic_row("generation_starts_at_byte" as *u8, gstart) 156 157 let set: *u8 = sys_mmap(IC_SETCAP) 158 var soff: i64 = 0 159 var names: i64 = 0 160 var cur: i64 = gstart 161 var scan: i64 = 1 162 while scan == 1 { 163 let h: i64 = ic_find(lbuf, ln, "DRYSWEEP gate=" as *u8, cur) 164 if h < 0 { scan = 0 } else { 165 var p: i64 = h + 14 166 let nstart: i64 = p 167 while lbuf[p] != (32 as u8) { p = p + 1 } 168 let nlen: i64 = p - nstart 169 let isIdiom: i64 = ic_find(lbuf, p + 40, cls, p) 170 var take: i64 = 0 171 if isIdiom >= 0 { if isIdiom < p + 20 { take = 1 } } 172 if take == 1 { 173 if names < maxn { 174 if soff + nlen + 2 < IC_SETCAP { 175 var d: i64 = 0 176 while d < nlen { set[soff+d] = lbuf[nstart+d]; d = d + 1 } 177 set[soff+nlen] = 0 as u8 178 soff = soff + nlen + 1 179 names = names + 1 180 } 181 } 182 } 183 cur = h + 14 184 } 185 } 186 ic_row("skip_idiom_rows_in_newest_generation" as *u8, names) 187 if names == 0 { 188 ic_puts(" NO SKIP-IDIOM ROWS -- NO CONCLUSION (refusing to publish a shape distribution over an empty set)\n" as *u8) 189 sys_exit(3); return 3 190 } 191 192 let src: *u8 = sys_mmap(IC_SRCCAP) 193 let path: *u8 = sys_mmap(IC_NAMECAP) 194 var c_gv: i64 = 0 195 var c_pass_rows: i64 = 0 196 var c_pass: i64 = 0 197 var c_ok: i64 = 0 198 var c_fails: i64 = 0 199 var c_passedlit: i64 = 0 200 var c_unknown: i64 = 0 201 var c_unread: i64 = 0 202 var m_verdict: i64 = 0 203 var m_vgreen: i64 = 0 204 var m_rows: i64 = 0 205 var m_gvctr: i64 = 0 206 207 var idx: i64 = 0 208 var off: i64 = 0 209 while idx < names { 210 var po: i64 = 0 211 var q: i64 = 0 212 while dir[q] != (0 as u8) { path[po] = dir[q]; po = po + 1; q = q + 1 } 213 path[po] = 47 as u8; po = po + 1 214 var r: i64 = 0 215 while set[off+r] != (0 as u8) { path[po] = set[off+r]; po = po + 1; r = r + 1 } 216 let ext: *u8 = ".nx" 217 var e: i64 = 0 218 while e < 3 { path[po] = ext[e]; po = po + 1; e = e + 1 } 219 path[po] = 0 as u8 220 221 let rawn: i64 = ic_read(path, src, IC_SRCCAP) 222 var sn: i64 = 0 223 if rawn > 0 { sn = ic_strip(src, rawn) } 224 if rawn <= 0 { c_unread = c_unread + 1 } else { 225 if ic_has(src, sn, "verdict=" as *u8) == 1 { m_verdict = m_verdict + 1 } 226 // ★THE DISCRIMINATOR FOR THE *NOANCHOR* FAMILY: a gate dry_apply calls NOANCHOR whose source 227 // already carries a verdict=GREEN tail is MISCLASSIFIED, not unanchored. Measuring it here 228 // means the same run answers "is this family real?" instead of assuming the label is true. 229 if ic_has(src, sn, "verdict=GREEN" as *u8) == 1 { m_vgreen = m_vgreen + 1 } 230 if ic_has(src, sn, "let rows" as *u8) == 1 { m_rows = m_rows + 1 } 231 if ic_has(src, sn, "gv_ctr" as *u8) == 1 { m_gvctr = m_gvctr + 1 } 232 let hasGv: i64 = ic_has(src, sn, "gv_check(" as *u8) 233 let hasPass: i64 = ic_has(src, sn, "var pass" as *u8) 234 let hasRows: i64 = ic_has(src, sn, "let rows" as *u8) 235 let hasOk: i64 = ic_has(src, sn, "var ok" as *u8) 236 let hasFails: i64 = ic_has(src, sn, "fails" as *u8) 237 let hasLit: i64 = ic_has(src, sn, "passed " as *u8) 238 if hasGv == 1 { c_gv = c_gv + 1 } else { 239 if hasPass == 1 { if hasRows == 1 { c_pass_rows = c_pass_rows + 1 } else { c_pass = c_pass + 1 } } else { 240 if hasOk == 1 { c_ok = c_ok + 1 } else { 241 if hasFails == 1 { c_fails = c_fails + 1 } else { 242 if hasLit == 1 { c_passedlit = c_passedlit + 1 } else { 243 c_unknown = c_unknown + 1 244 }}}}} 245 } 246 while set[off] != (0 as u8) { off = off + 1 } 247 off = off + 1 248 idx = idx + 1 249 } 250 251 ic_puts("-- EXCLUSIVE PARTITION (what IS this gate's counter shape; first match wins, most specific first) --\n" as *u8) 252 ic_row("gv_check_baseclass" as *u8, c_gv) 253 ic_row("var_pass_PLUS_let_rows_shapeG" as *u8, c_pass_rows) 254 ic_row("var_pass_only" as *u8, c_pass) 255 ic_row("var_ok" as *u8, c_ok) 256 ic_row("fails_counter" as *u8, c_fails) 257 ic_row("passed_literal_only" as *u8, c_passedlit) 258 ic_row("UNKNOWN_own_bucket" as *u8, c_unknown) 259 ic_row("UNREADABLE_source" as *u8, c_unread) 260 let sum: i64 = c_gv + c_pass_rows + c_pass + c_ok + c_fails + c_passedlit + c_unknown + c_unread 261 ic_puts("-- NON-EXCLUSIVE MARKERS (how many gates CONTAIN x -- deliberately a different question, never mixed into the partition) --\n" as *u8) 262 ic_row("contains_verdict_literal" as *u8, m_verdict) 263 ic_row("contains_verdict_EQ_GREEN_ALREADY_ANCHORED" as *u8, m_vgreen) 264 ic_row("contains_let_rows" as *u8, m_rows) 265 ic_row("contains_gv_ctr" as *u8, m_gvctr) 266 ic_puts("-- PARTITION CHECK (a partition is a claim: the parts must SUM to the population) --\n" as *u8) 267 ic_puts(" parts_sum=" as *u8); ic_n(sum); ic_puts(" population=" as *u8); ic_n(names); ic_puts("\n" as *u8) 268 if sum != names { 269 ic_puts(" verdict=RED PARTITION DOES NOT SUM -- the distribution above is NOT publishable\n" as *u8) 270 sys_exit(3); return 3 271 } 272 ic_puts(" parts SUM to the population\n" as *u8) 273 ic_puts("verdict=GREEN\n" as *u8) 274 sys_exit(0) 275 return 0 276}