code wiki / _hdl_build / nx_drysweep.nx

nx_drysweep.nx source

↩ module page · 228 lines · 11699 B

1// nx_drysweep.nx -- WHAT DOES nx_gate_dry_apply ACTUALLY SAY ABOUT EVERY GATE? The D001 lane has been 2// sized from a constant nobody measured: dry_apply's own SKIP text asserts "the fails==0 family, 36 3// gates" and nothing in the tree derives it (debt 1786236085). dry_apply has NO sweep verb -- its usage 4// is `<gate> <out-candidate-path>` -- so the census could not be taken. This is that census. 5// 6// ★COMPOSES THE RULER, NEVER RE-IMPLEMENTS IT. It FORKS nx_gate_dry_apply per gate and only TALLIES the 7// answer, exactly as nx_forkgrade forks nx_srcdiff per pair so that exactly ONE line-differ exists in the 8// estate. Re-deriving dry_apply's classification here would create a second, silently-diverging judge -- 9// and a census that disagrees with the tool it describes is worse than no census. 10// 11// ★DURABLE AS IT GOES. Rows APPEND to knowledge/status/drysweep.log per gate, before any summary. A long 12// sweep that buffers its output has NO partial results: an interruption costs everything, not the 13// remainder. Resume with <skip>. 14// ★NO SILENT CAPS: <max> bounds the run and the DEFERRED remainder is printed. A cap reached in silence 15// becomes a measurement nobody knows is partial. 16// 17// nx_drysweep <max> [skip] [dir] 18// exit: 0 swept clean | 1 at least one ERROR/TIMEOUT (the tally is still printed) | 2 usage 19// 3 NO-CONCLUSION (dry_apply unresolvable, or the gate dir cannot be opened) 20// license_tier: ORIGINAL No hw writes (Rule 26). 21import "nx_syscalls.nx" 22import "nx_artifact_root.nx" 23import "nx_tool_run.nx" 24 25const DS_DIR: *u8 = "buildroot/runtime/_hdl_build" 26const DS_LOG: *u8 = "knowledge/status/drysweep.log" 27const DS_CAND: *u8 = "/tmp/drysweep_cand.nx" 28const DS_OUTCAP: i64 = 65536 29const DS_TIMEOUT: i64 = 20000 30const DS_DIRBUF: i64 = 1048576 31const DS_NAMECAP: i64 = 512 32 33func ds_puts(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 } 34func ds_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 } 35func ds_n(fd: i64, v: i64) -> i64 { 36 if v == 0 { sys_write(fd, "0" as *u8, 1); return 0 } 37 var m: i64 = v 38 if m < 0 { sys_write(fd, "-" as *u8, 1); m = 0 - m } 39 let t: *u8 = sys_mmap(32); var k: i64 = 0 40 while m > 0 { t[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 } 41 let o: *u8 = sys_mmap(32); var i: i64 = 0 42 while i < k { o[i] = t[k-1-i]; i = i + 1 } 43 sys_write(fd, o, k) 44 return 0 45} 46 47// does buf contain pat? plain scan, bounded by n. 48func ds_has(buf: *u8, n: i64, pat: *u8) -> i64 { 49 var pl: i64 = 0 50 while pat[pl] != (0 as u8) { pl = pl + 1 } 51 if pl == 0 { return 0 } 52 var i: i64 = 0 53 while i + pl <= n { 54 var k: i64 = 0 55 var ok: i64 = 1 56 while k < pl { if buf[i+k] != pat[k] { ok = 0; k = pl } else { k = k + 1 } } 57 if ok == 1 { return 1 } 58 i = i + 1 59 } 60 return 0 61} 62 63// name ends with "_gate.nx" ? 64func ds_is_gate(nm: *u8) -> i64 { 65 var l: i64 = 0 66 while nm[l] != (0 as u8) { l = l + 1 } 67 if l <= 8 { return 0 } 68 let suf: *u8 = "_gate.nx" 69 var i: i64 = 0 70 while i < 8 { if nm[l-8+i] != suf[i] { return 0 } i = i + 1 } 71 return 1 72} 73 74func main(argc: i64, argv: *i64) -> i64 { 75 if argc < 2 { 76 ds_puts("usage: nx_drysweep <max> [skip] [dir] -- fork nx_gate_dry_apply per gate, tally its answer\n" as *u8) 77 sys_exit(2); return 2 78 } 79 var maxn: i64 = 0 80 var i0: i64 = 0 81 let a1: *u8 = argv[1] as *u8 82 while a1[i0] != (0 as u8) { let c: i64 = a1[i0] as i64; if c >= 48 { if c <= 57 { maxn = maxn*10 + (c-48) } } i0 = i0 + 1 } 83 var skipn: i64 = 0 84 if argc >= 3 { 85 let a2: *u8 = argv[2] as *u8 86 var i1: i64 = 0 87 while a2[i1] != (0 as u8) { let c: i64 = a2[i1] as i64; if c >= 48 { if c <= 57 { skipn = skipn*10 + (c-48) } } i1 = i1 + 1 } 88 } 89 var dir: *u8 = DS_DIR 90 if argc >= 4 { dir = argv[3] as *u8 } 91 92 // ★RESOLVE THE RULER, DO NOT ASSUME ITS PATH -- the same CWD-relative trap this estate keeps paying for. 93 let elf: *u8 = sys_mmap(DS_NAMECAP) 94 if ar_resolve("nx_gate_dry_apply.elf" as *u8, elf) == 0 { 95 ds_puts("nx_drysweep: cannot resolve nx_gate_dry_apply.elf from here or any configured root -- NO CONCLUSION\n" as *u8) 96 sys_exit(3); return 3 97 } 98 let dfd: i64 = sys_openat_rd(dir) 99 if dfd < 0 { ds_puts("nx_drysweep: cannot open gate dir -- NO CONCLUSION\n" as *u8); sys_exit(3); return 3 } 100 101 let lf: i64 = sys_openat_append(DS_LOG, 0x1a4) 102 let dbuf: *u8 = sys_mmap(DS_DIRBUF) 103 let out: *u8 = sys_mmap(DS_OUTCAP) 104 let olen: *i64 = sys_mmap(16) as *i64 105 let gname: *u8 = sys_mmap(DS_NAMECAP) 106 let av: *i64 = sys_mmap(64) as *i64 107 108 var seen: i64 = 0 109 var done: i64 = 0 110 var adopter: i64 = 0 111 var f0: i64 = 0 112 var idiom: i64 = 0 113 var oskip: i64 = 0 114 var noanch: i64 = 0 115 var migd: i64 = 0 116 var errn: i64 = 0 117 var go: i64 = 1 118 ds_puts("=== nx_drysweep -- forking nx_gate_dry_apply per gate; it is the judge, this only tallies ===\n" as *u8) 119 while go == 1 { 120 let nb: i64 = sys_getdents64(dfd, dbuf, DS_DIRBUF) 121 if nb <= 0 { go = 0 } 122 if nb > 0 { 123 var off: i64 = 0 124 while off < nb { 125 let rec: *u8 = (dbuf as i64 + off) as *u8 126 let rl: i64 = dirent_reclen(rec) 127 if rl <= 0 { off = nb } 128 if rl > 0 { 129 let nm: *u8 = dirent_name(rec) 130 if ds_is_gate(nm) == 1 { 131 seen = seen + 1 132 if seen > skipn { if done < maxn { 133 // strip ".nx" -> the bare gate name dry_apply expects 134 var l: i64 = 0 135 while nm[l] != (0 as u8) { gname[l] = nm[l]; l = l + 1 } 136 gname[l-3] = 0 as u8 137 // ★ZERO THE RESULT BUFFER EVERY ITERATION: a reused buffer reports the PREVIOUS 138 // item's measurement as this item's, and the tally would be silently wrong. 139 out[0] = 0 as u8 140 olen[0] = 0 141 av[0] = elf as i64 142 av[1] = gname as i64 143 av[2] = DS_CAND as i64 144 av[3] = 0 145 let rc: i64 = tr_run_capture_to(elf, av, out, DS_OUTCAP - 1, olen, DS_TIMEOUT) 146 let on: i64 = olen[0] 147 var cls: *u8 = "ERROR" as *u8 148 if on > 0 { 149 if ds_has(out, on, "fails==0 family" as *u8) == 1 { cls = "SKIP-FAILS0" as *u8; f0 = f0 + 1 } 150 if ds_has(out, on, "counter idiom not recognised" as *u8) == 1 { cls = "SKIP-IDIOM" as *u8; idiom = idiom + 1 } 151 if ds_has(out, on, "fails==0 family" as *u8) == 0 { if ds_has(out, on, "counter idiom not recognised" as *u8) == 0 { 152 // ★NAME THE REASON, NEVER POOL IT. My first run put 6 of 8 into a catch-all 153 // SKIP-OTHER; reading one showed it was "no verdict=GREEN tail (anchor rung, 154 // not this one)" -- a DIFFERENT family needing the ANCHOR rung, not the counter 155 // migration. A bucket named for how the READER failed merges findings whose 156 // remedies are opposite, and the pooled count is what someone plans against. 157 // ★MIGRATED IS PROGRESS, NOT RESIDUAL. dry_apply answers an already-migrated 158 // gate with `already inherits the base class`, which v1 pooled into 159 // SKIP-OTHER -- so as the D001 lane advances, ADOPTER shrinks and the 160 // catch-all grows, and the census reads like regression while it is 161 // actually progress. Name it, or the number inverts its own meaning. 162 let alr: i64 = ds_has(out, on, "already inherits the base class" as *u8) 163 let anch: i64 = ds_has(out, on, "no verdict=GREEN tail" as *u8) 164 if alr == 1 { cls = "MIGRATED" as *u8; migd = migd + 1 } 165 if alr == 0 { if anch == 1 { cls = "SKIP-NOANCHOR" as *u8; noanch = noanch + 1 } } 166 if alr == 0 { if anch == 0 { 167 if ds_has(out, on, "DRY-APPLY SKIP" as *u8) == 1 { cls = "SKIP-OTHER" as *u8; oskip = oskip + 1 } 168 if ds_has(out, on, "DRY-APPLY SKIP" as *u8) == 0 { cls = "ADOPTER" as *u8; adopter = adopter + 1 } 169 } } 170 } } 171 } 172 if on <= 0 { errn = errn + 1 } 173 ds_puts(" " as *u8); ds_puts(cls); ds_puts(" " as *u8); ds_puts(gname); ds_puts("\n" as *u8) 174 if lf >= 0 { 175 ds_w(lf, "DRYSWEEP gate=" as *u8); ds_w(lf, gname) 176 ds_w(lf, " class=" as *u8); ds_w(lf, cls) 177 ds_w(lf, " rc=" as *u8); ds_n(lf, rc) 178 ds_w(lf, " bytes=" as *u8); ds_n(lf, on) 179 ds_w(lf, "\n" as *u8) 180 } 181 done = done + 1 182 } } 183 } 184 off = off + rl 185 } 186 } 187 } 188 } 189 sys_close(dfd) 190 191 let sum: i64 = adopter + f0 + idiom + noanch + migd + oskip + errn 192 ds_puts("\n gates_seen=" as *u8); ds_n(1, seen) 193 ds_puts(" swept=" as *u8); ds_n(1, done) 194 ds_puts(" skipped_by_arg=" as *u8); ds_n(1, skipn) 195 ds_puts("\n ADOPTER=" as *u8); ds_n(1, adopter) 196 ds_puts(" SKIP-FAILS0=" as *u8); ds_n(1, f0) 197 ds_puts(" SKIP-IDIOM=" as *u8); ds_n(1, idiom) 198 ds_puts(" SKIP-NOANCHOR=" as *u8); ds_n(1, noanch) 199 ds_puts(" MIGRATED=" as *u8); ds_n(1, migd) 200 ds_puts(" SKIP-OTHER=" as *u8); ds_n(1, oskip) 201 ds_puts(" ERROR=" as *u8); ds_n(1, errn) 202 ds_puts(" partition: " as *u8); ds_n(1, sum); ds_puts(" of " as *u8); ds_n(1, done) 203 if sum == done { ds_puts(" -- SUMS\n" as *u8) } 204 if sum != done { ds_puts(" -- ⚠DOES NOT SUM (a gate went uncounted)\n" as *u8) } 205 let deferred: i64 = seen - skipn - done 206 if deferred > 0 { 207 ds_puts(" ⚠DEFERRED " as *u8); ds_n(1, deferred) 208 ds_puts(" gate(s) -- the cap was reached. THIS TALLY IS PARTIAL; resume with skip=" as *u8) 209 ds_n(1, skipn + done); ds_puts("\n" as *u8) 210 } 211 if lf >= 0 { 212 ds_w(lf, "DRYSWEEP-TOTAL seen=" as *u8); ds_n(lf, seen) 213 ds_w(lf, " swept=" as *u8); ds_n(lf, done) 214 ds_w(lf, " adopter=" as *u8); ds_n(lf, adopter) 215 ds_w(lf, " fails0=" as *u8); ds_n(lf, f0) 216 ds_w(lf, " idiom=" as *u8); ds_n(lf, idiom) 217 ds_w(lf, " noanchor=" as *u8); ds_n(lf, noanch) 218 ds_w(lf, " migrated=" as *u8); ds_n(lf, migd) 219 ds_w(lf, " other=" as *u8); ds_n(lf, oskip) 220 ds_w(lf, " error=" as *u8); ds_n(lf, errn) 221 ds_w(lf, " deferred=" as *u8); ds_n(lf, deferred) 222 ds_w(lf, " verdict=" as *u8) 223 if errn == 0 { ds_w(lf, "GREEN\n" as *u8) } else { ds_w(lf, "RED\n" as *u8) } 224 sys_close(lf) 225 } 226 if errn > 0 { sys_exit(1); return 1 } 227 sys_exit(0); return 0 228}