code wiki / _hdl_build / nx_docportal_search_seg_gate.nx
nx_docportal_search_seg_gate.nx source
↩ module page · 547 lines · 34726 B
1// nx_docportal_search_seg_gate.nx -- GATE for the SOVEREIGN seg_store-native onsite search (nx_docportal_search_seg).
2// Writes 3 PUBLIC docs into a test shard through the RAW sovereign store (doc:<cid> keys, text values so
3// ss_write_seg builds .terms), then drives dss_search end-to-end over the REAL seg_store -- proving the sovereign
4// path (ss_open -> ss_term postings -> ss_hget -> rank) with NO tsv anywhere. Negative controls: absent term -> 0,
5// absent shard -> 0 (isolation, not a crash). license_tier: ORIGINAL
6import "nx_docportal_search_seg.nx"
7
8// evidence-line builders (local, so this gate stays self-contained)
9func dsg_cat(b: *u8, off: i64, s: *u8) -> i64 { var o: i64 = off; var i: i64 = 0; while s[i] != (0 as u8) { b[o] = s[i]; o = o + 1; i = i + 1 } return o }
10func dsg_catn(b: *u8, off: i64, v: i64) -> i64 {
11 var m: i64 = v
12 if m < 0 { m = 0 }
13 let t: *u8 = sys_mmap(28)
14 var k: i64 = 0
15 if m == 0 { t[0] = 48 as u8; k = 1 }
16 while m > 0 { t[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 }
17 var o: i64 = off
18 var i: i64 = 0
19 while i < k { b[o] = t[k - 1 - i]; o = o + 1; i = i + 1 }
20 return o
21}
22
23func g_puts(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } sys_write(1, s, n); return 0 }
24func g_num(v: i64) -> i64 {
25 let bb: *u8 = sys_mmap(28); var m: i64 = v
26 if m < 0 { sys_write(1, "-" as *u8, 1); m = 0 - m }
27 let t: *u8 = sys_mmap(28); var k: i64 = 0
28 if m == 0 { t[0] = 48 as u8; k = 1 }
29 while m > 0 { t[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 }
30 var i: i64 = 0; while i < k { bb[i] = t[k - 1 - i]; i = i + 1 }
31 sys_write(1, bb, k); return 0
32}
33func g_strlen(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n }
34
35// one check: got n results with cids_out[0]==want_top (want_top<0 = don't care about top); expect_n<0 = don't care
36func g_check(name: *u8, got_n: i64, cids: *i64, expect_n: i64, want_top: i64, pass: *i64, total: *i64) -> i64 {
37 total[0] = total[0] + 1
38 var ok: i64 = 1
39 if expect_n >= 0 { if got_n != expect_n { ok = 0 } }
40 if want_top >= 0 { if got_n < 1 { ok = 0 } else { if cids[0] != want_top { ok = 0 } } }
41 g_puts(name); g_puts(" n="); g_num(got_n)
42 if ok == 1 { pass[0] = pass[0] + 1; g_puts(" PASS\n") } else { g_puts(" FAIL\n") }
43 return 0
44}
45
46func main(argc: i64, argv: *i64) -> i64 {
47 g_puts("=== nx_docportal_search_seg gate (SOVEREIGN seg_store search, no tsv) ===\n")
48 // --- write a test PUBLIC shard through the raw sovereign store ---
49 let prefix: *u8 = "knowledge/store/dp-ssgatetest-pub-" as *u8
50 let d1: *u8 = "Estate Planning wills living trusts probate inheritance executor" as *u8
51 let d2: *u8 = "Family Law divorce child custody support alimony parenting plans" as *u8
52 let d3: *u8 = "Business Law llc corporation formation contracts operating agreement" as *u8
53 // consent rows (same segment, deterministic re-runs): 104 opted OUT of search (pol=2 = AI_BLOG only),
54 // 105 opted IN (pol=1). 101-103 stay pol-FREE = the absent-pol default-searchable path.
55 let d4: *u8 = "Adoption confidential retainer matters" as *u8
56 let d5: *u8 = "Municipal annexation ordinance guidance" as *u8
57 let w: *i64 = ss_begin()
58 ss_add(w, 1, "doc:101" as *u8, d1, g_strlen(d1))
59 ss_add(w, 1, "doc:102" as *u8, d2, g_strlen(d2))
60 ss_add(w, 1, "doc:103" as *u8, d3, g_strlen(d3))
61 // url rows for the site: field-filter rows (103 deliberately has NO url = not site-attributable)
62 ss_add(w, 1, "url:101" as *u8, "https://en.wikipedia.org/wiki/Trust_law" as *u8, 39)
63 ss_add(w, 1, "url:102" as *u8, "https://law.example.com/family" as *u8, 30)
64 ss_add(w, 1, "doc:104" as *u8, d4, g_strlen(d4))
65 ss_add(w, 1, "pol:104" as *u8, "2" as *u8, 1)
66 ss_add(w, 1, "doc:105" as *u8, d5, g_strlen(d5))
67 ss_add(w, 1, "pol:105" as *u8, "1" as *u8, 1)
68 // IDF fixture (T9): idfrare lives in ONE doc (106); idfcommon in FOUR (107-110). Equal tf. The OLD
69 // distinct+tf scorer TIED 106 vs 107 (first candidate won = 107, postings order); only IDF ranking
70 // puts the rare-term doc on top -- this row fails on the old scorer BY CONSTRUCTION.
71 let d6: *u8 = "idfrare idfrare notice" as *u8
72 let d7: *u8 = "idfcommon idfcommon memo" as *u8
73 let d8: *u8 = "idfcommon lorem" as *u8
74 let d9: *u8 = "idfcommon ipsum" as *u8
75 let d10: *u8 = "idfcommon dolor" as *u8
76 ss_add(w, 1, "doc:106" as *u8, d6, g_strlen(d6))
77 ss_add(w, 1, "doc:107" as *u8, d7, g_strlen(d7))
78 ss_add(w, 1, "doc:108" as *u8, d8, g_strlen(d8))
79 ss_add(w, 1, "doc:109" as *u8, d9, g_strlen(d9))
80 ss_add(w, 1, "doc:110" as *u8, d10, g_strlen(d10))
81 // length-norm fixture (T14): the LONG doc (126) is inserted FIRST -- under b=0 equal tf tied and
82 // candidate order won (126); full BM25's verbosity correction must put the SHORT doc (127) on top.
83 let dlong: *u8 = sys_mmap(4096)
84 var dlo: i64 = 0
85 var lr: i64 = 0
86 while lr < 80 { let wf: *u8 = "verbose filler prose words continue onward " as *u8; var wj: i64 = 0; while wf[wj] != (0 as u8) { dlong[dlo] = wf[wj]; dlo = dlo + 1; wj = wj + 1 } lr = lr + 1 }
87 let lm: *u8 = "lennorm appears once here" as *u8
88 var lj: i64 = 0
89 while lm[lj] != (0 as u8) { dlong[dlo] = lm[lj]; dlo = dlo + 1; lj = lj + 1 }
90 let dshort: *u8 = "lennorm short focused note" as *u8
91 ss_add(w, 1, "doc:126" as *u8, dlong, dlo)
92 ss_add(w, 1, "doc:127" as *u8, dshort, g_strlen(dshort))
93 // stemming fixture (T18): a doc that only says the INFLECTED form -- query stem-expansion must recall it
94 let dstem: *u8 = "stemtoken indexing crawlers were ranking pages" as *u8
95 ss_add(w, 1, "doc:128" as *u8, dstem, g_strlen(dstem))
96 // pagination fixture (T10): 15 pgseg docs -> offset/total behavior is provable (page sizes 10/5/0)
97 let dpg: *u8 = "pgseg pagination fixture entry" as *u8
98 let pgkey: *u8 = sys_mmap(24)
99 var pgi: i64 = 111
100 while pgi <= 125 {
101 var ko: i64 = 0
102 let kp: *u8 = "doc:" as *u8
103 while kp[ko] != (0 as u8) { pgkey[ko] = kp[ko]; ko = ko + 1 }
104 pgkey[ko] = (48 + (pgi / 100)) as u8
105 pgkey[ko + 1] = (48 + ((pgi / 10) % 10)) as u8
106 pgkey[ko + 2] = (48 + (pgi % 10)) as u8
107 pgkey[ko + 3] = 0 as u8
108 ss_add(w, 1, pgkey, dpg, g_strlen(dpg))
109 pgi = pgi + 1
110 }
111 // host-diversity fixture (T22/T23): 5 docs on crowd.example.com (tf=2) + 2 on other.example.com (tf=1),
112 // all matching "diversitytest". WITHOUT the cap (webdiv=0) the 5 tf=2 crowd docs take the top 5 slots
113 // (cids[3]=304); WITH the cap (webdiv=1, DSS_HOSTCAP=3) an OTHER-host doc is promoted into slot 3
114 // (cids[3]=306) once crowd hits the cap -- distinguishing by construction (the old scorer had no cap).
115 let dcrowd: *u8 = "diversitytest diversitytest note" as *u8
116 let dother: *u8 = "diversitytest memo" as *u8
117 ss_add(w, 1, "doc:301" as *u8, dcrowd, g_strlen(dcrowd))
118 ss_add(w, 1, "url:301" as *u8, "https://crowd.example.com/1" as *u8, 27)
119 ss_add(w, 1, "doc:302" as *u8, dcrowd, g_strlen(dcrowd))
120 ss_add(w, 1, "url:302" as *u8, "https://crowd.example.com/2" as *u8, 27)
121 ss_add(w, 1, "doc:303" as *u8, dcrowd, g_strlen(dcrowd))
122 ss_add(w, 1, "url:303" as *u8, "https://crowd.example.com/3" as *u8, 27)
123 ss_add(w, 1, "doc:304" as *u8, dcrowd, g_strlen(dcrowd))
124 ss_add(w, 1, "url:304" as *u8, "https://crowd.example.com/4" as *u8, 27)
125 ss_add(w, 1, "doc:305" as *u8, dcrowd, g_strlen(dcrowd))
126 ss_add(w, 1, "url:305" as *u8, "https://crowd.example.com/5" as *u8, 27)
127 ss_add(w, 1, "doc:306" as *u8, dother, g_strlen(dother))
128 ss_add(w, 1, "url:306" as *u8, "https://other.example.com/6" as *u8, 27)
129 ss_add(w, 1, "doc:307" as *u8, dother, g_strlen(dother))
130 ss_add(w, 1, "url:307" as *u8, "https://other.example.com/7" as *u8, 27)
131 // authority fusion fixture (T28/T29): two docs identical content (equal BM25), different urls; doc 601's url
132 // carries a high pr: prior, doc 600's has none. webdiv=0 -> tie broken by candidate order (600 first);
133 // webdiv=1 -> the PageRank prior lifts 601 over 600 (distinguishing: pre-fuse, webdiv=1 also gave 600).
134 let dae: *u8 = "authorityterm equalcontent alpha" as *u8
135 let u600: *u8 = "https://plain.example/b" as *u8
136 let u601: *u8 = "https://authority.example/a" as *u8
137 ss_add(w, 1, "doc:600" as *u8, dae, g_strlen(dae))
138 ss_add(w, 1, "url:600" as *u8, u600, g_strlen(u600))
139 ss_add(w, 1, "doc:601" as *u8, dae, g_strlen(dae))
140 ss_add(w, 1, "url:601" as *u8, u601, g_strlen(u601))
141 let prk: *u8 = sys_mmap(48)
142 dss_prkey(dss_urlcid(u601, g_strlen(u601)), prk)
143 let prv: *i64 = sys_mmap(16) as *i64
144 prv[0] = 500000000
145 ss_add(w, 1, prk, prv as *u8, 8)
146 // url-dedup fixture (T30/T31): docs 700+701 = two crawl SNAPSHOTS of the SAME url (identical content ->
147 // equal BM25; distinct content cids in prod, distinct doc keys here). webdiv=1 must serve ONE.
148 let ddup: *u8 = "zqduppage snapshot content for url dedup" as *u8
149 let udup: *u8 = "https://dup.example.com/page" as *u8
150 ss_add(w, 1, "doc:700" as *u8, ddup, g_strlen(ddup))
151 ss_add(w, 1, "url:700" as *u8, udup, g_strlen(udup))
152 ss_add(w, 1, "doc:701" as *u8, ddup, g_strlen(ddup))
153 ss_add(w, 1, "url:701" as *u8, udup, g_strlen(udup))
154 // proximity fixture (T-prox, R1b): 801 (scattered) + 800 (clustered) have the SAME length + SAME tf
155 // -> IDENTICAL BM25; ONLY the proximity boost distinguishes them. 801 is indexed FIRST (so a naive
156 // tie would pick 801); the CLUSTERED 800 must win via proximity. proxterma/proxtermb/zfil* are unique.
157 let dpxs: *u8 = "proxterma zfila zfilb zfilc zfild zfile zfilf proxtermb" as *u8
158 let dpxc: *u8 = "zfilg zfilh zfili zfilj proxterma proxtermb zfilk zfill" as *u8
159 ss_add(w, 1, "doc:801" as *u8, dpxs, g_strlen(dpxs))
160 ss_add(w, 1, "doc:800" as *u8, dpxc, g_strlen(dpxc))
161 // title-field fixture (T-title, R1c): 901 (body) + 900 (title) have SAME length + SAME tf -> IDENTICAL
162 // BM25; only the title-field boost distinguishes. 901 indexed FIRST; the TITLE-match 900 must win.
163 let dttl: *u8 = "titletok aaa1 aaa2 aaa3 aaa4 aaa5 aaa6 aaa7" as *u8
164 let dbod: *u8 = "bbb1 bbb2 bbb3 bbb4 bbb5 bbb6 titletok bbb7" as *u8
165 ss_add(w, 1, "doc:901" as *u8, dbod, g_strlen(dbod))
166 ss_add(w, 1, "doc:900" as *u8, dttl, g_strlen(dttl))
167 // multilingual fixture (2026-07-23, T33-T36): Russian (Cyrillic word tokens, case-folded),
168 // Japanese (Han bigrams), Korean (Hangul bigrams) -- end-to-end through the FULL dss path
169 // (query tokenize -> postings -> BM25 tf-scan re-tokenizing the doc). Unique terms, no fixture overlap.
170 let dru: *u8 = "\xD1\x81\xD1\x83\xD0\xB4 \xD0\xBF\xD0\xBE \xD0\xBD\xD0\xB0\xD1\x81\xD0\xBB\xD0\xB5\xD0\xB4\xD1\x81\xD1\x82\xD0\xB2\xD1\x83 \xD0\xB2 \xD0\xBC\xD0\xBE\xD1\x81\xD0\xBA\xD0\xB2\xD0\xB5 \xD1\x80\xD0\xB0\xD1\x81\xD1\x81\xD0\xBC\xD0\xBE\xD1\x82\xD1\x80\xD0\xB5\xD0\xBB \xD0\xB4\xD0\xB5\xD0\xBB\xD0\xBE" as *u8
171 let dja: *u8 = "\xE6\x9D\xB1\xE4\xBA\xAC\xE5\xA4\xA7\xE5\xAD\xA6 \xE7\xA0\x94\xE7\xA9\xB6" as *u8
172 let dko: *u8 = "\xED\x95\x9C\xEA\xB5\xAD \xEA\xB2\x80\xEC\x83\x89 \xEC\x97\x94\xEC\xA7\x84 \xEA\xB0\x9C\xEB\xB0\x9C" as *u8
173 ss_add(w, 1, "doc:950" as *u8, dru, g_strlen(dru))
174 ss_add(w, 1, "doc:951" as *u8, dja, g_strlen(dja))
175 ss_add(w, 1, "doc:952" as *u8, dko, g_strlen(dko))
176 // R2b url-scope fixture (T37-T40, 2026-08-04): four docs share the term "subgadget"; only 960 lives
177 // under /r/gadgetlab on reddit. 963 = the SEGMENT-ANCHOR decoy (/r/gadgetlabmemes must NOT satisfy
178 // r/gadgetlab). 962 = the off-reddit control for inurl: (its url carries no "comments").
179 let dsr1: *u8 = "subgadget review thread alpha" as *u8
180 let dsr2: *u8 = "subgadget review thread beta" as *u8
181 let dsr3: *u8 = "subgadget review blogpost" as *u8
182 let dsr4: *u8 = "subgadget meme collection" as *u8
183 ss_add(w, 1, "doc:960" as *u8, dsr1, g_strlen(dsr1))
184 let u960: *u8 = "https://old.reddit.com/r/gadgetlab/comments/ab1/thread/" as *u8
185 ss_add(w, 1, "url:960" as *u8, u960, g_strlen(u960))
186 ss_add(w, 1, "doc:961" as *u8, dsr2, g_strlen(dsr2))
187 let u961: *u8 = "https://old.reddit.com/r/cooking/comments/cd2/thread/" as *u8
188 ss_add(w, 1, "url:961" as *u8, u961, g_strlen(u961))
189 ss_add(w, 1, "doc:962" as *u8, dsr3, g_strlen(dsr3))
190 let u962: *u8 = "https://techblog.example.com/subgadget-review" as *u8
191 ss_add(w, 1, "url:962" as *u8, u962, g_strlen(u962))
192 ss_add(w, 1, "doc:963" as *u8, dsr4, g_strlen(dsr4))
193 let u963: *u8 = "https://old.reddit.com/r/gadgetlabmemes/xyz" as *u8
194 ss_add(w, 1, "url:963" as *u8, u963, g_strlen(u963))
195 ss_commit(prefix, w, 1)
196 g_puts("wrote 40 docs (+2 pol, +7 host-crowding, +2 authority +1 pr:, +2 url-dup, +4 url-scope) -> dp-ssgatetest-pub-\n")
197
198 let pass: *i64 = sys_mmap(16) as *i64; pass[0] = 0
199 let total: *i64 = sys_mmap(16) as *i64; total[0] = 0
200 let cids: *i64 = sys_mmap(64 * 8) as *i64
201 let scores: *i64 = sys_mmap(64 * 8) as *i64
202 let dom: *u8 = "ssgatetest" as *u8
203
204 // T1: "probate" -> exactly doc 101 (only estate mentions probate)
205 let q1: *u8 = "probate" as *u8
206 let n1: i64 = dss_search(dom, q1, g_strlen(q1), cids, scores, 10)
207 g_check("T1 probate->101" as *u8, n1, cids, 1, 101, pass, total)
208
209 // T2: "divorce custody" -> doc 102 top (matches BOTH terms)
210 let q2: *u8 = "divorce custody" as *u8
211 let n2: i64 = dss_search(dom, q2, g_strlen(q2), cids, scores, 10)
212 g_check("T2 divorce+custody->102" as *u8, n2, cids, 1, 102, pass, total)
213
214 // T3: "law contracts" -> doc 103 TOP (matches law+contracts=2) above 102 (law=1). 2 candidates.
215 let q3: *u8 = "law contracts" as *u8
216 let n3: i64 = dss_search(dom, q3, g_strlen(q3), cids, scores, 10)
217 g_check("T3 law+contracts->103 top" as *u8, n3, cids, 2, 103, pass, total)
218
219 // T4: "law" -> both 102 (Family Law) and 103 (Business Law); 101 has no 'law'
220 let q4: *u8 = "law" as *u8
221 let n4: i64 = dss_search(dom, q4, g_strlen(q4), cids, scores, 10)
222 g_check("T4 law->2 docs" as *u8, n4, cids, 2, 0 - 1, pass, total)
223
224 // T5 NEG: absent term -> 0 results (no false hit)
225 let q5: *u8 = "zzznotpresentanywhere" as *u8
226 let n5: i64 = dss_search(dom, q5, g_strlen(q5), cids, scores, 10)
227 g_check("T5 NEG absent-term->0" as *u8, n5, cids, 0, 0 - 1, pass, total)
228
229 // T6 NEG (isolation): a domain with NO shard -> 0, not -2, not a crash
230 let q6: *u8 = "probate" as *u8
231 let n6: i64 = dss_search("nosuchdomain" as *u8, q6, g_strlen(q6), cids, scores, 10)
232 g_check("T6 NEG absent-shard->0" as *u8, n6, cids, 0, 0 - 1, pass, total)
233
234 // T7 NEG (owner consent): doc 104 exists in the pub shard but its pol row LACKS the search bit
235 // (pol=2 = AI_BLOG only) -> query-time consent filter EXCLUDES it (the retired tsv emitter's
236 // emission-time enforcement, now live per hit)
237 let q7: *u8 = "adoption" as *u8
238 let n7: i64 = dss_search(dom, q7, g_strlen(q7), cids, scores, 10)
239 g_check("T7 NEG consent opt-out excluded" as *u8, n7, cids, 0, 0 - 1, pass, total)
240
241 // T8 (owner consent): doc 105's pol row HAS the search bit (pol=1) -> included
242 let q8: *u8 = "annexation" as *u8
243 let n8: i64 = dss_search(dom, q8, g_strlen(q8), cids, scores, 10)
244 g_check("T8 consent opt-in included" as *u8, n8, cids, 1, 105, pass, total)
245
246 // T9 (IDF ranking): query "idfcommon idfrare" -- 5 candidates; the RARE-term doc (106) must be TOP.
247 // idf(idfrare)=log2(N/1) >> idf(idfcommon)=log2(N/4); tf equal (2 each for 106/107). The retired
248 // distinct+tf scorer tied them and candidate order picked 107 -- this row is the ranking-rung proof.
249 let q9: *u8 = "idfcommon idfrare" as *u8
250 let n9: i64 = dss_search(dom, q9, g_strlen(q9), cids, scores, 10)
251 g_check("T9 IDF: rare-term doc outranks common-term doc" as *u8, n9, cids, 5, 106, pass, total)
252
253 // T10 (pagination): 15 pgseg docs -- offset windows must return 10/5/0 with total=15 and disjoint pages
254 let qp: *u8 = "pgseg" as *u8
255 let tot: *i64 = sys_mmap(16) as *i64
256 let np0: i64 = dss_search_off(dom, qp, g_strlen(qp), cids, scores, 10, 0, tot)
257 let p0top: i64 = cids[0]
258 let np1: i64 = dss_search_off(dom, qp, g_strlen(qp), cids, scores, 10, 10, tot)
259 let p1top: i64 = cids[0]
260 let np2: i64 = dss_search_off(dom, qp, g_strlen(qp), cids, scores, 10, 20, tot)
261 var t10: i64 = 0
262 if np0 == 10 { if np1 == 5 { if np2 == 0 { if tot[0] == 15 { if p0top != p1top { t10 = 1 } } } } }
263 g_puts("T10 pagination offsets 10/5/0 total=15 disjoint")
264 total[0] = total[0] + 1
265 if t10 == 1 { pass[0] = pass[0] + 1; g_puts(" PASS\n") } else { g_puts(" FAIL\n") }
266
267 // T11 (+term AND): "law +contracts" keeps ONLY the doc that carries contracts (plain OR returned 2)
268 let q11: *u8 = "law +contracts" as *u8
269 let n11: i64 = dss_search(dom, q11, g_strlen(q11), cids, scores, 10)
270 g_check("T11 +term AND filter" as *u8, n11, cids, 1, 103, pass, total)
271
272 // T12 did-you-mean: an unknown term corrects to the closest dictionary term (probete -> probate)
273 let fix: *u8 = sys_mmap(256)
274 let fl: i64 = dss_correct(dom, "probete" as *u8, 7, fix, 255)
275 var t12: i64 = 0
276 if fl == 7 {
277 let want: *u8 = "probate" as *u8
278 var eq12: i64 = 1
279 var z12: i64 = 0
280 while z12 < 7 { if fix[z12] != want[z12] { eq12 = 0; z12 = 7 } else { z12 = z12 + 1 } }
281 t12 = eq12
282 }
283 g_puts("T12 did-you-mean probete->probate")
284 total[0] = total[0] + 1
285 if t12 == 1 { pass[0] = pass[0] + 1; g_puts(" PASS\n") } else { g_puts(" FAIL\n") }
286
287 // T13 suggest: the dictionary completes "prob" (top completion = probate)
288 let sg: *u8 = sys_mmap(8 * 64)
289 let n13: i64 = dss_suggest(dom, "prob" as *u8, 4, sg, 8)
290 var t13: i64 = 0
291 if n13 >= 1 {
292 let w13: *u8 = "probate" as *u8
293 var eq13: i64 = 1
294 var z13: i64 = 0
295 while z13 < 8 { if sg[z13] != w13[z13] { eq13 = 0; z13 = 8 } else { z13 = z13 + 1 } }
296 t13 = eq13
297 }
298 g_puts("T13 suggest prob->probate")
299 total[0] = total[0] + 1
300 if t13 == 1 { pass[0] = pass[0] + 1; g_puts(" PASS\n") } else { g_puts(" FAIL\n") }
301
302 // T14 (BM25 length norm): equal tf, wildly different lengths -- the SHORT doc must outrank the LONG
303 // one (b=0 tied them and insertion order picked the long 126; b=0.75 must pick 127)
304 let q14: *u8 = "lennorm" as *u8
305 let n14: i64 = dss_search(dom, q14, g_strlen(q14), cids, scores, 10)
306 g_check("T14 length-norm: short doc outranks verbose doc" as *u8, n14, cids, 2, 127, pass, total)
307
308 // T15/T16 PHRASE through dss: d1 carries "... living trusts ..." adjacent -- the quoted phrase
309 // matches; the REVERSED phrase must not (order-sensitive adjacency via the NXQ1 sidecar)
310 let q15: *u8 = "\"living trusts\"" as *u8
311 let n15: i64 = dss_search(dom, q15, g_strlen(q15), cids, scores, 10)
312 g_check("T15 phrase [living trusts] -> doc 101" as *u8, n15, cids, 1, 101, pass, total)
313 let q16: *u8 = "\"trusts living\"" as *u8
314 let n16: i64 = dss_search(dom, q16, g_strlen(q16), cids, scores, 10)
315 g_check("T16 NEG phrase [trusts living] -> 0" as *u8, n16, cids, 0, 0 - 1, pass, total)
316
317 // T17 (-term NOT): "law -contracts" -- OR gave both law docs; the exclusion drops the contracts one
318 let q17: *u8 = "law -contracts" as *u8
319 let n17: i64 = dss_search(dom, q17, g_strlen(q17), cids, scores, 10)
320 g_check("T17 -term exclusion (law -contracts -> 102 only)" as *u8, n17, cids, 1, 102, pass, total)
321
322 // T18b (NO ZERO-SCORE NOISE, operator-reported "julia kyoka" bug): doc 128 has "ranking" (matched via
323 // stem) but NOT "zznomatch". A 2-term query "ranking zznomatch" must return ONLY positively-scored docs;
324 // no doc may appear at score 0. Assert every returned score is > 0.
325 let qzs: *u8 = "ranking zznomatchword" as *u8
326 let nzs: i64 = dss_search(dom, qzs, g_strlen(qzs), cids, scores, 20)
327 var allpos: i64 = 1
328 var zi: i64 = 0
329 while zi < nzs { if scores[zi] <= 0 { allpos = 0 } zi = zi + 1 }
330 g_puts("T18b no zero-score results (n="); g_num(nzs); g_puts(")")
331 total[0] = total[0] + 1
332 if allpos == 1 { if nzs >= 1 { pass[0] = pass[0] + 1; g_puts(" PASS\n") } else { g_puts(" FAIL(none)\n") } } else { g_puts(" FAIL(zero-score shown)\n") }
333
334 // T18 (STEMMING recall): the doc says "indexing"/"crawlers"/"ranking"; queries for the STEM-shared
335 // forms "index"/"crawler"/"rank" must recall it via query-time dictionary stem-expansion (no index change)
336 let q18a: *u8 = "index" as *u8
337 let n18a: i64 = dss_search(dom, q18a, g_strlen(q18a), cids, scores, 10)
338 var t18: i64 = 0
339 if n18a >= 1 {
340 // 128 must be among the results (its only 'index'-family token is 'indexing')
341 var f18: i64 = 0
342 var z18: i64 = 0
343 while z18 < n18a { if cids[z18] == 128 { f18 = 1 } z18 = z18 + 1 }
344 // and a query for "crawler" must recall 128 (which only says "crawlers")
345 let n18b: i64 = dss_search(dom, "crawler" as *u8, 7, cids, scores, 10)
346 var f18b: i64 = 0
347 var z18b: i64 = 0
348 while z18b < n18b { if cids[z18b] == 128 { f18b = 1 } z18b = z18b + 1 }
349 if f18 == 1 { if f18b == 1 { t18 = 1 } }
350 }
351 g_puts("T18 stemming recall (index->indexing, crawler->crawlers)")
352 total[0] = total[0] + 1
353 if t18 == 1 { pass[0] = pass[0] + 1; g_puts(" PASS\n") } else { g_puts(" FAIL\n") }
354
355 // T19-T21 (site: FIELD FILTER, the faceted rung): "law" matches 102 (law.example.com) + 103 (no url).
356 // site:example.com keeps only 102 (dot-suffix host match; url-less 103 dropped as not site-attributable)
357 let q19: *u8 = "law site:example.com" as *u8
358 let n19: i64 = dss_search(dom, q19, g_strlen(q19), cids, scores, 10)
359 g_check("T19 site: filter (law site:example.com -> 102 only)" as *u8, n19, cids, 1, 102, pass, total)
360 // cross-host NEG: no "law" doc lives on wikipedia.org
361 let q20: *u8 = "law site:wikipedia.org" as *u8
362 let n20: i64 = dss_search(dom, q20, g_strlen(q20), cids, scores, 10)
363 g_check("T20 NEG site: cross-host (law site:wikipedia.org -> 0)" as *u8, n20, cids, 0, 0 - 1, pass, total)
364 // suffix-boundary NEG: kipedia.org must NOT match en.wikipedia.org (the '.' boundary rule)
365 let q21: *u8 = "trusts site:kipedia.org" as *u8
366 let n21: i64 = dss_search(dom, q21, g_strlen(q21), cids, scores, 10)
367 var t21b: i64 = 0
368 if n21 == 0 {
369 let q21b: *u8 = "trusts site:wikipedia.org" as *u8
370 let n21b: i64 = dss_search(dom, q21b, g_strlen(q21b), cids, scores, 10)
371 if n21b == 1 { if cids[0] == 101 { t21b = 1 } }
372 }
373 g_puts("T21 suffix boundary (kipedia.org->0, wikipedia.org->101)")
374 total[0] = total[0] + 1
375 if t21b == 1 { pass[0] = pass[0] + 1; g_puts(" PASS\n") } else { g_puts(" FAIL\n") }
376
377 // T22 (host-diversity CONTROL, webdiv=0): no cap -> the 5 tf=2 crowd-host docs fill the top 5, so the
378 // 4th result (cids[3]) is a crowd-host doc (304). Non-web scopes (site/trusted) always use this path.
379 let qd: *u8 = "diversitytest" as *u8
380 let td: *i64 = sys_mmap(16) as *i64
381 let nd0: i64 = dss_search_off_div(dom, qd, g_strlen(qd), cids, scores, 10, 0, td, 0)
382 var t22: i64 = 0
383 if nd0 == 7 { if cids[3] == 304 { t22 = 1 } }
384 g_puts("T22 host-cap CONTROL (webdiv=0: crowd fills top, cids[3]=304)")
385 total[0] = total[0] + 1
386 if t22 == 1 { pass[0] = pass[0] + 1; g_puts(" PASS\n") } else { g_puts(" FAIL cids[3]="); g_num(cids[3]); g_puts(" n="); g_num(nd0); g_puts("\n") }
387
388 // T23 (host-diversity CAP, webdiv=1): crowd host caps at DSS_HOSTCAP=3, so an OTHER-host doc (306) is
389 // promoted into slot 3 -- and ALL 7 still return (over-cap crowd docs overflow via phase B, never
390 // deleted). Fails on the old code by construction (no cap -> cids[3]=304).
391 let nd1: i64 = dss_search_off_div(dom, qd, g_strlen(qd), cids, scores, 10, 0, td, 1)
392 var t23: i64 = 0
393 if nd1 == 7 { if cids[3] == 306 { t23 = 1 } }
394 g_puts("T23 host-cap FIRES (webdiv=1: cids[3]=306, all 7 still returned)")
395 total[0] = total[0] + 1
396 if t23 == 1 { pass[0] = pass[0] + 1; g_puts(" PASS\n") } else { g_puts(" FAIL cids[3]="); g_num(cids[3]); g_puts(" n="); g_num(nd1); g_puts("\n") }
397
398 // T24 (dss_is_web predicate): only the exact "web" shard triggers the cap; site domains + "trusted" +
399 // a "web"-prefixed decoy do NOT (so a customer site named web*.com is never wrongly capped).
400 var t24: i64 = 0
401 if dss_is_web("web" as *u8) == 1 { if dss_is_web("trusted" as *u8) == 0 { if dss_is_web("andelinwest.com" as *u8) == 0 { if dss_is_web("weblog.com" as *u8) == 0 { t24 = 1 } } } }
402 g_puts("T24 dss_is_web exact-match (web=1; trusted/site/web*=0)")
403 total[0] = total[0] + 1
404 if t24 == 1 { pass[0] = pass[0] + 1; g_puts(" PASS\n") } else { g_puts(" FAIL\n") }
405
406 // T25 (dss_hosthash): same host -> same fingerprint; different host -> different; no url host -> 0.
407 let hscr2: *u8 = sys_mmap(256)
408 let hh_a: i64 = dss_hosthash("https://crowd.example.com/x" as *u8, 27, hscr2)
409 let hh_b: i64 = dss_hosthash("https://crowd.example.com/y" as *u8, 27, hscr2)
410 let hh_c: i64 = dss_hosthash("https://other.example.com/z" as *u8, 27, hscr2)
411 let hh_d: i64 = dss_hosthash("relative/path/nohost" as *u8, 20, hscr2)
412 var t25: i64 = 0
413 if hh_a == hh_b { if hh_a != hh_c { if hh_a != 0 { if hh_d == 0 { t25 = 1 } } } }
414 g_puts("T25 dss_hosthash (same-host eq, diff-host neq, no-host=0)")
415 total[0] = total[0] + 1
416 if t25 == 1 { pass[0] = pass[0] + 1; g_puts(" PASS\n") } else { g_puts(" FAIL\n") }
417
418 // T28 (P1 authority CONTROL, webdiv=0): equal-BM25 tie -> candidate order -> doc 600 first (no pr fusion)
419 let qa: *u8 = "authorityterm" as *u8
420 let ta: *i64 = sys_mmap(16) as *i64
421 let na0: i64 = dss_search_off_div(dom, qa, g_strlen(qa), cids, scores, 10, 0, ta, 0)
422 g_check("T28 authority CONTROL (webdiv=0: tie -> 600)" as *u8, na0, cids, 2, 600, pass, total)
423 // T29 (P1 authority FUSION, webdiv=1): doc 601's PageRank prior lifts it above the equal-BM25 doc 600
424 let na1: i64 = dss_search_off_div(dom, qa, g_strlen(qa), cids, scores, 10, 0, ta, 1)
425 g_check("T29 authority FUSION (webdiv=1: pr: prior -> 601 first)" as *u8, na1, cids, 2, 601, pass, total)
426
427 // T30 URL-DEDUP CONTROL (webdiv=0): both snapshots of one url serve; site/trusted stay byte-identical
428 let qd: *u8 = "zqduppage" as *u8
429 let nd0: i64 = dss_search_off_div(dom, qd, g_strlen(qd), cids, scores, 10, 0, ta, 0)
430 g_check("T30 url-dedup CONTROL (webdiv=0: both snapshots serve)" as *u8, nd0, cids, 2, 700, pass, total)
431 // T31 URL-DEDUP (webdiv=1): ONE result per url (tie -> first candidate) and totals = DISTINCT pages
432 let nd1: i64 = dss_search_off_div(dom, qd, g_strlen(qd), cids, scores, 10, 0, ta, 1)
433 var t31: i64 = 0
434 if nd1 == 1 { if cids[0] == 700 { if ta[0] == 1 { t31 = 1 } } }
435 g_puts("T31 url-dedup (webdiv=1: 1 result, cid 700, total=1)")
436 total[0] = total[0] + 1
437 if t31 == 1 { pass[0] = pass[0] + 1; g_puts(" PASS\n") } else { g_puts(" FAIL\n") }
438
439 // T-prox (R1b PROXIMITY): 800 (clustered) and 801 (scattered) carry IDENTICAL BM25 (same len+tf);
440 // the proximity boost must rank the CLUSTERED doc 800 first even though 801 was indexed first. This
441 // row FAILS by construction without the boost (tie -> indexed-first 801) and PASSES with it.
442 let qpx: *u8 = "proxterma proxtermb" as *u8
443 let npx: i64 = dss_search(dom, qpx, g_strlen(qpx), cids, scores, 10)
444 g_check("T-prox clustered 800 outranks scattered 801" as *u8, npx, cids, 2, 800, pass, total)
445
446 // T-title (R1c): 900 (query term in the TITLE) vs 901 (in the BODY), IDENTICAL BM25; the title-field
447 // boost must rank the TITLE-match doc 900 first even though 901 was indexed first.
448 let qtt: *u8 = "titletok" as *u8
449 let ntt: i64 = dss_search(dom, qtt, g_strlen(qtt), cids, scores, 10)
450 g_check("T-title: title-field match 900 outranks body match 901" as *u8, ntt, cids, 2, 900, pass, total)
451
452 // T33 RUSSIAN end-to-end: Cyrillic query term -> doc 950 (word tokens through the whole dss path)
453 let q33: *u8 = "\xD0\xBD\xD0\xB0\xD1\x81\xD0\xBB\xD0\xB5\xD0\xB4\xD1\x81\xD1\x82\xD0\xB2\xD1\x83" as *u8
454 let n33: i64 = dss_search(dom, q33, g_strlen(q33), cids, scores, 10)
455 g_check("T33 russian (nasledstvu)->950" as *u8, n33, cids, 1, 950, pass, total)
456 // T34 JAPANESE end-to-end: 4-char Han query -> overlapping bigrams -> doc 951
457 let q34: *u8 = "\xE6\x9D\xB1\xE4\xBA\xAC\xE5\xA4\xA7\xE5\xAD\xA6" as *u8
458 let n34: i64 = dss_search(dom, q34, g_strlen(q34), cids, scores, 10)
459 g_check("T34 japanese (toukyoudaigaku)->951" as *u8, n34, cids, 1, 951, pass, total)
460 // T35 KOREAN end-to-end: Hangul bigram query -> doc 952
461 let q35: *u8 = "\xEA\xB2\x80\xEC\x83\x89" as *u8
462 let n35: i64 = dss_search(dom, q35, g_strlen(q35), cids, scores, 10)
463 g_check("T35 korean (geomsaek)->952" as *u8, n35, cids, 1, 952, pass, total)
464 // T36 CYRILLIC CASE-FOLD: uppercase query MOSKVE matches the lowercase doc
465 let q36: *u8 = "\xD0\x9C\xD0\x9E\xD0\xA1\xD0\x9A\xD0\x92\xD0\x95" as *u8
466 let n36: i64 = dss_search(dom, q36, g_strlen(q36), cids, scores, 10)
467 g_check("T36 cyrillic case-fold (MOSKVE)->950" as *u8, n36, cids, 1, 950, pass, total)
468
469 // T37 SUBREDDIT idiom (R2b, 2026-08-04): "r/GadgetLab subgadget" implies site:reddit.com + a case-
470 // folded, segment-anchored /r/gadgetlab path -> ONLY 960. 961 = other sub, 962 = off-reddit, 963 =
471 // /r/gadgetlabmemes (the anchor decoy). The pre-rewrite engine returned all four ("r" died at the
472 // tokenizer's 2-char floor) -- this tooth fails without the fix BY CONSTRUCTION.
473 let q37: *u8 = "r/GadgetLab subgadget" as *u8
474 let n37: i64 = dss_search(dom, q37, g_strlen(q37), cids, scores, 10)
475 g_check("T37 r/<sub> scopes to the subreddit (960 only)" as *u8, n37, cids, 1, 960, pass, total)
476 // T38 inurl: general URL filter, ANY site: docs whose url carries "comments" = 960+961 exactly
477 let q38: *u8 = "inurl:comments subgadget" as *u8
478 let n38: i64 = dss_search(dom, q38, g_strlen(q38), cids, scores, 10)
479 g_check("T38 inurl:comments -> the two thread docs" as *u8, n38, cids, 2, 0 - 1, pass, total)
480 // T39 CONTROL: the bare term returns ALL FOUR docs -- queries without a url-scope clause are
481 // byte-identical to the pre-R2b engine (the ruler-safety claim, positively controlled)
482 let q39: *u8 = "subgadget" as *u8
483 let n39: i64 = dss_search(dom, q39, g_strlen(q39), cids, scores, 10)
484 g_check("T39 CONTROL bare term -> all 4 docs" as *u8, n39, cids, 4, 0 - 1, pass, total)
485 // T40 NEG: an unknown subreddit -> honest 0, never a silent fallback to unscoped results
486 let q40: *u8 = "r/nosuchsub subgadget" as *u8
487 let n40: i64 = dss_search(dom, q40, g_strlen(q40), cids, scores, 10)
488 g_check("T40 NEG r/nosuchsub -> 0" as *u8, n40, cids, 0, 0 - 1, pass, total)
489
490 // T41 (R2d stuffing penalty): KATs on the factored decision, pinned to the MEASURED live docs
491 // (nx_doc_lexstat 2026-08-04). bign=150000, common dcnt=40000 (blood/pressure class),
492 // rare dcnt=120 (entity name). Spam blogspot tf34/825 -> 512; real paper tf14/1226 -> 1024;
493 // a RARE name at profile density tf40/800 -> 1024 (the julia exemption); tiny doc + small
494 // corpus -> inert 1024 (why every fixture tooth above stays byte-identical).
495 var t41: i64 = 1
496 if dss_stuff_factor(34, 825, 40000, 150000) != 512 { t41 = 0 }
497 if dss_stuff_factor(14, 1226, 40000, 150000) != 1024 { t41 = 0 }
498 if dss_stuff_factor(40, 800, 120, 150000) != 1024 { t41 = 0 }
499 if dss_stuff_factor(30, 40, 40000, 150000) != 1024 { t41 = 0 }
500 if dss_stuff_factor(34, 825, 40000, 500) != 1024 { t41 = 0 }
501 total[0] = total[0] + 1
502 g_puts("T41 stuffing factor: spam 512 / real+rare+tiny+small-corpus 1024")
503 if t41 == 1 { pass[0] = pass[0] + 1; g_puts(" PASS\n") } else { g_puts(" FAIL\n") }
504
505 // T42 (R2d brand-label exemption): a dense term that IS a host label of the doc's url is the
506 // term's owner, not a stuffer -- and a substring without a boundary earns NOTHING (the fix for
507 // the 368->297 navigational regression; the measured spam domain must stay penalized).
508 let t42scr: *u8 = sys_mmap(256)
509 var t42: i64 = 1
510 let u42a: *u8 = "https://github.com/features" as *u8
511 let u42b: *u8 = "https://highbloodpressure67.blogspot.com/" as *u8
512 let u42c: *u8 = "https://www.rust-lang.org/learn" as *u8
513 if dss_host_label_match(u42a, g_strlen(u42a), "github" as *u8, t42scr) != 1 { t42 = 0 }
514 if dss_host_label_match(u42b, g_strlen(u42b), "blood" as *u8, t42scr) != 0 { t42 = 0 }
515 if dss_host_label_match(u42b, g_strlen(u42b), "pressure" as *u8, t42scr) != 0 { t42 = 0 }
516 if dss_host_label_match(u42c, g_strlen(u42c), "rust" as *u8, t42scr) != 1 { t42 = 0 }
517 if dss_host_label_match(u42a, g_strlen(u42a), "hub" as *u8, t42scr) != 0 { t42 = 0 }
518 total[0] = total[0] + 1
519 g_puts("T42 brand-label: github/rust exempt, blood/pressure/hub substrings not")
520 if t42 == 1 { pass[0] = pass[0] + 1; g_puts(" PASS\n") } else { g_puts(" FAIL\n") }
521
522 g_puts("=== dss gate: "); g_num(pass[0]); g_puts("/"); g_num(total[0]); g_puts(" ")
523
524 // EVIDENCE (2026-07-30): this gate is the SEARCH lane's only NAS-runnable witness -- 36 teeth over
525 // BM25 ranking, proximity, title-field boost and Cyrillic/CJK case-folding -- and it wrote its
526 // verdict to STDOUT ONLY, so nx_gatereg_derive could not see the lane and the maturity rollup could
527 // not grade it. Same defect that hid lab-science and the browser renderer.
528 // ★It is SAFE to publish: every tooth runs against SYNTHETIC fixture docs (800/801/900/901/950-952),
529 // never sampled production content, so no dp-*-secret / dp-*-prv material can reach this log.
530 // ★Plain verdict=GREEN|RED -- gv_is_pass accepts GREEN|PASS|VALID only, and this ecosystem has
531 // already invented four different pass-words. Do not add a fifth.
532 let lfd: i64 = sys_openat_append("knowledge/status/search_seg_gate.log\x00" as *u8, 420)
533 if lfd >= 0 {
534 let lb: *u8 = sys_mmap(256)
535 var lo: i64 = 0
536 lo = dsg_cat(lb, lo, "DSS-GATE rows=" as *u8)
537 lo = dsg_catn(lb, lo, total[0])
538 lo = dsg_cat(lb, lo, " passed=" as *u8)
539 lo = dsg_catn(lb, lo, pass[0])
540 if pass[0] == total[0] { lo = dsg_cat(lb, lo, " verdict=GREEN\n" as *u8) } else { lo = dsg_cat(lb, lo, " verdict=RED\n" as *u8) }
541 sys_write(lfd, lb, lo)
542 sys_close(lfd)
543 }
544
545 if pass[0] == total[0] { g_puts("GREEN\n"); return 0 }
546 g_puts("RED\n"); return 1
547}