code wiki / _hdl_build / nx_docportal_search_serve_snip_20260912.nx
nx_docportal_search_serve_snip_20260912.nx source
↩ module page · 1269 lines · 73291 B
1// nx_docportal_search_serve.nx -- R2: the PUBLIC /search serve handler over the SOVEREIGN seg_store search.
2// bytes-in -> bytes-out (no socket -- the gate drives it directly, like dad_handle). Parses GET /search?q=<query>,
3// runs dss_search over the domain's PUBLIC seg_store shard (NO tsv), reads each hit's text (ss_hget) and renders a
4// branded results page with Content-Length (sites.elf's buffered reverse proxy needs the length). A stale/old-
5// format shard (-2) degrades to "0 results", never a 500. license_tier: ORIGINAL
6import "nx_docportal_search_seg.nx"
7import "nx_artifact_root.nx" // ar_resolve/ar_read: the estate's ONE artifact-root resolver (CWD-independent conf lookup)
8import "nx_textcut.nx" // tc_cut_trim/tc_start: NO title ends mid-word, NO snippet begins mid-word
9import "nx_docprose.nx" // dpr_title/dpr_content_start: skip HTTP-capture headers and markup front matter
10
11// Consts for the zero-alloc numeric emitter + timespec buffer; MUST precede their first readers.
12const DSV_ASCII_0: i64 = 48
13const DSV_DEC: i64 = 10
14const DSV_TSBUF: i64 = 16
15
16const DSV_MAGIC_1000000: i64 = 1000000
17const DSV_MAGIC_1024: i64 = 1024
18const DSV_MAGIC_80000: i64 = 80000
19
20const DSV_OUTCAP: i64 = 262144
21const DSV_BODYCAP: i64 = 786432 // uniform per-request body mmap size (>= the largest body 600000); munmap'd every request to kill the leak
22const DSV_MAXR: i64 = 30 // results per page (20->30 2026-07-24: fuller SERPs; the shrunk tf-scan cap keeps it fast)
23const DSV_SNIP: i64 = 240 // chars of a hit's text to show
24// ---- caps that were BARE LITERALS at their cut sites until 2026-08-25 (rule 11). Naming them is not
25// cosmetic here: DSV_TITLE_CAP is the exact number that produced the live "...Database (RE" title, and a
26// reader who could not see it named could not connect the title defect to the snippet defect it caused.
27const DSV_TITLE_CAP: i64 = 72 // bytes of the title line shown
28const DSV_TITLE_FLOOR: i64 = 56 // degenerate fallback when a document has no titled line at all
29const DSV_SENT_MAX: i64 = 320 // hard cap on one "sentence" before dsv_best_sentence gives up looking for . ! ?
30const DSV_SNIPSCAN: i64 = 8000 // head window scanned for the best query-covering sentence
31const DSV_SENT_MIN: i64 = 40 // shortest span that can qualify as a sentence
32const DSV_SENT_MAXNL: i64 = 2 // newlines tolerated inside prose before it reads as a nav blob
33
34func dsv_slen(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n }
35func dsv_cat(out: *u8, o: i64, s: *u8) -> i64 { var i: i64 = 0; while s[i] != (0 as u8) { out[o] = s[i]; o = o + 1; i = i + 1 } return o }
36func dsv_catn(out: *u8, o: i64, v: i64) -> i64 {
37 if v == 0 { out[o] = 48 as u8; return o + 1 }
38 var m: i64 = v
39 if m < 0 { out[o] = 45 as u8; o = o + 1; m = 0 - m }
40 // MSB-FIRST: zero allocation (2026-07-31, debt 1785516350). Byte-identical output.
41 var pw: i64 = 1
42 while m / pw >= DSV_DEC { pw = pw * DSV_DEC }
43 while pw > 0 { out[o] = (DSV_ASCII_0 + ((m / pw) % DSV_DEC)) as u8; o = o + 1; pw = pw / DSV_DEC }
44 return o
45}
46// HTML-escape src[0..n) into out (defensive at the boundary: query echo + doc text are untrusted)
47func dsv_esc(out: *u8, o: i64, src: *u8, n: i64) -> i64 {
48 var i: i64 = 0
49 while i < n {
50 let c: u8 = src[i]
51 if c == (60 as u8) { o = dsv_cat(out, o, "<" as *u8) }
52 else { if c == (62 as u8) { o = dsv_cat(out, o, ">" as *u8) }
53 else { if c == (38 as u8) { o = dsv_cat(out, o, "&" as *u8) }
54 else { if c == (34 as u8) { o = dsv_cat(out, o, """ as *u8) }
55 else { out[o] = c; o = o + 1 } } } }
56 i = i + 1
57 }
58 return o
59}
60func dsv_hexval(c: u8) -> i64 {
61 if c >= (48 as u8) { if c <= (57 as u8) { return (c - (48 as u8)) as i64 } }
62 if c >= (97 as u8) { if c <= (102 as u8) { return ((c - (97 as u8)) as i64) + 10 } }
63 if c >= (65 as u8) { if c <= (70 as u8) { return ((c - (65 as u8)) as i64) + 10 } }
64 return 0 - 1
65}
66// url-decode src[0..n) -> out (cap outcap). %XX -> byte, '+' -> space. Returns out length.
67func dsv_urldecode(src: *u8, n: i64, out: *u8, outcap: i64) -> i64 {
68 var i: i64 = 0
69 var o: i64 = 0
70 while i < n {
71 if o >= outcap { return o }
72 let c: u8 = src[i]
73 if c == (37 as u8) {
74 var handled: i64 = 0
75 if i + 2 < n {
76 let hh: i64 = dsv_hexval(src[i + 1])
77 let ll: i64 = dsv_hexval(src[i + 2])
78 if hh >= 0 { if ll >= 0 { out[o] = (hh * 16 + ll) as u8; o = o + 1; i = i + 3; handled = 1 } }
79 }
80 if handled == 0 { out[o] = c; o = o + 1; i = i + 1 }
81 } else {
82 if c == (43 as u8) { out[o] = 32 as u8 } else { out[o] = c }
83 o = o + 1; i = i + 1
84 }
85 }
86 return o
87}
88// extract query param `name` (nlen chars) from the request line "M <url>?a=b&name=val HTTP/1.1". urldecoded -> out.
89// Returns value length, or 0 if absent.
90func dsv_qparam(req: *u8, req_n: i64, name: *u8, nlen: i64, out: *u8, outcap: i64) -> i64 {
91 var us: i64 = 0 - 1
92 var ue: i64 = req_n
93 var sp: i64 = 0
94 var i: i64 = 0
95 while i < req_n {
96 if req[i] == (32 as u8) {
97 if sp == 0 { us = i + 1; sp = 1 } else { if sp == 1 { ue = i; sp = 2 } }
98 }
99 i = i + 1
100 }
101 if us < 0 { return 0 }
102 var qs: i64 = 0 - 1
103 i = us
104 while i < ue { if req[i] == (63 as u8) { if qs < 0 { qs = i + 1 } } i = i + 1 }
105 if qs < 0 { return 0 }
106 var p: i64 = qs
107 while p < ue {
108 var m: i64 = 1
109 var x: i64 = 0
110 while x < nlen { if (p + x) >= ue { m = 0 } else { if req[p + x] != name[x] { m = 0 } } x = x + 1 }
111 if m == 1 { if (p + nlen) < ue { if req[p + nlen] == (61 as u8) {
112 let vs: i64 = p + nlen + 1
113 var vend: i64 = 0 - 1
114 var ve: i64 = vs
115 while ve < ue { if req[ve] == (38 as u8) { if vend < 0 { vend = ve } } ve = ve + 1 }
116 if vend < 0 { vend = ue }
117 return dsv_urldecode(((req as i64) + vs) as *u8, vend - vs, out, outcap)
118 } } }
119 var adv: i64 = 0 - 1
120 var y: i64 = p
121 while y < ue { if req[y] == (38 as u8) { if adv < 0 { adv = y + 1 } } y = y + 1 }
122 if adv < 0 { p = ue } else { p = adv }
123 }
124 return 0
125}
126// dsv_host: extract the Host header value (the domain) from an HTTP request -> the search shard is dp-<domain>-pub-.
127// Port stripped; empty if absent (search then finds no shard -> graceful "0 results"). Matches "Host:" and "host:".
128func dsv_host(req: *u8, req_n: i64, out: *u8, cap: i64) -> i64 {
129 var i: i64 = 0
130 var hs: i64 = 0 - 1
131 while i + 5 < req_n {
132 if req[i] == (10 as u8) {
133 var hmatch: i64 = 0
134 if req[i + 1] == (72 as u8) { hmatch = 1 }
135 if req[i + 1] == (104 as u8) { hmatch = 1 }
136 if hmatch == 1 { if req[i + 2] == (111 as u8) { if req[i + 3] == (115 as u8) { if req[i + 4] == (116 as u8) { if req[i + 5] == (58 as u8) { hs = i + 6 } } } } }
137 }
138 i = i + 1
139 }
140 if hs < 0 { out[0] = 0 as u8; return 0 }
141 var p: i64 = hs
142 var g1: i64 = 1
143 while g1 == 1 { if p < req_n { if req[p] == (32 as u8) { p = p + 1 } else { g1 = 0 } } else { g1 = 0 } }
144 var o: i64 = 0
145 var g2: i64 = 1
146 while g2 == 1 {
147 if p >= req_n { g2 = 0 } else {
148 let c: u8 = req[p]
149 if c == (13 as u8) { g2 = 0 } else { if c == (10 as u8) { g2 = 0 } else { if c == (58 as u8) { g2 = 0 } else {
150 if o < cap { out[o] = c; o = o + 1 }
151 p = p + 1
152 } } }
153 }
154 }
155 out[o] = 0 as u8
156 return o
157}
158// tokenize the query with the INDEX'S OWN tokenizer (mirrors dss_search's inline block) so highlight
159// decisions align exactly with what matched. termstore = 16x64 bytes; returns nterms.
160func dsv_tokq(q: *u8, qn: i64, termstore: *u8, termptrs: *i64, tbl: *u8) -> i64 {
161 var nterms: i64 = 0
162 let qpos: *i64 = sys_mmap(16) as *i64
163 qpos[0] = 0
164 let tb: *u8 = sys_mmap(64)
165 var qgo: i64 = 1
166 while qgo == 1 {
167 let l: i64 = ss_tok_next2(q, qn, qpos, tb, tbl)
168 if l < 0 { qgo = 0 } else {
169 if nterms < 16 {
170 let dst: *u8 = (termstore as i64 + nterms * 64) as *u8
171 var i: i64 = 0
172 while tb[i] != (0 as u8) { dst[i] = tb[i]; i = i + 1 }
173 dst[i] = 0 as u8
174 termptrs[nterms] = dst as i64
175 nterms = nterms + 1
176 }
177 }
178 }
179 return nterms
180}
181// escape src[0..n) into out while <b>-wrapping every token that matches a query term. Own scanner over the
182// SAME classifier table as the index tokenizer (lowercase alnum runs, len>=2, 32-char compare cap), with
183// explicit run offsets -- so highlights == matches and the raw bytes still pass through dsv_esc (XSS-safe).
184func dsv_hl(out: *u8, o: i64, src: *u8, n: i64, termptrs: *i64, nterms: i64, tbl: *u8) -> i64 {
185 let tok: *u8 = sys_mmap(40)
186 var i: i64 = 0
187 while i < n {
188 let m: i64 = tbl[src[i]] as i64
189 if m == 0 {
190 o = dsv_esc(out, o, ((src as i64) + i) as *u8, 1)
191 i = i + 1
192 } else {
193 var e: i64 = i
194 var l: i64 = 0
195 var run: i64 = 1
196 while run == 1 {
197 if e >= n { run = 0 } else {
198 let c: i64 = tbl[src[e]] as i64
199 if c == 0 { run = 0 } else {
200 if l < 32 { tok[l] = c as u8; l = l + 1 }
201 e = e + 1
202 }
203 }
204 }
205 tok[l] = 0 as u8
206 var hit: i64 = 0
207 if l >= 2 {
208 var t: i64 = 0
209 while t < nterms { if dss_streq(tok, termptrs[t] as *u8) == 1 { hit = 1 } t = t + 1 }
210 }
211 if hit == 1 { o = dsv_cat(out, o, "<b>" as *u8) }
212 o = dsv_esc(out, o, ((src as i64) + i) as *u8, e - i)
213 if hit == 1 { o = dsv_cat(out, o, "</b>" as *u8) }
214 i = e
215 }
216 }
217 return o
218}
219// url-encode src[0..n) -> out (alnum passthrough, else %XX) so a decoded query can ride a result href.
220func dsv_urlenc(out: *u8, o: i64, src: *u8, n: i64) -> i64 {
221 let hex: *u8 = "0123456789ABCDEF" as *u8
222 var i: i64 = 0
223 while i < n {
224 let c: i64 = src[i] as i64
225 var plain: i64 = 0
226 if c >= 48 { if c <= 57 { plain = 1 } }
227 if c >= 97 { if c <= 122 { plain = 1 } }
228 if c >= 65 { if c <= 90 { plain = 1 } }
229 if plain == 1 { out[o] = c as u8; o = o + 1 }
230 else {
231 out[o] = 37 as u8
232 out[o + 1] = hex[(c >> 4) & 15]
233 out[o + 2] = hex[c & 15]
234 o = o + 3
235 }
236 i = i + 1
237 }
238 return o
239}
240// build the source-url key "url:<cid>" -- an ingested SITE PAGE / crawled web page carries the page's real
241// location in this row, so its result links to the PAGE itself instead of the /doc text view.
242func dsv_mkurlkey(cid: i64, out: *u8) -> i64 {
243 out[0] = 117 as u8; out[1] = 114 as u8; out[2] = 108 as u8; out[3] = 58 as u8 // "url:"
244 var o: i64 = 4
245 if cid == 0 { out[o] = 48 as u8; o = o + 1; out[o] = 0 as u8; return o }
246 let t: *u8 = sys_mmap(24)
247 var k: i64 = 0
248 var m: i64 = cid
249 while m > 0 { t[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 }
250 var j: i64 = 0
251 while j < k { out[o] = t[k - 1 - j]; o = o + 1; j = j + 1 }
252 out[o] = 0 as u8
253 return o
254}
255// render one result: linked title + snippet, query terms <b>-highlighted. Link target: the doc's url:<cid>
256// row when present (a real page), else the /doc?cid text view (q + web scope ride the /doc link).
257// ONE process-lifetime scratch box, replacing sys_mmap-per-call. dsv_result runs once PER RESULT and the
258// old body mmap'd two 16-byte out-boxes every time; sys_mmap rounds up to a PAGE, so a 30-result SERP
259// asked the kernel for 60 pages of scratch it never released. Whether that is a leak or merely repeated
260// waste depends on this daemon's process model, so the claim made here is only the one that is certain:
261// it removes the per-call page allocations. Same defect class as the nx_ts_lumadiff c_num body.
262const DSV_BOXBYTES: i64 = 64
263static dsv_box_g: i64
264func dsv_box() -> *i64 {
265 if dsv_box_g == 0 { dsv_box_g = sys_mmap(DSV_BOXBYTES) as i64 }
266 return dsv_box_g as *i64
267}
268// slot i of a box, as a pointer an out-param can be written through
269func dsv_slot(b: *i64, i: i64) -> *i64 { return ((b as i64) + i * 8) as *i64 }
270
271// Raw source span only: HTML highlighting and JSON escaping remain at their own boundaries.
272func dsv_snippet_span(txt: *u8, tn: i64, title_end: i64, termptrs: *i64, nterms: i64, tbl: *u8, offout: *i64, lenout: *i64, cutbox: *i64) -> i64 {
273 var scanlen: i64 = tn
274 if scanlen > DSV_SNIPSCAN { scanlen = DSV_SNIPSCAN }
275 let matched: i64 = dsv_best_sentence(txt, scanlen, termptrs, nterms, tbl, offout, lenout)
276 if matched == 0 {
277 var start: i64 = tc_start(txt, tn, title_end)
278 if start >= tn { start = tc_skip_ws(txt, tn, 0) }
279 offout[0] = start
280 lenout[0] = tc_cut_trim(((txt as i64) + start) as *u8, tn - start, DSV_SNIP, cutbox)
281 }
282 return matched
283}
284
285func dsv_result(body: *u8, b: i64, txt: *u8, tn: i64, cid: i64, q: *u8, qn: i64, termptrs: *i64, nterms: i64, tbl: *u8, url: *u8, ul: i64, webscope: i64) -> i64 {
286 // ---- TITLE. WAS: "the first non-empty LINE, up to 72 bytes". That comment claimed it avoided nav
287 // chrome, and it did skip blank lines -- but it then served whatever the first line WAS, and on this
288 // corpus that is routinely an HTTP status line or a raw markup tag, because evidence-mirror captures
289 // are indexed with their wire bytes intact. It also cut at a fixed 72 bytes, mid-token.
290 // NOW: nx_docprose steps past capture headers and markup-only front matter, and nx_textcut cuts on a
291 // TOKEN boundary. That second half also repairs the SNIPPET, because the snippet fallback below starts
292 // exactly where the title ended -- one cap, two visible defects.
293 let tbox: *i64 = dsv_box()
294 var ts: i64 = 0
295 var te: i64 = 0
296 if dpr_title(txt, tn, DSV_TITLE_CAP, dsv_slot(tbox, 0), dsv_slot(tbox, 1), dsv_slot(tbox, 2)) == 1 {
297 ts = tbox[0]
298 te = ts + tbox[1]
299 } else {
300 // No titled line in the scan window. Fall back to the document head, STILL cut on a token
301 // boundary: an honest degenerate case, never a fabricated title.
302 ts = tc_skip_ws(txt, tn, 0)
303 te = ts + tc_cut_trim(((txt as i64) + ts) as *u8, tn - ts, DSV_TITLE_FLOOR, dsv_slot(tbox, 2))
304 }
305 if te <= ts { ts = 0; te = tn; if te > DSV_TITLE_FLOOR { te = DSV_TITLE_FLOOR } }
306 // semantic result: <article><h3><a> -- real structure, query terms bolded in the title
307 var o: i64 = dsv_cat(body, b, "<article class=r><h3 class=t><a href=\"" as *u8)
308 if ul > 0 {
309 o = dsv_esc(body, o, url, ul)
310 } else {
311 o = dsv_cat(body, o, "/doc?cid=" as *u8)
312 o = dsv_catn(body, o, cid)
313 if qn > 0 { o = dsv_cat(body, o, "&q=" as *u8); o = dsv_urlenc(body, o, q, qn) }
314 o = dsv_scope_link(body, o, webscope)
315 }
316 o = dsv_cat(body, o, "\">" as *u8)
317 o = dsv_hl(body, o, ((txt as i64) + ts) as *u8, te - ts, termptrs, nterms, tbl)
318 o = dsv_cat(body, o, "</a></h3>" as *u8)
319 if ul > 0 {
320 o = dsv_cat(body, o, "<div class=u>" as *u8)
321 o = dsv_esc(body, o, url, ul)
322 o = dsv_cat(body, o, "</div>" as *u8)
323 }
324 // ---- query-biased SNIPPET (the SOTA fix): show the best query-COVERING sentence (Google/Mojeek style),
325 // NOT the page's leading nav chrome. Fall back to content just past the title only when the query isn't
326 // found in prose. dsv_best_sentence already filters newline-dense nav blobs, so snippets read like content. ----
327 o = dsv_cat(body, o, "<div class=s>" as *u8)
328 let aoff: *i64 = dsv_slot(tbox, 5)
329 let alen: *i64 = dsv_slot(tbox, 6)
330 dsv_snippet_span(txt, tn, te, termptrs, nterms, tbl, aoff, alen, dsv_slot(tbox, 4))
331 o = dsv_hl(body, o, ((txt as i64) + aoff[0]) as *u8, alen[0], termptrs, nterms, tbl)
332 o = dsv_cat(body, o, "</div></article>" as *u8)
333 return o
334}
335// shared page style (search + doc views render as one system). MOBILE-FIRST by measured markers:
336// 16px inputs (iOS never auto-zooms), >=44px touch targets (button + tabs), text-size-adjust locked,
337// prefers-color-scheme dark palette, overflow-wrap on urls -- the serve gate asserts each marker.
338func dsv_style(body: *u8, b: i64) -> i64 {
339 var o: i64 = dsv_cat(body, b, "<style>html{-webkit-text-size-adjust:100%;text-size-adjust:100%}body{font-family:-apple-system,Segoe UI,sans-serif;max-width:680px;margin:3vh auto;padding:0 16px;color:#1c1c1e}header{margin:0 0 1rem}.brand{font-size:1.15rem;font-weight:700;color:#1c1c1e;text-decoration:none;letter-spacing:-.02em}.brand span{color:#0a6}form{display:flex;gap:8px}input[name=q]{flex:1;min-width:0;padding:12px;border:1px solid #ccc;border-radius:10px;font-size:16px}button{min-height:44px;padding:10px 20px;border:0;border-radius:10px;background:#0a6;color:#fff;font-size:16px}.meta{color:#666;font-size:.9rem;margin:1rem 0}.meta a{color:#0a6;text-decoration:none}.tabs{margin:.6rem 0 0}.tabs a{display:inline-block;min-height:44px;line-height:24px;color:#666;text-decoration:none;font-size:.95rem;padding:10px 14px;border-radius:8px}.tabs a.on{background:#e6f6ef;color:#064;font-weight:600}.ans{border:1px solid #bfe8d4;background:#f3fbf7;border-radius:12px;padding:14px 16px;margin:0 0 .4rem}.anstxt{font-size:1.02rem;line-height:1.5}.anssrc{color:#666;font-size:.8rem;margin-top:6px}.r{padding:.9rem 0;border-top:1px solid #eee;margin:0}.t{font-weight:600;font-size:1rem;margin:0}.t a{color:inherit;text-decoration:none}.t a:hover{text-decoration:underline;color:#0a6}.u{color:#0a6;font-size:.82rem;overflow-wrap:anywhere}.s{color:#444;font-size:.94rem}b{background:#e6f6ef}.doc{white-space:pre-wrap;line-height:1.55;overflow-wrap:anywhere}.pager{padding:1rem 0;border-top:1px solid #eee}.pager a{display:inline-block;min-height:44px;line-height:24px;padding:10px 14px;color:#0a6;text-decoration:none;font-weight:600}.credo{color:#8e8e93;font-size:.78rem;padding:1.4rem 0 2rem;border-top:1px solid #eee;margin-top:1rem}" as *u8)
340 o = dsv_cat(body, o, "@media (prefers-color-scheme:dark){body{background:#111214;color:#e8e8ea}.brand{color:#e8e8ea}input[name=q]{background:#1c1c1e;color:#e8e8ea;border-color:#3a3a3c}.s{color:#a8a8ad}.meta{color:#8e8e93}.r,.pager,.credo{border-top-color:#2c2c2e}b{background:#0f3d2e;color:#b7f0d4}.tabs a{color:#a8a8ad}.tabs a.on{background:#0f3d2e;color:#7fd4ae}.t a:hover{color:#3fbf8f}.u{color:#3fbf8f}.meta a{color:#3fbf8f}.ans{background:#12241c;border-color:#1d4a36}.anssrc{color:#8e8e93}.pager a{color:#3fbf8f}}</style>" as *u8)
341 return o
342}
343// JSON string escaper (API-first boundary: title/snippet/text are untrusted bytes -> \" \\ and controls)
344// R-UTF8 (2026-09-04): length of the VALID UTF-8 sequence starting at src[i], or 0 if the bytes there are
345// not valid UTF-8. Rejects stray continuations (0x80-0xBF), the overlong C0/C1 leads, and anything above
346// the U+10FFFF lead (0xF5+), and requires every continuation byte to be 0x80-0xBF. Bounded by n, so a
347// truncated sequence at the tail reports 0 rather than reading past the buffer.
348func dsv_u8seq(src: *u8, n: i64, i: i64) -> i64 {
349 let c: i64 = src[i] as i64
350 if c < 128 { return 1 }
351 if c < 194 { return 0 }
352 var need: i64 = 0
353 if c < 224 { need = 1 } else { if c < 240 { need = 2 } else { if c < 245 { need = 3 } else { need = 0 } } }
354 if need == 0 { return 0 }
355 if i + need > n - 1 { return 0 }
356 var ok: i64 = 1
357 var k: i64 = 1
358 while k <= need {
359 let cc: i64 = src[i + k] as i64
360 if cc < 128 { ok = 0 }
361 if cc > 191 { ok = 0 }
362 k = k + 1
363 }
364 if ok == 0 { return 0 }
365 return need + 1
366}
367func dsv_jesc(out: *u8, o: i64, src: *u8, n: i64) -> i64 {
368 let hex: *u8 = "0123456789abcdef" as *u8
369 var i: i64 = 0
370 while i < n {
371 let c: i64 = src[i] as i64
372 if c == 34 { o = dsv_cat(out, o, "\\\"" as *u8) }
373 else { if c == 92 { o = dsv_cat(out, o, "\\\\" as *u8) }
374 else { if c == 10 { o = dsv_cat(out, o, "\\n" as *u8) }
375 else { if c == 13 { o = dsv_cat(out, o, "\\r" as *u8) }
376 else { if c == 9 { o = dsv_cat(out, o, "\\t" as *u8) }
377 else { if c < 32 {
378 o = dsv_cat(out, o, "\\u00" as *u8)
379 out[o] = hex[(c >> 4) & 15]; o = o + 1
380 out[o] = hex[c & 15]; o = o + 1
381 } else {
382 // R-UTF8 (2026-09-04): EMIT ONLY VALID UTF-8. The old line copied every byte >= 32 verbatim,
383 // so raw Latin-1/CP1252 crawl bytes -- and a gzip magic header stored as a document title --
384 // went straight into a body declared `charset=utf-8`. MEASURED: 3 of 30 sampled queries could
385 // not be decoded by a standards-compliant JSON client at all. A public API must never emit a
386 // document its own Content-Type says is impossible.
387 let sl: i64 = dsv_u8seq(src, n, i)
388 if sl > 0 {
389 // already valid UTF-8 (ASCII included): copy the WHOLE sequence, never split it
390 var z: i64 = 0
391 while z < sl { out[o] = src[i + z]; o = o + 1; z = z + 1 }
392 i = i + (sl - 1)
393 } else { if c > 159 {
394 // invalid UTF-8 in the Latin-1 printable range: the crawler stored an undecoded
395 // ISO-8859-1 / CP1252 page. Transcode it, so "f\xfcr" serves as "fuer"-with-umlaut --
396 // the information is RECOVERED rather than destroyed, and the output is valid UTF-8.
397 out[o] = (192 + (c >> 6)) as u8; o = o + 1
398 out[o] = (128 + (c & 63)) as u8; o = o + 1
399 } else {
400 // a C1 control, or a byte of binary content (a gzip stream indexed as text): there is no
401 // text meaning to recover, so emit U+FFFD REPLACEMENT CHARACTER as raw UTF-8 (EF BF BD).
402 out[o] = 239 as u8; o = o + 1
403 out[o] = 191 as u8; o = o + 1
404 out[o] = 189 as u8; o = o + 1
405 } }
406 } } } } } }
407 i = i + 1
408 }
409 return o
410}
411// wrap a finished JSON body in a response with CORS (a PUBLIC read API any site/app may call)
412// wrap a JSON body + FREE it. EVERY per-request body is mmap'd at DSV_BODYCAP (uniform) so munmap of that
413// size is always exact. This eliminates the ~256-586KB/request leak that forced the daemon to recycle every
414// 5000 requests -- the ~15s respawn gap was the "takes forever" the operator hit (2026-07-03). With the leak
415// gone the daemon runs a high budget without growing RSS. rule 16/21.
416func dsv_respond_json(out: *u8, status: *u8, body: *u8, b: i64) -> i64 {
417 var o: i64 = 0
418 o = dsv_cat(out, o, "HTTP/1.1 " as *u8)
419 o = dsv_cat(out, o, status)
420 o = dsv_cat(out, o, "\r\nContent-Type: application/json; charset=utf-8\r\nAccess-Control-Allow-Origin: *\r\nCache-Control: no-store\r\nConnection: close\r\nContent-Length: " as *u8)
421 o = dsv_catn(out, o, b)
422 o = dsv_cat(out, o, "\r\n\r\n" as *u8)
423 var z: i64 = 0
424 while z < b { out[o] = body[z]; o = o + 1; z = z + 1 }
425 sys_munmap(body, DSV_BODYCAP)
426 return o
427}
428// wrap an HTML body + FREE it (Content-Length for the buffered proxy).
429func dsv_respond(out: *u8, status: *u8, body: *u8, b: i64) -> i64 {
430 var o: i64 = 0
431 o = dsv_cat(out, o, "HTTP/1.1 " as *u8)
432 o = dsv_cat(out, o, status)
433 o = dsv_cat(out, o, "\r\nContent-Type: text/html; charset=utf-8\r\nConnection: close\r\nContent-Length: " as *u8)
434 o = dsv_catn(out, o, b)
435 o = dsv_cat(out, o, "\r\n\r\n" as *u8)
436 var z: i64 = 0
437 while z < b { out[o] = body[z]; o = o + 1; z = z + 1 }
438 sys_munmap(body, DSV_BODYCAP)
439 return o
440}
441// scope resolution: THREE scopes (the operator's model 2026-07-04) -> 0 SITE (this Host domain's own shard),
442// 1 WEB (the broad crawled-everything corpus "web"), 2 TRUSTED (client-flagged good resources "trusted").
443// effdom = the resolved shard name. The return value drives the tabs + all scope-preserving links.
444// THE DEFAULT SEARCH SCOPE IS DATA, NOT A CONSTANT (rules 11 + 17). Measured 2026-08-22: the default was
445// hardcoded `var scope = 1` (WEB) on 2026-07-24 with a rationale naming nishifamily.com ONLY -- but ONE
446// daemon serves every domain, so it silently turned every CLIENT site's own search into an open-web search
447// (andelinwest.com, a law firm: /search?q=probate returned recipe blogs and auction lots, ZERO firm pages).
448// A change justified for one subject was applied to all subjects. Now sourced from search_default_scope.conf.
449const DSV_SCOPE_SITE: i64 = 0
450const DSV_SCOPE_WEB: i64 = 1
451const DSV_SCOPE_TRUSTED: i64 = 2
452const DSV_SCOPE_CONF_CAP: i64 = 4096
453const DSV_PATHCAP: i64 = 1024
454const DSV_CH_LF: i64 = 10
455const DSV_CH_CR: i64 = 13
456const DSV_CH_SP: i64 = 32
457const DSV_CH_HASH: i64 = 35
458static dsv_sc_buf: *u8
459static dsv_sc_n: i64
460static dsv_sc_loaded: i64
461// Loaded ONCE into a static (the conf is config, not per-request state): dsv_scope runs on EVERY request
462// and this file already munmaps its body buffer per request to kill a leak -- an mmap per call here would
463// reintroduce exactly that. Same static-cache shape as nx_artifact_root's own ar_buf/ar_n/ar_loaded.
464func dsv_scope_conf_load() -> i64 {
465 if dsv_sc_loaded == 1 { return dsv_sc_n }
466 dsv_sc_loaded = 1
467 dsv_sc_n = 0
468 dsv_sc_buf = sys_mmap(DSV_SCOPE_CONF_CAP)
469 let p: *u8 = sys_mmap(DSV_PATHCAP)
470 if ar_resolve("knowledge/hosting/search_default_scope.conf" as *u8, p) == 1 {
471 let rn: i64 = ar_read(p, dsv_sc_buf, DSV_SCOPE_CONF_CAP - 1)
472 if rn > 0 { dsv_sc_n = rn }
473 }
474 return dsv_sc_n
475}
476// compare a conf token against a NAMED literal -- never against character codes: a string spelled as
477// numbers is the same defect as a magic number and no grep can find it.
478func dsv_tok_eq(off: i64, len: i64, lit: *u8) -> i64 {
479 if dsv_slen(lit) != len { return 0 }
480 var i: i64 = 0
481 while i < len { if dsv_sc_buf[off+i] != lit[i] { return 0 } i = i + 1 }
482 return 1
483}
484// Rows: "<domain> <site|web|trusted>". A domain with NO row returns SITE deliberately -- the miss
485// direction fails SAFE: a site's own search searching its own site is never harmful, whereas
486// web-by-default publishes unrelated third-party content onto someone else's site.
487func dsv_default_scope(domain: *u8) -> i64 {
488 let n: i64 = dsv_scope_conf_load()
489 if n <= 0 { return DSV_SCOPE_SITE }
490 let dn: i64 = dsv_slen(domain)
491 var ls: i64 = 0
492 var i: i64 = 0
493 while i <= n {
494 var eol: i64 = 0
495 if i == n { eol = 1 } else { if dsv_sc_buf[i] == (DSV_CH_LF as u8) { eol = 1 } }
496 if eol == 1 {
497 var le: i64 = i
498 if le > ls { if dsv_sc_buf[le-1] == (DSV_CH_CR as u8) { le = le - 1 } }
499 if le > ls { if dsv_sc_buf[ls] != (DSV_CH_HASH as u8) {
500 var same: i64 = 1
501 var k: i64 = 0
502 while k < dn {
503 if ls + k >= le { same = 0; k = dn }
504 else { if dsv_sc_buf[ls+k] != domain[k] { same = 0; k = dn } else { k = k + 1 } }
505 }
506 if same == 1 {
507 let vs: i64 = ls + dn + 1
508 if vs < le { if dsv_sc_buf[ls+dn] == (DSV_CH_SP as u8) {
509 let vl: i64 = le - vs
510 if dsv_tok_eq(vs, vl, "web" as *u8) == 1 { return DSV_SCOPE_WEB }
511 if dsv_tok_eq(vs, vl, "site" as *u8) == 1 { return DSV_SCOPE_SITE }
512 if dsv_tok_eq(vs, vl, "trusted" as *u8) == 1 { return DSV_SCOPE_TRUSTED }
513 } }
514 }
515 } }
516 ls = i + 1
517 }
518 i = i + 1
519 }
520 return DSV_SCOPE_SITE
521}
522func dsv_scope(req: *u8, req_n: i64, domain: *u8, effdom: *u8) -> i64 {
523 let sc: *u8 = sys_mmap(32)
524 let sn: i64 = dsv_qparam(req, req_n, "scope" as *u8, 5, sc, 15)
525 var scope: i64 = dsv_default_scope(domain) // PER-DOMAIN default from search_default_scope.conf (2026-08-22).
526 // The hardcoded WEB default was right for nishifamily.com and WRONG for every CLIENT site
527 // this same daemon serves. Explicit ?scope= below still overrides. WAS (2026-07-24): nishifamily.com/search IS a web search engine; the site
528 // corpus + trusted are opt-in tabs. Was 0/site -> users landed on a tiny site-search and
529 // never saw the CC/entity web index or any ranking work. Explicit ?scope=site selects site.
530 if sn == 4 { if sc[0] == (115 as u8) { if sc[1] == (105 as u8) { if sc[2] == (116 as u8) { if sc[3] == (101 as u8) { scope = 0 } } } } }
531 if sn == 3 { if sc[0] == (119 as u8) { if sc[1] == (101 as u8) { if sc[2] == (98 as u8) { scope = 1 } } } }
532 if sn == 7 {
533 if sc[0] == (116 as u8) { if sc[1] == (114 as u8) { if sc[2] == (117 as u8) { if sc[3] == (115 as u8) { if sc[4] == (116 as u8) { if sc[5] == (101 as u8) { if sc[6] == (100 as u8) { scope = 2 } } } } } } }
534 }
535 if scope == 1 {
536 effdom[0] = 119 as u8; effdom[1] = 101 as u8; effdom[2] = 98 as u8; effdom[3] = 0 as u8 // "web"
537 return 1
538 }
539 if scope == 2 {
540 let tn0: *u8 = "trusted" as *u8
541 var t: i64 = 0
542 while tn0[t] != (0 as u8) { effdom[t] = tn0[t]; t = t + 1 }
543 effdom[t] = 0 as u8
544 return 2
545 }
546 var i: i64 = 0
547 while domain[i] != (0 as u8) { effdom[i] = domain[i]; i = i + 1 }
548 effdom[i] = 0 as u8
549 return 0
550}
551// append the scope-preserving query param for a link (nothing for site, &scope=web, &scope=trusted)
552func dsv_scope_link(body: *u8, b: i64, scope: i64) -> i64 {
553 if scope == 1 { return dsv_cat(body, b, "&scope=web" as *u8) }
554 if scope == 2 { return dsv_cat(body, b, "&scope=trusted" as *u8) }
555 return dsv_cat(body, b, "&scope=site" as *u8) // web is the default now -> site links MUST be explicit
556}
557// the JSON scope name (site/web/trusted)
558func dsv_scope_name(body: *u8, b: i64, scope: i64) -> i64 {
559 if scope == 1 { return dsv_cat(body, b, "web" as *u8) }
560 if scope == 2 { return dsv_cat(body, b, "trusted" as *u8) }
561 return dsv_cat(body, b, "site" as *u8)
562}
563// the scope tabs: [This site] [Trusted] [Web] -- each preserves the current query, active one highlighted
564func dsv_tabs(body: *u8, b: i64, q: *u8, qn: i64, scope: i64) -> i64 {
565 var o: i64 = dsv_cat(body, b, "<p class=tabs><a " as *u8)
566 if scope == 1 { o = dsv_cat(body, o, "class=on " as *u8) }
567 o = dsv_cat(body, o, "href=\"/search?scope=web" as *u8)
568 if qn > 0 { o = dsv_cat(body, o, "&q=" as *u8); o = dsv_urlenc(body, o, q, qn) }
569 o = dsv_cat(body, o, "\">Web</a> <a " as *u8)
570 if scope == 0 { o = dsv_cat(body, o, "class=on " as *u8) }
571 o = dsv_cat(body, o, "href=\"/search?scope=site" as *u8)
572 if qn > 0 { o = dsv_cat(body, o, "&q=" as *u8); o = dsv_urlenc(body, o, q, qn) }
573 o = dsv_cat(body, o, "\">This site</a> <a " as *u8)
574 if scope == 2 { o = dsv_cat(body, o, "class=on " as *u8) }
575 o = dsv_cat(body, o, "href=\"/search?scope=trusted" as *u8)
576 if qn > 0 { o = dsv_cat(body, o, "&q=" as *u8); o = dsv_urlenc(body, o, q, qn) }
577 o = dsv_cat(body, o, "\">Trusted</a></p>" as *u8)
578 return o
579}
580// monotonic microseconds (integer; the SERP shows real measured query latency like the big engines --
581// except ours is TRUE per-request wall time, not a cached estimate)
582func dsv_now_us() -> i64 {
583 let ts: *i64 = sys_mmap(DSV_TSBUF) as *i64
584 sys_clock_gettime_mono(ts)
585 // read BOTH fields out before releasing -- computing after the munmap would be a use-after-free.
586 let sec: i64 = ts[0]
587 let nsec: i64 = ts[1]
588 sys_munmap(ts as *u8, DSV_TSBUF)
589 return sec * DSV_MAGIC_1000000 + nsec / 1000
590}
591// FEATURED ANSWER (our own featured-snippet, extracted not asserted): scan the text's sentences
592// (. ! ? boundaries; 40..320 bytes) and return the one matching the MOST distinct query terms via the
593// index's own tokenizer. offout/lenout = the winning sentence; returns distinct terms matched (0 = none).
594func dsv_best_sentence(txt: *u8, tn: i64, termptrs: *i64, nterms: i64, tbl: *u8, offout: *i64, lenout: *i64) -> i64 {
595 let tok: *u8 = sys_mmap(40)
596 var best: i64 = 0
597 offout[0] = 0
598 lenout[0] = 0
599 var s: i64 = 0
600 while s < tn {
601 // sentence end: next . ! ? or hard cap
602 var e: i64 = s
603 var run: i64 = 1
604 while run == 1 {
605 if e >= tn { run = 0 } else {
606 let c: i64 = txt[e] as i64
607 if c == 46 { run = 0 } else { if c == 33 { run = 0 } else { if c == 63 { run = 0 } else {
608 if e - s >= DSV_SENT_MAX { run = 0 } else { e = e + 1 }
609 } } }
610 }
611 }
612 let slen: i64 = e - s
613 // PROSE filter: extracted-page nav chrome ("Jump to content\nMain menu\n...") arrives as newline-
614 // dense blobs between real periods -- a genuine sentence carries at most a stray wrap. >2 newlines
615 // = not prose, never an answer (the okapi live catch, 2026-07-03).
616 var nlcount: i64 = 0
617 var nz: i64 = s
618 while nz < e { if txt[nz] == (10 as u8) { nlcount = nlcount + 1 } nz = nz + 1 }
619 if slen >= DSV_SENT_MIN { if nlcount <= DSV_SENT_MAXNL {
620 // count distinct query terms present in [s, e)
621 var matched: i64 = 0
622 var t: i64 = 0
623 while t < nterms {
624 var hit: i64 = 0
625 var i: i64 = s
626 while i < e {
627 let m: i64 = tbl[txt[i]] as i64
628 if m == 0 { i = i + 1 } else {
629 var e2: i64 = i
630 var l: i64 = 0
631 var r2: i64 = 1
632 while r2 == 1 {
633 if e2 >= e { r2 = 0 } else {
634 let c2: i64 = tbl[txt[e2]] as i64
635 if c2 == 0 { r2 = 0 } else {
636 if l < 32 { tok[l] = c2 as u8; l = l + 1 }
637 e2 = e2 + 1
638 }
639 }
640 }
641 tok[l] = 0 as u8
642 if l >= 2 { if dss_streq(tok, termptrs[t] as *u8) == 1 { hit = 1; i = e } }
643 if i < e { i = e2 }
644 }
645 }
646 matched = matched + hit
647 t = t + 1
648 }
649 if matched > best {
650 best = matched
651 offout[0] = s
652 lenout[0] = slen
653 }
654 } }
655 s = e + 1
656 }
657 // ---- NORMALISE BOTH ENDS OF THE CHOSEN SPAN (2026-08-25). The segmentation above ends a sentence at
658 // . ! ? OR at DSV_SENT_MAX, and that second arm cuts MID-TOKEN -- so the FOLLOWING span begins mid-word.
659 // That is how a live snippet came to read "FPROP) Version 9", and another "dia, the free encyclopedia".
660 // Repairing the segmenter alone would not be enough: whichever span WINS must be sound at both ends, so
661 // it is normalised once here rather than at each of the three call sites (result snippet, featured
662 // answer, JSON api) -- one fix, and no call site can forget it.
663 if best > 0 {
664 let s0: i64 = tc_start(txt, tn, offout[0])
665 var l0: i64 = (offout[0] + lenout[0]) - s0
666 if l0 < 0 { l0 = 0 }
667 // cap = l0 measured against the REAL remaining length (tn - s0), which is what makes tc_cut walk
668 // the END back to a boundary instead of returning the span unchanged.
669 offout[0] = s0
670 lenout[0] = tc_cut_trim(((txt as i64) + s0) as *u8, tn - s0, l0, dsv_slot(dsv_box(), 3))
671 }
672 return best
673}
674// THE SERVE: (domain, request bytes) -> branded HTTP results page bytes into out. Returns out length.
675func dss_serve(domain: *u8, req: *u8, req_n: i64, out: *u8) -> i64 {
676 let t0: i64 = dsv_now_us()
677 let q: *u8 = sys_mmap(DSV_MAGIC_1024)
678 let qn: i64 = dsv_qparam(req, req_n, "q" as *u8, 1, q, 1023)
679 let effdom: *u8 = sys_mmap(256)
680 let webscope: i64 = dsv_scope(req, req_n, domain, effdom)
681 // page param (digits; junk -> page 0)
682 let pbuf: *u8 = sys_mmap(32)
683 let pbn: i64 = dsv_qparam(req, req_n, "p" as *u8, 1, pbuf, 15)
684 let pok: *i64 = sys_mmap(16) as *i64
685 var page: i64 = dsv_atoin(pbuf, pbn, pok)
686 if pok[0] == 0 { page = 0 }
687 if page > 25 { page = 25 }
688 let cids: *i64 = sys_mmap(DSV_MAXR * 8) as *i64
689 let scores: *i64 = sys_mmap(DSV_MAXR * 8) as *i64
690 let totalbox: *i64 = sys_mmap(16) as *i64
691 var nres: i64 = 0
692 if qn > 0 { nres = dss_search_off(effdom, q, qn, cids, scores, DSV_MAXR, page * DSV_MAXR, totalbox) }
693 if nres < 0 { nres = 0 }
694 let total: i64 = totalbox[0]
695 let qus: i64 = dsv_now_us() - t0
696 // INDEX-UNAVAILABLE MARKER (2026-08-22). Web scope + zero results + no/empty cached web handle => say
697 // "index unavailable" instead of "0 result(s)". nres==0 is in the predicate ON PURPOSE: dss_search_off can
698 // answer from the shared query memo without opening anything in this child, so a memo hit carries results
699 // while dsc_handle is still NULL -- a "withheld" header over a rendered list would be a lie. Site/trusted
700 // shards open per request and are not cached: 0 there means nothing published, and "0 result(s)" stays true.
701 var idxdown: i64 = 0
702 if webscope == 1 { if nres == 0 { if dss_web_index_segments() <= 0 { idxdown = 1 } } }
703 // query terms + classifier table, once per request: dsv_result highlights with the index's own tokens
704 let tbl: *u8 = sys_mmap(272)
705 ss_tok_table(tbl)
706 let termstore: *u8 = sys_mmap(16 * 64)
707 let termptrs: *i64 = sys_mmap(16 * 8) as *i64
708 var nterms: i64 = 0
709 if qn > 0 { nterms = dsv_tokq(q, qn, termstore, termptrs, tbl) }
710 let body: *u8 = sys_mmap(DSV_BODYCAP)
711 var b: i64 = 0
712 b = dsv_cat(body, b, "<!DOCTYPE html><meta charset=utf-8><meta name=viewport content=\"width=device-width,initial-scale=1\"><title>" as *u8)
713 if qn > 0 { b = dsv_esc(body, b, q, qn); b = dsv_cat(body, b, " — " as *u8) }
714 b = dsv_cat(body, b, "Nishi Search</title>" as *u8)
715 b = dsv_style(body, b)
716 b = dsv_cat(body, b, "<header><a class=brand href=\"/search\">Nishi<span>Search</span></a></header><main>" as *u8)
717 b = dsv_cat(body, b, "<form action=/search method=get role=search>" as *u8)
718 if webscope == 1 { b = dsv_cat(body, b, "<input type=hidden name=scope value=web>" as *u8) }
719 if webscope == 2 { b = dsv_cat(body, b, "<input type=hidden name=scope value=trusted>" as *u8) }
720 b = dsv_cat(body, b, "<input name=q value=\"" as *u8)
721 b = dsv_esc(body, b, q, qn)
722 b = dsv_cat(body, b, "\" placeholder=\"Search\" autofocus aria-label=\"Search query\"><button>Search</button></form>" as *u8)
723 b = dsv_tabs(body, b, q, qn, webscope)
724 if qn == 0 {
725 b = dsv_cat(body, b, "<p class=meta>Enter a search term.</p>" as *u8)
726 } else {
727 if idxdown == 1 { b = dsv_cat(body, b, "<p class=meta><b>index unavailable — results withheld</b> for “" as *u8) } else { b = dsv_cat(body, b, "<p class=meta>" as *u8); b = dsv_catn(body, b, nres); b = dsv_cat(body, b, " result(s) for “" as *u8) }
728 b = dsv_esc(body, b, q, qn); b = dsv_cat(body, b, "”" as *u8)
729 // SAY WHEN THE TOTAL IS AN ESTIMATE (2026-08-25). Once candidacy saturates at DSS_MAXCAND the
730 // total stops being an enumeration and becomes a df-derived LOWER BOUND -- and it was printed in
731 // byte-identical form to an exact count, so "of 372317 matched" read as more precise than the
732 // "of 201 matched" beside it when it was strictly less so. "about" is the whole fix: it costs five
733 // characters and it stops the page asserting a precision the engine never had.
734 if total > nres {
735 b = dsv_cat(body, b, " of " as *u8)
736 if dss_last_estimated() == 1 { b = dsv_cat(body, b, "about " as *u8) }
737 b = dsv_catn(body, b, total)
738 b = dsv_cat(body, b, " matched" as *u8)
739 }
740 if page > 0 { b = dsv_cat(body, b, " · page " as *u8); b = dsv_catn(body, b, page + 1) }
741 b = dsv_cat(body, b, " · " as *u8)
742 if qus < 1000 { b = dsv_cat(body, b, "<1" as *u8) } else { b = dsv_catn(body, b, qus / 1000) }
743 b = dsv_cat(body, b, " ms" as *u8)
744 if totalbox[1] == 0 { b = dsv_cat(body, b, " · phrase matched loosely (index upgrading)" as *u8) }
745 b = dsv_cat(body, b, "</p>" as *u8)
746 // ★COVERAGE HONESTY (operator 2026-07-04: "we dont want partial results thinking we return full
747 // results"): the web scope is NISHI'S OWN INDEX (our crawl + Common Crawl), NOT the whole live web.
748 // This line appears on EVERY web result set so N results is never mistaken for "all the web has".
749 if webscope == 1 { b = dsv_cat(body, b, "<p class=meta style=\"color:#666;font-size:.85rem\">Scope: Nishi’s own index (our crawl + Common Crawl) — not the whole live web. Some sites block all automated crawlers (anti-bot walls), so their pages may be absent here even though we never filter lawful content.</p>" as *u8) }
750 // DID-YOU-MEAN: on zero hits, offer the dictionary's closest reading of the query (typo rung)
751 if nres == 0 {
752 let fix: *u8 = sys_mmap(DSV_MAGIC_1024)
753 let fl: i64 = dss_correct(effdom, q, qn, fix, 1023)
754 if fl > 0 {
755 b = dsv_cat(body, b, "<p class=meta>Did you mean <a href=\"/search?q=" as *u8)
756 b = dsv_urlenc(body, b, fix, fl)
757 b = dsv_scope_link(body, b, webscope)
758 b = dsv_cat(body, b, "\"><b>" as *u8)
759 b = dsv_esc(body, b, fix, fl)
760 b = dsv_cat(body, b, "</b></a>?</p>" as *u8)
761 }
762 // HONEST scope empty states: our "web" is a sovereign crawl (a bounded index), NOT the live
763 // internet; "trusted" is the client-curated good-resources set (small by design).
764 if webscope == 1 { b = dsv_cat(body, b, "<p class=meta>The Web tab searches Nishi’s own sovereign crawl — a growing index of pages we’ve fetched, not the whole live internet. Try a broad topic, or search <a href=\"/search?q=" as *u8); b = dsv_urlenc(body, b, q, qn); b = dsv_cat(body, b, "\">this site</a>.</p>" as *u8) }
765 if webscope == 2 { b = dsv_cat(body, b, "<p class=meta>The Trusted tab searches resources clients have flagged as good references. Nothing matched yet — try the <a href=\"/search?scope=web&q=" as *u8); b = dsv_urlenc(body, b, q, qn); b = dsv_cat(body, b, "\">Web</a> tab.</p>" as *u8) }
766 }
767 let prefix: *u8 = sys_mmap(512); dss_prefix(effdom, prefix)
768 let h: *i64 = dss_open_maybe_cached(prefix)
769 let key: *u8 = sys_mmap(64)
770 let ukey: *u8 = sys_mmap(64)
771 let dptr: *i64 = sys_mmap(16) as *i64; let dlen: *i64 = sys_mmap(16) as *i64
772 let uptr: *i64 = sys_mmap(16) as *i64; let ulen2: *i64 = sys_mmap(16) as *i64
773 // host FACET accumulator (the faceted rung): distinct hosts among this page's results
774 let fhosts: *u8 = sys_mmap(256 * 12)
775 let fcnt: *i64 = sys_mmap(8 * 12) as *i64
776 var nfh: i64 = 0
777 let hbuf: *u8 = sys_mmap(256)
778 var i: i64 = 0
779 while i < nres {
780 dss_mkkey(cids[i], key)
781 if (h as i64) != 0 { if ss_hget(h, key, dptr, dlen) == 1 {
782 dsv_mkurlkey(cids[i], ukey)
783 var up: i64 = 0
784 var ul: i64 = 0
785 if ss_hget(h, ukey, uptr, ulen2) == 1 { up = uptr[0]; ul = ulen2[0] }
786 if ul > 0 {
787 let hl9: i64 = dss_url_host(up as *u8, ul, hbuf)
788 if hl9 > 0 {
789 var ff: i64 = 0 - 1
790 var fz: i64 = 0
791 while fz < nfh {
792 let fp9: *u8 = (fhosts as i64 + fz * 256) as *u8
793 var feq: i64 = 1
794 var fx: i64 = 0
795 var fgo: i64 = 1
796 while fgo == 1 { if fp9[fx] != hbuf[fx] { feq = 0; fgo = 0 } else { if hbuf[fx] == (0 as u8) { fgo = 0 } else { fx = fx + 1 } } }
797 if feq == 1 { ff = fz; fz = nfh } else { fz = fz + 1 }
798 }
799 if ff >= 0 { fcnt[ff] = fcnt[ff] + 1 } else { if nfh < 12 {
800 let fd9: *u8 = (fhosts as i64 + nfh * 256) as *u8
801 var fc9: i64 = 0
802 var fgo2: i64 = 1
803 while fgo2 == 1 { fd9[fc9] = hbuf[fc9]; if hbuf[fc9] == (0 as u8) { fgo2 = 0 } else { fc9 = fc9 + 1 } }
804 fcnt[nfh] = 1
805 nfh = nfh + 1
806 } }
807 }
808 }
809 // FEATURED ANSWER on the top hit of page 0: the best sentence, only when it actually
810 // covers the query (all terms, or 2+ of a multi-term query) -- extracted, never asserted
811 if i == 0 { if page == 0 {
812 let aoff: *i64 = sys_mmap(16) as *i64
813 let alen: *i64 = sys_mmap(16) as *i64
814 let am: i64 = dsv_best_sentence(dptr[0] as *u8, dlen[0], termptrs, nterms, tbl, aoff, alen)
815 var show: i64 = 0
816 if am >= nterms { if nterms > 0 { show = 1 } }
817 if nterms >= 3 { if am >= 2 { show = 1 } }
818 if show == 1 {
819 b = dsv_cat(body, b, "<div class=ans><div class=anstxt>" as *u8)
820 b = dsv_hl(body, b, ((dptr[0] as i64) + aoff[0]) as *u8, alen[0], termptrs, nterms, tbl)
821 b = dsv_cat(body, b, "</div><div class=anssrc>from the top result below</div></div>" as *u8)
822 }
823 } }
824 b = dsv_result(body, b, dptr[0] as *u8, dlen[0], cids[i], q, qn, termptrs, nterms, tbl, up as *u8, ul, webscope)
825 } }
826 i = i + 1
827 }
828 // host FACETS (zero-JS): when this page's results span 2+ sites, offer one-click site: narrowing.
829 // Skipped when the query already carries a site: clause (narrowing twice is noise).
830 var hassite: i64 = 0
831 var hz: i64 = 0
832 while hz + 5 <= qn {
833 if q[hz] == (115 as u8) { if q[hz+1] == (105 as u8) { if q[hz+2] == (116 as u8) { if q[hz+3] == (101 as u8) { if q[hz+4] == (58 as u8) { hassite = 1 } } } } }
834 hz = hz + 1
835 }
836 if nfh >= 2 { if hassite == 0 {
837 b = dsv_cat(body, b, "<p class=meta>Sites: " as *u8)
838 // top 4 hosts by count (selection)
839 let fused: *i64 = sys_mmap(8 * 12) as *i64
840 var fu: i64 = 0
841 while fu < nfh { fused[fu] = 0; fu = fu + 1 }
842 var fshown: i64 = 0
843 var frank: i64 = 0
844 while frank < 4 {
845 var fbest: i64 = 0 - 1
846 var fk: i64 = 0
847 while fk < nfh {
848 if fused[fk] == 0 { if fbest < 0 { fbest = fk } else { if fcnt[fk] > fcnt[fbest] { fbest = fk } } }
849 fk = fk + 1
850 }
851 if fbest < 0 { frank = 4 } else {
852 fused[fbest] = 1
853 let fh9: *u8 = (fhosts as i64 + fbest * 256) as *u8
854 if fshown > 0 { b = dsv_cat(body, b, " · " as *u8) }
855 b = dsv_cat(body, b, "<a href=\"/search?q=" as *u8)
856 b = dsv_urlenc(body, b, q, qn)
857 b = dsv_cat(body, b, "+site%3A" as *u8)
858 b = dsv_cat(body, b, fh9)
859 b = dsv_scope_link(body, b, webscope)
860 b = dsv_cat(body, b, "\">" as *u8)
861 b = dsv_cat(body, b, fh9)
862 b = dsv_cat(body, b, "</a> (" as *u8)
863 b = dsv_catn(body, b, fcnt[fbest])
864 b = dsv_cat(body, b, ")" as *u8)
865 fshown = fshown + 1
866 frank = frank + 1
867 }
868 }
869 b = dsv_cat(body, b, "</p>" as *u8)
870 } }
871 // pager: Prev when past page 0; Next while ranked matches remain (total is the truth)
872 if qn > 0 { if total > DSV_MAXR {
873 b = dsv_cat(body, b, "<nav class=pager>" as *u8)
874 if page > 0 {
875 b = dsv_cat(body, b, "<a href=\"/search?q=" as *u8)
876 b = dsv_urlenc(body, b, q, qn)
877 b = dsv_scope_link(body, b, webscope)
878 b = dsv_cat(body, b, "&p=" as *u8); b = dsv_catn(body, b, page - 1)
879 b = dsv_cat(body, b, "\">← Prev</a> " as *u8)
880 }
881 if (page + 1) * DSV_MAXR < total {
882 b = dsv_cat(body, b, "<a href=\"/search?q=" as *u8)
883 b = dsv_urlenc(body, b, q, qn)
884 b = dsv_scope_link(body, b, webscope)
885 b = dsv_cat(body, b, "&p=" as *u8); b = dsv_catn(body, b, page + 1)
886 b = dsv_cat(body, b, "\">Next →</a>" as *u8)
887 }
888 b = dsv_cat(body, b, "</nav>" as *u8)
889 } }
890 }
891 // the credo footer: MEASURED page facts the big engines cannot print (their SERPs ship megabytes of
892 // script and ad/tracker payloads; this page is what it says it is)
893 b = dsv_cat(body, b, "</main><footer class=credo>~" as *u8)
894 b = dsv_catn(body, b, (b + 400 + 1023) / DSV_MAGIC_1024)
895 b = dsv_cat(body, b, " KB · 0 JavaScript · 0 ads · 0 trackers · sovereign nishi search · <a href=\"/api/openapi.json\">API</a></footer></body></html>" as *u8)
896 return dsv_respond(out, "200 OK" as *u8, body, b)
897}
898
899// digits-only parse of s[0..n); okbox[0]=1 iff every byte was a digit and n>0 (defensive: a cid is ONLY digits)
900func dsv_atoin(s: *u8, n: i64, okbox: *i64) -> i64 {
901 okbox[0] = 0
902 if n <= 0 { return 0 }
903 if n > 19 { return 0 }
904 var v: i64 = 0
905 var i: i64 = 0
906 while i < n {
907 let c: i64 = s[i] as i64
908 if c < 48 { return 0 }
909 if c > 57 { return 0 }
910 v = v * 10 + (c - 48)
911 i = i + 1
912 }
913 okbox[0] = 1
914 return v
915}
916// /doc?cid=<cid>[&q=<query>] -- the PUBLIC document view that completes the search loop (result -> readable
917// doc). Serves ONLY the -pub- shard (dss_prefix); the -prv- shard is physically never opened. Visibility is
918// the owner's public/private choice at upload; the SEARCH flag governs indexing consent, not public
919// readability, so /doc serves any public doc by cid. q (if present) re-highlights + links back to results.
920func dsv_doc_serve(domain: *u8, req: *u8, req_n: i64, out: *u8) -> i64 {
921 let tbl: *u8 = sys_mmap(272)
922 ss_tok_table(tbl)
923 let q: *u8 = sys_mmap(DSV_MAGIC_1024)
924 let qn: i64 = dsv_qparam(req, req_n, "q" as *u8, 1, q, 1023)
925 let effdom: *u8 = sys_mmap(256)
926 let webscope: i64 = dsv_scope(req, req_n, domain, effdom)
927 let termstore: *u8 = sys_mmap(16 * 64)
928 let termptrs: *i64 = sys_mmap(16 * 8) as *i64
929 var nterms: i64 = 0
930 if qn > 0 { nterms = dsv_tokq(q, qn, termstore, termptrs, tbl) }
931 let cidbuf: *u8 = sys_mmap(64)
932 let cn: i64 = dsv_qparam(req, req_n, "cid" as *u8, 3, cidbuf, 31)
933 let okbox: *i64 = sys_mmap(16) as *i64
934 let cid: i64 = dsv_atoin(cidbuf, cn, okbox)
935 var found: i64 = 0
936 let dptr: *i64 = sys_mmap(16) as *i64
937 let dlen: *i64 = sys_mmap(16) as *i64
938 if okbox[0] == 1 {
939 let prefix: *u8 = sys_mmap(512); dss_prefix(effdom, prefix)
940 let h: *i64 = dss_open_maybe_cached(prefix)
941 if (h as i64) != 0 {
942 let key: *u8 = sys_mmap(64); dss_mkkey(cid, key)
943 if ss_hget(h, key, dptr, dlen) == 1 { found = 1 }
944 }
945 }
946 let body: *u8 = sys_mmap(DSV_BODYCAP)
947 var b: i64 = 0
948 b = dsv_cat(body, b, "<!DOCTYPE html><meta charset=utf-8><meta name=viewport content=\"width=device-width,initial-scale=1\"><title>Document</title>" as *u8)
949 b = dsv_style(body, b)
950 b = dsv_cat(body, b, "<p class=meta><a href=\"/search" as *u8)
951 if qn > 0 { b = dsv_cat(body, b, "?q=" as *u8); b = dsv_urlenc(body, b, q, qn) }
952 if webscope == 1 {
953 if qn > 0 { b = dsv_cat(body, b, "&scope=web" as *u8) } else { b = dsv_cat(body, b, "?scope=web" as *u8) }
954 }
955 b = dsv_cat(body, b, "\">← " as *u8)
956 if qn > 0 { b = dsv_cat(body, b, "Back to results" as *u8) } else { b = dsv_cat(body, b, "Search" as *u8) }
957 b = dsv_cat(body, b, "</a></p>" as *u8)
958 if found == 0 {
959 b = dsv_cat(body, b, "<div class=t>Document not found</div><p class=s>No public document has that id.</p></body></html>" as *u8)
960 return dsv_respond(out, "404 Not Found" as *u8, body, b)
961 }
962 let txt: *u8 = dptr[0] as *u8
963 var tn: i64 = dlen[0]
964 // bounded BY CONSTRUCTION: html-escape expands up to 6x ("""), and the daemon's out buffer is
965 // 512KB -- 80000 * 6 + page chrome stays safely inside it. Longer docs render truncated, marked.
966 var trunc: i64 = 0
967 if tn > DSV_MAGIC_80000 { tn = DSV_MAGIC_80000; trunc = 1 }
968 // title = the same leading-sentence rule the results page uses
969 var dot: i64 = 0 - 1
970 var i: i64 = 0
971 while i < tn { if i < 80 { if txt[i] == (46 as u8) { if dot < 0 { dot = i } } } i = i + 1 }
972 var tt: i64 = dot
973 if tt < 0 { tt = 56 }
974 if tt > tn { tt = tn }
975 b = dsv_cat(body, b, "<div class=t>" as *u8)
976 b = dsv_hl(body, b, txt, tt, termptrs, nterms, tbl)
977 b = dsv_cat(body, b, "</div><p class=\"s doc\">" as *u8)
978 if tt < tn { b = dsv_hl(body, b, ((txt as i64) + tt) as *u8, tn - tt, termptrs, nterms, tbl) }
979 if trunc == 1 { b = dsv_cat(body, b, " … [truncated]" as *u8) }
980 b = dsv_cat(body, b, "</p></body></html>" as *u8)
981 return dsv_respond(out, "200 OK" as *u8, body, b)
982}
983
984// ================= API-FIRST SURFACE (versioned JSON; the HTML SERP is just one client) =================
985// GET /api/openapi.json -> the machine-readable OpenAPI 3.1 contract for the search API (enterprise-grade:
986// client codegen, Swagger UI, contract testing all consume this). CORS-open like the data endpoints. The
987// spec is generated in code (SSOT = this file) so it can never drift from the handlers. `srv` = the Host
988// so the served spec names the caller's own domain in the servers[] block.
989func dss_api_openapi(srv: *u8, out: *u8) -> i64 {
990 let body: *u8 = sys_mmap(DSV_BODYCAP)
991 var b: i64 = 0
992 b = dsv_cat(body, b, "{\"openapi\":\"3.1.0\",\"info\":{\"title\":\"Nishi Search API\",\"version\":\"1.0.0\",\"description\":\"Sovereign full-text search: a domain's docs + site pages, the nishi library, and the crawled open web. Integer BM25 (b=0.75), stemmed recall, phrase/boolean queries, did-you-mean. Zero third-party dependencies.\",\"x-notes\":\"cid is a STRING: 63-bit content ids exceed JSON 2^53 safe-integer range.\"}," as *u8)
993 b = dsv_cat(body, b, "\"servers\":[{\"url\":\"https://" as *u8)
994 b = dsv_jesc(body, b, srv, dsv_slen(srv))
995 b = dsv_cat(body, b, "\"}]," as *u8)
996 b = dsv_cat(body, b, "\"paths\":{" as *u8)
997 // /api/search
998 b = dsv_cat(body, b, "\"/api/search\":{\"get\":{\"operationId\":\"search\",\"summary\":\"Ranked full-text search\",\"parameters\":[" as *u8)
999 b = dsv_cat(body, b, "{\"name\":\"q\",\"in\":\"query\",\"required\":true,\"schema\":{\"type\":\"string\"},\"description\":\"Query. Supports OR (default), +required, -excluded, \\\"quoted phrase\\\", and site:host field scoping (dot-suffix match); terms are stemmed for recall.\"}," as *u8)
1000 b = dsv_cat(body, b, "{\"name\":\"scope\",\"in\":\"query\",\"required\":false,\"schema\":{\"type\":\"string\",\"enum\":[\"web\",\"trusted\"]},\"description\":\"web = the broad crawled open-web corpus; trusted = resources clients flagged as good references; omit = this site's own corpus.\"}," as *u8)
1001 b = dsv_cat(body, b, "{\"name\":\"page\",\"in\":\"query\",\"required\":false,\"schema\":{\"type\":\"integer\",\"minimum\":0},\"description\":\"0-based results page, 20 per page.\"}]," as *u8)
1002 b = dsv_cat(body, b, "\"responses\":{\"200\":{\"description\":\"Ranked results\",\"content\":{\"application/json\":{\"schema\":{\"$ref\":\"#/components/schemas/SearchResponse\"}}}}}}}," as *u8)
1003 // /api/doc
1004 b = dsv_cat(body, b, "\"/api/doc\":{\"get\":{\"operationId\":\"getDoc\",\"summary\":\"Fetch a document by content id\",\"parameters\":[" as *u8)
1005 b = dsv_cat(body, b, "{\"name\":\"cid\",\"in\":\"query\",\"required\":true,\"schema\":{\"type\":\"string\"},\"description\":\"Decimal content id (string).\"}," as *u8)
1006 b = dsv_cat(body, b, "{\"name\":\"scope\",\"in\":\"query\",\"required\":false,\"schema\":{\"type\":\"string\",\"enum\":[\"web\"]}}]," as *u8)
1007 b = dsv_cat(body, b, "\"responses\":{\"200\":{\"description\":\"The document\",\"content\":{\"application/json\":{\"schema\":{\"$ref\":\"#/components/schemas/Doc\"}}}},\"400\":{\"description\":\"bad_cid\"},\"404\":{\"description\":\"not_found\"}}}}," as *u8)
1008 // /api/suggest
1009 b = dsv_cat(body, b, "\"/api/suggest\":{\"get\":{\"operationId\":\"suggest\",\"summary\":\"Autocomplete term completions\",\"parameters\":[" as *u8)
1010 b = dsv_cat(body, b, "{\"name\":\"q\",\"in\":\"query\",\"required\":true,\"schema\":{\"type\":\"string\"},\"description\":\"Term prefix.\"}," as *u8)
1011 b = dsv_cat(body, b, "{\"name\":\"scope\",\"in\":\"query\",\"required\":false,\"schema\":{\"type\":\"string\",\"enum\":[\"web\"]}}]," as *u8)
1012 b = dsv_cat(body, b, "\"responses\":{\"200\":{\"description\":\"Completions\",\"content\":{\"application/json\":{\"schema\":{\"$ref\":\"#/components/schemas/Suggest\"}}}}}}}" as *u8)
1013 b = dsv_cat(body, b, "}," as *u8)
1014 // components
1015 b = dsv_cat(body, b, "\"components\":{\"schemas\":{" as *u8)
1016 b = dsv_cat(body, b, "\"Result\":{\"type\":\"object\",\"properties\":{\"cid\":{\"type\":\"string\"},\"score\":{\"type\":\"integer\"},\"title\":{\"type\":\"string\"},\"snippet\":{\"type\":\"string\"},\"doc\":{\"type\":\"string\"},\"url\":{\"type\":\"string\"},\"host\":{\"type\":\"string\"}},\"required\":[\"cid\",\"score\",\"title\"]}," as *u8)
1017 b = dsv_cat(body, b, "\"SearchResponse\":{\"type\":\"object\",\"properties\":{\"v\":{\"type\":\"integer\"},\"query\":{\"type\":\"string\"},\"scope\":{\"type\":\"string\"},\"page\":{\"type\":\"integer\"},\"total\":{\"type\":\"integer\"},\"nresults\":{\"type\":\"integer\"},\"did_you_mean\":{\"type\":\"string\"},\"phrase_exact\":{\"type\":\"boolean\"},\"results\":{\"type\":\"array\",\"items\":{\"$ref\":\"#/components/schemas/Result\"}}},\"required\":[\"v\",\"nresults\",\"results\"]}," as *u8)
1018 b = dsv_cat(body, b, "\"Doc\":{\"type\":\"object\",\"properties\":{\"v\":{\"type\":\"integer\"},\"found\":{\"type\":\"boolean\"},\"cid\":{\"type\":\"string\"},\"url\":{\"type\":\"string\"},\"truncated\":{\"type\":\"boolean\"},\"text\":{\"type\":\"string\"}}}," as *u8)
1019 b = dsv_cat(body, b, "\"Suggest\":{\"type\":\"object\",\"properties\":{\"v\":{\"type\":\"integer\"},\"prefix\":{\"type\":\"string\"},\"suggestions\":{\"type\":\"array\",\"items\":{\"type\":\"string\"}}}}" as *u8)
1020 b = dsv_cat(body, b, "}}}" as *u8)
1021 return dsv_respond_json(out, "200 OK" as *u8, body, b)
1022}
1023// GET /api/search?q=<terms>[&scope=web] -> {"v":1,"query","scope","nresults","results":[{cid,score,title,
1024// snippet,doc[,url]}]}. cid is a STRING on purpose (63-bit content ids exceed JSON's 2^53 safe-integer
1025// range -- an enterprise client must never receive a silently-rounded id). No q -> a 200 self-describing
1026// usage document (the endpoint documents itself); structured errors carry machine-readable codes (rule 6).
1027func dss_api_search(domain: *u8, req: *u8, req_n: i64, out: *u8) -> i64 {
1028 let q: *u8 = sys_mmap(DSV_MAGIC_1024)
1029 let qn: i64 = dsv_qparam(req, req_n, "q" as *u8, 1, q, 1023)
1030 let effdom: *u8 = sys_mmap(256)
1031 let webscope: i64 = dsv_scope(req, req_n, domain, effdom)
1032 let body: *u8 = sys_mmap(DSV_BODYCAP)
1033 var b: i64 = 0
1034 if qn == 0 {
1035 b = dsv_cat(body, b, "{\"v\":1,\"endpoint\":\"/api/search\",\"params\":{\"q\":\"required: search terms\",\"scope\":\"optional: web = the sovereign-crawled open-web corpus; default = this site's corpus\",\"page\":\"optional: 0-based results page (20/page)\"},\"results_cap\":20,\"doc_endpoint\":\"/api/doc?cid=<cid>[&scope=web]\"}" as *u8)
1036 return dsv_respond_json(out, "200 OK" as *u8, body, b)
1037 }
1038 let pgbuf: *u8 = sys_mmap(32)
1039 let pgn: i64 = dsv_qparam(req, req_n, "page" as *u8, 4, pgbuf, 15)
1040 let pgok: *i64 = sys_mmap(16) as *i64
1041 var page: i64 = dsv_atoin(pgbuf, pgn, pgok)
1042 if pgok[0] == 0 { page = 0 }
1043 if page > 25 { page = 25 }
1044 let cids: *i64 = sys_mmap(DSV_MAXR * 8) as *i64
1045 let scores: *i64 = sys_mmap(DSV_MAXR * 8) as *i64
1046 let totalbox: *i64 = sys_mmap(16) as *i64
1047 let rc: i64 = dss_search_off(effdom, q, qn, cids, scores, DSV_MAXR, page * DSV_MAXR, totalbox)
1048 var nres: i64 = rc
1049 if nres < 0 { nres = 0 }
1050 b = dsv_cat(body, b, "{\"v\":1,\"query\":\"" as *u8)
1051 b = dsv_jesc(body, b, q, qn)
1052 b = dsv_cat(body, b, "\",\"scope\":\"" as *u8)
1053 b = dsv_scope_name(body, b, webscope)
1054 b = dsv_cat(body, b, "\",\"page\":" as *u8)
1055 b = dsv_catn(body, b, page)
1056 b = dsv_cat(body, b, ",\"total\":" as *u8)
1057 b = dsv_catn(body, b, totalbox[0])
1058 // ADDITIVE contract field (rule 19: adding is safe, renaming is not). A machine consumer had no way
1059 // to know that `total` silently changes meaning from an exact enumeration to a df-derived LOWER BOUND
1060 // once candidacy saturates -- so any client computing pagination or coverage from it was doing
1061 // arithmetic on an estimate it believed was a count.
1062 b = dsv_cat(body, b, ",\"total_is_estimate\":" as *u8)
1063 if dss_last_estimated() == 1 { b = dsv_cat(body, b, "true" as *u8) } else { b = dsv_cat(body, b, "false" as *u8) }
1064 b = dsv_cat(body, b, ",\"nresults\":" as *u8)
1065 b = dsv_catn(body, b, nres)
1066 if rc == (0 - 2) { b = dsv_cat(body, b, ",\"degraded\":true" as *u8) }
1067 if totalbox[1] != 2 {
1068 b = dsv_cat(body, b, ",\"phrase_exact\":" as *u8)
1069 if totalbox[1] == 1 { b = dsv_cat(body, b, "true" as *u8) } else { b = dsv_cat(body, b, "false" as *u8) }
1070 }
1071 if nres == 0 {
1072 let fixj: *u8 = sys_mmap(DSV_MAGIC_1024)
1073 let flj: i64 = dss_correct(effdom, q, qn, fixj, 1023)
1074 if flj > 0 {
1075 b = dsv_cat(body, b, ",\"did_you_mean\":\"" as *u8)
1076 b = dsv_jesc(body, b, fixj, flj)
1077 b = dsv_cat(body, b, "\"" as *u8)
1078 }
1079 }
1080 // COVERAGE HONESTY (operator 2026-07-04): the web scope is our own index, NOT the whole web -- the
1081 // machine-readable contract flag so a client never treats partial coverage as complete.
1082 if webscope == 1 { b = dsv_cat(body, b, ",\"coverage\":{\"index\":\"nishi\",\"complete\":false,\"note\":\"Nishi's own index (crawl + Common Crawl); not the whole live web. Some sites block all crawlers; lawful content is never filtered.\"}" as *u8) }
1083 b = dsv_cat(body, b, ",\"results\":[" as *u8)
1084 let prefix: *u8 = sys_mmap(512); dss_prefix(effdom, prefix)
1085 let h: *i64 = dss_open_maybe_cached(prefix)
1086 let key: *u8 = sys_mmap(64)
1087 let ukey: *u8 = sys_mmap(64)
1088 let dptr: *i64 = sys_mmap(16) as *i64; let dlen: *i64 = sys_mmap(16) as *i64
1089 let uptr: *i64 = sys_mmap(16) as *i64; let ulen2: *i64 = sys_mmap(16) as *i64
1090 let snip_tbl: *u8 = sys_mmap(272)
1091 ss_tok_table(snip_tbl)
1092 let snip_terms: *u8 = sys_mmap(DSS_MAXTERMS * 64)
1093 let snip_ptrs: *i64 = sys_mmap(DSS_MAXTERMS * 8) as *i64
1094 let snip_nterms: i64 = dsv_tokq(q, qn, snip_terms, snip_ptrs, snip_tbl)
1095 var emitted: i64 = 0
1096 var i: i64 = 0
1097 while i < nres {
1098 dss_mkkey(cids[i], key)
1099 if (h as i64) != 0 { if ss_hget(h, key, dptr, dlen) == 1 {
1100 if emitted > 0 { b = dsv_cat(body, b, "," as *u8) }
1101 emitted = emitted + 1
1102 let txt: *u8 = dptr[0] as *u8
1103 let dn2: i64 = dlen[0]
1104 // ONE TITLE RULER FOR THE WHOLE FILE (2026-08-25). This block derived the title as "everything
1105 // up to the first '.' within 80 bytes, else 56 bytes" -- a THIRD rule, agreeing with neither the
1106 // HTML SERP's nor anything else. MEASURED LIVE on the deployed binary: it emitted the title
1107 // "HTTP/1" (the dot inside "HTTP/1.1"), the title "<p align=..." for a markup document, and
1108 // 56-byte titles cut mid-word whose snippet then began "ain menu move to sidebar".
1109 // A FIX THAT LIVES IN ONE ORGAN AND NOT ITS SIBLING IS HALF A FIX, AND THE HALF LEFT UNDONE IS
1110 // THE ONE THAT SHIPS: the HTML path was repaired and this one went out broken in the SAME
1111 // binary, invisible to anyone not calling the JSON API. Both now share dpr_title + nx_textcut,
1112 // so the two surfaces cannot drift apart again -- there is only one of it.
1113 let abox: *i64 = dsv_box()
1114 var ats: i64 = 0
1115 var atl: i64 = 0
1116 if dpr_title(txt, dn2, DSV_TITLE_CAP, dsv_slot(abox, 0), dsv_slot(abox, 1), dsv_slot(abox, 2)) == 1 {
1117 ats = abox[0]
1118 atl = abox[1]
1119 } else {
1120 ats = tc_skip_ws(txt, dn2, 0)
1121 atl = tc_cut_trim(((txt as i64) + ats) as *u8, dn2 - ats, DSV_TITLE_FLOOR, dsv_slot(abox, 2))
1122 }
1123 dsv_snippet_span(txt, dn2, ats + atl, snip_ptrs, snip_nterms, snip_tbl, dsv_slot(abox, 5), dsv_slot(abox, 6), dsv_slot(abox, 4))
1124 let asn: i64 = abox[5]
1125 // Preserve the API's existing byte cap even when HTML selects a longer sentence.
1126 var asl: i64 = abox[6]
1127 if asl > DSV_SNIP { asl = tc_cut_trim(((txt as i64) + asn) as *u8, dn2 - asn, DSV_SNIP, dsv_slot(abox, 3)) }
1128 b = dsv_cat(body, b, "{\"cid\":\"" as *u8)
1129 b = dsv_catn(body, b, cids[i])
1130 b = dsv_cat(body, b, "\",\"score\":" as *u8)
1131 b = dsv_catn(body, b, scores[i])
1132 b = dsv_cat(body, b, ",\"title\":\"" as *u8)
1133 b = dsv_jesc(body, b, ((txt as i64) + ats) as *u8, atl)
1134 b = dsv_cat(body, b, "\",\"snippet\":\"" as *u8)
1135 b = dsv_jesc(body, b, ((txt as i64) + asn) as *u8, asl)
1136 b = dsv_cat(body, b, "\",\"doc\":\"/doc?cid=" as *u8)
1137 b = dsv_catn(body, b, cids[i])
1138 if webscope == 1 { b = dsv_cat(body, b, "&scope=web" as *u8) }
1139 b = dsv_cat(body, b, "\"" as *u8)
1140 dsv_mkurlkey(cids[i], ukey)
1141 if ss_hget(h, ukey, uptr, ulen2) == 1 {
1142 if ulen2[0] > 0 {
1143 b = dsv_cat(body, b, ",\"url\":\"" as *u8)
1144 b = dsv_jesc(body, b, uptr[0] as *u8, ulen2[0])
1145 b = dsv_cat(body, b, "\"" as *u8)
1146 // host: the site: filter/facet key, parsed from the url (additive contract field)
1147 let hostb: *u8 = sys_mmap(256)
1148 let hostl: i64 = dss_url_host(uptr[0] as *u8, ulen2[0], hostb)
1149 if hostl > 0 {
1150 b = dsv_cat(body, b, ",\"host\":\"" as *u8)
1151 b = dsv_jesc(body, b, hostb, hostl)
1152 b = dsv_cat(body, b, "\"" as *u8)
1153 }
1154 }
1155 }
1156 b = dsv_cat(body, b, "}" as *u8)
1157 } }
1158 i = i + 1
1159 }
1160 b = dsv_cat(body, b, "]" as *u8)
1161 // INDEX STATE (2026-08-22, ADDITIVE, rule 19). Unconditional on purpose (coverage above is web-only and an
1162 // abstain signal absent where it matters is no signal). segments = h[0] of the handle THIS response rendered
1163 // from (web: the parent-cached one; site/trusted: this request's own open) -- MEASURED per scope. state: ok(>0)
1164 // | unavailable(web,0 = OUTAGE, never no-results) | empty(site/trusted,0 = nothing published, not an outage)
1165 // | unopened(-1). A stale memo hit can ship as ok for <= one refresh window. HTTP status UNCHANGED on purpose:
1166 // a 503 reads as daemon-down to every health probe (the amplifying failure). Body only.
1167 var iseg: i64 = 0 - 1
1168 if (h as i64) != 0 { iseg = h[0] }
1169 b = dsv_cat(body, b, ",\"index\":{\"segments\":" as *u8)
1170 b = dsv_catn(body, b, iseg)
1171 b = dsv_cat(body, b, ",\"state\":\"" as *u8)
1172 if iseg > 0 { b = dsv_cat(body, b, "ok" as *u8) }
1173 if iseg == 0 { if webscope == 1 { b = dsv_cat(body, b, "unavailable" as *u8) } else { b = dsv_cat(body, b, "empty" as *u8) } }
1174 if iseg < 0 { b = dsv_cat(body, b, "unopened" as *u8) }
1175 b = dsv_cat(body, b, "\"}}" as *u8)
1176 return dsv_respond_json(out, "200 OK" as *u8, body, b)
1177}
1178// GET /api/suggest?q=<prefix>[&scope=web] -> ranked completions from the index's OWN term dictionary
1179// (API-first autocomplete: apps/clients wire the keystroke loop; the HTML SERP stays zero-JS by design)
1180func dss_api_suggest(domain: *u8, req: *u8, req_n: i64, out: *u8) -> i64 {
1181 let q: *u8 = sys_mmap(256)
1182 let qn: i64 = dsv_qparam(req, req_n, "q" as *u8, 1, q, 63)
1183 let effdom: *u8 = sys_mmap(256)
1184 let webscope: i64 = dsv_scope(req, req_n, domain, effdom)
1185 let body: *u8 = sys_mmap(DSV_BODYCAP)
1186 var b: i64 = 0
1187 if qn == 0 {
1188 b = dsv_cat(body, b, "{\"v\":1,\"endpoint\":\"/api/suggest\",\"params\":{\"q\":\"required: term prefix\",\"scope\":\"optional: web\"},\"max\":8}" as *u8)
1189 return dsv_respond_json(out, "200 OK" as *u8, body, b)
1190 }
1191 // normalize the prefix with the index's own classifier (lowercase alnum)
1192 let tbl: *u8 = sys_mmap(272)
1193 ss_tok_table(tbl)
1194 let pfx: *u8 = sys_mmap(64)
1195 var pn: i64 = 0
1196 var i: i64 = 0
1197 while i < qn { if pn < 32 { let m: i64 = tbl[q[i]] as i64; if m != 0 { pfx[pn] = m as u8; pn = pn + 1 } } i = i + 1 }
1198 let sg: *u8 = sys_mmap(8 * 64)
1199 var n: i64 = 0
1200 if pn >= 1 { n = dss_suggest(effdom, pfx, pn, sg, 8) }
1201 b = dsv_cat(body, b, "{\"v\":1,\"prefix\":\"" as *u8)
1202 b = dsv_jesc(body, b, pfx, pn)
1203 b = dsv_cat(body, b, "\",\"scope\":\"" as *u8)
1204 b = dsv_scope_name(body, b, webscope)
1205 b = dsv_cat(body, b, "\",\"suggestions\":[" as *u8)
1206 var k: i64 = 0
1207 while k < n {
1208 if k > 0 { b = dsv_cat(body, b, "," as *u8) }
1209 b = dsv_cat(body, b, "\"" as *u8)
1210 let sp: *u8 = (sg as i64 + k * 64) as *u8
1211 var sl: i64 = 0
1212 while sp[sl] != (0 as u8) { sl = sl + 1 }
1213 b = dsv_jesc(body, b, sp, sl)
1214 b = dsv_cat(body, b, "\"" as *u8)
1215 k = k + 1
1216 }
1217 b = dsv_cat(body, b, "]}" as *u8)
1218 return dsv_respond_json(out, "200 OK" as *u8, body, b)
1219}
1220// GET /api/doc?cid=<cid>[&scope=web] -> the full public document as JSON (text bounded like the HTML view)
1221func dss_api_doc(domain: *u8, req: *u8, req_n: i64, out: *u8) -> i64 {
1222 let effdom: *u8 = sys_mmap(256)
1223 let webscope: i64 = dsv_scope(req, req_n, domain, effdom)
1224 let cidbuf: *u8 = sys_mmap(64)
1225 let cn: i64 = dsv_qparam(req, req_n, "cid" as *u8, 3, cidbuf, 31)
1226 let okbox: *i64 = sys_mmap(16) as *i64
1227 let cid: i64 = dsv_atoin(cidbuf, cn, okbox)
1228 let body: *u8 = sys_mmap(DSV_BODYCAP)
1229 var b: i64 = 0
1230 if okbox[0] == 0 {
1231 b = dsv_cat(body, b, "{\"v\":1,\"error\":{\"code\":\"bad_cid\",\"message\":\"cid must be a decimal content id\"}}" as *u8)
1232 return dsv_respond_json(out, "400 Bad Request" as *u8, body, b)
1233 }
1234 let dptr: *i64 = sys_mmap(16) as *i64
1235 let dlen: *i64 = sys_mmap(16) as *i64
1236 var found: i64 = 0
1237 let prefix: *u8 = sys_mmap(512); dss_prefix(effdom, prefix)
1238 let h: *i64 = dss_open_maybe_cached(prefix)
1239 let key: *u8 = sys_mmap(64)
1240 if (h as i64) != 0 {
1241 dss_mkkey(cid, key)
1242 if ss_hget(h, key, dptr, dlen) == 1 { found = 1 }
1243 }
1244 if found == 0 {
1245 b = dsv_cat(body, b, "{\"v\":1,\"error\":{\"code\":\"not_found\",\"message\":\"no public document with that cid\"}}" as *u8)
1246 return dsv_respond_json(out, "404 Not Found" as *u8, body, b)
1247 }
1248 var tn: i64 = dlen[0]
1249 var trunc: i64 = 0
1250 if tn > DSV_MAGIC_80000 { tn = DSV_MAGIC_80000; trunc = 1 }
1251 b = dsv_cat(body, b, "{\"v\":1,\"found\":true,\"cid\":\"" as *u8)
1252 b = dsv_catn(body, b, cid)
1253 b = dsv_cat(body, b, "\",\"scope\":\"" as *u8)
1254 b = dsv_scope_name(body, b, webscope)
1255 b = dsv_cat(body, b, "\",\"truncated\":" as *u8)
1256 if trunc == 1 { b = dsv_cat(body, b, "true" as *u8) } else { b = dsv_cat(body, b, "false" as *u8) }
1257 let ukey: *u8 = sys_mmap(64)
1258 let uptr: *i64 = sys_mmap(16) as *i64; let ulen2: *i64 = sys_mmap(16) as *i64
1259 dsv_mkurlkey(cid, ukey)
1260 if ss_hget(h, ukey, uptr, ulen2) == 1 {
1261 b = dsv_cat(body, b, ",\"url\":\"" as *u8)
1262 b = dsv_jesc(body, b, uptr[0] as *u8, ulen2[0])
1263 b = dsv_cat(body, b, "\"" as *u8)
1264 }
1265 b = dsv_cat(body, b, ",\"text\":\"" as *u8)
1266 b = dsv_jesc(body, b, dptr[0] as *u8, tn)
1267 b = dsv_cat(body, b, "\"}" as *u8)
1268 return dsv_respond_json(out, "200 OK" as *u8, body, b)
1269}