nx_research_verify.nx source
↩ module page · 176 lines · 9471 B
1// nx_research_verify.nx -- the RESEARCH-VERIFICATION STAGE: batch, autonomous, sovereign claim verification.
2// Upgrades the researcher from "fetch + extract" to "fetch + extract + VERIFY against the cited source" -- the
3// SOTA research behavior. Reads a claims TSV (a researcher's findings), FETCHES each cited source itself over the
4// sovereign TLS-1.3 stack, extracts the real value, and banks a verdict ledger + a summary. Composes the proven
5// single-claim primitive (nx_claim_verify) over a batch; the anti-gaming discipline made a pipeline stage:
6// every claim is CONFIRMED/DISCREDITED against real fetched evidence, or UNVERIFIABLE (never fabricated).
7//
8// INPUT (argv[1] or default knowledge/index/rv_claims.tsv): lines of label<TAB>url<TAB>pattern<TAB>claim_tenths<TAB>tol_tenths
9// OUTPUT knowledge/index/rv_verified.tsv: label<TAB>source<TAB>extracted<TAB>claim<TAB>verdict + a stdout summary.
10// license_tier: ORIGINAL expect_exit: 0
11import "nx_syscalls.nx"
12import "nx_itoa_lib.nx" // shared MSB-first emitter (zero-alloc)
13import "nx_x509_trust_store.nx"
14import "nx_trust_store_load_from_certdata.nx"
15import "nx_https_fetch_follow.nx"
16const K_MAGIC_262144: i64 = 262144
17const K_MAGIC_4194304: i64 = 4194304
18const K_MAGIC_1024: i64 = 1024
19const K_MAGIC_1500: i64 = 1500
20
21func rv_puts(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } sys_write(1, s, n); return 0 }
22// MIGRATED to the shared emitter (debt 1785563586). The old body mmapped a scratch buffer
23// per call and never freed it. At PAGE granularity that is 4096B leaked PER CALL -- the
24// defect that took 28.5GB of a 36GB host in nx_ts_lumadiff (2MB input, ~3.66M calls).
25// nxi_* is MSB-first, allocates NOTHING, and emits identical bytes including the sign.
26func rv_putn(v: i64) -> i64 { nxi_out(v); return 0 }
27func rv_slen(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n }
28func rv_iabs(x: i64) -> i64 { if x < 0 { return 0-x } return x }
29
30// find pat in buf[0..blen); index just AFTER the match, or -1.
31func rv_find_after(buf: *u8, blen: i64, pat: *u8, patlen: i64) -> i64 {
32 if patlen == 0 { return 0-1 }
33 var i: i64 = 0
34 while i + patlen <= blen {
35 var k: i64 = 0
36 var ok: i64 = 1
37 while k < patlen { if ok == 1 { if buf[i+k] != pat[k] { ok = 0 } } k = k + 1 }
38 if ok == 1 { return i + patlen }
39 i = i + 1
40 }
41 return 0-1
42}
43// parse decimal at buf[off..] as TENTHS ("86.8"->868); -1 if no digit.
44func rv_parse_tenths(buf: *u8, blen: i64, off: i64) -> i64 {
45 if off < 0 { return 0-1 }
46 var i: i64 = off
47 var whole: i64 = 0
48 var any: i64 = 0
49 var go: i64 = 1
50 while go == 1 {
51 go = 0
52 if i < blen { let c: i64 = buf[i] as i64
53 if c >= 48 { if c <= 57 { whole = whole*10 + (c-48); any = 1; i = i + 1; go = 1 } } }
54 }
55 if any == 0 { return 0-1 }
56 var tenths: i64 = whole * 10
57 if i < blen { if (buf[i] as i64) == 46 {
58 if i+1 < blen { let d: i64 = buf[i+1] as i64
59 if d >= 48 { if d <= 57 { tenths = tenths + (d-48) } } } } }
60 return tenths
61}
62func rv_int(s: *u8, n: i64) -> i64 { // parse an unsigned int from s[0..n)
63 var v: i64 = 0; var i: i64 = 0
64 while i < n { let c: i64 = s[i] as i64; if c >= 48 { if c <= 57 { v = v*10 + (c-48) } } i = i + 1 }
65 return v
66}
67
68func main(argc: i64, argv: *i64) -> i64 {
69 var inpath: *u8 = "knowledge/index/rv_claims.tsv\x00" as *u8
70 if argc >= 2 { inpath = argv[1] as *u8 }
71
72 // load the claims file
73 let ifd: i64 = sys_openat_rd(inpath)
74 if ifd < 0 { rv_puts("nx_research_verify: cannot open claims file\n" as *u8); return 1 }
75 let cap: i64 = K_MAGIC_262144
76 let raw: *u8 = sys_mmap(cap)
77 var got: i64 = 0
78 var r: i64 = 1
79 while r > 0 { r = sys_read(ifd, (raw as i64 + got) as *u8, cap-got); if r > 0 { got = got + r } }
80 sys_close(ifd)
81
82 // trust store (once) + fetch scratch
83 let ts: i64 = nx_trust_store_load_from_certdata("data/mozilla_certdata.txt\x00" as *u8, 512, K_MAGIC_4194304)
84 if ts <= 0 { rv_puts("nx_research_verify: certdata load failed\n" as *u8); return 1 }
85 let store: *TrustStore = ts as *TrustStore
86 let out: *u8 = sys_mmap(K_MAGIC_4194304)
87 let status: *i64 = sys_mmap(8) as *i64
88
89 // output ledger (truncate)
90 let ofd: i64 = sys_openat_wr("knowledge/index/rv_verified.tsv\x00" as *u8, 420)
91
92 rv_puts("=== nx_research_verify: verify each cited claim against its FETCHED source ===\n\n" as *u8)
93 var nconf: i64 = 0; var ndisc: i64 = 0; var nunv: i64 = 0; var nfail: i64 = 0
94
95 // iterate lines; split each into 5 TAB fields: label, url, pattern, claim_tenths, tol_tenths
96 var p: i64 = 0
97 while p < got {
98 // line end = index of the next '\n' at/after p (or got). go-flag scan (preserves the position).
99 var lineend: i64 = p
100 var goL: i64 = 1
101 while goL == 1 { goL = 0; if lineend < got { if (raw[lineend] as i64) != 10 { lineend = lineend + 1; goL = 1 } } }
102 // field boundaries (TAB=9) within [p, lineend)
103 let fstart: *i64 = sys_mmap(6*8) as *i64
104 let fend: *i64 = sys_mmap(6*8) as *i64
105 var nf: i64 = 0
106 var fs: i64 = p
107 var i: i64 = p
108 while i <= lineend {
109 var cut: i64 = 0
110 if i == lineend { cut = 1 } else { if (raw[i] as i64) == 9 { cut = 1 } }
111 if cut == 1 { if nf < 6 { fstart[nf] = fs; fend[nf] = i; nf = nf + 1 } fs = i + 1 }
112 i = i + 1
113 }
114 // skip blank/short lines (need 5 fields); also skip a leading '#' comment
115 var iscomment: i64 = 0
116 if fend[0] > fstart[0] { if (raw[fstart[0]] as i64) == 35 { iscomment = 1 } }
117 if nf >= 5 { if iscomment == 0 {
118 // NUL-terminate label, url, pattern into fresh buffers; parse claim + tol
119 let lbl: *u8 = sys_mmap(256)
120 let url: *u8 = sys_mmap(K_MAGIC_1024)
121 let pat: *u8 = sys_mmap(512)
122 var a: i64 = 0
123 var q: i64 = fstart[0]; while q < fend[0] { if a < 255 { lbl[a] = raw[q]; a = a + 1 } q = q + 1 } lbl[a] = 0 as u8
124 a = 0; q = fstart[1]; while q < fend[1] { if a < 1023 { url[a] = raw[q]; a = a + 1 } q = q + 1 } url[a] = 0 as u8
125 a = 0; q = fstart[2]; while q < fend[2] { if a < 511 { pat[a] = raw[q]; a = a + 1 } q = q + 1 } pat[a] = 0 as u8
126 let claim: i64 = rv_int((raw as i64 + fstart[3]) as *u8, fend[3]-fstart[3])
127 let tol: i64 = rv_int((raw as i64 + fstart[4]) as *u8, fend[4]-fstart[4])
128
129 // fetch + extract + verdict
130 var n: i64 = nx_https_fetch_follow_best(url, store, out, K_MAGIC_4194304, 6, status)
131 if n <= 0 { sys_sleep_ms(K_MAGIC_1500); n = nx_https_fetch_follow_best(url, store, out, K_MAGIC_4194304, 6, status) }
132 var http: i64 = 0
133 if n > 0 { http = status[0] }
134 var ext: i64 = 0-1
135 var verdict: *u8 = "FETCH-FAILED" as *u8
136 if n > 0 { if http < 400 {
137 ext = rv_parse_tenths(out, n, rv_find_after(out, n, pat, rv_slen(pat)))
138 if ext < 0 { verdict = "UNVERIFIABLE" as *u8; nunv = nunv + 1 } else {
139 if rv_iabs(ext - claim) <= tol { verdict = "CONFIRMED" as *u8; nconf = nconf + 1 } else { verdict = "DISCREDITED" as *u8; ndisc = ndisc + 1 }
140 }
141 } }
142 var isfail: i64 = 1
143 if n > 0 { if http < 400 { isfail = 0 } }
144 if isfail == 1 { nfail = nfail + 1 }
145
146 // print row
147 rv_puts(" " as *u8); rv_puts(verdict); rv_puts(" " as *u8); rv_puts(lbl)
148 rv_puts(" (extracted=" as *u8); rv_putn(ext); rv_puts(" claim=" as *u8); rv_putn(claim)
149 rv_puts(" http=" as *u8); rv_putn(http); rv_puts(")\n" as *u8)
150 // bank ledger row: label\tsource\textracted\tclaim\tverdict\n
151 if ofd >= 0 {
152 sys_write(ofd, lbl, rv_slen(lbl)); sys_write(ofd, "\t" as *u8, 1)
153 sys_write(ofd, url, rv_slen(url)); sys_write(ofd, "\t" as *u8, 1)
154 let nb: *u8 = sys_mmap(32); var ne: i64 = 0
155 if ext < 0 { nb[0] = 45 as u8; ne = 1 } else { var tv: i64 = ext; if tv==0 { nb[0]=48 as u8; ne=1 } else { let tmp: *u8=sys_mmap(24); var tk: i64=0; while tv>0 { tmp[tk]=(48+(tv%10)) as u8; tv=tv/10; tk=tk+1 } while ne<tk { nb[ne]=tmp[tk-1-ne]; ne=ne+1 } } }
156 sys_write(ofd, nb, ne); sys_write(ofd, "\t" as *u8, 1)
157 let cb: *u8 = sys_mmap(32); var ce: i64 = 0; var cv: i64 = claim; if cv==0 { cb[0]=48 as u8; ce=1 } else { let tmp2: *u8=sys_mmap(24); var ck: i64=0; while cv>0 { tmp2[ck]=(48+(cv%10)) as u8; cv=cv/10; ck=ck+1 } while ce<ck { cb[ce]=tmp2[ck-1-ce]; ce=ce+1 } }
158 sys_write(ofd, cb, ce); sys_write(ofd, "\t" as *u8, 1)
159 sys_write(ofd, verdict, rv_slen(verdict)); sys_write(ofd, "\n" as *u8, 1)
160 }
161 sys_sleep_ms(500) // be polite to rate-limited hosts between claims
162 } }
163 // advance to next line
164 var np: i64 = lineend + 1
165 if np <= p { np = p + 1 }
166 p = np
167 }
168 if ofd >= 0 { sys_close(ofd) }
169
170 rv_puts("\n=== SUMMARY: CONFIRMED=" as *u8); rv_putn(nconf)
171 rv_puts(" DISCREDITED=" as *u8); rv_putn(ndisc)
172 rv_puts(" UNVERIFIABLE=" as *u8); rv_putn(nunv)
173 rv_puts(" FETCH-FAILED=" as *u8); rv_putn(nfail)
174 rv_puts("\nledger -> knowledge/index/rv_verified.tsv\n" as *u8)
175 return 0
176}