nx_sitesweep_gate.nx source
↩ module page · 282 lines · 15995 B
1// nx_sitesweep_gate.nx -- the referee for the site-wide broken-asset sweep.
2//
3// WHAT IT CAN AND CANNOT PROVE, STATED UP FRONT. nx_sitesweep adds exactly TWO pieces of judgement to
4// nx_page_verify: the ref PREFILTER (which pages can be proven ref-free without a fetch) and the RULER
5// VERDICT PARSER (how nx_page_verify's output is read). Everything else about a page is the ruler's
6// judgement, already refereed by nx_page_verify_gate. So this gate bites those two, and it bites them
7// IN PROCESS by importing nx_sitesweep_lib -- the same copy the sweep ships. There is no second
8// implementation for the teeth to agree with.
9//
10// The in-process teeth need no fork and no network, so they run in milliseconds and are safe on the
11// fast gate roster. The END-TO-END cell is a different cost class: it forks the deployed sweep against
12// six live pages and takes minutes. It is therefore OPT-IN (e2e=1) and, when it does not run, the gate
13// SAYS SO IN A NAMED LINE rather than silently counting one fewer tooth. A skipped cell that announces
14// itself is a fact; a skipped cell that does not is a false sense of coverage.
15//
16// FIXTURES. The bite cells read two PERMANENT PUBLISHED negative controls that exist for exactly this
17// purpose -- sites/nishifamily/render3d/negctl_bare.html (unquoted src=, the form the ruler was blind to
18// until 2026-08-25) and negctl_sq.html (single-quoted src=, the form it was blind to until 2026-08-18).
19// They are read ONLY, never written, so this gate shares no scratch with any production beat; the
20// fixture-ratchet law is about a gate WRITING where a beat writes, and there is no write here at all.
21// Synthetic fixtures are built in memory at RUNTIME, byte by byte, so no detector that scans source can
22// mistake a gate fixture for a real occurrence, and no literal newline inside a string is required.
23//
24// usage: nx_sitesweep_gate [e2e=1]
25// license_tier: ORIGINAL
26import "nx_syscalls.nx"
27import "nx_gate_verdict.nx"
28import "nx_sitesweep_lib.nx"
29import "nx_tool_run.nx"
30
31const SG_NAME: *u8 = "nx_sitesweep_gate"
32const SG_FIX_BARE: *u8 = "sites/nishifamily/render3d/negctl_bare.html"
33const SG_FIX_SQ: *u8 = "sites/nishifamily/render3d/negctl_sq.html"
34const SG_SWEEP_ELF: *u8 = "nx_sitesweep.elf"
35const SG_DOCROOT: *u8 = "sites/nishifamily"
36const SG_ORIGIN: *u8 = "https://nishifamily.com"
37
38const SG_BUF: i64 = 65536
39const SG_E2E_BUF: i64 = 1048576
40// 300 s: the e2e cell sweeps six live pages and one measured page costs ~5.5 s of TLS plus asset
41// decode (measured 2026-08-25 over 24 live checks in 131 s). 300 s is roughly 9x the expected 33 s, so
42// the bound fires only on a genuine hang.
43const SG_E2E_TMO_MS: i64 = 300000
44const SG_ARGVN: i64 = 32
45
46// URLs the end-to-end cell discriminates between. All three live in ONE directory and come from ONE
47// generator, so the cell varies the DEFECT and holds everything else fixed.
48const SG_URL_BARE: *u8 = "/render3d/negctl_bare"
49const SG_URL_SQ: *u8 = "/render3d/negctl_sq"
50const SG_URL_GOOD: *u8 = "/render3d/negctl_noviewport"
51
52func sgw(s: *u8) -> i64 { sys_write(1, s, ss_len(s)); return 0 }
53
54// build a synthetic nx_page_verify tail in buf; returns length. Newlines are CONSTRUCTED, never written
55// as a literal inside a string: this dialect permits a literal newline in a string and that has silently
56// shifted a scanner's mask before.
57func sg_tail(buf: *u8, summary: *u8, verdict: *u8) -> i64 {
58 var o: i64 = ss_cat(buf, 0, "page status=200 bytes=4096" as *u8)
59 buf[o] = SS_CH_NL as u8; o = o + 1
60 if summary[0] != (0 as u8) {
61 o = ss_cat(buf, o, summary)
62 buf[o] = SS_CH_NL as u8; o = o + 1
63 }
64 o = ss_cat(buf, o, verdict)
65 buf[o] = SS_CH_NL as u8; o = o + 1
66 return o
67}
68
69func main(argc: i64, argv: *i64) -> i64 {
70 var e2e: i64 = 0
71 var ai: i64 = 1
72 while ai < argc {
73 let a: *u8 = argv[ai] as *u8
74 let eo: i64 = ss_pfx(a, "e2e=" as *u8)
75 if eo >= 0 { e2e = ss_int_at(a, ss_len(a), eo) }
76 ai = ai + 1
77 }
78 gv_head("=== nx_sitesweep_gate -- referee for the site-wide broken-asset sweep ===" as *u8)
79 let ctr: *i64 = gv_ctr()
80 let outv: *i64 = sys_mmap(SS_WORD * SS_V_N) as *i64
81 let buf: *u8 = sys_mmap(SG_BUF)
82 let url: *u8 = sys_mmap(SG_BUF)
83 let dl: i64 = ss_len(SG_DOCROOT)
84
85 // ---- SUBJECTS: bind every aggregate below to a NON-ZERO denominator of REAL published bytes. ----
86 let lp: *i64 = sys_mmap(SS_WORD * 2) as *i64
87 let bare: *u8 = sys_read_file(SG_FIX_BARE, lp)
88 var bare_n: i64 = 0
89 if (bare as i64) != 0 { bare_n = lp[0] }
90 let lp2: *i64 = sys_mmap(SS_WORD * 2) as *i64
91 let sq: *u8 = sys_read_file(SG_FIX_SQ, lp2)
92 var sq_n: i64 = 0
93 if (sq as i64) != 0 { sq_n = lp2[0] }
94 var nfix: i64 = 0
95 if bare_n > 0 { nfix = nfix + 1 }
96 if sq_n > 0 { nfix = nfix + 1 }
97 sgw(" fixture bytes: negctl_bare=" as *u8); gv_num(bare_n)
98 sgw(" negctl_sq=" as *u8); gv_num(sq_n); sgw("\n" as *u8)
99 let have_fix: i64 = gv_subjects("published-negative-control-fixtures-readable" as *u8, nfix, ctr)
100
101 // ---- THE PREFILTER: bite it against the two attribute forms the ruler was once blind to. --------
102 // A ref-free control is built in memory so the good side is fully determined.
103 var gn: i64 = ss_cat(buf, 0, "<html lang=en><head><title>t</title></head><body><h1>x</h1>" as *u8)
104 gn = ss_cat(buf, gn, "<p>no assets here at all</p></body></html>" as *u8)
105 let good_free: i64 = ss_may_have_refs(buf, gn)
106
107 if have_fix == 1 {
108 var bad_bare: i64 = 0
109 if bare_n > 0 { bad_bare = ss_may_have_refs(bare, bare_n) }
110 gv_bite("prefilter-sees-the-UNQUOTED-src-fixture-and-not-a-ref-free-page" as *u8, bad_bare, good_free, ctr)
111 var bad_sq: i64 = 0
112 if sq_n > 0 { bad_sq = ss_may_have_refs(sq, sq_n) }
113 gv_bite("prefilter-sees-the-SINGLE-QUOTED-src-fixture-and-not-a-ref-free-page" as *u8, bad_sq, good_free, ctr)
114 }
115
116 // The prefilter must key on the ruler's actual trigger TOKEN, not on the word. A page whose only
117 // "src" is inside another attribute name has no ref for the ruler to find, and treating it as one
118 // would quietly convert a proof into a guess in the direction of extra network load.
119 var dn: i64 = ss_cat(buf, 0, "<html><body><img data-source=x.png alt=a></body></html>" as *u8)
120 gv_check("neg-control-prefilter-must-not-fire-on-data-source-attribute" as *u8, 1 - ss_may_have_refs(buf, dn), ctr)
121 // ...and it MUST fire on a stylesheet link, the ruler's other trigger.
122 var kn: i64 = ss_cat(buf, 0, "<html><head><link rel=stylesheet href=/s.css></head></html>" as *u8)
123 gv_check("prefilter-fires-on-a-link-tag-the-rulers-other-trigger" as *u8, ss_may_have_refs(buf, kn), ctr)
124
125 // ---- THE VERDICT PARSER: both signals present, so the cell proves DISCRIMINATION, not detection --
126 let tail: *u8 = sys_mmap(SG_BUF)
127 let tn_red: i64 = sg_tail(tail, "checked=16 skipped=0 law-violations=15 broken=15" as *u8, "VERDICT=RED broken=15" as *u8)
128 let c_red: i64 = ss_parse_ruler(tail, tn_red, 0, outv)
129 let red_broken: i64 = outv[SS_V_BROKEN]
130 let red_law: i64 = outv[SS_V_LAW]
131 let red_checked: i64 = outv[SS_V_CHECKED]
132
133 let tail2: *u8 = sys_mmap(SG_BUF)
134 let tn_grn: i64 = sg_tail(tail2, "checked=16 skipped=0 law-violations=0 broken=0" as *u8, "VERDICT=GREEN (every referenced asset fetches AND decodes)" as *u8)
135 let c_grn: i64 = ss_parse_ruler(tail2, tn_grn, 0, outv)
136
137 var f_red: i64 = 0
138 if c_red == SS_C_BROKEN { f_red = 1 }
139 var f_grn: i64 = 0
140 if c_grn == SS_C_BROKEN { f_grn = 1 }
141 gv_bite("verdict-parser-fires-on-RED-and-is-silent-on-GREEN" as *u8, f_red, f_grn, ctr)
142
143 sgw(" parsed RED: broken=" as *u8); gv_num(red_broken)
144 sgw(" law=" as *u8); gv_num(red_law)
145 sgw(" checked=" as *u8); gv_num(red_checked); sgw("\n" as *u8)
146 var nums_ok: i64 = 0
147 if red_broken == 15 { if red_law == 15 { if red_checked == 16 { nums_ok = 1 } } }
148 gv_check("parser-carries-the-rulers-own-numbers-not-just-its-word" as *u8, nums_ok, ctr)
149
150 // A RED with NO asset-summary line means the ruler exited before it ever looked at an asset: the
151 // PAGE did not serve. Folding that into the broken-image count sends the next reader to fix the
152 // wrong thing. Both cases are asserted TOGETHER so the tooth proves the split, not one half of it.
153 let tail3: *u8 = sys_mmap(SG_BUF)
154 let tn_pr: i64 = sg_tail(tail3, "" as *u8, "VERDICT=RED (page not 200)" as *u8)
155 let c_pr: i64 = ss_parse_ruler(tail3, tn_pr, 0, outv)
156 var split_ok: i64 = 0
157 if c_pr == SS_C_PAGERED { if c_red == SS_C_BROKEN { split_ok = 1 } }
158 gv_check("parser-splits-PAGE-RED-from-BROKEN-both-signals-present" as *u8, split_ok, ctr)
159
160 // GREEN-PARTIAL must never be read as GREEN: the ruler emits it precisely when its own coverage is
161 // UNPROVEN, and a prefix match on the shorter word would launder that into a clean pass.
162 let tail4: *u8 = sys_mmap(SG_BUF)
163 let tn_gp: i64 = sg_tail(tail4, "checked=1 skipped=0 law-violations=0 broken=0" as *u8, "VERDICT=GREEN-PARTIAL (examined assets fetch AND decode; 15 img ref(s) unread)" as *u8)
164 let c_gp: i64 = ss_parse_ruler(tail4, tn_gp, 0, outv)
165 var gp_ok: i64 = 0
166 if c_gp == SS_C_PARTIAL { gp_ok = 1 }
167 gv_check("green-partial-is-its-own-class-never-folded-into-green" as *u8, gp_ok, ctr)
168
169 // THE THIRD STATE, twice. A vantage failure and a destroyed capture are both "I could not look",
170 // and neither may be spelled RED. The cut case reuses the REAL RED bytes, so the only thing that
171 // changes is the truncation flag -- if the parser ignored it, this tooth reads BROKEN and fails.
172 let tail5: *u8 = sys_mmap(SG_BUF)
173 let tn_uo: i64 = sg_tail(tail5, "" as *u8, "VERDICT=UNOBSERVABLE vantage=pinned:127.0.0.1:8443 reason=no-connection(connect)" as *u8)
174 let c_uo: i64 = ss_parse_ruler(tail5, tn_uo, 0, outv)
175 var uo_ok: i64 = 0
176 if c_uo == SS_C_UNOBSERVABLE { uo_ok = 1 }
177 gv_check("unobservable-stays-unobservable-never-red" as *u8, uo_ok, ctr)
178
179 let c_cut: i64 = ss_parse_ruler(tail, tn_red, 1, outv)
180 var cut_ok: i64 = 0
181 if c_cut == SS_C_UNREADABLE { cut_ok = 1 }
182 gv_check("neg-control-a-CUT-capture-reads-UNREADABLE-not-BROKEN" as *u8, cut_ok, ctr)
183
184 // An empty capture is a fork that produced nothing, not a clean page.
185 let c_empty: i64 = ss_parse_ruler(tail, 0, 0, outv)
186 var emp_ok: i64 = 0
187 if c_empty == SS_C_UNREADABLE { emp_ok = 1 }
188 gv_check("neg-control-an-EMPTY-capture-reads-UNREADABLE-not-GREEN" as *u8, emp_ok, ctr)
189
190 // POSITIONAL ANCHORING. The ruler quotes verdict words in its own prose, so the answer is the LAST
191 // occurrence and only the last. This fixture puts a GREEN ahead of the real RED: a first-match or
192 // unanchored parser reads GREEN and the whole sweep silently acquits every broken page.
193 let tail6: *u8 = sys_mmap(SG_BUF)
194 var t6: i64 = ss_cat(tail6, 0, "note: a page that passes prints VERDICT=GREEN here" as *u8)
195 tail6[t6] = SS_CH_NL as u8; t6 = t6 + 1
196 t6 = ss_cat(tail6, t6, "checked=3 skipped=0 law-violations=2 broken=2" as *u8)
197 tail6[t6] = SS_CH_NL as u8; t6 = t6 + 1
198 t6 = ss_cat(tail6, t6, "VERDICT=RED broken=2" as *u8)
199 tail6[t6] = SS_CH_NL as u8; t6 = t6 + 1
200 let c_anch: i64 = ss_parse_ruler(tail6, t6, 0, outv)
201 var anch_ok: i64 = 0
202 if c_anch == SS_C_BROKEN { anch_ok = 1 }
203 gv_check("verdict-read-from-the-LAST-occurrence-not-the-first" as *u8, anch_ok, ctr)
204
205 // ---- THE PATH -> URL MAP. These three cases are the whole contract. -----------------------------
206 ss_url_of(SG_ORIGIN, dl, "sites/nishifamily/world/foundation.html" as *u8, url)
207 var u1: i64 = 0
208 if ss_tok_eq(url, ss_len(url), 0, "https://nishifamily.com/world/foundation" as *u8) == 1 { u1 = 1 }
209 sgw(" url(world/foundation.html) = " as *u8); sgw(url); sgw("\n" as *u8)
210 gv_check("url-map-drops-the-html-extension" as *u8, u1, ctr)
211
212 ss_url_of(SG_ORIGIN, dl, "sites/nishifamily/world/index.html" as *u8, url)
213 var u2: i64 = 0
214 if ss_tok_eq(url, ss_len(url), 0, "https://nishifamily.com/world" as *u8) == 1 { u2 = 1 }
215 sgw(" url(world/index.html) = " as *u8); sgw(url); sgw("\n" as *u8)
216 gv_check("url-map-collapses-index-to-its-own-directory" as *u8, u2, ctr)
217
218 ss_url_of(SG_ORIGIN, dl, "sites/nishifamily/index.html" as *u8, url)
219 var u3: i64 = 0
220 if ss_tok_eq(url, ss_len(url), 0, "https://nishifamily.com/" as *u8) == 1 { u3 = 1 }
221 sgw(" url(index.html) = " as *u8); sgw(url); sgw("\n" as *u8)
222 gv_check("url-map-root-index-is-the-site-root" as *u8, u3, ctr)
223
224 // ---- CLASS NAMES ROUND-TRIP. The ledger is rewritten every run and re-read the next run, so a
225 // name that does not survive the round trip silently resets a page to UNCHECKED and the coverage
226 // number quietly falls without anything reporting a fault.
227 var c: i64 = 0
228 var rt_ok: i64 = 1
229 var rt_n: i64 = 0
230 while c < SS_C_N {
231 if ss_class_of_name(ss_class_name(c)) != c { rt_ok = 0 }
232 rt_n = rt_n + 1
233 c = c + 1
234 }
235 sgw(" class round-trip checked=" as *u8); gv_num(rt_n); sgw("\n" as *u8)
236 var rt_pop: i64 = 0
237 if rt_n == SS_C_N { rt_pop = 1 }
238 gv_check("class-roundtrip-covers-EVERY-declared-class" as *u8, rt_pop, ctr)
239 gv_check("every-class-name-round-trips-through-the-ledger-spelling" as *u8, rt_ok, ctr)
240
241 // ---- THE END-TO-END CELL --------------------------------------------------------------------
242 if e2e == 1 {
243 let eb: *u8 = sys_mmap(SG_E2E_BUF)
244 let av: *i64 = sys_mmap(SG_ARGVN) as *i64
245 av[0] = SG_SWEEP_ELF as i64
246 av[1] = "root=render3d" as *u8 as i64
247 av[2] = 0
248 let elp: *i64 = sys_mmap(SS_WORD * 2) as *i64
249 let etr: *i64 = sys_mmap(SS_WORD * 2) as *i64
250 etr[0] = 0
251 elp[0] = 0
252 tr_run_capture_tr(SG_SWEEP_ELF, av, eb, SG_E2E_BUF, elp, SG_E2E_TMO_MS, etr)
253 let en: i64 = elp[0]
254 sgw(" e2e capture bytes=" as *u8); gv_num(en)
255 sgw(" cut=" as *u8); gv_num(etr[0]); sgw("\n" as *u8)
256 var ran: i64 = 0
257 if en > 0 { if etr[0] == 0 { ran = 1 } }
258 if gv_need("e2e-sweep-produced-a-readable-capture" as *u8, ran, ctr) == 1 {
259 var e_bare: i64 = ss_contains(eb, en, SG_URL_BARE)
260 var e_sq: i64 = ss_contains(eb, en, SG_URL_SQ)
261 var e_good: i64 = ss_contains(eb, en, SG_URL_GOOD)
262 var e_bad: i64 = 0
263 if e_bare == 1 { if e_sq == 1 { e_bad = 1 } }
264 sgw(" e2e worklist: bare=" as *u8); gv_num(e_bare)
265 sgw(" sq=" as *u8); gv_num(e_sq)
266 sgw(" good=" as *u8); gv_num(e_good); sgw("\n" as *u8)
267 // Both fixtures named AND the asset-clean sibling absent, from ONE run over ONE directory
268 // produced by ONE generator: the only thing that varies between them is the defect.
269 gv_bite("e2e-sweep-names-both-published-fixtures-and-not-their-clean-sibling" as *u8, e_bad, e_good, ctr)
270 gv_check("e2e-verdict-line-is-present-and-last" as *u8, ss_contains(eb, en, "verdict=RED" as *u8), ctr)
271 }
272 } else {
273 // A NAMED ABSENCE, NOT A PASS. The cell simply does not run, the denominator is smaller, and the
274 // reader is told which proof is missing and exactly how to obtain it.
275 sgw(" E2E-CELL: NOT EXERCISED THIS RUN -- the end-to-end bite forks the deployed sweep against\n" as *u8)
276 sgw(" six live pages (~35 s) and is opt-in so this gate stays safe on the fast roster.\n" as *u8)
277 sgw(" Run `nx_sitesweep_gate e2e=1` to exercise it. The tooth count below is SMALLER by 3\n" as *u8)
278 sgw(" because those teeth did not run -- it is not that they passed.\n" as *u8)
279 }
280
281 return gv_verdict(SG_NAME, ctr, "prefilter and verdict-parser bitten against the PUBLISHED unquoted and single-quoted negative controls; third state proven for cut, empty and unobservable captures" as *u8)
282}