code wiki / _hdl_build / nx_wiki_answer.nx
nx_wiki_answer.nx
buildroot/runtime/_hdl_build/nx_wiki_answer.nx
about
nx_wiki_answer.nx -- THE INSTANT-ANSWER organ for the live 12-page wiki corpus (IMS Thrust B rung 1).
answer(query) returns THE ANSWER -- a direct snippet + its source page -- in ONE step, NOT a results list.
This is the operator's "<10s / 1-click answer" surface: type a question, get the passage that answers it
with a source link, no second click into a SERP.
FLOW (compose proven engines, ZERO ranking/snippet math reinvented):
1. registry-driven site lookup (site=wiki -> idx + manifest + base_url) over the committed onsite registry
knowledge/index/onsite_sites.tsv -- the SAME data-driven model nx_onsite_search uses (per-site isolation
by construction: the wiki index file physically cannot return another site's docs).
2. nx_inv_load (nx_search_inverted_persist) -> the durable inverted index; parse the manifest into
url/title(=slug)/body slices (docid = line), EXACTLY as nx_onsite_search does.
3. BM25F top page: shortlist via nx_inv_query_term, score every candidate with bmf_score (nx_bm25f --
title-field=slug boost + body), pick top-1. Title hits (the slug) outrank body hits.
4. best answer passage from that top page via nx_search_snippet_extract (densest-cluster window picker
below) + <mark> highlight over the query terms.
5. threshold gate: if the top-1 BM25F score (x1e6) does NOT exceed wiki_answer_min_score (READ from the
params.tsv ledger -- no magic number, rule 11) -> WA_NO_ANSWER. We REFUSE rather than fabricate.
REUSE: nx_search_inverted_persist (nx_inv_load + nx_inv_query_term), nx_bm25f (bmf_score/bm_token_count),
nx_search_snippet_extract (nx_search_snippet_extract + NxSearchQuery via nx_search_query_parser), nx_syscalls.
Library organ (no main when imported by the gate; the self-test main below makes it runnable standalone).
ADDITIVE-ONLY: reads index+manifest+params; writes nothing. license_tier: ORIGINAL
dependencies 3 imports · 2 importers
imports: nx_search_inverted_persist.nxnx_bm25f.nxnx_search_snippet_extract.nx
imported by: nx_wiki_answer_gate.nxnx_wiki_search_page.nx
call flow from main pre-order; caps 40 nodes / depth 6 declared; ↻ = already shown
structs
| 56 | struct WaAnswer |
consts
| 26 | const WA_MAGIC_1000000: i64 = 1000000 |
| 27 | const WA_MAGIC_10000: i64 = 10000 |
| 30 | const WA_OK: i64 = 0 |
| 31 | const WA_NO_ANSWER: i64 = 5200 // top-1 below threshold OR no candidate matched -> refuse (no fabrication) |
| 32 | const WA_BAD_INPUT: i64 = 5201 |
| 33 | const WA_NO_REGISTRY: i64 = 5202 // onsite registry missing / site row absent |
| 34 | const WA_NO_INDEX: i64 = 5203 // index or manifest missing / stale pair |
| 35 | const WA_QUERY_FAIL: i64 = 5204 // query parse failed |
| 38 | const WA_REG_PATH: *u8 = "knowledge/index/onsite_sites.tsv" // committed production onsite registry |
| 39 | const WA_PARAMS_PATH: *u8 = "knowledge/registry/params.tsv" // measured-parameters ledger |
| 40 | const WA_PARAM_NAME: *u8 = "wiki_answer_min_score" // the NO_ANSWER floor (BM25F x1e6) |
| 41 | const WA_MIN_FALLBACK: i64 = 100000 // used ONLY if the params row is unreadable |
| 42 | const WA_SITE: *u8 = "wiki" |
| 43 | const WA_ROWID_CAP: i64 = 16384 // matches NX_INV_MAX_POSTINGS_PER |
| 44 | const WA_MAX_TERMS: i64 = 16 // query terms considered for BM25F (parser caps at 32) |
| 45 | const WA_SNIP_CAP: i64 = 2048 // snippet output buffer (>= NX_SSE_DEFAULT_OUTPUT_CAP) |
| 46 | const WA_TERMS_CAP: i64 = 1024 // NxSearchQuery terms buffer (NX_SQP_TERMS_BUF_MIN_CAP) |
| 47 | const WA_SLUG_CAP: i64 = 256 |
| 48 | const WA_DENSE_WIN: i64 = 240 // densest-cluster scan window (bytes) for the answer passage |
functions
| 65 | func wa_strlen(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n } |
| 66 | func wa_streq(a: *u8, b: *u8) -> i64 { var i: i64 = 0; while a[i] != (0 as u8) { if a[i] != b[i] { return 0 } i = i + 1 } if b[i] != (0 as u8) { return 0 } return 1 } called by 1: wa_lookup_site |
| 67 | func wa_fold(s: *u8, n: i64) -> i64 { var i: i64 = 0; while i < n { let c: i64 = s[i] as i64; if c >= 65 { if c <= 90 { s[i] = (c + 32) as u8 } } i = i + 1 } return 0 } called by 1: answer_ex |
| 71 | func wa_lookup_site(reg: *u8, n: i64, site: *u8, out_idx: *i64, out_mf: *i64, out_base: *i64) -> i64 |
| 108 | func wa_read_threshold() -> i64 |
| 157 | func wa_best_window(body: *u8, blen: i64, qterms: *i64, qlens: *i64, nq: i64) -> i64 called by 1: answer_ex |
| 191 | func answer_ex(reg_path: *u8, site: *u8, query: *u8, out: *WaAnswer) -> i64 called by 1: answer calls 13: wa_strlensys_read_filewa_lookup_sitenx_inv_loadnx_inv_is_token_charnx_inv_query_term+7 |
| 379 | func answer(query: *u8, out: *WaAnswer) -> i64 |
| 384 | func wa_new() -> *WaAnswer |
| 395 | func wa_verdict_name(v: i64) -> *u8 |
| 407 | func wa_puts(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } sys_write(1, s, n); return 0 } |
| 408 | func wa_pscore(v: i64) -> i64 called by 1: wa_demo |
| 420 | func wa_demo(query: *u8) -> i64 |
| 432 | func main() -> i64 |