nx_research_answer.nx source
↩ module page · 115 lines · 5872 B
1// nx_research_answer.nx -- GROUNDED, CITED research-answer primitive: "research that cannot hallucinate."
2// The product face of the verification stack. Given a question's answer-pattern and a source URL, it FETCHES the
3// source itself over sovereign TLS-1.3, extracts the PHRASE that follows the pattern (up to a natural delimiter),
4// and returns a grounded answer WITH provenance -- or UNVERIFIABLE if the pattern is absent (it NEVER invents an
5// answer). Unlike hosted answer engines that can fabricate, this returns only what the cited source actually says.
6// usage: nx_research_answer <url> <answer_pattern> [maxlen] (run from a dir with data/mozilla_certdata.txt)
7// e.g.: nx_research_answer https://arxiv.org/abs/1606.05250 "human performance (" -> ANSWER: 86.8 [grounded]
8// license_tier: ORIGINAL expect_exit: 0
9import "nx_syscalls.nx"
10import "nx_itoa_lib.nx" // shared MSB-first emitter (zero-alloc)
11import "nx_x509_trust_store.nx"
12import "nx_trust_store_load_from_certdata.nx"
13import "nx_https_fetch_follow.nx"
14const K_MAGIC_4194304: i64 = 4194304
15const K_MAGIC_2000: i64 = 2000
16
17func ra_puts(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } sys_write(1, s, n); return 0 }
18// MIGRATED to the shared emitter (debt 1785563586). The old body mmapped a scratch buffer
19// per call and never freed it. At PAGE granularity that is 4096B leaked PER CALL -- the
20// defect that took 28.5GB of a 36GB host in nx_ts_lumadiff (2MB input, ~3.66M calls).
21// nxi_* is MSB-first, allocates NOTHING, and emits identical bytes including the sign.
22func ra_putn(v: i64) -> i64 { nxi_out(v); return 0 }
23func ra_slen(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n }
24func ra_int(s: *u8) -> i64 { var v: i64=0; var i: i64=0; while s[i] != (0 as u8) { let c: i64=s[i] as i64; if c>=48 { if c<=57 { v=v*10+(c-48) } } i=i+1 } return v }
25
26func ra_find_after(buf: *u8, blen: i64, pat: *u8) -> i64 {
27 let pl: i64 = ra_slen(pat)
28 if pl == 0 { return 0-1 }
29 var i: i64 = 0
30 while i + pl <= blen {
31 var k: i64 = 0
32 var ok: i64 = 1
33 while k < pl { if ok == 1 { if buf[i+k] != pat[k] { ok = 0 } } k = k + 1 }
34 if ok == 1 { return i + pl }
35 i = i + 1
36 }
37 return 0-1
38}
39// is byte c a natural answer-ending delimiter? . , ) ; < newline tab
40func ra_isdelim(c: i64) -> i64 {
41 if c == 46 { return 1 }
42 if c == 44 { return 1 }
43 if c == 41 { return 1 }
44 if c == 59 { return 1 }
45 if c == 60 { return 1 }
46 if c == 10 { return 1 }
47 if c == 9 { return 1 }
48 if c == 37 { return 1 } // '%' (numbers like 86.8% -> "86.8")
49 return 0
50}
51
52func main(argc: i64, argv: *i64) -> i64 {
53 if argc < 3 { ra_puts("usage: nx_research_answer <url> <answer_pattern> [maxlen]\n" as *u8); return 1 }
54 let url: *u8 = argv[1] as *u8
55 let pat: *u8 = argv[2] as *u8
56 var maxlen: i64 = 80
57 if argc >= 4 { let m: i64 = ra_int(argv[3] as *u8); if m > 0 { maxlen = m } }
58 if maxlen > 240 { maxlen = 240 }
59
60 let ts: i64 = nx_trust_store_load_from_certdata("data/mozilla_certdata.txt\x00" as *u8, 512, K_MAGIC_4194304)
61 if ts <= 0 { ra_puts("{\"grounded\":false,\"reason\":\"certdata load failed\"}\n" as *u8); return 2 }
62 let store: *TrustStore = ts as *TrustStore
63 let out: *u8 = sys_mmap(K_MAGIC_4194304)
64 let status: *i64 = sys_mmap(8) as *i64
65 var n: i64 = nx_https_fetch_follow_best(url, store, out, K_MAGIC_4194304, 6, status)
66 if n <= 0 { sys_sleep_ms(K_MAGIC_2000); n = nx_https_fetch_follow_best(url, store, out, K_MAGIC_4194304, 6, status) }
67 var http: i64 = 0
68 if n > 0 { http = status[0] }
69 var fetch_ok: i64 = 0
70 if n > 0 { if http < 400 { fetch_ok = 1 } }
71
72 if fetch_ok == 0 {
73 ra_puts("{\"source\":\"" as *u8); ra_puts(url); ra_puts("\",\"http_status\":" as *u8); ra_putn(http)
74 ra_puts(",\"grounded\":false,\"answer\":null,\"verdict\":\"FETCH-FAILED\"}\n" as *u8)
75 return 3
76 }
77
78 let at: i64 = ra_find_after(out, n, pat)
79 if at < 0 {
80 ra_puts("{\"source\":\"" as *u8); ra_puts(url); ra_puts("\",\"http_status\":" as *u8); ra_putn(http)
81 ra_puts(",\"grounded\":false,\"answer\":null,\"verdict\":\"UNVERIFIABLE\"}\n" as *u8) // pattern absent -> NO hallucinated answer
82 return 4
83 }
84
85 // extract the phrase after the pattern: skip a leading space, copy until a delimiter or maxlen.
86 let ans: *u8 = sys_mmap(256)
87 var i: i64 = at
88 if i < n { if (out[i] as i64) == 32 { i = i + 1 } } // trim one leading space
89 var w: i64 = 0
90 var go: i64 = 1
91 while go == 1 { // advance while in-bounds, under maxlen, and not at a delimiter
92 go = 0
93 if i < n { if w < maxlen {
94 let c: i64 = out[i] as i64
95 var isd: i64 = ra_isdelim(c)
96 if c == 46 { // '.' is a DECIMAL point (keep) if the next char is a digit, else a sentence end (stop)
97 if i+1 < n { let d: i64 = out[i+1] as i64; if d >= 48 { if d <= 57 { isd = 0 } } }
98 }
99 if isd == 0 { ans[w] = out[i]; w = w + 1; i = i + 1; go = 1 }
100 } }
101 }
102 ans[w] = 0 as u8
103 // trim a trailing space if any
104 if w > 0 { if (ans[w-1] as i64) == 32 { ans[w-1] = 0 as u8; w = w - 1 } }
105
106 var grounded: i64 = 0
107 if w > 0 { grounded = 1 }
108 ra_puts("{\"source\":\"" as *u8); ra_puts(url); ra_puts("\",\"http_status\":" as *u8); ra_putn(http)
109 ra_puts(",\"pattern\":\"" as *u8); ra_puts(pat); ra_puts("\",\"answer\":" as *u8)
110 if grounded == 1 { ra_puts("\"" as *u8); ra_puts(ans); ra_puts("\"" as *u8) } else { ra_puts("null" as *u8) }
111 ra_puts(",\"grounded\":" as *u8)
112 if grounded == 1 { ra_puts("true,\"verdict\":\"GROUNDED\"}\n" as *u8) } else { ra_puts("false,\"verdict\":\"UNVERIFIABLE\"}\n" as *u8) }
113 if grounded == 1 { return 0 }
114 return 4
115}