code wiki / _hdl_build / nx_page_verify.nx
nx_page_verify.nx source
↩ module page · 446 lines · 21766 B
1// nx_page_verify.nx -- BROWSER-GRADE LIVE PAGE VERIFIER (the "my verify was shit" cure, operator 2026-07-16).
2// Status-200-on-the-page is NOT verification: a page can 200 while every image on it is broken (the /render3d
3// incident: the edge 301-strips trailing slashes, so RELATIVE img srcs resolve to the site root -> 404/fallback
4// -> broken images that a direct asset fetch never catches). This organ verifies a page THE WAY A BROWSER
5// EXPERIENCES IT:
6// 1. fetch the page (sovereign TLS, redirects followed) -- must be 200
7// 2. extract every asset ref (img/script src=, link href=)
8// 3. LAW CHECK: a RELATIVE asset ref = RED by construction on our slash-stripping edge (use absolute /path)
9// 4. fetch every same-origin asset -- 200 required
10// 5. DEEP-DECODE: PNG assets run through the full sovereign decoder (nx_png_decode: signature, IHDR,
11// zlib inflate, unfilter incl Paeth) -- "200 + magic bytes" is not proof; DECODED WxH is
12// 6. an asset that answers with HTML (the 404-fallback class) = RED even though its status is 200
13// Composes nx_https_fetch_follow (the games_url_check fetch spine) + nx_png_decode. Exit = broken count.
14// usage: nx_page_verify <https-url> [connect-host:port] (run from repo root: needs data/mozilla_certdata.txt)
15// [connect-host:port] = OPTIONAL connect-override (curl --connect-to): page + every asset fetch opens
16// TCP+TLS to THIS endpoint while SNI/Host/cert-name stay the URL host -- use 127.0.0.1:8443 to verify
17// our OWN vhosts deterministically from the sovereign edge (kills the DSM-nginx :443 coin-flip false-RED).
18// license_tier: ORIGINAL
19import "nx_syscalls.nx"
20import "nx_x509_trust_store.nx"
21import "nx_trust_store_load_from_certdata.nx"
22import "nx_https_url_connect.nx"
23import "nx_https_fetch_follow.nx"
24import "nx_png_decoder.nx"
25
26const PV_CAP: i64 = 8388608 // the EYE must out-read the pages it audits (the 2MiB-truncation lesson)
27const PV_MAXREF: i64 = 64
28// hoisted to satisfy the magic-number ratchet (rule 11 / LAW L001+L006, enforced at the
29// build gate by nx_magicratchet -- it REFUSED the seq911 build until the count went down).
30// Named for what they bound, not for their value, so a future reader can judge the size.
31const PV_CERTDATA_CAP: i64 = 4194304 // trust-store parse arena for mozilla_certdata.txt
32const PV_URL_CAP: i64 = 4096 // one absolute URL (origin, and each resolved ref)
33const PV_REF_MAX: i64 = 2048 // longest relative ref we will resolve
34const PV_FULLURL_CAP: i64 = 8192 // origin + ref joined
35
36func hw(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 }
37func pn(v: i64) -> i64 { let t: *u8=sys_mmap(24); var m: i64=v; if m<0{sys_write(1,"-" as *u8,1);m=0-m} var k: i64=0; if m==0{t[0]=48 as u8;k=1} while m>0{t[k]=(48+(m%10)) as u8;m=m/10;k=k+1} let b: *u8=sys_mmap(24); var j: i64=0; while j<k{b[j]=t[k-1-j];j=j+1} sys_write(1,b,k); return 0 }
38func pw(s: *u8, n: i64) -> i64 { sys_write(1, s, n); return 0 }
39
40func sw_starts(b: *u8, off: i64, lit: *u8) -> i64 {
41 var i: i64 = 0
42 while lit[i] != (0 as u8) { if b[off+i] != lit[i] { return 0 } i = i + 1 }
43 return 1
44}
45
46// origin = "https://host" prefix of url (through the 3rd slash, exclusive)
47func pv_origin(url: *u8, out: *u8) -> i64 {
48 var i: i64 = 0
49 var slashes: i64 = 0
50 while url[i] != (0 as u8) {
51 if url[i] == (47 as u8) {
52 slashes = slashes + 1
53 if slashes == 3 { out[i] = 0 as u8; return i }
54 }
55 out[i] = url[i]
56 i = i + 1
57 }
58 out[i] = 0 as u8
59 return i
60}
61
62// check one asset URL: fetch + validate. kind: 1=img-ish (png expected ok), 0=other. returns 0 ok / 1 broken
63func pv_check_asset(store: *TrustStore, aurl: *u8, body: *u8) -> i64 {
64 let st: *i64 = sys_mmap(8) as *i64
65 let n: i64 = nx_https_fetch_follow(aurl, store, body, PV_CAP, 6, st)
66 hw(" asset " as *u8); hw(aurl)
67 hw(" -> status=" as *u8); pn(st[0]); hw(" bytes=" as *u8); pn(n)
68 if st[0] != 200 { hw(" BROKEN (non-200)\n" as *u8); return 1 }
69 if n <= 0 { hw(" BROKEN (empty body)\n" as *u8); return 1 }
70 // PNG? deep-decode (signature + IHDR + inflate + unfilter) -- the real proof
71 if n > 8 {
72 if body[0] == (137 as u8) {
73 if body[1] == (80 as u8) {
74 let res: *NxPngResult = nx_png_decode(body, n)
75 if (res as i64) == 0 { hw(" BROKEN (png decode null)\n" as *u8); return 1 }
76 if res.error_code != 0 { hw(" BROKEN (png decode err=" as *u8); pn(res.error_code); hw(")\n" as *u8); return 1 }
77 let hdr: *NxPngHeader = res.header
78 if hdr.width <= 0 { hw(" BROKEN (png w=0)\n" as *u8); return 1 }
79 hw(" PNG DECODE-OK " as *u8); pn(hdr.width); hw("x" as *u8); pn(hdr.height); hw("\n" as *u8)
80 return 0
81 }
82 }
83 // an "image" that answers HTML = the 404-fallback class (status was 200!)
84 if body[0] == (60 as u8) { // '<'
85 var isp: i64 = 0
86 if sw_starts(body, 0, "<!doctype" as *u8) == 1 { isp = 1 }
87 if sw_starts(body, 0, "<!DOCTYPE" as *u8) == 1 { isp = 1 }
88 if sw_starts(body, 0, "<html" as *u8) == 1 { isp = 1 }
89 if isp == 1 {
90 // only broken if the URL says it should be an image
91 var j: i64 = 0
92 var dot: i64 = 0 - 1
93 while aurl[j] != (0 as u8) { if aurl[j] == (46 as u8) { dot = j } j = j + 1 }
94 if dot >= 0 {
95 if sw_starts(aurl, dot, ".png" as *u8) == 1 { hw(" BROKEN (.png answers HTML -- 404-fallback class)\n" as *u8); return 1 }
96 if sw_starts(aurl, dot, ".jpg" as *u8) == 1 { hw(" BROKEN (.jpg answers HTML)\n" as *u8); return 1 }
97 if sw_starts(aurl, dot, ".css" as *u8) == 1 { hw(" BROKEN (.css answers HTML)\n" as *u8); return 1 }
98 if sw_starts(aurl, dot, ".js" as *u8) == 1 { hw(" BROKEN (.js answers HTML)\n" as *u8); return 1 }
99 }
100 }
101 }
102 }
103 hw(" OK\n" as *u8)
104 return 0
105}
106
107// a11y-lite: integer substring presence + count over the page (axe-core / Lighthouse-class checks, NO float)
108func pv_has(b: *u8, n: i64, lit: *u8) -> i64 {
109 var i: i64 = 0
110 while i < n { if sw_starts(b, i, lit) == 1 { return 1 } i = i + 1 }
111 return 0
112}
113func pv_count(b: *u8, n: i64, lit: *u8) -> i64 {
114 var c: i64 = 0
115 var i: i64 = 0
116 while i < n { if sw_starts(b, i, lit) == 1 { c = c + 1 } i = i + 1 }
117 return c
118}
119
120// heading-level skip detector (axe/Lighthouse structural rule: no downward jump >1, e.g. h1->h3) -- integer scan
121func pv_hskip(b: *u8, n: i64) -> i64 {
122 var prev: i64 = 0
123 var skips: i64 = 0
124 var i: i64 = 0
125 while i < n - 3 {
126 if b[i] == (60 as u8) { if b[i+1] == (104 as u8) {
127 let d: i64 = b[i+2] as i64
128 if d >= 49 { if d <= 54 {
129 let lvl: i64 = d - 48
130 if prev > 0 { if lvl > prev + 1 { skips = skips + 1 } }
131 prev = lvl
132 } }
133 } }
134 i = i + 1
135 }
136 return skips
137}
138
139// does s start with pfx? returns the offset just past pfx, or -1. Lets the optional
140// args be recognised by NAME in any position, so adding them cannot disturb the existing
141// positional [connect-host:port] callers (rule 19: adding is safe, reordering is not).
142func pv_pfx(s: *u8, pfx: *u8) -> i64 {
143 var i: i64 = 0
144 while pfx[i] != (0 as u8) {
145 if s[i] != pfx[i] { return 0 - 1 }
146 i = i + 1
147 }
148 return i
149}
150// ============================================================================================
151// AUTO CONNECT-OVERRIDE -- RECOVERED 2026-07-25 (debt seq1008 / frontier F1144).
152// The DEPLOYED nx_page_verify.elf implemented this; NO SOURCE IN THE TREE DID. It was built
153// ~2026-07-20, deployed and documented, and its source was lost, so the ordinary /api/build +
154// /api/promote loop would have SILENTLY DELETED it -- turning every our-domain verification back
155// into a :443 coin flip against the co-squatting DSM nginx. That failure mode already manufactured
156// one false sev-7 debt (seq984, retracted). Reimplemented here from the contract documented in the
157// registry header so the binary is reproducible from source again.
158// CONTRACT: rows are <host><TAB><a.b.c.d:port>, '#' comments skipped, an explicit argv[2] override
159// ALWAYS wins, and an absent registry is FAIL-SAFE (verification still runs) -- but never silently:
160// see the vantage line in main(), which is now unconditional.
161const PV_DOMCONF: *u8 = "knowledge/registry/our_domains.conf"
162const PV_DOMCAP: i64 = 65536
163const PV_EP_CAP: i64 = 256
164
165// host of "https://HOST[:port]/path" -> out. 1 ok, 0 if not an https url.
166func pv_host(url: *u8, out: *u8, cap: i64) -> i64 {
167 if sw_starts(url, 0, "https://" as *u8) != 1 { return 0 }
168 var i: i64 = 8
169 var o: i64 = 0
170 var go: i64 = 1
171 while go == 1 {
172 let c: i64 = url[i] as i64
173 if c == 0 { go = 0 }
174 else {
175 if c == 47 { go = 0 }
176 else {
177 if c == 58 { go = 0 }
178 else {
179 if o < (cap - 1) { out[o] = url[i]; o = o + 1 }
180 i = i + 1
181 }
182 }
183 }
184 }
185 out[o] = 0 as u8
186 if o == 0 { return 0 }
187 return 1
188}
189
190// 1 = hit (ep filled) | 0 = not one of ours | -1 = registry unreadable (caller must SAY SO)
191func pv_dom_lookup(host: *u8, ep: *u8, epcap: i64) -> i64 {
192 let fd: i64 = sys_openat_rd(PV_DOMCONF)
193 if fd < 0 { return 0 - 1 }
194 let buf: *u8 = sys_mmap(PV_DOMCAP)
195 var total: i64 = 0
196 var go: i64 = 1
197 while go == 1 {
198 if total >= PV_DOMCAP { go = 0 }
199 else {
200 let n: i64 = sys_read(fd, (buf as i64 + total) as *u8, PV_DOMCAP - total)
201 if n > 0 { total = total + n } else { go = 0 }
202 }
203 }
204 sys_close(fd)
205 var hl: i64 = 0
206 while host[hl] != (0 as u8) { hl = hl + 1 }
207 var found: i64 = 0
208 var ls: i64 = 0
209 var i: i64 = 0
210 while i <= total {
211 var nl: i64 = 0
212 if i >= total { nl = 1 } else { if buf[i] == (10 as u8) { nl = 1 } }
213 if nl == 1 {
214 if found == 0 {
215 let len: i64 = i - ls
216 if len > 0 {
217 if buf[ls] != (35 as u8) {
218 var t: i64 = ls
219 var tab: i64 = 0 - 1
220 while t < i { if buf[t] == (9 as u8) { if tab < 0 { tab = t } } t = t + 1 }
221 if tab > 0 {
222 if (tab - ls) == hl {
223 var k: i64 = 0
224 var same: i64 = 1
225 while k < hl { if buf[ls + k] != host[k] { same = 0 } k = k + 1 }
226 if same == 1 {
227 var o: i64 = 0
228 var p: i64 = tab + 1
229 while p < i {
230 if buf[p] != (13 as u8) { if o < (epcap - 1) { ep[o] = buf[p]; o = o + 1 } }
231 p = p + 1
232 }
233 ep[o] = 0 as u8
234 found = 1
235 }
236 }
237 }
238 }
239 }
240 }
241 ls = i + 1
242 }
243 i = i + 1
244 }
245 return found
246}
247
248func pv_atoi(a: *u8) -> i64 {
249 var v: i64 = 0
250 var i: i64 = 0
251 while a[i] != (0 as u8) {
252 let c: i64 = a[i] as i64
253 if c >= 48 { if c <= 57 { v = v * 10 + (c - 48) } }
254 i = i + 1
255 }
256 return v
257}
258
259func main(argc: i64, argv: *i64) -> i64 {
260 if argc < 2 { hw("usage: nx_page_verify <https-url> [connect-host:port] [expect=<substring>] [minbytes=<n>]\n" as *u8); sys_exit(2); return 2 }
261 let url: *u8 = argv[1] as *u8
262 hw("=== nx_page_verify -- browser-grade live verification of " as *u8); hw(url); hw(" ===\n" as *u8)
263 var expoff: i64 = 0
264 var minbytes: i64 = 0
265 var ov_given: i64 = 0
266 var ai: i64 = 2
267 while ai < argc {
268 let a: *u8 = argv[ai] as *u8
269 let eo: i64 = pv_pfx(a, "expect=" as *u8)
270 let mo: i64 = pv_pfx(a, "minbytes=" as *u8)
271 if eo >= 0 { expoff = (a as i64) + eo }
272 else {
273 if mo >= 0 { minbytes = pv_atoi(((a as i64) + mo) as *u8) }
274 else {
275 if nx_https_connect_override_set(a) != 1 { hw("RED bad connect-override (want a.b.c.d:port)\n" as *u8); sys_exit(2); return 2 }
276 hw("vantage=EXPLICIT connect-override " as *u8); hw(a); hw(" (SNI/Host stay the URL host)\n" as *u8)
277 ov_given = 1
278 }
279 }
280 ai = ai + 1
281 }
282
283 // ---- VANTAGE RESOLUTION (recovered + hardened 2026-07-25; seq1008 recovery, seq990 hardening) ----
284 // The whole point: this organ must NEVER be able to grade one server while the reader believes it
285 // graded another. So the vantage is now stated on EVERY run -- there is no silent path.
286 let pv_h: *u8 = sys_mmap(PV_URL_CAP)
287 var pv_isours: i64 = 0
288 var pv_pinned: i64 = ov_given
289 if pv_host(url, pv_h, PV_URL_CAP) == 1 {
290 let pv_ep: *u8 = sys_mmap(PV_EP_CAP)
291 let d: i64 = pv_dom_lookup(pv_h, pv_ep, PV_EP_CAP)
292 if d == 1 { pv_isours = 1 }
293 if ov_given == 0 {
294 if d == 1 {
295 if nx_https_connect_override_set(pv_ep) != 1 {
296 hw("VERDICT=UNMEASURED (our-domain " as *u8); hw(pv_h)
297 hw(" but its registry endpoint " as *u8); hw(pv_ep)
298 hw(" is malformed -- refusing to grade an unknown server)\n" as *u8)
299 sys_exit(4); return 4
300 }
301 hw("auto connect-override (our-domain " as *u8); hw(pv_h)
302 hw(" -> " as *u8); hw(pv_ep); hw("; SNI/Host stay the URL host)\n" as *u8)
303 pv_pinned = 1
304 }
305 if d == (0 - 1) {
306 hw("WARNING registry " as *u8); hw(PV_DOMCONF)
307 hw(" unreadable -- cannot tell if this host is ours; proceeding via DNS (fail-safe)\n" as *u8)
308 }
309 }
310 }
311 if pv_pinned == 1 { hw("vantage=PINNED (deterministic sovereign edge)\n" as *u8) }
312 else {
313 hw("vantage=DNS (no override)" as *u8)
314 if pv_isours == 1 {
315 // Cannot happen once the registry is readable, but if it ever does, the reader is told
316 // LOUDLY rather than handed a confident RED from whatever answered port 443.
317 hw(" <== WARNING: this IS one of our domains and it is NOT pinned. A 404/RED here may be\n" as *u8)
318 hw(" the co-squatting server on :443, not our edge. TREAT AS UNMEASURED." as *u8)
319 }
320 hw("\n" as *u8)
321 }
322
323 let r: i64 = nx_trust_store_load_from_certdata("data/mozilla_certdata.txt" as *u8, 512, PV_CERTDATA_CAP)
324 if r <= 0 { hw("RED cannot load trust store (run from repo root)\n" as *u8); sys_exit(3); return 3 }
325 let store: *TrustStore = r as *TrustStore
326
327 let page: *u8 = sys_mmap(PV_CAP)
328 let st: *i64 = sys_mmap(8) as *i64
329 let n: i64 = nx_https_fetch_follow(url, store, page, PV_CAP, 6, st)
330 hw("page status=" as *u8); pn(st[0]); hw(" bytes=" as *u8); pn(n); hw("\n" as *u8)
331 if st[0] != 200 { hw("VERDICT=RED (page not 200)\n" as *u8); sys_exit(1); return 1 }
332 if n <= 0 { hw("VERDICT=RED (empty page)\n" as *u8); sys_exit(1); return 1 }
333
334 // ★CONTENT ASSERTION (debt seq911). A 200 DOES NOT MEAN YOUR PAGE. The edge serves a
335 // root fallback for unknown paths, so a failed publish yields 200 with a perfectly
336 // valid, fully-decoding page that simply is not yours -- and every asset on it fetches,
337 // so the old asset-only verdict said GREEN. Measured 2026-07-25: verifying
338 // /research/rt004.html reported status=200 VERDICT=GREEN while the edge was serving the
339 // 835-byte site root and the 10201-byte page had landed nowhere. Asset liveness is not
340 // page identity; the caller must be able to assert WHICH page it expects.
341 if minbytes > 0 {
342 if n < minbytes {
343 hw("VERDICT=RED (page is " as *u8); pn(n)
344 hw(" bytes, below the asserted floor of " as *u8); pn(minbytes)
345 hw(" -- a 200 is not your page)\n" as *u8)
346 sys_exit(1); return 1
347 }
348 hw("byte-floor OK (" as *u8); pn(n); hw(" >= " as *u8); pn(minbytes); hw(")\n" as *u8)
349 }
350 if expoff != 0 {
351 if pv_has(page, n, expoff as *u8) == 0 {
352 hw("VERDICT=RED (expected content ABSENT: " as *u8); hw(expoff as *u8)
353 hw(") -- the server returned 200 but this is not the page you published\n" as *u8)
354 sys_exit(1); return 1
355 }
356 hw("content-assert OK (expect=" as *u8); hw(expoff as *u8); hw(")\n" as *u8)
357 }
358
359 let origin: *u8 = sys_mmap(PV_URL_CAP)
360 pv_origin(url, origin)
361
362 // --- a11y-lite audit (integer, no float): axe-core / Lighthouse-class page checks ---
363 hw("-- a11y-lite --\n" as *u8)
364 var a11y: i64 = 0
365 if pv_has(page, n, "<title" as *u8) == 1 { hw(" title OK\n" as *u8) } else { hw(" A11Y missing <title>\n" as *u8); a11y = a11y + 1 }
366 if pv_has(page, n, "lang=" as *u8) == 1 { hw(" lang OK\n" as *u8) } else { hw(" A11Y missing lang= on <html>\n" as *u8); a11y = a11y + 1 }
367 if pv_has(page, n, "viewport" as *u8) == 1 { hw(" viewport OK\n" as *u8) } else { hw(" A11Y missing <meta viewport>\n" as *u8); a11y = a11y + 1 }
368 let nimg: i64 = pv_count(page, n, "<img" as *u8)
369 let nalt: i64 = pv_count(page, n, " alt=" as *u8)
370 hw(" img=" as *u8); pn(nimg); hw(" with-alt=" as *u8); pn(nalt); hw("\n" as *u8)
371 if nalt < nimg { hw(" A11Y " as *u8); pn(nimg - nalt); hw(" image(s) missing alt\n" as *u8); a11y = a11y + 1 }
372 let nh1: i64 = pv_count(page, n, "<h1" as *u8)
373 if nh1 == 1 { hw(" single-h1 OK\n" as *u8) } else { hw(" A11Y h1-count=" as *u8); pn(nh1); hw(" (want exactly 1)\n" as *u8); a11y = a11y + 1 }
374 let hsk: i64 = pv_hskip(page, n)
375 if hsk == 0 { hw(" heading-order OK\n" as *u8) } else { hw(" A11Y " as *u8); pn(hsk); hw(" heading-level skip(s)\n" as *u8); a11y = a11y + 1 }
376 if pv_has(page, n, "<main" as *u8) == 1 { hw(" landmark <main> OK\n" as *u8) } else { hw(" A11Y no <main> landmark\n" as *u8); a11y = a11y + 1 }
377 hw(" a11y-issues=" as *u8); pn(a11y); hw("\n" as *u8)
378
379 // extract src="..." / href="..." refs (img/script/link surface)
380 let abuf: *u8 = sys_mmap(PV_CAP)
381 var broken: i64 = 0
382 var checked: i64 = 0
383 var skipped: i64 = 0
384 var lawred: i64 = 0
385 var i: i64 = 0
386 while i < n - 8 {
387 var hit: i64 = 0
388 if sw_starts(page, i, "src=\"" as *u8) == 1 { hit = 5 }
389 if hit == 0 { if sw_starts(page, i, "href=\"" as *u8) == 1 {
390 // href only counts for <link ...> stylesheet-ish tags: look back for '<link' within 80 bytes
391 var b: i64 = i
392 var found: i64 = 0
393 var back: i64 = 0
394 while back < 80 {
395 if b <= 0 { back = 80 } else {
396 if page[b] == (60 as u8) {
397 if sw_starts(page, b, "<link" as *u8) == 1 { found = 1 }
398 back = 80
399 } else { b = b - 1; back = back + 1 }
400 }
401 }
402 if found == 1 { hit = 6 }
403 } }
404 if hit > 0 {
405 let rs: i64 = i + hit
406 var re: i64 = rs
407 while page[re] != (34 as u8) { re = re + 1 }
408 let rlen: i64 = re - rs
409 if rlen > 0 { if rlen < PV_REF_MAX { if checked + skipped + lawred < PV_MAXREF {
410 let ref: *u8 = sys_mmap(PV_URL_CAP)
411 var k: i64 = 0
412 while k < rlen { ref[k] = page[rs+k]; k = k + 1 }
413 ref[rlen] = 0 as u8
414 if sw_starts(ref, 0, "data:" as *u8) == 1 { skipped = skipped + 1 } else {
415 if sw_starts(ref, 0, "http" as *u8) == 1 {
416 if sw_starts(ref, 0, origin) == 1 { checked = checked + 1; broken = broken + pv_check_asset(store, ref, abuf) } else { hw(" skip foreign " as *u8); hw(ref); hw("\n" as *u8); skipped = skipped + 1 }
417 } else {
418 if ref[0] == (47 as u8) {
419 let full: *u8 = sys_mmap(PV_FULLURL_CAP)
420 var o: i64 = 0
421 while origin[o] != (0 as u8) { full[o] = origin[o]; o = o + 1 }
422 var q: i64 = 0
423 while ref[q] != (0 as u8) { full[o+q] = ref[q]; q = q + 1 }
424 full[o+q] = 0 as u8
425 checked = checked + 1
426 broken = broken + pv_check_asset(store, full, abuf)
427 } else {
428 // RELATIVE ref = RED BY LAW on our slash-stripping edge (the /render3d broken-image class)
429 hw(" asset " as *u8); hw(ref); hw(" BROKEN-BY-LAW (relative ref; the edge 301-strips trailing slashes so browsers resolve this against the PARENT -- use absolute /path)\n" as *u8)
430 lawred = lawred + 1
431 broken = broken + 1
432 } } }
433 } } }
434 i = re
435 } else { i = i + 1 }
436 }
437
438 hw("checked=" as *u8); pn(checked)
439 hw(" skipped=" as *u8); pn(skipped)
440 hw(" law-violations=" as *u8); pn(lawred)
441 hw(" broken=" as *u8); pn(broken); hw("\n" as *u8)
442 if broken == 0 { hw("VERDICT=GREEN (every referenced asset fetches AND decodes)\n" as *u8); sys_exit(0); return 0 }
443 hw("VERDICT=RED broken=" as *u8); pn(broken); hw("\n" as *u8)
444 sys_exit(broken)
445 return broken
446}