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}