code wiki / _hdl_build / nx_wasmpage_census.nx
nx_wasmpage_census.nx source
↩ module page · 314 lines · 19780 B
1// nx_wasmpage_census.nx -- EVERY SHIPPED PAGE THAT CARRIES A WASM MODULE, VERIFIED. NO SAMPLING.
2//
3// WHY IT EXISTS. On 2026-08-14 /craft shipped black twice because its framebuffer had outgrown the
4// module's own declared linear memory, and nothing in the pipeline could see it: size floors and
5// magic bytes cannot tell a module that RUNS from one that TRAPS. The fit guard now lives in the
6// shared emitter, so no NEW page can ship with that defect -- but every page emitted BEFORE the
7// guard existed is still out there unmeasured, and I could not enumerate them: a grep across the
8// docroot's 79,966 files times out.
9// ★"TOO SLOW TO MEASURE" IS A TOOLING GAP, NEVER A LICENCE TO SAMPLE. This is the tool.
10//
11// WHAT IT DOES: walks the docroot, and for every .html that carries an embedded module (the emitter
12// writes it as const B="<base64>") forks nx_wasm_vm_verify on that page and classifies the verdict.
13// ★IT COMPOSES THE RULER RATHER THAN RE-IMPLEMENTING IT. The decode, the parse, the declared-memory
14// read and the fit arithmetic all live in nx_wasm_vm_verify; duplicating any of that here would give
15// the estate two answers to one question and no way to tell which had rotted.
16//
17// The partition is printed and RECONCILED against the file count -- a census whose parts do not sum
18// is a leak, and every OVERSIZE page is NAMED, because a count without a worklist is not actionable.
19// license_tier: ORIGINAL expect_exit: 0
20import "nx_syscalls.nx"
21import "nx_tool_run.nx"
22import "nx_gate_verdict.nx"
23
24const WC_VERIFY: *u8 = "nx_wasm_vm_verify.elf"
25// ★★★★★★ANCHOR ON THE PAYLOAD, NEVER ON THE EMITTER'S SPELLING. This was `const B="` and it made
26// the census measure ONE emitter's output: MEASURED 2026-08-15 it found 9 pages while an independent
27// grep found 67 calling WebAssembly.instantiate -- racing, pong, explorer, adventure, td, city, shmup,
28// voxelworld, sudoku and viz-zoom embed via `var b64='...'`. The census then reported 4/4 GREEN over
29// 13% of its subject, which is exactly the shape of failure it was built to prevent.
30// "AGFzbQEAAAA" is the base64 of a wasm module's own magic + version, so it matches what is CARRIED
31// rather than what wrapped it, and no future emitter can hide a module from this walk by renaming a
32// variable. ★TWO INSTRUMENTS THAT DISAGREE LOCATE A DEFECT NEITHER COULD FIND ALONE.
33const WC_ANCHOR: *u8 = "AGFzbQEAAAA"
34const WC_DIRBUF: i64 = 131072
35const WC_PATHBUF: i64 = 4096
36const WC_OUTCAP: i64 = 262144
37// a page that carries a module is at least this big; below it there is no base64 blob to find and
38// reading the file is wasted work. The smallest emitted game page measured on 2026-08-14 was over
39// 200,000 bytes, so this is two orders of magnitude below the real floor and cannot exclude one.
40const WC_MIN_PAGE: i64 = 4096
41// the child parses and runs a module; craft's is 131,675 bytes and returns in about a second. Ten
42// seconds is the point past which something is wrong rather than slow, and the row says TIMEOUT
43// instead of silently counting as a pass.
44const WC_TIMEOUT_MS: i64 = 10000
45// depth bound for the walk. The docroot is a site tree, not a filesystem -- 12 is far past its real
46// nesting and exists only so a symlink cycle cannot spin forever. Reaching it is REPORTED.
47const WC_MAXDEPTH: i64 = 12
48
49// The call any page must make to run a module, embedded or fetched. Deliberately the full call and
50// not the bare word "WebAssembly": prose on documentation pages says the word constantly, and a
51// detector with false positives is worse than none because everyone learns to ignore it.
52const WC_JSMARK: *u8 = "WebAssembly.instantiate"
53
54// argv handed to the forked verifier: elf, path, noinit, nopaint, NULL terminator.
55const WC_ARGV_SLOTS: i64 = 5
56
57// ★★★★★DELETE THE DUPLICATE, DO NOT BALANCE IT. nx_mmapbal -- the estate's static mmap/munmap
58// scanner, which I should have run BEFORE reasoning about my own frees -- flagged the hand-rolled
59// formatter here as `mmap=2 munmap=0`, a leak per number printed. My first fix made its two scratch
60// buffers into singletons so the scanner would pass, which is treating the symptom. This file already
61// imports nx_gate_verdict, whose gv_puts/gv_num the same scanner measures CLEAN, so the honest fix is
62// that there is ONE formatter and these are names for it. I had hand-rolled the identical pair in
63// nx_wasm_vm_verify and again in nx_wasmfit -- three copies in one session.
64// ★A BUG YOU FIX BY REWRITING THE LINE, RATHER THAN BY EXTRACTING THE FIX, IS A BUG YOU WILL WRITE
65// AGAIN, and the proof is that I wrote it twice more before an existing ruler told me.
66func wc_puts(s: *u8) -> i64 { return gv_puts(s) }
67func wc_num(v: i64) -> i64 { return gv_num(v) }
68func wc_slen(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} return n }
69func wc_is_html(nm: *u8) -> i64 {
70 let n: i64 = wc_slen(nm)
71 if n < 6 { return 0 }
72 if nm[n-5] != (46 as u8) { return 0 }
73 if nm[n-4] != (104 as u8) { return 0 }
74 if nm[n-3] != (116 as u8) { return 0 }
75 if nm[n-2] != (109 as u8) { return 0 }
76 if nm[n-1] != (108 as u8) { return 0 }
77 return 1
78}
79func wc_find(buf: *u8, len: i64, needle: *u8) -> i64 {
80 let nl: i64 = wc_slen(needle)
81 if nl == 0 { return 0 - 1 }
82 var i: i64 = 0
83 while i + nl <= len {
84 var k: i64 = 0
85 var m: i64 = 1
86 while k < nl { if buf[i+k] != needle[k] { m = 0; k = nl } else { k = k + 1 } }
87 if m == 1 { return i }
88 i = i + 1
89 }
90 return 0 - 1
91}
92
93// tallies: [0]=html seen [1]=carries a module [2]=painted [3]=REFUSED [4]=fits-paint-not-claimed
94// [5]=no answer [6]=depth-capped dirs [7]=answered by the structural fallback
95// ⚠SIZED FROM THE SLOTS IT HOLDS. 64 bytes is EIGHT i64 slots (0..7); adding the two coverage
96// counters below would have written past the end exactly as the argv array did earlier this session.
97const WC_TAL_SLOTS: i64 = 16
98static WC_TAL: i64
99func wc_tal() -> *i64 { if WC_TAL == 0 { WC_TAL = sys_mmap(WC_TAL_SLOTS * 8) as i64 } return WC_TAL as *i64 }
100
101// ★NEVER ALLOCATE IN A HOT LOOP. wc_check runs once per html file in a 79,966-file tree, so a
102// fixed-size scratch allocation inside it is not "small" -- mmap rounds up to a 4 KB page, making a
103// 16-byte length box cost a page per file, ~180 MB across the docroot for two integers. These live
104// once and are reused, which is also why the buffers are singletons rather than parameters: there is
105// exactly one walk in flight, and threading four buffers through the recursion would buy nothing.
106static WC_LENBOX: i64
107func wc_lenbox() -> *i64 { if WC_LENBOX == 0 { WC_LENBOX = sys_mmap(16) as i64 } return WC_LENBOX as *i64 }
108static WC_ARGVBOX: i64
109func wc_argvbox() -> *i64 { if WC_ARGVBOX == 0 { WC_ARGVBOX = sys_mmap(WC_ARGV_SLOTS * 8) as i64 } return WC_ARGVBOX as *i64 }
110static WC_OUTBOX: i64
111func wc_outbox() -> *u8 { if WC_OUTBOX == 0 { WC_OUTBOX = sys_mmap(WC_OUTCAP) as i64 } return WC_OUTBOX as *u8 }
112static WC_OLENBOX: i64
113func wc_olenbox() -> *i64 { if WC_OLENBOX == 0 { WC_OLENBOX = sys_mmap(16) as i64 } return WC_OLENBOX as *i64 }
114
115func wc_check(path: *u8) -> i64 {
116 let tal: *i64 = wc_tal()
117 let lp: *i64 = wc_lenbox()
118 // ⚠⚠RELEASE THE MAPPING ON EVERY PATH OUT. sys_read_file mmaps the whole file; this walk visits
119 // tens of thousands of pages, so a mapping retained per file is an unbounded leak, and MEASURED
120 // live it was exactly that -- 537 -> 556 -> 570 MB resident across three samples of one run.
121 // ★RESOURCE EXCELLENCE IS A SHIPPING CRITERION: a census that answers correctly while growing
122 // without bound is still a bug. The three early returns below are the whole hazard -- a fix that
123 // only frees on the path the author happened to be thinking about leaks on the common case, which
124 // here is the 44,000 pages that carry no module at all and return at the anchor test.
125 let buf: *u8 = sys_read_file(path, lp)
126 if (buf as i64) == 0 { return 0 }
127 if lp[0] < WC_MIN_PAGE { sys_munmap(buf, lp[0]); return 0 }
128
129 // ★MEASURE THE FILTER'S OWN COVERAGE, DO NOT ASSERT IT. The anchor above finds an EMBEDDED module;
130 // a page can also fetch a .wasm at runtime, and such a page is outside this walk's reach entirely.
131 // Counting the pages that instantiate WebAssembly gives a second, independent census of the same
132 // population, and the two numbers reconcile or they name a gap. Without this the walk reports a
133 // confident total for whatever its anchor happens to match -- which is precisely how the first
134 // version reported 9 of 67.
135 let hasmod: i64 = (wc_find(buf, lp[0], WC_ANCHOR) >= 0) as i64
136 let hasjs: i64 = (wc_find(buf, lp[0], WC_JSMARK) >= 0) as i64
137 if hasjs == 1 {
138 tal[8] = tal[8] + 1
139 if hasmod == 0 {
140 tal[9] = tal[9] + 1
141 // ★★★★★NAME A BUCKET FOR WHAT WAS MEASURED, NEVER FOR THE CONCLUSION YOU IMAGINE FOLLOWS.
142 // This said "instantiates wasm it does not carry", which is a FALSE CLAIM for most of the
143 // class: MEASURED, the bulk are code/src_*.html source-VIEWER pages that merely DISPLAY an
144 // organ's text, and the marker cannot tell a call from a rendering of a call -- the same
145 // law as "a scanner that does not skip comments measures the documentation", wearing a new
146 // costume. Only the two video/ pages genuinely fetch a module at runtime. The honest row
147 // states the observation and leaves the two readings open.
148 wc_puts(" NO-EMBEDDED-MODULE " as *u8); wc_puts(path)
149 wc_puts(" -- names WebAssembly.instantiate but carries no module: it either fetches one\n" as *u8)
150 wc_puts(" at runtime or is a page displaying source. Outside this walk's reach either way.\n" as *u8)
151 }
152 }
153 if hasmod == 0 { sys_munmap(buf, lp[0]); return 0 }
154 sys_munmap(buf, lp[0])
155 tal[1] = tal[1] + 1
156
157 // ★FORK THE RULER. One implementation of "does this module run in its declared memory", and this
158 // census is only its bookkeeper.
159 // ★ASK THE CHEAP QUESTION AT CENSUS SCALE. "noinit" tells the verifier to skip init(), and that is
160 // not a shortcut -- it is what this census actually claims. World-scale modules generate their
161 // terrain in init (craft: 786,432 voxels of noise), which an interpreter cannot finish; MEASURED
162 // here on the first run, every world page timed out at 10s and the census learned nothing at all.
163 // Without init the quality slot reads zero, which clamps to the FINEST setting, so ww/hh report
164 // the worst case the adaptive controller can ever reach -- precisely the case that has to fit,
165 // and precisely the case that took /craft down. Frame CONTENT stays each module's own gate's job.
166 // ⚠SIZE THE ALLOCATION FROM THE SLOTS IT HOLDS, NOT FROM A BYTE COUNT THAT HAPPENED TO FIT.
167 // sys_mmap takes BYTES; this array holds i64 SLOTS. The first cut asked for 32 -- exactly the four
168 // slots it then used -- and the moment the structural-fallback added a fifth (av[4]=0) it wrote 8
169 // bytes past the end. The arena guard ANNOUNCED it (ARENA-OVERRUN prev_alloc_size=32) instead of
170 // letting it corrupt quietly, which is the whole argument for fail-loud allocation; a silent
171 // overrun here would have surfaced as an unrelated wrong answer somewhere downstream.
172 let av: *i64 = wc_argvbox()
173 av[0] = WC_VERIFY as i64
174 av[1] = path as i64
175 // ★★★★★★ASK ONLY THE QUESTION YOU CAN ANSWER FOR AN ARBITRARY MODULE. A census cannot know any
176 // given module's contract -- whether render() takes camera arguments, whether a world must be
177 // generated first -- so a frame it drives blind proves nothing about the page and, MEASURED on
178 // voxelworld/index.html, actively LIES: fit passed with 1.8 MB of headroom and the blank frame
179 // still landed the page in REFUSED, indicting a healthy page for the one defect this census
180 // exists to find. Structural fit is the question this walk CAN answer for every module, and it is
181 // the question that took /craft down twice. Frame content belongs to each module's own gate,
182 // where the arguments and the init are known.
183 av[2] = ("noinit" as *u8) as i64
184 av[3] = ("nopaint" as *u8) as i64
185 av[4] = 0
186 let out: *u8 = wc_outbox()
187 let olen: *i64 = wc_olenbox()
188 // Asking the structural question only, this cannot hang: no frame is ever rendered, so the
189 // interpreter's per-pixel cost -- which timed out four of four world pages on the first run -- is
190 // out of the path entirely rather than retried around.
191 let rc: i64 = tr_run_capture_to(WC_VERIFY, av, out, WC_OUTCAP, olen, WC_TIMEOUT_MS)
192
193 if rc == 0 { tal[2] = tal[2] + 1 } else {
194 if rc == 3 { tal[4] = tal[4] + 1 } else {
195 if rc < 0 {
196 tal[5] = tal[5] + 1
197 wc_puts(" TIMEOUT-EVEN-STRUCTURAL " as *u8); wc_puts(path); wc_puts("\n" as *u8)
198 } else {
199 tal[3] = tal[3] + 1
200 wc_puts(" REFUSED " as *u8); wc_puts(path)
201 wc_puts(" -- the module does not run in the memory it declares\n" as *u8)
202 }
203 }
204 }
205 return 0
206}
207
208func wc_walk(dir: *u8, depth: i64) -> i64 {
209 let tal: *i64 = wc_tal()
210 if depth > WC_MAXDEPTH { tal[6] = tal[6] + 1; return 0 }
211 let fd: i64 = sys_openat_rd(dir)
212 if fd < 0 { return 0 }
213 let dbuf: *u8 = sys_mmap(WC_DIRBUF)
214 var go: i64 = 1
215 while go == 1 {
216 // ⚠ONE getdents64 CALL IS NOT A DIRECTORY LISTING -- loop until it returns 0, or a big
217 // directory is silently read as a prefix and its total published as fact.
218 let nb: i64 = sys_getdents64(fd, dbuf, WC_DIRBUF)
219 if nb <= 0 { go = 0 } else {
220 var off: i64 = 0
221 while off < nb {
222 let rec: *u8 = ((dbuf as i64) + off) as *u8
223 let rl: i64 = dirent_reclen(rec)
224 if rl <= 0 { off = nb } else {
225 let nm: *u8 = dirent_name(rec)
226 let dt: i64 = dirent_type(rec)
227 var skip: i64 = 0
228 if nm[0] == (46 as u8) { skip = 1 } // . and ..
229 if skip == 0 {
230 let p: *u8 = sys_mmap(WC_PATHBUF)
231 var c: i64 = 0
232 while dir[c] != (0 as u8) { p[c] = dir[c]; c = c + 1 }
233 p[c] = 47 as u8
234 c = c + 1
235 var d: i64 = 0
236 while nm[d] != (0 as u8) { p[c+d] = nm[d]; d = d + 1 }
237 p[c+d] = 0 as u8
238 if dt == 4 { wc_walk(p, depth + 1) } else {
239 if wc_is_html(nm) == 1 { tal[0] = tal[0] + 1; wc_check(p) }
240 }
241 // ⚠FREE THE PATH: this allocation is PER DIRECTORY ENTRY, not per directory, so
242 // across 62,906 files it is ~250 MB of requests. The arena's recycling ring
243 // absorbed most of it, which is precisely why the process READ as flat and why
244 // I described it that way -- ★AN ALLOCATOR THAT HIDES AN IMBALANCE MAKES THE
245 // IMBALANCE A PROPERTY OF THE ALLOCATOR, NOT A PROPERTY OF THE CODE, AND THE
246 // NEXT SIZE CHANGE UNHIDES IT. p is dead once the branch above returns.
247 sys_munmap(p, WC_PATHBUF)
248 }
249 off = off + rl
250 }
251 }
252 }
253 }
254 sys_close(fd)
255 sys_munmap(dbuf, WC_DIRBUF)
256 return 0
257}
258
259func main(argc: i64, argv: *i64) -> i64 {
260 let ctr: *i64 = gv_ctr()
261 var root: *u8 = "sites/nishifamily" as *u8
262 if argc >= 2 { root = argv[1] as *u8 }
263 wc_puts("=== nx_wasmpage_census " as *u8); wc_puts(root); wc_puts(" ===\n" as *u8)
264
265 let tal: *i64 = wc_tal()
266 var z: i64 = 0
267 while z < WC_TAL_SLOTS { tal[z] = 0; z = z + 1 }
268 wc_walk(root, 0)
269
270 wc_puts("\n html_pages=" as *u8); wc_num(tal[0])
271 wc_puts(" carrying_a_module=" as *u8); wc_num(tal[1])
272 // ★NAME THE BUCKET FOR WHAT WAS MEASURED. "skipped" said how the reader failed, not what the
273 // subject is: a module whose framebuffer FITS but whose frame this interpreter cannot afford is a
274 // PASS on the only question this census asks. Calling it a skip invites the next reader to treat
275 // the estate's flagship pages as unmeasured when they are the best-measured things here.
276 wc_puts("\n FITS=" as *u8); wc_num(tal[4])
277 wc_puts(" REFUSED=" as *u8); wc_num(tal[3])
278 wc_puts(" no_answer=" as *u8); wc_num(tal[5])
279 // ★AN UNREACHABLE BUCKET STILL GETS A COUNTER, BECAUSE THE DAY IT FIRES IS THE DAY A CONTRACT
280 // CHANGED. The verifier is asked the structural question only, so it can answer 3 (fits) or 1
281 // (does not); a 0 means it painted a frame nobody asked for and this census is reading a tool it
282 // no longer understands. It stays in the partition sum for exactly that reason.
283 if tal[2] > 0 { wc_puts(" ⚠unexpected_painted=" as *u8); wc_num(tal[2]) }
284 let sum: i64 = tal[2] + tal[3] + tal[4] + tal[5]
285 wc_puts("\n partition sum=" as *u8); wc_num(sum)
286 wc_puts(" of carrying_a_module=" as *u8); wc_num(tal[1])
287 if sum == tal[1] { wc_puts(" RECONCILES\n" as *u8) } else { wc_puts(" LEAKS -- do not trust these numbers\n" as *u8) }
288
289 // ★COVERAGE IS PART OF THE CLAIM. The verdict above is about EMBEDDED modules; this line says how
290 // much of the wasm on this site that is, so nobody reads a GREEN as covering more than it does.
291 wc_puts(" wasm reach: pages instantiating WebAssembly=" as *u8); wc_num(tal[8])
292 wc_puts(" of which carry their module (verified here)=" as *u8); wc_num(tal[1])
293 wc_puts(" fetch it at runtime (NOT verified here)=" as *u8); wc_num(tal[9])
294 let reach: i64 = tal[1] + tal[9]
295 wc_puts("\n reach sum=" as *u8); wc_num(reach)
296 wc_puts(" of instantiating=" as *u8); wc_num(tal[8])
297 if reach == tal[8] { wc_puts(" RECONCILES\n" as *u8) } else { wc_puts(" LEAKS -- a page instantiates wasm and fell into neither class\n" as *u8) }
298 if tal[6] > 0 {
299 wc_puts(" ⚠depth cap reached in " as *u8); wc_num(tal[6])
300 wc_puts(" directories -- the walk is a FLOOR, not a total\n" as *u8)
301 }
302
303 gv_check("the walk reconciles: every page carrying a module landed in exactly one bucket" as *u8, (sum == tal[1]) as i64, ctr)
304 gv_check("no shipped page carries a module that refuses to run in the memory it declares" as *u8, (tal[3] == 0) as i64, ctr)
305 // ★A CENSUS THAT CANNOT ANSWER FOR A PAGE HAS NOT MEASURED THE POPULATION, IT HAS MEASURED THE
306 // PAGES THAT WERE EASY. Bound to the denominator on purpose: this cannot pass on an empty walk.
307 gv_check("every page carrying a module produced an answer -- no non-answers left in the population" as *u8, ((tal[5] == 0) && (tal[1] > 0)) as i64, ctr)
308 gv_check("the walk completed without hitting its depth cap, so this is a total and not a floor" as *u8, (tal[6] == 0) as i64, ctr)
309 // ★THE SECOND CENSUS MUST ACCOUNT FOR THE FIRST. Every page that instantiates wasm is either one
310 // this walk verified or one it NAMED as out of reach -- a page in neither class is a page the
311 // anchor silently missed, which is the exact defect that made the first run report 9 of 67.
312 gv_check("every page that instantiates wasm is either verified here or named as fetching it" as *u8, ((reach == tal[8]) && (tal[8] > 0)) as i64, ctr)
313 return gv_verdict("WASMPAGE-CENSUS" as *u8, ctr, "every shipped page carrying an embedded module was run, not sampled" as *u8)
314}