code wiki / _hdl_build / nx_page_verify.nx
nx_page_verify.nx source
↩ module page · 1006 lines · 59259 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// ONE DEFINITION OF -AN IMG WITH USABLE ATTRIBUTES-, shared with the compare generator that WRITES
26// them, so the emitter and this ruler cannot drift into two answers (2026-08-26).
27import "nx_imgattr_lib.nx"
28import "nx_pageref_lib.nx" // the asset-reference vocabulary: ONE owner, shared with nx_pageref_gate
29import "nx_sha256.nx" // canonical artifact/evidence identity hashing
30
31const PV_CAP: i64 = 8388608 // the EYE must out-read the pages it audits (the 2MiB-truncation lesson)
32const PV_MAXREF: i64 = 256 // per-page ref ceiling; the compare gallery lane emits 15+ figures beside
33 // chrome refs and pushed 64 -- reaching this cap now ANNOUNCES (never a silent floor)
34// hoisted to satisfy the magic-number ratchet (rule 11 / LAW L001+L006, enforced at the
35// build gate by nx_magicratchet -- it REFUSED the seq911 build until the count went down).
36// Named for what they bound, not for their value, so a future reader can judge the size.
37const PV_CERTDATA_CAP: i64 = 4194304 // trust-store parse arena for mozilla_certdata.txt
38const PV_URL_CAP: i64 = 4096 // one absolute URL (origin, and each resolved ref)
39const PV_REF_MAX: i64 = 2048 // longest relative ref we will resolve
40// scratch for nx_pageref_lib's pr_attr_hit: [0]=bytes to skip to the value, [1]=the closing quote.
41// Two slots because the vocabulary answers two questions per hit, and one i64 is eight bytes.
42const PV_PROUT_SLOTS: i64 = 2
43const PV_WORD_BYTES: i64 = 8
44const PV_FULLURL_CAP: i64 = 8192 // origin + ref joined
45// ATTRIBUTE DELIMITERS (2026-08-25) -- named so the BARE (unquoted) attribute scan reads as intent
46// rather than as character codes. HTML permits an unquoted attribute value, terminated by whitespace
47// or '>'. The 2026-08-18 fix taught this scanner BOTH QUOTE STYLES and stopped at two; our own
48// sites/nishifamily/world/foundation.html emits <img src=nx_worldpipe.png ...> with NO quotes, and
49// that page reported img tags=16 but refs resolved=1.
50const PV_ATTR_DQ: i64 = 34 // "
51const PV_ATTR_SQ: i64 = 39 // '
52const PV_ATTR_GT: i64 = 62 // >
53const PV_ATTR_SP: i64 = 32 // space
54const PV_ATTR_TAB: i64 = 9 // tab
55const PV_ATTR_LF: i64 = 10 // newline
56const PV_ATTR_CR: i64 = 13
57const PV_ATTR_LT: i64 = 60 // <
58// PV_TAG_LOOKBACK / pv_in_tag -- ADDED 2026-08-25, after the first POPULATION-SCALE run of the new
59// nx_sitesweep measured THIS scanner's bare-attribute branch firing on INLINE JAVASCRIPT. Adjudicated
60// by hand over four pages: /world/skull (3 refs) and /world/models (9) were REAL broken images, while
61// /atlashygiene reported AI_SYNTHESIZED / PRIMARY_EMPIRICAL x3 / COORDINATION_ROW and /listen reported
62// a fragment of minified script -- six refs that are JavaScript, not markup.
63// THE CAUSE IS STRUCTURAL, NOT A VOCABULARY GAP: a BARE attribute has no delimiter, so el.src=url
64// inside a script is byte-for-byte the same SHAPE as an unquoted src= on an img tag. A DETECTOR WITH
65// FALSE POSITIVES IS WORSE THAN NONE -- it teaches everyone to ignore it -- and this branch had just
66// been handed the whole site to shout at.
67// THE FIX IS HTML, NOT A BLOCKLIST: an attribute can only occur INSIDE an open tag, so scan back and
68// require the nearest angle bracket to be the opener. Inline script always sits after the bracket that
69// closed its script tag, so every JS occurrence is rejected BY CONSTRUCTION and no keyword list can
70// ever go stale.
71// APPLIED ONLY TO THE BARE FORM. The quoted forms are deliberately untouched: a quoted src assigned in
72// a script IS an asset the browser really fetches, and a relative one really does break under the same
73// edge rule -- narrowing those would LOSE true positives instead of removing false ones.
74// UNDECIDABLE REJECTS. A genuine attribute is always a few dozen bytes from its own opening bracket,
75// so the bound is unreachable for real markup; and an accusation is the wrong thing to make on a guess.
76const PV_TAG_LOOKBACK: i64 = 4096
77func pv_in_tag(page: *u8, at: i64) -> i64 {
78 var b: i64 = at
79 var back: i64 = 0
80 while back < PV_TAG_LOOKBACK {
81 if b <= 0 { return 0 }
82 b = b - 1
83 let c: i64 = page[b] as i64
84 if c == PV_ATTR_LT { return 1 }
85 if c == PV_ATTR_GT { return 0 }
86 back = back + 1
87 }
88 return 0
89} // carriage return
90
91// ============================================================================================
92// THE THIRD STATE -- "I COULD NOT REACH IT" IS NOT "IT IS BROKEN" (2026-08-22).
93// MEASURED: a seat ran this organ on a HEALTHY page from a CWD where the domain registry did not
94// resolve, the auto-override silently fell to DNS, :443 on the NAS is the co-squatting side, the
95// fetch NEVER CONNECTED (status=0 bytes=-2), and the verdict said RED. Two untouched control pages
96// returned byte-identical output; the loopback vantage served the same page 200 with every asset.
97// The page was fine. The verifier could not see it. And it reported that in the same word as a
98// page that is genuinely broken -- which is the failure mode that teaches everyone to ignore a
99// detector. AN AXIS THAT CANNOT SEE MUST ABSTAIN, NOT ACQUIT -- AND EQUALLY MUST NOT CONVICT.
100// The discriminator is already in the fetch layer's return contract and this organ was throwing it
101// away: nx_https_fetch_follow returns -NX_FF_<stage> with out_status[0] UNTOUCHED (0) when no HTTP
102// response was ever received. So: (n<0 AND status==0) = no server answered = UNOBSERVABLE, exit 3.
103// Any run where status!=0 means a server DID answer, and a wrong answer stays RED.
104// Exit 3 is the fleet's SKIP/UNOBSERVABLE code (nx_gate_verdict returns 3; /api/gate_run maps 3 ->
105// SKIP, excluded from RED). The trust-store-load failure below already exits 3 for the same reason:
106// it is a "could not look", not a "looked and it is broken". The RED exit (1) and the broken-count
107// exit are UNCHANGED, so every consumer that branches on 0/1 keeps its meaning; only runs that
108// previously LIED now say so. The verdict line stays LAST (gv_last_line anchors by position).
109const PV_EXIT_GREEN: i64 = 0
110const PV_EXIT_RED: i64 = 1
111const PV_EXIT_USAGE: i64 = 2
112const PV_EXIT_UNOBSERVABLE: i64 = 3
113const PV_EXIT_UNMEASURED: i64 = 4 // our-domain host with a malformed registry endpoint
114// fetch-layer stage codes, mirrored from nx_https_fetch_follow so the UNOBSERVABLE line can NAME
115// the stage that never completed instead of printing a bare negative number
116const PV_FF_BAD_URL: i64 = 1
117const PV_FF_CONNECT: i64 = 2
118const PV_FF_HANDSHAKE: i64 = 3
119const PV_FF_GET: i64 = 4
120const PV_VANTAGE_CAP: i64 = 320 // "dns:<host>" or "pinned:<a.b.c.d:port>" for the verdict line
121const PV_NO_STATUS: i64 = 0 // out_status when no HTTP response was ever parsed
122
123// append NUL-terminated s into the vantage buffer at off; bounded by PV_VANTAGE_CAP (a vantage
124// string that does not fit is truncated AND announced by the cap, never silently overrun)
125func pv_vcat(d: *u8, off: i64, s: *u8) -> i64 {
126 var o: i64 = off
127 var i: i64 = 0
128 while s[i] != (0 as u8) { if o < PV_VANTAGE_CAP - 1 { d[o] = s[i]; o = o + 1 } i = i + 1 }
129 d[o] = 0 as u8
130 return o
131}
132func pv_stage_name(n: i64) -> *u8 {
133 let code: i64 = 0 - n
134 if code == PV_FF_BAD_URL { return "bad-url" as *u8 }
135 if code == PV_FF_CONNECT { return "connect" as *u8 }
136 if code == PV_FF_HANDSHAKE { return "tls-handshake" as *u8 }
137 if code == PV_FF_GET { return "http-get" as *u8 }
138 return "fetch" as *u8
139}
140// 1 iff the fetch never produced an HTTP response: negative length AND no status was parsed.
141// A non-200 WITH a status is a server that answered (404, 500, a redirect loop) -> that is RED
142// territory and must NOT land here.
143func pv_unobservable(n: i64, status: i64) -> i64 {
144 if n < 0 { if status == PV_NO_STATUS { return 1 } }
145 return 0
146}
147
148func hw(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 }
149// pv_normpath -- RFC 3986 5.2.4 remove_dot_segments over an ABSOLUTE PATH (2026-08-18). A browser
150// resolves src='/compare/graphics/../../world/x.png' to /world/x.png before it ever asks the edge; this
151// EYE fetched the literal string, got the client's own bad-url body (status=0, 82 bytes) and reported
152// BROKEN x5 / VERDICT=RED on a page whose every asset served 200 -- a false red on the ruler, the kind
153// everyone learns to ignore. Segments: '.' dropped, '..' pops one (never above root), else copied. In
154// place, same buffer, returns the new length. Only path bytes are touched (stops at '?' or '#').
155func pv_normpath(p: *u8) -> i64 {
156 var r: i64 = 0
157 var wpos: i64 = 0
158 var n: i64 = 0
159 while p[n] != (0 as u8) { if p[n] == (63 as u8) { break } if p[n] == (35 as u8) { break } n = n + 1 }
160 let tail: i64 = n
161 while r < n {
162 // r sits on a '/', segment = bytes after it up to next '/' or end
163 var e: i64 = r + 1
164 while e < n { if p[e] == (47 as u8) { break } e = e + 1 }
165 let sl: i64 = e - r - 1
166 var dot: i64 = 0
167 if sl == 1 { if p[r+1] == (46 as u8) { dot = 1 } }
168 if sl == 2 { if p[r+1] == (46 as u8) { if p[r+2] == (46 as u8) { dot = 2 } } }
169 if dot == 2 {
170 // pop the last written segment (leave at least the root '/')
171 if wpos > 0 { wpos = wpos - 1; while wpos > 0 { if p[wpos] == (47 as u8) { break } wpos = wpos - 1 } }
172 } else { if dot == 0 {
173 var k: i64 = r
174 while k < e { p[wpos] = p[k]; wpos = wpos + 1; k = k + 1 }
175 } }
176 r = e
177 }
178 if wpos == 0 { p[0] = 47 as u8; wpos = 1 }
179 // carry query/fragment forward untouched
180 var t: i64 = tail
181 var w2: i64 = wpos
182 while p[t] != (0 as u8) { p[w2] = p[t]; w2 = w2 + 1; t = t + 1 }
183 p[w2] = 0 as u8
184 return w2
185}
186func 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 }
187func pw(s: *u8, n: i64) -> i64 { sys_write(1, s, n); return 0 }
188
189func sw_starts(b: *u8, off: i64, lit: *u8) -> i64 {
190 var i: i64 = 0
191 while lit[i] != (0 as u8) { if b[off+i] != lit[i] { return 0 } i = i + 1 }
192 return 1
193}
194
195// PV_RAW_* / pv_in_rawtext -- ADDED 2026-08-25 after the SECOND fleet sweep, because pv_in_tag ALONE
196// still admits inline JavaScript, and A DETECTOR WITH FALSE POSITIVES IS WORSE THAN NONE. MEASURED
197// from source, not inferred, at sites/nishifamily/listen/index.html line 29, whose script assigns
198// au.src from a variable inside a function body; the extractor read the JavaScript that follows as a
199// RELATIVE ASSET REF and the page reported RED with law=1. Five live pages carried this one shape.
200// pv_in_tag cannot see it and is not wrong to miss it: JavaScript uses the less-than character as a
201// comparison operator, so inside a script the nearest preceding bracket genuinely IS an opener.
202// THE FIX IS HTML AGAIN, NEVER A KEYWORD LIST: script and style are RAW TEXT elements -- a browser
203// tokenizer does not look for attributes inside them at all -- so a position between such an open tag
204// and its matching close is not attribute context, whatever the surrounding bytes look like.
205// SCOPED TO THE BARE FORM ONLY, DELIBERATELY, AND THIS DIRECTION CANNOT LOSE A TRUE POSITIVE: a
206// QUOTED src assigned in a script IS a literal the browser really fetches and a relative one really
207// does break under the same edge rule, so narrowing those would lose real findings; JavaScript has no
208// UNQUOTED string literal, so a bare src= inside a script can never have been a real ref.
209// COST: one backward scan per bare candidate that ALREADY passed pv_in_tag -- that is, only on the
210// false positives this exists to remove. Bounded by page size (PV_CAP) times PV_MAXREF, both bounded.
211const PV_RAW_NONE: i64 = 0
212const PV_RAW_SCRIPT: i64 = 1
213const PV_RAW_STYLE: i64 = 2
214func pv_in_rawtext(page: *u8, at: i64) -> i64 {
215 var b: i64 = at
216 while b > 0 {
217 b = b - 1
218 if page[b] == (PV_ATTR_LT as u8) {
219 if sw_starts(page, b, "</script" as *u8) == 1 { return PV_RAW_NONE }
220 if sw_starts(page, b, "</style" as *u8) == 1 { return PV_RAW_NONE }
221 if sw_starts(page, b, "<script" as *u8) == 1 { return PV_RAW_SCRIPT }
222 if sw_starts(page, b, "<style" as *u8) == 1 { return PV_RAW_STYLE }
223 }
224 }
225 return PV_RAW_NONE
226}
227
228// origin = "https://host" prefix of url (through the 3rd slash, exclusive)
229func pv_origin(url: *u8, out: *u8) -> i64 {
230 var i: i64 = 0
231 var slashes: i64 = 0
232 while url[i] != (0 as u8) {
233 if url[i] == (47 as u8) {
234 slashes = slashes + 1
235 if slashes == 3 { out[i] = 0 as u8; return i }
236 }
237 out[i] = url[i]
238 i = i + 1
239 }
240 out[i] = 0 as u8
241 return i
242}
243
244// check one asset URL: fetch + validate. kind: 1=img-ish (png expected ok), 0=other. returns 0 ok / 1 broken
245// assets this run could not READ. Counted apart from `broken` because they are a different question with
246// a different remedy, and a reader who cannot tell them apart cannot audit either.
247static PV_UNOBS: i64
248// HEAD-RANGE VERIFICATION (2026-09-05). MEASURED on the live surface: /world/ref9d.nxa is 10,758,232 B
249// against PV_CAP 8,388,608, so the whole-body fetch returned -NX_FF_GET and the declared rig read
250// UNOBSERVABLE -- the seed-san.vrm class named in pv_check_asset, now hit by the FIRST asset the declared-asset
251// rule ever resolved. The proof a rig asset needs is its MAGIC, eight bytes at offset 0; reading ten megabytes
252// to check eight is the cap-as-a-guess defect wearing a verifier's clothes. So when the whole-body read does
253// not complete, the asset is re-fetched as a HEAD RANGE (bytes 0..PV_HEAD_CAP-1) through the fetch spine's own
254// range entry, and a head that carries a known magic is VERIFIED-BY-HEAD: counted apart from the whole-body
255// checks and apart from unobservable, because it answers a narrower question and a reader must see which.
256// A head that reads but carries no known magic stays UNOBSERVABLE (abstain -- a partial read may not convict),
257// and a head that cannot be read at all keeps the old UNOBSERVABLE line. The window is the fetch spine's own
258// padding unit (NX_MAGIC_65536, the smallest read it already sizes for), not a fresh number. MEASURED LIVE
259// 2026-09-05 on /world/rigview: the retry's TLS 1.3 handshake completed on the pinned edge and the GET stage
260// failed with NO status (head-range status=0 bytes=-4) -- the edge answered the Range request with the whole
261// 10 MB body and the spine's completing reader FAILS on overflow rather than handing back a prefix, so on
262// this edge the retry adds one honest measurement per asset and no verdict. It can never remove one: every
263// path out of the retry is the old UNOBSERVABLE line or a magic-carrying head. The verdict it was built for
264// needs an edge that honours Range (206 + Content-Range) or a bounded-prefix reader in the fetch spine.
265// The reader landed the same day (nx_https_fetch_head over nx_https_req_prefix, browser BR48) and this retry
266// composes it; the edge half is browser BR49, the traffic owner's, and lights the 206 branch when it lands.
267const PV_HEAD_CAP: i64 = 65536
268const PV_HTTP_PARTIAL: i64 = 206 // RFC 9110 Partial Content: the server honoured the Range
269const PV_HTTP_OK: i64 = 200 // a server that ignored the Range and answered whole; the spine bounds the body
270static PV_HEADVER: i64
271
272// NXA (Nishi Animated 3D) magic: the eight ASCII bytes NXANIM01, owned by nx_nxa.nx. Compared byte for byte here
273// so the verifier proves a declared rig asset is a rig and not the edge's error page, without forking a decoder.
274func pv_nxa_magic(b: *u8, n: i64) -> i64 {
275 if n < 8 { return 0 }
276 let m: *u8 = "NXANIM01" as *u8
277 var i: i64 = 0
278 while i < 8 { if b[i] != m[i] { return 0 } i = i + 1 }
279 return 1
280}
281
282func pv_check_asset(store: *TrustStore, aurl: *u8, body: *u8) -> i64 {
283 let st: *i64 = sys_mmap(8) as *i64
284 let n: i64 = nx_https_fetch_follow(aurl, store, body, PV_CAP, 6, st)
285 hw(" asset " as *u8); hw(aurl)
286 hw(" -> status=" as *u8); pn(st[0]); hw(" bytes=" as *u8); pn(n)
287 // A READ THAT NEVER COMPLETED IS NOT A BROKEN ASSET. A negative n is a fetch-STAGE code, not a body:
288 // the asset may serve perfectly and merely exceed PV_CAP. MEASURED 2026-08-26 -- seed-san.vrm is
289 // 10,917,800 B against a PV_CAP of 8,388,608 and came back n=-4, which this function spelled
290 // "BROKEN (non-200)", while an independent client fetching the same URL got 200 OK with the full
291 // Content-Length. This organ already carries the third state on the PAGE path (could not connect ->
292 // UNOBSERVABLE, never RED); it was never carried on the ASSET path, and the half of a law left undone
293 // is the half that ships. n >= 0 with a non-200 status is a REAL failure and still counts as broken --
294 // that is exactly how a 404 whose body we could read is caught.
295 if n < 0 {
296 // HEAD-RANGE RETRY (see PV_HEAD_CAP): the whole body did not arrive; ask for its head and let the magic decide.
297 let hst: *i64 = sys_mmap(8) as *i64
298 hst[0] = PV_NO_STATUS
299 let hn: i64 = nx_https_fetch_head(aurl, store, body, PV_HEAD_CAP, 0, PV_HEAD_CAP - 1, hst, 0)
300 hw(" head-range status=" as *u8); pn(hst[0]); hw(" bytes=" as *u8); pn(hn)
301 var hok: i64 = 0
302 if hst[0] == PV_HTTP_PARTIAL { hok = 1 }
303 if hst[0] == PV_HTTP_OK { hok = 1 }
304 if hn > 0 { if hok == 1 {
305 if pv_nxa_magic(body, hn) == 1 {
306 hw(" NXA MAGIC-OK VERIFIED-BY-HEAD (the whole body exceeds the read budget; the head carries the rig magic)\n" as *u8)
307 PV_HEADVER = PV_HEADVER + 1
308 return 0
309 }
310 hw(" head read but carries no known magic -- a partial read may not convict, so this stays UNOBSERVABLE\n" as *u8)
311 } }
312 hw(" UNOBSERVABLE (could not read this asset; fetch stage " as *u8); pn(0 - n)
313 hw(" -- it may exceed the read budget, so it is NOT counted as broken)\n" as *u8)
314 PV_UNOBS = PV_UNOBS + 1
315 return 0
316 }
317 if st[0] != 200 { hw(" BROKEN (non-200)\n" as *u8); return 1 }
318 if n <= 0 { hw(" BROKEN (empty body)\n" as *u8); return 1 }
319 // PNG? deep-decode (signature + IHDR + inflate + unfilter) -- the real proof
320 if n > 8 {
321 if body[0] == (137 as u8) {
322 if body[1] == (80 as u8) {
323 let res: *NxPngResult = nx_png_decode(body, n)
324 if (res as i64) == 0 { hw(" BROKEN (png decode null)\n" as *u8); return 1 }
325 if res.error_code != 0 { hw(" BROKEN (png decode err=" as *u8); pn(res.error_code); hw(")\n" as *u8); return 1 }
326 let hdr: *NxPngHeader = res.header
327 if hdr.width <= 0 { hw(" BROKEN (png w=0)\n" as *u8); return 1 }
328 hw(" PNG DECODE-OK " as *u8); pn(hdr.width); hw("x" as *u8); pn(hdr.height); hw("\n" as *u8)
329 return 0
330 }
331 }
332 // NXA (Nishi Animated 3D): a declared rig asset must open with the NXANIM01 magic (pv_nxa_magic above)
333 if pv_nxa_magic(body, n) == 1 { hw(" NXA MAGIC-OK bytes=" as *u8); pn(n); hw("\n" as *u8); return 0 }
334 // AN ARTIFACT THAT ANSWERS HTML IS THE 404-FALLBACK CLASS, and the status was 200. The decision
335 // moved into nx_pageref_lib so this organ and nx_pageref_gate read ONE table: the chain that used
336 // to live here knew four extensions -- png, jpg, css, js -- so a mesh, a VRM, a wasm module or a
337 // viewer blob that answered the edge's error page with status 200 read as OK, and those are
338 // precisely what an /exceed asset page is made of. The extension match is also exact to
339 // end-of-url now, where the old chain accepted any suffix beginning at the dot.
340 if pr_is_fallback(aurl, body, n) == 1 {
341 hw(" BROKEN (artifact answers HTML -- 404-fallback class, extension class " as *u8)
342 pn(pr_ext_class(aurl))
343 hw(")\n" as *u8)
344 return 1
345 }
346 }
347 hw(" OK\n" as *u8)
348 return 0
349}
350
351// a11y-lite: integer substring presence + count over the page (axe-core / Lighthouse-class checks, NO float)
352func pv_has(b: *u8, n: i64, lit: *u8) -> i64 {
353 var i: i64 = 0
354 while i < n { if sw_starts(b, i, lit) == 1 { return 1 } i = i + 1 }
355 return 0
356}
357func pv_count(b: *u8, n: i64, lit: *u8) -> i64 {
358 var c: i64 = 0
359 var i: i64 = 0
360 while i < n { if sw_starts(b, i, lit) == 1 { c = c + 1 } i = i + 1 }
361 return c
362}
363
364// heading-level skip detector (axe/Lighthouse structural rule: no downward jump >1, e.g. h1->h3) -- integer scan
365func pv_hskip(b: *u8, n: i64) -> i64 {
366 var prev: i64 = 0
367 var skips: i64 = 0
368 var i: i64 = 0
369 while i < n - 3 {
370 if b[i] == (60 as u8) { if b[i+1] == (104 as u8) {
371 let d: i64 = b[i+2] as i64
372 if d >= 49 { if d <= 54 {
373 let lvl: i64 = d - 48
374 if prev > 0 { if lvl > prev + 1 { skips = skips + 1 } }
375 prev = lvl
376 } }
377 } }
378 i = i + 1
379 }
380 return skips
381}
382
383// does s start with pfx? returns the offset just past pfx, or -1. Lets the optional
384// args be recognised by NAME in any position, so adding them cannot disturb the existing
385// positional [connect-host:port] callers (rule 19: adding is safe, reordering is not).
386func pv_pfx(s: *u8, pfx: *u8) -> i64 {
387 var i: i64 = 0
388 while pfx[i] != (0 as u8) {
389 if s[i] != pfx[i] { return 0 - 1 }
390 i = i + 1
391 }
392 return i
393}
394// ============================================================================================
395// AUTO CONNECT-OVERRIDE -- RECOVERED 2026-07-25 (debt seq1008 / frontier F1144).
396// The DEPLOYED nx_page_verify.elf implemented this; NO SOURCE IN THE TREE DID. It was built
397// ~2026-07-20, deployed and documented, and its source was lost, so the ordinary /api/build +
398// /api/promote loop would have SILENTLY DELETED it -- turning every our-domain verification back
399// into a :443 coin flip against the co-squatting DSM nginx. That failure mode already manufactured
400// one false sev-7 debt (seq984, retracted). Reimplemented here from the contract documented in the
401// registry header so the binary is reproducible from source again.
402// CONTRACT: rows are <host><TAB><a.b.c.d:port>, '#' comments skipped, an explicit argv[2] override
403// ALWAYS wins, and an absent registry is FAIL-SAFE (verification still runs) -- but never silently:
404// see the vantage line in main(), which is now unconditional.
405const PV_DOMCONF: *u8 = "knowledge/registry/our_domains.conf"
406const PV_DOMCAP: i64 = 65536
407const PV_EP_CAP: i64 = 256
408
409// host of "https://HOST[:port]/path" -> out. 1 ok, 0 if not an https url.
410func pv_host(url: *u8, out: *u8, cap: i64) -> i64 {
411 if sw_starts(url, 0, "https://" as *u8) != 1 { return 0 }
412 var i: i64 = 8
413 var o: i64 = 0
414 var go: i64 = 1
415 while go == 1 {
416 let c: i64 = url[i] as i64
417 if c == 0 { go = 0 }
418 else {
419 if c == 47 { go = 0 }
420 else {
421 if c == 58 { go = 0 }
422 else {
423 if o < (cap - 1) { out[o] = url[i]; o = o + 1 }
424 i = i + 1
425 }
426 }
427 }
428 }
429 out[o] = 0 as u8
430 if o == 0 { return 0 }
431 return 1
432}
433
434// 1 = hit (ep filled) | 0 = not one of ours | -1 = registry unreadable (caller must SAY SO)
435func pv_dom_lookup(host: *u8, ep: *u8, epcap: i64) -> i64 {
436 let fd: i64 = sys_openat_rd(PV_DOMCONF)
437 if fd < 0 { return 0 - 1 }
438 let buf: *u8 = sys_mmap(PV_DOMCAP)
439 var total: i64 = 0
440 var go: i64 = 1
441 while go == 1 {
442 if total >= PV_DOMCAP { go = 0 }
443 else {
444 let n: i64 = sys_read(fd, (buf as i64 + total) as *u8, PV_DOMCAP - total)
445 if n > 0 { total = total + n } else { go = 0 }
446 }
447 }
448 sys_close(fd)
449 var hl: i64 = 0
450 while host[hl] != (0 as u8) { hl = hl + 1 }
451 var found: i64 = 0
452 var ls: i64 = 0
453 var i: i64 = 0
454 while i <= total {
455 var nl: i64 = 0
456 if i >= total { nl = 1 } else { if buf[i] == (10 as u8) { nl = 1 } }
457 if nl == 1 {
458 if found == 0 {
459 let len: i64 = i - ls
460 if len > 0 {
461 if buf[ls] != (35 as u8) {
462 var t: i64 = ls
463 var tab: i64 = 0 - 1
464 while t < i { if buf[t] == (9 as u8) { if tab < 0 { tab = t } } t = t + 1 }
465 if tab > 0 {
466 if (tab - ls) == hl {
467 var k: i64 = 0
468 var same: i64 = 1
469 while k < hl { if buf[ls + k] != host[k] { same = 0 } k = k + 1 }
470 if same == 1 {
471 var o: i64 = 0
472 var p: i64 = tab + 1
473 while p < i {
474 if buf[p] != (13 as u8) { if o < (epcap - 1) { ep[o] = buf[p]; o = o + 1 } }
475 p = p + 1
476 }
477 ep[o] = 0 as u8
478 found = 1
479 }
480 }
481 }
482 }
483 }
484 }
485 ls = i + 1
486 }
487 i = i + 1
488 }
489 return found
490}
491
492func pv_atoi(a: *u8) -> i64 {
493 var v: i64 = 0
494 var i: i64 = 0
495 while a[i] != (0 as u8) {
496 let c: i64 = a[i] as i64
497 if c >= 48 { if c <= 57 { v = v * 10 + (c - 48) } }
498 i = i + 1
499 }
500 return v
501}
502
503
504const PV_CONTRACT_OK: i64 = 0
505const PV_CONTRACT_RED: i64 = 1
506const PV_CONTRACT_USAGE: i64 = 2
507const PV_CONTRACT_HEX_BYTES: i64 = 32
508const PV_CONTRACT_HEX_CHARS: i64 = 64
509const PV_CONTRACT_PATH_CAP: i64 = 4096
510const PV_CONTRACT_EVIDENCE_CAP: i64 = 262144
511const PV_CONTRACT_DEFAULT_MAX_AGE: i64 = 900
512
513func pv_contract_hex(c: i64) -> i64 {
514 if c >= 48 { if c <= 57 { return c - 48 } }
515 if c >= 65 { if c <= 70 { return c - 55 } }
516 if c >= 97 { if c <= 102 { return c - 87 } }
517 return 0 - 1
518}
519func pv_contract_copy(dst: *u8, cap: i64, src: *u8, off: i64) -> i64 {
520 var i: i64 = 0
521 while src[off+i] != (0 as u8) {
522 if i >= cap - 1 { return 0 - 1 }
523 dst[i] = src[off+i]
524 i = i + 1
525 }
526 dst[i] = 0 as u8
527 return i
528}
529func pv_contract_hex_equal(text: *u8, digest: *u8) -> i64 {
530 var i: i64 = 0
531 while i < PV_CONTRACT_HEX_BYTES {
532 let bv: i64 = digest[i] as i64
533 let hi: i64 = (bv >> 4) & 15
534 let lo: i64 = bv & 15
535 var hc: i64 = 48 + hi
536 if hi >= 10 { hc = 87 + hi }
537 var lc: i64 = 48 + lo
538 if lo >= 10 { lc = 87 + lo }
539 if text[i*2] as i64 != hc { return 0 }
540 if text[i*2+1] as i64 != lc { return 0 }
541 i = i + 1
542 }
543 if text[PV_CONTRACT_HEX_CHARS] != (0 as u8) { return 0 }
544 return 1
545}
546func pv_contract_has(buf: *u8, n: i64, lit: *u8) -> i64 {
547 var q: i64 = 0
548 var m: i64 = 0
549 while lit[m] != (0 as u8) { m = m + 1 }
550 if m == 0 { return 1 }
551 while q + m <= n {
552 var j: i64 = 0
553 var same: i64 = 1
554 while j < m { if buf[q+j] != lit[j] { same = 0; j = m } else { j = j + 1 } }
555 if same == 1 { return 1 }
556 q = q + 1
557 }
558 return 0
559}
560func pv_contract_verify(url: *u8, page: *u8, page_n: i64, artifact: *u8, evidence_path: *u8, evidence_sha: *u8, interaction: *u8, runtime: *u8, observed: *u8, max_age: i64) -> i64 {
561 if (artifact as i64) == 0 { hw("served-review RED reason=missing-artifact-identity\n" as *u8); return PV_CONTRACT_RED }
562 if (evidence_path as i64) == 0 { hw("served-review RED reason=missing-evidence-path\n" as *u8); return PV_CONTRACT_RED }
563 if (evidence_sha as i64) == 0 { hw("served-review RED reason=missing-evidence-identity\n" as *u8); return PV_CONTRACT_RED }
564 if (interaction as i64) == 0 { hw("served-review RED reason=missing-interaction-assertion\n" as *u8); return PV_CONTRACT_RED }
565 if (runtime as i64) == 0 { hw("served-review RED reason=missing-runtime-backend\n" as *u8); return PV_CONTRACT_RED }
566 let digest: *u8 = sys_mmap(PV_CONTRACT_HEX_BYTES)
567 if sha256_digest(page, page_n, digest) != 0 { hw("served-review RED reason=artifact-hash-failed\n" as *u8); return PV_CONTRACT_RED }
568 if pv_contract_hex_equal(artifact, digest) == 0 {
569 hw("served-review RED reason=artifact-hash-mismatch actual_sha256=" as *u8)
570 var hx: i64 = 0
571 while hx < PV_CONTRACT_HEX_BYTES {
572 let bv: i64 = digest[hx] as i64
573 let hi: i64 = (bv >> 4) & 15
574 let lo: i64 = bv & 15
575 let hc: *u8 = sys_mmap(2)
576 if hi < 10 { hc[0] = (48 + hi) as u8 } else { hc[0] = (87 + hi) as u8 }
577 if lo < 10 { hc[1] = (48 + lo) as u8 } else { hc[1] = (87 + lo) as u8 }
578 sys_write(1, hc, 2)
579 hx = hx + 1
580 }
581 hw("\n" as *u8)
582 return PV_CONTRACT_RED
583 }
584 let ep_len: *i64 = sys_mmap(8) as *i64
585 let ev: *u8 = sys_read_file(evidence_path, ep_len)
586 if (ev as i64) == 0 { hw("served-review RED reason=evidence-missing\n" as *u8); return PV_CONTRACT_RED }
587 if ep_len[0] <= 0 { hw("served-review RED reason=evidence-empty\n" as *u8); sys_free_file(ev, ep_len[0]); return PV_CONTRACT_RED }
588 let edigest: *u8 = sys_mmap(PV_CONTRACT_HEX_BYTES)
589 if sha256_digest(ev, ep_len[0], edigest) != 0 { hw("served-review RED reason=evidence-hash-failed\n" as *u8); sys_free_file(ev, ep_len[0]); return PV_CONTRACT_RED }
590 if pv_contract_hex_equal(evidence_sha, edigest) == 0 { hw("served-review RED reason=evidence-hash-mismatch\n" as *u8); sys_free_file(ev, ep_len[0]); return PV_CONTRACT_RED }
591 if pv_contract_has(ev, ep_len[0], "interaction=PASS\n" as *u8) == 0 { hw("served-review RED reason=interaction-evidence-missing-or-failed\n" as *u8); sys_free_file(ev, ep_len[0]); return PV_CONTRACT_RED }
592 if pv_contract_has(ev, ep_len[0], "screenshot=" as *u8) == 0 { hw("served-review RED reason=screenshot-evidence-missing\n" as *u8); sys_free_file(ev, ep_len[0]); return PV_CONTRACT_RED }
593 if pv_contract_has(ev, ep_len[0], "backend=" as *u8) == 0 { hw("served-review RED reason=backend-evidence-missing\n" as *u8); sys_free_file(ev, ep_len[0]); return PV_CONTRACT_RED }
594 if pv_contract_has(ev, ep_len[0], "observed_epoch=" as *u8) == 0 { hw("served-review RED reason=observation-time-missing\n" as *u8); sys_free_file(ev, ep_len[0]); return PV_CONTRACT_RED }
595 if pv_contract_has(ev, ep_len[0], interaction) == 0 { hw("served-review RED reason=interaction-assertion-not-in-evidence\n" as *u8); sys_free_file(ev, ep_len[0]); return PV_CONTRACT_RED }
596 if pv_contract_has(ev, ep_len[0], runtime) == 0 { hw("served-review RED reason=runtime-backend-assertion-not-in-evidence\n" as *u8); sys_free_file(ev, ep_len[0]); return PV_CONTRACT_RED }
597 let seen: i64 = pv_atoi(observed)
598 if seen <= 0 { hw("served-review RED reason=invalid-observation-time\n" as *u8); sys_free_file(ev, ep_len[0]); return PV_CONTRACT_RED }
599 let now: i64 = sys_now_realtime_sec()
600 if now < seen { hw("served-review RED reason=observation-in-future\n" as *u8); sys_free_file(ev, ep_len[0]); return PV_CONTRACT_RED }
601 let age: i64 = now - seen
602 if age > max_age { hw("served-review RED reason=stale-evidence age=" as *u8); pn(age); hw("\n" as *u8); sys_free_file(ev, ep_len[0]); return PV_CONTRACT_RED }
603 hw("served-review GREEN url=" as *u8); hw(url)
604 hw(" status=200 artifact_verified=1 interaction_verified=1 screenshot_verified=1 runtime=" as *u8); hw(runtime)
605 hw(" observed_epoch=" as *u8); hw(observed); hw(" evidence=" as *u8); hw(evidence_path); hw(" age=" as *u8); pn(age); hw("\n" as *u8)
606 sys_free_file(ev, ep_len[0])
607 return PV_CONTRACT_OK
608}
609
610func main(argc: i64, argv: *i64) -> i64 {
611 if argc < 2 { hw("usage: nx_page_verify <https-url> [connect-host:port] [expect=<substring>] [minbytes=<n>]\n" as *u8); sys_exit(PV_EXIT_USAGE); return PV_EXIT_USAGE }
612 let url: *u8 = argv[1] as *u8
613 var contract_mode: i64 = 0
614 let contract_artifact: *u8 = sys_mmap(96)
615 let contract_evidence: *u8 = sys_mmap(PV_CONTRACT_PATH_CAP)
616 let contract_evidence_sha: *u8 = sys_mmap(96)
617 let contract_interaction: *u8 = sys_mmap(96)
618 let contract_runtime: *u8 = sys_mmap(96)
619 let contract_observed: *u8 = sys_mmap(96)
620 var contract_max_age: i64 = PV_CONTRACT_DEFAULT_MAX_AGE
621 hw("=== nx_page_verify -- static HTTP asset checks (no browser execution) for " as *u8); hw(url); hw(" ===\n" as *u8)
622 var expoff: i64 = 0
623 var minbytes: i64 = 0
624 var ov_given: i64 = 0
625 // the vantage this run actually used, carried to the LAST line so a reader of the verdict alone
626 // can tell which server was (or was not) reached -- "RED from :443" and "RED from :8443" are
627 // different facts, and an UNOBSERVABLE is meaningless without the endpoint it failed to reach
628 let vant: *u8 = sys_mmap(PV_VANTAGE_CAP)
629 var vo: i64 = 0
630 var ai: i64 = 2
631 while ai < argc {
632 let a: *u8 = argv[ai] as *u8
633 let co: i64 = pv_pfx(a, "contract" as *u8)
634 if co >= 0 {
635 contract_mode = 1
636 } else {
637 let ao: i64 = pv_pfx(a, "artifact=" as *u8)
638 let ep: i64 = pv_pfx(a, "evidence=" as *u8)
639 let es: i64 = pv_pfx(a, "evidence_sha256=" as *u8)
640 let io: i64 = pv_pfx(a, "interaction=" as *u8)
641 let ro: i64 = pv_pfx(a, "runtime=" as *u8)
642 let ob: i64 = pv_pfx(a, "observed_epoch=" as *u8)
643 let ma: i64 = pv_pfx(a, "max_age=" as *u8)
644 let eo: i64 = pv_pfx(a, "expect=" as *u8)
645 let mo: i64 = pv_pfx(a, "minbytes=" as *u8)
646 if ao >= 0 { pv_contract_copy(contract_artifact, 96, a, ao) }
647 else {
648 if ep >= 0 { pv_contract_copy(contract_evidence, PV_CONTRACT_PATH_CAP, a, ep) }
649 else {
650 if es >= 0 { pv_contract_copy(contract_evidence_sha, 96, a, es) }
651 else {
652 if io >= 0 { pv_contract_copy(contract_interaction, 96, a, io) }
653 else {
654 if ro >= 0 { pv_contract_copy(contract_runtime, 96, a, ro) }
655 else {
656 if ob >= 0 { pv_contract_copy(contract_observed, 96, a, ob) }
657 else {
658 if ma >= 0 { contract_max_age = pv_atoi(((a as i64) + ma) as *u8) }
659 else {
660 if eo >= 0 { expoff = (a as i64) + eo }
661 else {
662 if mo >= 0 { minbytes = pv_atoi(((a as i64) + mo) as *u8) }
663 else {
664 if nx_https_connect_override_set(a) != 1 { hw("RED bad connect-override (want a.b.c.d:port)\n" as *u8); sys_exit(PV_EXIT_USAGE); return PV_EXIT_USAGE }
665 hw("vantage=EXPLICIT connect-override " as *u8); hw(a); hw(" (SNI/Host stay the URL host)\n" as *u8)
666 ov_given = 1
667 vo = pv_vcat(vant, 0, "pinned:" as *u8)
668 vo = pv_vcat(vant, vo, a)
669 }
670 }
671 }
672 }
673 }
674 }
675 }
676 }
677 }
678 }
679 ai = ai + 1
680 }
681
682 // ---- VANTAGE RESOLUTION (recovered + hardened 2026-07-25; seq1008 recovery, seq990 hardening) ----
683 // The whole point: this organ must NEVER be able to grade one server while the reader believes it
684 // graded another. So the vantage is now stated on EVERY run -- there is no silent path.
685 let pv_h: *u8 = sys_mmap(PV_URL_CAP)
686 pv_h[0] = 0 as u8
687 var pv_isours: i64 = 0
688 var pv_regunread: i64 = 0
689 var pv_pinned: i64 = ov_given
690 if pv_host(url, pv_h, PV_URL_CAP) == 1 {
691 let pv_ep: *u8 = sys_mmap(PV_EP_CAP)
692 let d: i64 = pv_dom_lookup(pv_h, pv_ep, PV_EP_CAP)
693 if d == 1 { pv_isours = 1 }
694 if ov_given == 0 {
695 if d == 1 {
696 if nx_https_connect_override_set(pv_ep) != 1 {
697 hw("VERDICT=UNMEASURED (our-domain " as *u8); hw(pv_h)
698 hw(" but its registry endpoint " as *u8); hw(pv_ep)
699 hw(" is malformed -- refusing to grade an unknown server)\n" as *u8)
700 sys_exit(PV_EXIT_UNMEASURED); return PV_EXIT_UNMEASURED
701 }
702 hw("auto connect-override (our-domain " as *u8); hw(pv_h)
703 hw(" -> " as *u8); hw(pv_ep); hw("; SNI/Host stay the URL host)\n" as *u8)
704 pv_pinned = 1
705 vo = pv_vcat(vant, 0, "pinned:" as *u8)
706 vo = pv_vcat(vant, vo, pv_ep)
707 }
708 if d == (0 - 1) {
709 hw("WARNING registry " as *u8); hw(PV_DOMCONF)
710 hw(" unreadable -- cannot tell if this host is ours; proceeding via DNS (fail-safe)\n" as *u8)
711 pv_regunread = 1
712 }
713 }
714 }
715 if pv_pinned == 1 { hw("vantage=PINNED (deterministic sovereign edge)\n" as *u8) }
716 else {
717 hw("vantage=DNS (no override)" as *u8)
718 vo = pv_vcat(vant, 0, "dns:" as *u8)
719 vo = pv_vcat(vant, vo, pv_h)
720 if pv_regunread == 1 { vo = pv_vcat(vant, vo, ",registry-unreadable-from-cwd" as *u8) }
721 if pv_isours == 1 {
722 // Cannot happen once the registry is readable, but if it ever does, the reader is told
723 // LOUDLY rather than handed a confident RED from whatever answered port 443.
724 hw(" <== WARNING: this IS one of our domains and it is NOT pinned. A 404/RED here may be\n" as *u8)
725 hw(" the co-squatting server on :443, not our edge. TREAT AS UNMEASURED." as *u8)
726 }
727 hw("\n" as *u8)
728 }
729
730 let r: i64 = nx_trust_store_load_from_certdata("data/mozilla_certdata.txt" as *u8, 512, PV_CERTDATA_CAP)
731 if r <= 0 {
732 // the eye has no trust store -> it cannot fetch anything -> it has NO EVIDENCE about the page.
733 // This was already exit 3; it now says so in the fleet's own word, on the last line.
734 hw("cannot load trust store (run from repo root)\n" as *u8)
735 hw("VERDICT=UNOBSERVABLE vantage=" as *u8); hw(vant); hw(" reason=no-trust-store\n" as *u8)
736 sys_exit(PV_EXIT_UNOBSERVABLE); return PV_EXIT_UNOBSERVABLE
737 }
738 let store: *TrustStore = r as *TrustStore
739
740 let page: *u8 = sys_mmap(PV_CAP)
741 let st: *i64 = sys_mmap(8) as *i64
742 st[0] = PV_NO_STATUS
743 let n: i64 = nx_https_fetch_follow(url, store, page, PV_CAP, 6, st)
744 hw("page status=" as *u8); pn(st[0]); hw(" bytes=" as *u8); pn(n)
745 if n < 0 { hw(" fetch-stage=" as *u8); hw(pv_stage_name(n)) }
746 hw("\n" as *u8)
747 // THE THIRD STATE. No status AND a negative length = no server ever answered. That is a
748 // fact about the VANTAGE (closed port, black-holed host, DNS landing on the wrong edge, a CWD
749 // that lost the registry), not about the page. It must not be spelled RED.
750 if pv_unobservable(n, st[0]) == 1 {
751 hw("VERDICT=UNOBSERVABLE vantage=" as *u8); hw(vant)
752 hw(" reason=no-connection(" as *u8); hw(pv_stage_name(n)); hw(")\n" as *u8)
753 sys_exit(PV_EXIT_UNOBSERVABLE); return PV_EXIT_UNOBSERVABLE
754 }
755 if st[0] != 200 { hw("VERDICT=RED (page not 200)\n" as *u8); sys_exit(PV_EXIT_RED); return PV_EXIT_RED }
756 if n <= 0 { hw("VERDICT=RED (empty page)\n" as *u8); sys_exit(PV_EXIT_RED); return PV_EXIT_RED }
757 if contract_mode == 1 {
758 if contract_max_age <= 0 { hw("served-review RED reason=invalid-max-age\n" as *u8); sys_exit(PV_CONTRACT_USAGE); return PV_CONTRACT_USAGE }
759 let crc: i64 = pv_contract_verify(url, page, n, contract_artifact, contract_evidence, contract_evidence_sha, contract_interaction, contract_runtime, contract_observed, contract_max_age)
760 sys_exit(crc)
761 return crc
762 }
763
764 // CONTENT ASSERTION (debt seq911). A 200 DOES NOT MEAN YOUR PAGE. The edge serves a
765 // root fallback for unknown paths, so a failed publish yields 200 with a perfectly
766 // valid, fully-decoding page that simply is not yours -- and every asset on it fetches,
767 // so the old asset-only verdict said GREEN. Measured 2026-07-25: verifying
768 // /research/rt004.html reported status=200 VERDICT=GREEN while the edge was serving the
769 // 835-byte site root and the 10201-byte page had landed nowhere. Asset liveness is not
770 // page identity; the caller must be able to assert WHICH page it expects.
771 if minbytes > 0 {
772 if n < minbytes {
773 hw("VERDICT=RED (page is " as *u8); pn(n)
774 hw(" bytes, below the asserted floor of " as *u8); pn(minbytes)
775 hw(" -- a 200 is not your page)\n" as *u8)
776 sys_exit(PV_EXIT_RED); return PV_EXIT_RED
777 }
778 hw("byte-floor OK (" as *u8); pn(n); hw(" >= " as *u8); pn(minbytes); hw(")\n" as *u8)
779 }
780 if expoff != 0 {
781 if pv_has(page, n, expoff as *u8) == 0 {
782 hw("VERDICT=RED (expected content ABSENT: " as *u8); hw(expoff as *u8)
783 hw(") -- the server returned 200 but this is not the page you published\n" as *u8)
784 sys_exit(PV_EXIT_RED); return PV_EXIT_RED
785 }
786 hw("content-assert OK (expect=" as *u8); hw(expoff as *u8); hw(")\n" as *u8)
787 }
788
789 let origin: *u8 = sys_mmap(PV_URL_CAP)
790 pv_origin(url, origin)
791
792 // --- a11y-lite audit (integer, no float): axe-core / Lighthouse-class page checks ---
793 hw("-- a11y-lite --\n" as *u8)
794 var a11y: i64 = 0
795 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 }
796 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 }
797 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 }
798 // ELEMENT-SCOPED SINCE 2026-08-26, AND THAT IS THE WHOLE POINT. These two lines used to be
799 // pv_count(page, n, "<img") and pv_count(page, n, " alt=") -- two whole-page SUBSTRING counts.
800 // A SUBSTRING COUNTER CANNOT SEE ATTRIBUTE SCOPE. Measured 2026-08-26 it read img=15 with-alt=15,
801 // a clean bill of health, for /compare/koikatsu, whose first figure served
802 // <img src='...' alt='The card's own portrait -- the oracle we match against' loading='lazy'>
803 // The caption's raw apostrophe ends alt at the two words -The card-, turns the rest of the sentence
804 // into attribute names and swallows loading='lazy'. Every byte the old rule looked for was present,
805 // so it counted a DESTROYED alt as a good one and the page validated GREEN for as long as the row
806 // had existed.
807 // ia_scan walks each img tag with the quoting rules a browser uses, and it is the SAME lib the
808 // compare generator now emits through -- the writer and the reader share one definition and cannot
809 // drift into two answers. It also skips comment, script and style bodies, so an img quoted inside
810 // inline JavaScript is no longer counted as an element; that makes the COVERAGE-GAP comparison
811 // below sharper too, because nimg is now a count of real elements rather than of a 4-byte pattern.
812 let iasl: *i64 = sys_mmap(IA_SCAN_SLOTS * IA_SLOT_BYTES) as *i64
813 ia_scan(page, n, iasl)
814 let nimg: i64 = iasl[IA_S_IMGS]
815 let nalt: i64 = iasl[IA_S_ALT_OK]
816 hw(" img=" as *u8); pn(nimg); hw(" with-alt=" as *u8); pn(nalt); hw("\n" as *u8)
817 if nalt < nimg { hw(" A11Y " as *u8); pn(nimg - nalt); hw(" image(s) missing alt\n" as *u8); a11y = a11y + 1 }
818 // ITS OWN AXIS, not folded into missing-alt: the alt is PRESENT here and merely truncated, so the
819 // remedy is the emitter's escaping and not a missing attribute. One counter for two causes is how a
820 // worklist stops pointing at the repair.
821 if iasl[IA_S_QUOTEBREAK] > 0 {
822 hw(" A11Y " as *u8); pn(iasl[IA_S_QUOTEBREAK])
823 hw(" img tag(s) whose own data escaped its attribute -- an unescaped quote ends the value early, so the alt a browser reads is a TRUNCATED prefix of the intended one\n" as *u8)
824 a11y = a11y + 1
825 }
826 if iasl[IA_S_MALFORMED] > 0 {
827 hw(" A11Y " as *u8); pn(iasl[IA_S_MALFORMED])
828 hw(" img tag(s) whose tag or attribute value never closed\n" as *u8)
829 a11y = a11y + 1
830 }
831 let nh1: i64 = pv_count(page, n, "<h1" as *u8)
832 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 }
833 let hsk: i64 = pv_hskip(page, n)
834 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 }
835 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 }
836 hw(" a11y-issues=" as *u8); pn(a11y); hw("\n" as *u8)
837
838 // extract src="..." / href="..." refs (img/script/link surface)
839 let abuf: *u8 = sys_mmap(PV_CAP)
840 let prout: *i64 = sys_mmap(PV_PROUT_SLOTS * PV_WORD_BYTES) as *i64
841 var broken: i64 = 0
842 var checked: i64 = 0
843 var skipped: i64 = 0
844 var lawred: i64 = 0
845 var declared: i64 = 0 // assets the page DECLARES its script will fetch (meta name=nishi-<kind> content=...; pr_declared_hit, 2026-09-05)
846 // bare src= occurrences REJECTED as not-inside-a-tag (inline script, almost always). Printed on
847 // the summary line so the new filter's effect on real pages is measurable rather than assumed.
848 var barerej: i64 = 0
849 // bare src= occurrences REJECTED as INSIDE script/style RAW TEXT (pv_in_rawtext above). Counted
850 // and printed SEPARATELY from barerej, because two rejection REASONS with opposite remedies must
851 // never share one counter -- a reader who cannot tell them apart cannot audit either.
852 var rawrej: i64 = 0
853 var i: i64 = 0
854 while i < n - 8 {
855 var hit: i64 = 0
856 // BOTH QUOTE STYLES (2026-08-18). This scanner recognised only src=" -- so a generator emitting
857 // src='...' (the whole compare gallery, 15 relative images that 404'd in every browser) was
858 // INVISIBLE to it: not checked, not skipped, not law-red -- and the verdict still said "every
859 // referenced asset fetches". A REF THE EXTRACTOR CANNOT SEE IS A REF THE VERDICT SILENTLY
860 // ACQUITS. The closing delimiter is whichever quote opened the attribute.
861 var bare: i64 = 0
862 var qch: i64 = 34
863 // IN-TAG GUARD ON EVERY ATTRIBUTE BRANCH (2026-08-25). pv_in_tag was added for the BARE branch
864 // and not its siblings -- the same half-a-fix shape one level down. MEASURED: the first fleet
865 // sweep reported 245 broken refs of which 216 were /code/ pages, and those pages carry NO <pre>
866 // at all (count=0) -- each line is a <span class='l'>, and the hits are the literal text src=
867 // inside RENDERED STRING LITERALS, e.g. gf_puts(" verdict=LIB src=" as *u8). Those sit in TEXT
868 // BETWEEN tags, so the nearest preceding bracket is '>' and pv_in_tag already rejects them.
869 // A real <img src="..."> has '<' as its nearest preceding bracket and is unaffected.
870 // ONE VOCABULARY OWNER (nx_pageref_lib, shared with nx_pageref_gate). This was two hand-written
871 // branches that knew only src=. The table now also carries data-glb=, the attribute nx_asset_page
872 // emits for every mesh panel on an /exceed page and the one this extractor had never heard of --
873 // so four mesh refs per page were acquitted without ever being fetched (measured on the live
874 // /exceed/vrm/seed-san: checked=2 against four data-glb canvases). Behaviour on src= is unchanged
875 // BY CONSTRUCTION: the skip is still the attribute length plus its quote, and the closing
876 // delimiter is still whichever quote opened the attribute.
877 if pr_attr_hit(page, n, i, prout) >= 0 { if pv_in_tag(page, i) == 1 { hit = prout[0]; qch = prout[1] } }
878 // DECLARED ASSETS (2026-09-05): a meta row named nishi-<kind> with a content path promises a script-fetched
879 // artifact (rigview declares its 1.7 MB rig this way and used to be acquitted on one advert PNG); followed like a src
880 if hit == 0 { if pr_declared_hit(page, n, i, prout) >= 0 { if pv_in_tag(page, i) == 1 { hit = prout[0]; qch = prout[1]; declared = declared + 1 } } }
881 // BARE (UNQUOTED) src= -- legal HTML, and our own sites/nishifamily/world/foundation.html emits
882 // <img src=nx_worldpipe.png ...>. Checked ONLY after both quoted forms miss, and only when the
883 // next byte is not a quote / space / '>', so an empty or quoted value can never land here.
884 // The terminator is whitespace or '>', handled in the extraction below.
885 if hit == 0 { if i + 4 < n { if sw_starts(page, i, "src=" as *u8) == 1 {
886 let c0: i64 = page[i+4] as i64
887 if c0 != PV_ATTR_DQ { if c0 != PV_ATTR_SQ { if c0 != PV_ATTR_SP { if c0 != PV_ATTR_GT {
888 // INSIDE AN OPEN TAG OR IT IS NOT AN ATTRIBUTE (2026-08-25, see pv_in_tag above).
889 // Counted, not silently dropped: a filter whose rejections are invisible cannot be
890 // audited, and this one is new enough to deserve being watched on real pages.
891 if pv_in_tag(page, i) == 1 {
892 // IN A TAG AND NOT IN RAW TEXT. Both conjuncts are required and each is counted
893 // under its own name, so a future reader can see WHICH rule fired on real pages.
894 if pv_in_rawtext(page, i) == PV_RAW_NONE { hit = 4; bare = 1 } else { rawrej = rawrej + 1 }
895 } else { barerej = barerej + 1 }
896 } } } }
897 } } }
898 if hit == 0 { if sw_starts(page, i, "href='" as *u8) == 1 {
899 var b1: i64 = i
900 var found1: i64 = 0
901 var back1: i64 = 0
902 while back1 < 80 {
903 if b1 <= 0 { back1 = 80 } else {
904 if page[b1] == (60 as u8) {
905 if sw_starts(page, b1, "<link" as *u8) == 1 { found1 = 1 }
906 back1 = 80
907 } else { b1 = b1 - 1; back1 = back1 + 1 }
908 }
909 }
910 if found1 == 1 { hit = 6; qch = 39 }
911 } }
912 if hit == 0 { if sw_starts(page, i, "href=\"" as *u8) == 1 {
913 // href only counts for <link ...> stylesheet-ish tags: look back for '<link' within 80 bytes
914 var b: i64 = i
915 var found: i64 = 0
916 var back: i64 = 0
917 while back < 80 {
918 if b <= 0 { back = 80 } else {
919 if page[b] == (60 as u8) {
920 if sw_starts(page, b, "<link" as *u8) == 1 { found = 1 }
921 back = 80
922 } else { b = b - 1; back = back + 1 }
923 }
924 }
925 if found == 1 { hit = 6 }
926 } }
927 if hit > 0 {
928 let rs: i64 = i + hit
929 var re: i64 = rs
930 if bare == 0 {
931 while page[re] != (qch as u8) { re = re + 1 }
932 } else {
933 // Unquoted value ends at the first whitespace or '>'. Bounded by n so a malformed tag
934 // cannot run the scan off the end of the buffer.
935 var stop: i64 = 0
936 while stop == 0 {
937 if re >= n { stop = 1 } else {
938 let ce: i64 = page[re] as i64
939 if ce == PV_ATTR_SP { stop = 1 } else {
940 if ce == PV_ATTR_GT { stop = 1 } else {
941 if ce == PV_ATTR_TAB { stop = 1 } else {
942 if ce == PV_ATTR_LF { stop = 1 } else {
943 if ce == PV_ATTR_CR { stop = 1 } else { re = re + 1 } } } } }
944 }
945 }
946 }
947 let rlen: i64 = re - rs
948 if rlen > 0 { if rlen < PV_REF_MAX { if checked + skipped + lawred < PV_MAXREF {
949 let ref: *u8 = sys_mmap(PV_URL_CAP)
950 var k: i64 = 0
951 while k < rlen { ref[k] = page[rs+k]; k = k + 1 }
952 ref[rlen] = 0 as u8
953 if sw_starts(ref, 0, "data:" as *u8) == 1 { skipped = skipped + 1 } else {
954 if sw_starts(ref, 0, "http" as *u8) == 1 {
955 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 }
956 } else {
957 if ref[0] == (47 as u8) {
958 pv_normpath(ref)
959 let full: *u8 = sys_mmap(PV_FULLURL_CAP)
960 var o: i64 = 0
961 while origin[o] != (0 as u8) { full[o] = origin[o]; o = o + 1 }
962 var q: i64 = 0
963 while ref[q] != (0 as u8) { full[o+q] = ref[q]; q = q + 1 }
964 full[o+q] = 0 as u8
965 checked = checked + 1
966 broken = broken + pv_check_asset(store, full, abuf)
967 } else {
968 // RELATIVE ref = RED BY LAW on our slash-stripping edge (the /render3d broken-image class)
969 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)
970 lawred = lawred + 1
971 broken = broken + 1
972 } } }
973 } } }
974 i = re
975 } else { i = i + 1 }
976 }
977
978 hw("checked=" as *u8); pn(checked)
979 hw(" skipped=" as *u8); pn(skipped)
980 hw(" law-violations=" as *u8); pn(lawred)
981 hw(" bare-src-rejected-not-in-tag=" as *u8); pn(barerej)
982 hw(" bare-src-rejected-in-rawtext=" as *u8); pn(rawrej)
983 hw(" declared-assets=" as *u8); pn(declared)
984 hw(" unobservable=" as *u8); pn(PV_UNOBS)
985 hw(" verified-by-head=" as *u8); pn(PV_HEADVER)
986 hw(" broken=" as *u8); pn(broken); hw("\n" as *u8)
987 // COVERAGE IS TWO QUESTIONS: per-asset (above) and whole-page. A verdict that says "every asset"
988 // must be able to say it saw every asset: refs beyond PV_MAXREF were never examined, and a page
989 // whose <img> count exceeds what the extractor resolved has refs the scanner could not read. Both
990 // are announced and turn the whole-page claim into UNPROVEN rather than a silent acquittal.
991 let seen: i64 = checked + skipped + lawred
992 if seen >= PV_MAXREF { hw("COVERAGE-CAP: ref cap PV_MAXREF=" as *u8); pn(PV_MAXREF); hw(" reached -- refs beyond it were NOT examined; whole-page claim UNPROVEN\n" as *u8) }
993 if nimg > seen { hw("COVERAGE-GAP: img tags=" as *u8); pn(nimg); hw(" but refs resolved=" as *u8); pn(seen); hw(" -- some src attributes were not readable by the extractor; whole-page claim UNPROVEN\n" as *u8) }
994 // AN ASSET THAT COULD NOT BE READ ABSTAINS; IT NEVER ACQUITS. Ordered ahead of both GREEN-PARTIAL
995 // arms deliberately: an unread asset is a stronger claim against the page than a capped ref count,
996 // and letting a partial-green outrank it would be the acquittal this whole ladder exists to refuse.
997 // Nothing that reads GREEN today can land here -- a negative read was already counted as broken and
998 // published the page as RED -- so this can only move a verdict toward honesty, never away from it.
999 if broken == 0 { if PV_UNOBS > 0 { hw("VERDICT=UNOBSERVABLE unreadable-assets=" as *u8); pn(PV_UNOBS); hw(" (nothing that was read came back broken, but at least one asset could not be READ, so the whole-page claim is UNPROVEN)\n" as *u8); sys_exit(PV_EXIT_UNOBSERVABLE); return PV_EXIT_UNOBSERVABLE } }
1000 if broken == 0 { if seen >= PV_MAXREF { hw("VERDICT=GREEN-PARTIAL (examined assets fetch AND decode; coverage capped, see above)\n" as *u8); sys_exit(PV_EXIT_GREEN); return PV_EXIT_GREEN } }
1001 if broken == 0 { if nimg > seen { hw("VERDICT=GREEN-PARTIAL (examined assets fetch AND decode; " as *u8); pn(nimg - seen); hw(" img ref(s) unread, see above)\n" as *u8); sys_exit(PV_EXIT_GREEN); return PV_EXIT_GREEN } }
1002 if broken == 0 { hw("VERDICT=GREEN (examined static/declarative assets passed HTTP checks; browser rendering and runtime-only dependencies unverified)\n" as *u8); sys_exit(PV_EXIT_GREEN); return PV_EXIT_GREEN }
1003 hw("VERDICT=RED broken=" as *u8); pn(broken); hw("\n" as *u8)
1004 sys_exit(broken)
1005 return broken
1006}