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, "&lt;" as *u8) } 52 else { if c == (62 as u8) { o = dsv_cat(out, o, "&gt;" as *u8) } 53 else { if c == (38 as u8) { o = dsv_cat(out, o, "&amp;" as *u8) } 54 else { if c == (34 as u8) { o = dsv_cat(out, o, "&quot;" 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, " &mdash; " 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 &mdash; results withheld</b> for &ldquo;" 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 &ldquo;" as *u8) } 728 b = dsv_esc(body, b, q, qn); b = dsv_cat(body, b, "&rdquo;" 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, " &middot; page " as *u8); b = dsv_catn(body, b, page + 1) } 741 b = dsv_cat(body, b, " &middot; " as *u8) 742 if qus < 1000 { b = dsv_cat(body, b, "&lt;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, " &middot; 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&rsquo;s own index (our crawl + Common Crawl) &mdash; 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&rsquo;s own sovereign crawl &mdash; a growing index of pages we&rsquo;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 &mdash; 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, " &middot; " 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, "\">&larr; 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 &rarr;</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 &middot; 0 JavaScript &middot; 0 ads &middot; 0 trackers &middot; sovereign nishi search &middot; <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, "\">&larr; " 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 ("&quot;"), 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, " &hellip; [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}