code wiki / _hdl_build / nx_web_crawl_step_gate.nx

nx_web_crawl_step_gate.nx source

↩ module page · 408 lines · 24415 B

1// nx_web_crawl_step_gate.nx -- network-free KATs for the frontier-persisted crawler's STORE mechanics: 2// the url filter, fr: row write/enumerate, the P->D state flip (append-only last-wins), cross-segment 3// dedupe, and unknown-state. The fetch/ingest spine is nx_web_ingest's, already proven on the real web. 4// Runs against a /tmp shard (wiped per boot). license_tier: ORIGINAL 5import "nx_web_crawl_step.nx" 6import "nx_gate_verdict.nx" 7 8func gw_puts(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } sys_write(1, s, n); return 0 } 9func gw_num(v: i64) -> i64 { 10 let bb: *u8 = sys_mmap(28); var m: i64 = v 11 if m < 0 { sys_write(1, "-" as *u8, 1); m = 0 - m } 12 let t: *u8 = sys_mmap(28); var k: i64 = 0 13 if m == 0 { t[0] = 48 as u8; k = 1 } 14 while m > 0 { t[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 } 15 var i: i64 = 0; while i < k { bb[i] = t[k - 1 - i]; i = i + 1 } 16 sys_write(1, bb, k); return 0 17} 18func gw_check(name: *u8, cond: i64, pass: *i64, total: *i64) -> i64 { 19 total[0] = total[0] + 1 20 gw_puts(name) 21 if cond == 1 { pass[0] = pass[0] + 1; gw_puts(" PASS\n" as *u8) } else { gw_puts(" FAIL\n" as *u8) } 22 return 0 23} 24func gw_ok(u: *u8) -> i64 { return wc_urlok(u, wc_len(u)) } 25 26func main() -> i64 { 27 gw_puts("=== nx_web_crawl_step gate (frontier store mechanics, network-free) ===\n" as *u8) 28 let pass: *i64 = sys_mmap(16) as *i64; pass[0] = 0 29 let total: *i64 = sys_mmap(16) as *i64; total[0] = 0 30 31 // R10: establish the query policy ONCE, up front, so EVERY tooth below runs under a known, 32 // self-contained deny list rather than whatever the live urlpolicy- plane happens to hold. 33 // 'action' earns its place next to 'utm_source': ?action=edit|raw|history is a MediaWiki ACTION 34 // ENDPOINT, not a document. R8 killed it for free via the blanket '?' reject; once queries are 35 // judged by shape, that free kill has to be paid for explicitly -- and T1 is what noticed. 36 // ★REMOVING A BLANKET RULE BILLS YOU FOR EVERY CASE IT WAS SILENTLY COVERING. 37 let gqd: *u8 = sys_mmap(32 * 8) 38 var gqi: i64 = 0 39 let gqd0: *u8 = "utm_source" as *u8 40 while gqd0[gqi] != (0 as u8) { gqd[gqi] = gqd0[gqi]; gqi = gqi + 1 } 41 gqd[gqi] = 0 as u8 42 let gqd1: *u8 = "action" as *u8 43 var gqj: i64 = 0 44 while gqd1[gqj] != (0 as u8) { gqd[32 + gqj] = gqd1[gqj]; gqj = gqj + 1 } 45 gqd[32 + gqj] = 0 as u8 46 wc_qdeny_g = gqd 47 wc_nqdeny_g = 2 48 49 // T1 url filter: keeps article urls, kills queries/fragments/meta/binaries 50 var f1: i64 = 1 51 if gw_ok("https://en.wikipedia.org/wiki/Chess" as *u8) != 1 { f1 = 0 } 52 if gw_ok("https://example.org/a/deep/page" as *u8) != 1 { f1 = 0 } 53 if gw_ok("https://en.wikipedia.org/w/index.php?action=edit" as *u8) != 0 { f1 = 0 } 54 if gw_ok("https://en.wikipedia.org/wiki/Chess#History" as *u8) != 0 { f1 = 0 } 55 if gw_ok("https://en.wikipedia.org/wiki/Special:Random" as *u8) != 0 { f1 = 0 } 56 if gw_ok("https://en.wikipedia.org/wiki/File:Board.png" as *u8) != 0 { f1 = 0 } 57 if gw_ok("https://x.org/logo.png" as *u8) != 0 { f1 = 0 } 58 if gw_ok("https://x.org/style.css" as *u8) != 0 { f1 = 0 } 59 if gw_ok("mailto:someone@example.org" as *u8) != 0 { f1 = 0 } 60 if gw_ok("/relative/only" as *u8) != 0 { f1 = 0 } 61 if gw_ok("https://ro.wikipedia.org/wiki/Literatura" as *u8) != 0 { f1 = 0 } // interwiki lang edition 62 if gw_ok("https://en.wikipedia.org/wiki/Chess_opening" as *u8) != 1 { f1 = 0 } // en stays 63 if gw_ok("https://commons.wikimedia.org/wiki/X" as *u8) != 0 { f1 = 0 } 64 // API / feed endpoints = real bytes but not content -> rejected 65 if gw_ok("https://creativecommons.org/wp-json/" as *u8) != 0 { f1 = 0 } 66 if gw_ok("https://site.com/api/data.json" as *u8) != 0 { f1 = 0 } 67 if gw_ok("https://blog.com/feed" as *u8) != 0 { f1 = 0 } 68 if gw_ok("https://blog.com/comments/feed/" as *u8) != 0 { f1 = 0 } 69 if gw_ok("https://site.com/articles/a-real-story" as *u8) != 1 { f1 = 0 } // content still passes 70 // anti-slop listing classes (2026-08-04): tag/category link farms refused at admission 71 if gw_ok("https://healthquerys.com/tag/puriva-france/" as *u8) != 0 { f1 = 0 } 72 if gw_ok("https://blog.com/category/wellness/" as *u8) != 0 { f1 = 0 } 73 if gw_ok("https://blog.com/posts/2024/tagged-story" as *u8) != 1 { f1 = 0 } // 'tag' inside a word still passes 74 gw_check("T1 url filter (21 KATs incl. interwiki + API/feed + tag/category farms)" as *u8, f1, pass, total) 75 76 // FIXTURE SELF-CLEAN (2026-08-04, debt 1785882035): /tmp persists across runs on the NAS, so a 77 // previous run's segments made the count teeth (T2-T4) go 4/7 RED on any second invocation -- a 78 // gate that is only green on a fresh boot is a boot-witness, not a gate. Unlink the whole fixture. 79 sys_unlinkat("/tmp/crawlgate-manifest.txt" as *u8) 80 let cleanbuf: *u8 = sys_mmap(96) 81 let cdig: *u8 = sys_mmap(28) 82 var ci0: i64 = 1 83 while ci0 <= 32 { 84 var ce: i64 = 0 85 while ce < 5 { 86 var ext: *u8 = ".docs" as *u8 87 if ce == 1 { ext = ".idx" as *u8 } 88 if ce == 2 { ext = ".pos" as *u8 } 89 if ce == 3 { ext = ".imp" as *u8 } 90 if ce == 4 { ext = ".terms" as *u8 } 91 var co: i64 = 0 92 let cpre: *u8 = "/tmp/crawlgate-seg-" as *u8 93 while cpre[co] != (0 as u8) { cleanbuf[co] = cpre[co]; co = co + 1 } 94 var cm: i64 = ci0 95 var ck: i64 = 0 96 while cm > 0 { cdig[ck] = (48 + (cm % 10)) as u8; cm = cm / 10; ck = ck + 1 } 97 var cj: i64 = 0 98 while cj < ck { cleanbuf[co] = cdig[ck - 1 - cj]; co = co + 1; cj = cj + 1 } 99 var cx: i64 = 0 100 while ext[cx] != (0 as u8) { cleanbuf[co] = ext[cx]; co = co + 1; cx = cx + 1 } 101 cleanbuf[co] = 0 as u8 102 sys_unlinkat(cleanbuf) 103 ce = ce + 1 104 } 105 ci0 = ci0 + 1 106 } 107 108 // build a tiny /tmp frontier shard 109 let prefix: *u8 = "/tmp/crawlgate-" as *u8 110 let segidbox: *i64 = sys_mmap(16) as *i64; segidbox[0] = 1 111 let segsbox: *i64 = sys_mmap(16) as *i64; segsbox[0] = 0 112 let w: *i64 = ss_begin() 113 let u1: *u8 = "https://a.example/one" as *u8 114 let u2: *u8 = "https://a.example/two" as *u8 115 let u3: *u8 = "https://a.example/three" as *u8 116 wc_frmark(w, prefix, segidbox, segsbox, u1, wc_len(u1), 1) 117 wc_frmark(w, prefix, segidbox, segsbox, u2, wc_len(u2), 1) 118 wc_frmark(w, prefix, segidbox, segsbox, u3, wc_len(u3), 2) // three = already done 119 ss_commit(prefix, w, segidbox[0]) 120 121 // T2 enumerate: exactly the two P urls 122 let h1: *i64 = ss_open(prefix) 123 let urls: *u8 = sys_mmap(2048 * 16) 124 let canh0: *u8 = sys_mmap(64 * 8) // R4: never read when canonly=0 -- T2/T3/T4 keep the pre-R4 contract 125 let n2: i64 = wc_pending(h1, prefix, urls, 16, canh0, 0, 0) 126 gw_check("T2 pending enumeration -> 2 (P rows only)" as *u8, (n2 == 2) as i64, pass, total) 127 128 // T3 state flip: mark one P->D in a NEW segment; enumeration drops to 1 (last-wins across segments) 129 segidbox[0] = segidbox[0] + 1 130 let w2: *i64 = ss_begin() 131 wc_frmark(w2, prefix, segidbox, segsbox, u1, wc_len(u1), 2) 132 ss_commit(prefix, w2, segidbox[0]) 133 let h2: *i64 = ss_open(prefix) 134 let n3: i64 = wc_pending(h2, prefix, urls, 16, canh0, 0, 0) 135 var t3: i64 = 0 136 if n3 == 1 { 137 // the survivor must be u2 138 var eq: i64 = 1 139 var x: i64 = 0 140 var go: i64 = 1 141 while go == 1 { if urls[x] != u2[x] { eq = 0; go = 0 } else { if u2[x] == (0 as u8) { go = 0 } else { x = x + 1 } } } 142 if eq == 1 { t3 = 1 } 143 } 144 gw_check("T3 P->D flip (append-only, last-wins) -> 1 pending = /two" as *u8, t3, pass, total) 145 146 // T4 duplicate P rows across segments dedupe to one pending 147 segidbox[0] = segidbox[0] + 1 148 let w3: *i64 = ss_begin() 149 wc_frmark(w3, prefix, segidbox, segsbox, u2, wc_len(u2), 1) // re-bank the SAME pending url 150 ss_commit(prefix, w3, segidbox[0]) 151 let h3: *i64 = ss_open(prefix) 152 let n4: i64 = wc_pending(h3, prefix, urls, 16, canh0, 0, 0) 153 gw_check("T4 dup P rows across segments dedupe -> still 1" as *u8, (n4 == 1) as i64, pass, total) 154 155 // T5 unknown state for a never-seen url 156 let s5: i64 = wc_frstate(h3, "https://a.example/never" as *u8, 23) 157 gw_check("T5 unknown url -> state 0" as *u8, (s5 == 0) as i64, pass, total) 158 // T5b known states read back 159 var t5b: i64 = 0 160 if wc_frstate(h3, u2, wc_len(u2)) == 1 { if wc_frstate(h3, u1, wc_len(u1)) == 2 { t5b = 1 } } 161 gw_check("T5b states read back (two=P, one=D)" as *u8, t5b, pass, total) 162 163 // T6 (P1 LINK GRAPH): wc_harvest captures ALL of a page's outlinks as out:<cid(base)> = packed i64 target 164 // cid(url)s -- the edge list PageRank runs on. Distinguishing by construction: before this change the 165 // crawler stored NO edges, so out:<cid> is absent and t6=0. 166 let t1u: *u8 = "https://tgt1.example/story-alpha" as *u8 167 let t2u: *u8 = "https://tgt2.example/story-beta" as *u8 168 let hbase: *u8 = "https://src.example/page-x" as *u8 169 let html6: *u8 = "<html><body><a href='https://tgt1.example/story-alpha'>A</a> <a href='https://tgt2.example/story-beta'>B</a></body></html>" as *u8 170 let hdisc: *i64 = sys_mmap(16) as *i64; hdisc[0] = 0 171 let hrs: *u8 = sys_mmap(256 * 64); let hnrs: *i64 = sys_mmap(16) as *i64; hnrs[0] = 0 172 segidbox[0] = segidbox[0] + 1 173 let w6: *i64 = ss_begin() 174 wc_harvest(html6, wc_len(html6), hbase, wc_len(hbase), 0 as *i64, w6, prefix, segidbox, segsbox, hdisc, hrs, hnrs) 175 ss_commit(prefix, w6, segidbox[0]) 176 let h6: *i64 = ss_open(prefix) 177 let okey6: *u8 = sys_mmap(64) 178 wc_outkey(ci_hash(hbase, wc_len(hbase)), okey6) 179 let op6: *i64 = sys_mmap(16) as *i64 180 let ol6: *i64 = sys_mmap(16) as *i64 181 var t6: i64 = 0 182 if ss_hget(h6, okey6, op6, ol6) == 1 { if ol6[0] == 16 { 183 let ev: *i64 = op6[0] as *i64 184 if ev[0] == ci_hash(t1u, wc_len(t1u)) { if ev[1] == ci_hash(t2u, wc_len(t2u)) { t6 = 1 } } 185 } } 186 gw_check("T6 P1 outlink capture (out:<cid(base)> = [cid(tgt1),cid(tgt2)], ordered)" as *u8, t6, pass, total) 187 188 // T7 (R3 host-health): hd:<hosthash> streak round-trip; an unknown host reads 0 189 segidbox[0] = segidbox[0] + 1 190 let w7: *i64 = ss_begin() 191 let hhA: i64 = wc_hosthash("dead.example" as *u8, 12) 192 wc_hd_put(w7, prefix, segidbox, segsbox, hhA, 3) 193 ss_commit(prefix, w7, segidbox[0]) 194 let h7: *i64 = ss_open(prefix) 195 var t7: i64 = 0 196 if wc_hd_streak(h7, hhA) == 3 { if wc_hd_streak(h7, wc_hosthash("live.example" as *u8, 12)) == 0 { t7 = 1 } } 197 gw_check("T7 hd: streak round-trip (3) + unknown-host 0" as *u8, t7, pass, total) 198 199 // T8 (R3): retire-if-rotten -- streak>=WC_HD_RETIRE retires a P row (P->D visible after commit), 200 // streak below the bar keeps it pending, and a SEED url NEVER retires even on a rotten host 201 // (wc_seed_add is blocked by any existing fr: row, so a retired seed would be permanently dead). 202 let ur1: *u8 = "https://dead.example/rot1" as *u8 203 let ur2: *u8 = "https://dying.example/fresh" as *u8 204 let ur3: *u8 = "https://dead.example/seedhub" as *u8 205 segidbox[0] = segidbox[0] + 1 206 let w8: *i64 = ss_begin() 207 wc_frmark(w8, prefix, segidbox, segsbox, ur1, wc_len(ur1), 1) 208 wc_frmark(w8, prefix, segidbox, segsbox, ur2, wc_len(ur2), 1) 209 wc_frmark(w8, prefix, segidbox, segsbox, ur3, wc_len(ur3), 1) 210 let hhB: i64 = wc_hosthash("dying.example" as *u8, 13) 211 wc_hd_put(w8, prefix, segidbox, segsbox, hhB, 2) 212 ss_commit(prefix, w8, segidbox[0]) 213 let h8: *i64 = ss_open(prefix) 214 let seeds8: *u8 = sys_mmap(WC_MAGIC_2048) 215 var so8: i64 = 0 216 while ur3[so8] != (0 as u8) { seeds8[so8] = ur3[so8]; so8 = so8 + 1 } 217 seeds8[so8] = 0 as u8 218 segidbox[0] = segidbox[0] + 1 219 let w9: *i64 = ss_begin() 220 // the caller pattern: seed membership guards the retire (exactly what main's skip branch does) 221 var r1: i64 = 0 222 if wc_is_seed(seeds8, 1, ur1, wc_len(ur1)) == 0 { r1 = wc_retire_if_rotten(h8, w9, prefix, segidbox, segsbox, ur1, wc_len(ur1), hhA) } 223 var r2: i64 = 0 224 if wc_is_seed(seeds8, 1, ur2, wc_len(ur2)) == 0 { r2 = wc_retire_if_rotten(h8, w9, prefix, segidbox, segsbox, ur2, wc_len(ur2), hhB) } 225 var r3: i64 = 0 226 if wc_is_seed(seeds8, 1, ur3, wc_len(ur3)) == 0 { r3 = wc_retire_if_rotten(h8, w9, prefix, segidbox, segsbox, ur3, wc_len(ur3), hhA) } 227 if w9[1] > 0 { ss_commit(prefix, w9, segidbox[0]) } 228 let h9: *i64 = ss_open(prefix) 229 var t8: i64 = 0 230 if r1 == 1 { if r2 == 0 { if r3 == 0 { 231 if wc_frstate(h9, ur1, wc_len(ur1)) == 2 { if wc_frstate(h9, ur2, wc_len(ur2)) == 1 { if wc_frstate(h9, ur3, wc_len(ur3)) == 1 { t8 = 1 } } } 232 } } } 233 gw_check("T8 retire-if-rotten: streak>=3 retires, <3 keeps, seed exempt" as *u8, t8, pass, total) 234 235 // ---- T9 (R4 CANONICAL LANE) --------------------------------------------------------------- 236 // The host-filtered pull must keep ONLY canonical-seed hosts, match a SUBDOMAIN on the boundary 237 // dot, and REFUSE a lookalike host. Network-free -- store rows only. The pre-existing fixture 238 // rows (a.example / b.example) are non-canonical by construction, so they are excluded too and 239 // the count is stable regardless of what T1-T8 left pending. 240 segidbox[0] = segidbox[0] + 1 241 let q9w: *i64 = ss_begin() 242 let q9c1: *u8 = "https://en.wikipedia.org/wiki/Hypertension" as *u8 243 let q9c2: *u8 = "https://data.who.int/topic/air" as *u8 244 let q9c3: *u8 = "https://notwikipedia.org/lookalike" as *u8 245 let q9c4: *u8 = "https://junkfarm.example/tag/a" as *u8 246 wc_frmark(q9w, prefix, segidbox, segsbox, q9c1, wc_len(q9c1), 1) 247 wc_frmark(q9w, prefix, segidbox, segsbox, q9c2, wc_len(q9c2), 1) 248 wc_frmark(q9w, prefix, segidbox, segsbox, q9c3, wc_len(q9c3), 1) 249 wc_frmark(q9w, prefix, segidbox, segsbox, q9c4, wc_len(q9c4), 1) 250 ss_commit(prefix, q9w, segidbox[0]) 251 let q9seeds: *u8 = sys_mmap(WC_MAGIC_2048 * 4) 252 let q9s1: *u8 = "https://www.who.int/" as *u8 253 var q9a: i64 = 0 254 while q9s1[q9a] != (0 as u8) { q9seeds[q9a] = q9s1[q9a]; q9a = q9a + 1 } 255 q9seeds[q9a] = 0 as u8 256 let q9d2: *u8 = (q9seeds as i64 + WC_MAGIC_2048) as *u8 257 let q9s2: *u8 = "https://wikipedia.org/" as *u8 258 var q9b: i64 = 0 259 while q9s2[q9b] != (0 as u8) { q9d2[q9b] = q9s2[q9b]; q9b = q9b + 1 } 260 q9d2[q9b] = 0 as u8 261 let q9canh: *u8 = sys_mmap(64 * WC_MAXCANH) 262 let q9ncan: i64 = wc_canon_hosts(q9seeds, 2, q9canh) 263 let q9h: *i64 = ss_open(prefix) 264 let q9urls: *u8 = sys_mmap(WC_MAGIC_2048 * 32) 265 let q9n: i64 = wc_pending(q9h, prefix, q9urls, 32, q9canh, q9ncan, 1) 266 var t9: i64 = 0 267 if q9ncan == 2 { if wc_streq(q9canh, "who.int" as *u8) == 1 { 268 if wc_streq((q9canh as i64 + 64) as *u8, "wikipedia.org" as *u8) == 1 { if q9n == 2 { t9 = 1 } } 269 } } 270 gw_check("T9 canonical lane: www-stripped hosts, subdomain kept, junk excluded -> 2 of 4" as *u8, t9, pass, total) 271 // T9b THE NEGATIVE CONTROL that makes T9 non-vacuous: a lookalike host must NOT ride the lane. 272 let q9hb: *u8 = sys_mmap(64) 273 var t9b: i64 = 0 274 if wc_host_is_canon(q9canh, q9ncan, q9c1, q9hb) == 1 { if wc_host_is_canon(q9canh, q9ncan, q9c2, q9hb) == 1 { 275 if wc_host_is_canon(q9canh, q9ncan, q9c3, q9hb) == 0 { if wc_host_is_canon(q9canh, q9ncan, q9c4, q9hb) == 0 { t9b = 1 } } 276 } } 277 gw_check("T9b lookalike REFUSED: notwikipedia.org needs the boundary dot to match wikipedia.org" as *u8, t9b, pass, total) 278 // T9c canonly=0 is the pre-R4 contract: the SAME walk sees all four rows (plus fixture leftovers). 279 let q9all: i64 = wc_pending(q9h, prefix, q9urls, 32, q9canh, 0, 0) 280 gw_check("T9c canonly=0 unchanged: unfiltered walk still sees strictly more rows than the lane" as *u8, (q9all > q9n) as i64, pass, total) 281 // T9d (R4b): the host-string matcher is the ONE rule and the url matcher only wraps it. If these 282 // two ever disagree, the canonical LANE and the canonical DEPTH CAP would disagree about which 283 // hosts are curated -- a split definition is exactly how a privilege leaks to a lookalike host. 284 var q9agree: i64 = 1 285 if wc_host_str_is_canon(q9canh, q9ncan, "wikipedia.org" as *u8, 13) != 1 { q9agree = 0 } 286 if wc_host_str_is_canon(q9canh, q9ncan, "en.wikipedia.org" as *u8, 16) != 1 { q9agree = 0 } 287 if wc_host_str_is_canon(q9canh, q9ncan, "data.who.int" as *u8, 12) != 1 { q9agree = 0 } 288 if wc_host_str_is_canon(q9canh, q9ncan, "notwikipedia.org" as *u8, 16) != 0 { q9agree = 0 } 289 if wc_host_str_is_canon(q9canh, q9ncan, "junkfarm.example" as *u8, 16) != 0 { q9agree = 0 } 290 gw_check("T9d host-string matcher == url matcher (exact, subdomain, lookalike, junk)" as *u8, q9agree, pass, total) 291 292 // ---- T10 (R5 SEED FRESHNESS RE-QUEUE) ------------------------------------------------------- 293 // A D seed must return to P and be copied into the lane buffer; a P seed and a never-seen seed 294 // must be left alone. Network-free, store rows only. 295 segidbox[0] = segidbox[0] + 1 296 let qAw: *i64 = ss_begin() 297 let qA1: *u8 = "https://canon-a.example/hub" as *u8 298 let qA2: *u8 = "https://canon-b.example/hub" as *u8 299 let qA3: *u8 = "https://canon-c.example/hub" as *u8 300 wc_frmark(qAw, prefix, segidbox, segsbox, qA1, wc_len(qA1), 2) 301 wc_frmark(qAw, prefix, segidbox, segsbox, qA2, wc_len(qA2), 1) 302 ss_commit(prefix, qAw, segidbox[0]) 303 let qAseeds: *u8 = sys_mmap(WC_MAGIC_2048 * 4) 304 var qAi: i64 = 0 305 while qA1[qAi] != (0 as u8) { qAseeds[qAi] = qA1[qAi]; qAi = qAi + 1 } 306 qAseeds[qAi] = 0 as u8 307 let qAd2: *u8 = (qAseeds as i64 + WC_MAGIC_2048) as *u8 308 qAi = 0 309 while qA2[qAi] != (0 as u8) { qAd2[qAi] = qA2[qAi]; qAi = qAi + 1 } 310 qAd2[qAi] = 0 as u8 311 let qAd3: *u8 = (qAseeds as i64 + 2 * WC_MAGIC_2048) as *u8 312 qAi = 0 313 while qA3[qAi] != (0 as u8) { qAd3[qAi] = qA3[qAi]; qAi = qAi + 1 } 314 qAd3[qAi] = 0 as u8 315 let qAh: *i64 = ss_open(prefix) 316 segidbox[0] = segidbox[0] + 1 317 let qAw2: *i64 = ss_begin() 318 let qAdst: *u8 = sys_mmap(WC_MAGIC_2048 * 8) 319 let qAbox: *i64 = sys_mmap(16) as *i64 320 qAbox[0] = 0 321 qAbox[1] = 6 322 let qArq: i64 = wc_seed_refresh(qAh, qAw2, prefix, segidbox, segsbox, qAseeds, 3, qAdst, qAbox) 323 if qAw2[1] > 0 { ss_commit(prefix, qAw2, segidbox[0]) } 324 let qAh2: *i64 = ss_open(prefix) 325 var t10: i64 = 0 326 if qArq == 1 { if qAbox[0] == 1 { 327 if wc_frstate(qAh2, qA1, wc_len(qA1)) == 1 { if wc_frstate(qAh2, qA2, wc_len(qA2)) == 1 { if wc_frstate(qAh2, qA3, wc_len(qA3)) == 0 { 328 if wc_streq(qAdst, qA1) == 1 { t10 = 1 } 329 } } } 330 } } 331 gw_check("T10 seed re-queue: D seed -> P + copied to lane; P and never-seen UNTOUCHED" as *u8, t10, pass, total) 332 // T10b the persisted cursor round-trips (the rotation mechanism across runs) 333 segidbox[0] = segidbox[0] + 1 334 let qAw3: *i64 = ss_begin() 335 wc_sr_put(qAw3, prefix, segidbox, segsbox, 5) 336 if qAw3[1] > 0 { ss_commit(prefix, qAw3, segidbox[0]) } 337 let qAh3: *i64 = ss_open(prefix) 338 gw_check("T10b sr:cursor persists across commit (put 5 -> read 5)" as *u8, (wc_sr_cursor(qAh3) == 5) as i64, pass, total) 339 340 // ---- T11 (R10 SHAPE-BASED QUERY ADMISSION -- replaces R8's host allowlist) ------------------- 341 // R8 admitted query strings ONLY on curated hosts, so an uncurated content url was refused before 342 // a byte was fetched -- a DIRECTORY, not an index. R10 judges the query's SHAPE instead, so the 343 // SAME two fixtures now split on WHAT THE URL IS rather than WHO SERVES IT: 344 // clean content query, uncurated host -> ADMITTED (this is the whole point of R10) 345 // tracking param, uncurated host -> REFUSED (a duplicate of the clean url) 346 // Deny list set directly here, exactly as the canon table is a few lines below: the gate must be 347 // self-contained, never dependent on whatever the live urlpolicy- plane happens to hold today. 348 let qB: *u8 = "https://graphis.ne.jp/monthly/model.php?ID=260731_sp" as *u8 349 let qBjunk: *u8 = "https://tracker.example/page.php?utm_source=x" as *u8 350 var t11a: i64 = 0 351 if wc_urlok(qB, wc_len(qB)) == 1 { if wc_urlok(qBjunk, wc_len(qBjunk)) == 0 { t11a = 1 } } 352 gw_check("T11 R10: a CLEAN query url is ADMITTED with an EMPTY canon table; a TRACKING one is REFUSED" as *u8, t11a, pass, total) 353 // THE TOOTH THAT WOULD HAVE CAUGHT R8: the operator's real-world miss. An uncurated host serving 354 // paginated content must be reachable -- under R8 this was refused purely for lacking curation. 355 let qBv2: *u8 = "https://www.v2ph.com/actor/JULIA?page=3&hl=en" as *u8 356 gw_check("T11a-ii an UNCURATED host's paginated content url is ADMITTED (the R8 miss, by name)" as *u8, (wc_urlok(qBv2, wc_len(qBv2)) == 1) as i64, pass, total) 357 // and the trap half: a facet explosion beyond the param budget is still refused, on ANY host 358 let qBfacet: *u8 = "https://shop.example/list?a=1&b=2&c=3&d=4&e=5&f=6" as *u8 359 gw_check("T11a-iii a 6-param facet explosion is REFUSED (budget, not curation, is the limit)" as *u8, (wc_urlok(qBfacet, wc_len(qBfacet)) == 0) as i64, pass, total) 360 // now publish a canon table holding ONLY graphis.ne.jp 361 let qBcanh: *u8 = sys_mmap(64 * WC_MAXCANH) 362 var qBi: i64 = 0 363 let qBhost: *u8 = "graphis.ne.jp" as *u8 364 while qBhost[qBi] != (0 as u8) { qBcanh[qBi] = qBhost[qBi]; qBi = qBi + 1 } 365 qBcanh[qBi] = 0 as u8 366 wc_canh_g = qBcanh 367 wc_ncan_g = 1 368 wc_qscratch_g = sys_mmap(64) 369 // BISECT: which layer is failing -- the policy flag, or the canon match? 370 let t11p: i64 = olh_urlok_q(qB, wc_len(qB), 1) 371 gw_check("T11b-i policy layer: olh_urlok_q(allowq=1) admits the query-string url" as *u8, (t11p == 1) as i64, pass, total) 372 let t11m: i64 = wc_host_is_canon(qBcanh, 1, qB, wc_qscratch_g) 373 gw_check("T11b-ii matcher layer: wc_host_is_canon sees graphis.ne.jp in the table" as *u8, (t11m == 1) as i64, pass, total) 374 // R10: curation is now a BOOST, not a gate. The curated host keeps admitting its content, and the 375 // tracking url stays refused ON THE CURATED PATH TOO -- trust buys a bigger param budget, it does 376 // NOT buy immunity from junk. A curated host that could launder tracking urls into the index would 377 // make curation a liability rather than a signal. 378 var t11b: i64 = 0 379 if wc_urlok(qB, wc_len(qB)) == 1 { if wc_urlok(qBjunk, wc_len(qBjunk)) == 0 { t11b = 1 } } 380 let qBcurjunk: *u8 = "https://graphis.ne.jp/p.php?utm_source=x" as *u8 381 gw_check("T11b curated host ADMITS its content; a TRACKING url is refused on the CURATED path too" as *u8, (t11b == 1) as i64 * (wc_urlok(qBcurjunk, wc_len(qBcurjunk)) == 0) as i64, pass, total) 382 // the other kill-classes must NOT be weakened for the curated host either 383 let qBtag: *u8 = "https://graphis.ne.jp/tag/foo?ID=1" as *u8 384 let qBimg: *u8 = "https://graphis.ne.jp/i/photo.jpg" as *u8 385 var t11c: i64 = 0 386 if wc_urlok(qBtag, wc_len(qBtag)) == 0 { if wc_urlok(qBimg, wc_len(qBimg)) == 0 { t11c = 1 } } 387 gw_check("T11c curation relaxes ONLY '?' -- tag-farm and binary-extension kills still hold" as *u8, t11c, pass, total) 388 // T12 (R9): a CURATED host is never retired -- we cannot distinguish "host is down" from "we 389 // cannot speak its TLS", so retiring it would launder our own capability gap into permanent 390 // coverage loss. Uncurated rot must STILL retire (that is the control). 391 var t12: i64 = 0 392 let qCu: *u8 = "https://graphis.ne.jp/some/page" as *u8 393 let qCj: *u8 = "https://rotten.example/dead" as *u8 394 var qCcur: i64 = 0 395 var qCrot: i64 = 0 396 if wc_host_is_canon(qBcanh, 1, qCu, wc_qscratch_g) == 1 { qCcur = 1 } 397 if wc_host_is_canon(qBcanh, 1, qCj, wc_qscratch_g) == 0 { qCrot = 1 } 398 if qCcur == 1 { if qCrot == 1 { t12 = 1 } } 399 gw_check("T12 retire-exemption predicate: curated host protected, uncurated rot still retirable" as *u8, t12, pass, total) 400 wc_ncan_g = 0 401 402 gw_puts("=== crawl-step gate: " as *u8); gw_num(pass[0]); gw_puts("/" as *u8); gw_num(total[0]); gw_puts(" " as *u8) 403 if pass[0] == total[0] { gw_puts("GREEN\n" as *u8) } else { gw_puts("RED\n" as *u8) } 404 let ctr: *i64 = gv_ctr() 405 ctr[0] = pass[0] 406 ctr[1] = total[0] 407 return gv_verdict("WEB-CRAWL-STEP-GATE" as *u8, ctr, "frontier store mechanics: url filter, P-to-D state flip, cross-segment dedupe, outlink capture" as *u8) 408}