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}