nx_research_crossval.nx source
↩ module page · 147 lines · 6999 B
1// nx_research_crossval.nx -- MULTI-SOURCE CROSS-VALIDATION: the one refutation sub-axis peers lead (the matrix:
2// "DeepResearcher cross-validates across sources"). Over ONE numeric claim and N fetched evidence texts (each
3// with its own pattern + a caller-supplied HOST id), verdicts each source via cvc_verify_text, then CROSSES them
4// with the INDEPENDENCE DISCIPLINE: corroboration requires >=2 CONFIRMS from DISTINCT hosts (the same host twice
5// is an echo, not corroboration); any CONFIRM+DISCREDIT mix is CONFLICTED (surfaced, never averaged); all-absent
6// stays UNVERIFIABLE (invents nothing); zero sources fail CLOSED to UNVERIFIABLE. Pure/deterministic/$0 -- the
7// fetches stay in the caller (Tier-2), same split as nx_research_refute. Composes nx_claim_verify_core (cvc_*).
8// Cross verdicts: 0=CORROBORATED 1=CONFIRMED-SINGLE 3=CONFLICTED 4=UNVERIFIABLE 5=REFUTED.
9// license_tier: ORIGINAL
10import "nx_syscalls.nx"
11import "nx_claim_verify_core.nx"
12import "nx_research_verify_synth.nx"
13
14// ORIGIN ID from a URL: FNV-1a over the lowercased host of "scheme://HOST[:port]/..." -- the fetch layer calls
15// this per source URL and threads the ids to cvx_answer_verify/nxr_assess_hosts so corroboration is host-TRUE
16// (two docs from the same real host share one id -> echo never counts). Returns 0 when no "://host" is present
17// (callers then fall back to index-as-host). Pure, deterministic.
18func cvx_host_id(url: *u8) -> i64 {
19 var i: i64 = 0
20 var at: i64 = 0 - 1
21 var go: i64 = 1
22 while go == 1 {
23 go = 0
24 if url[i] != (0 as u8) {
25 if url[i] == (58 as u8) { if url[i+1] == (47 as u8) { if url[i+2] == (47 as u8) { at = i + 3 } } }
26 if at < 0 { i = i + 1; go = 1 }
27 }
28 }
29 if at < 0 { return 0 }
30 var h: i64 = 1469598103934665603 // FNV-1a offset basis
31 var k: i64 = at
32 var go2: i64 = 1
33 while go2 == 1 {
34 go2 = 0
35 let c: i64 = url[k] as i64 & 0xff
36 if c != 0 { if c != 47 { if c != 58 { if c != 63 { // host ends at '/' ':' '?' or NUL
37 var lc: i64 = c
38 if lc >= 65 { if lc <= 90 { lc = lc + 32 } } // case-insensitive host
39 h = ((h ^ lc) * 1099511628211) & 0x7FFFFFFFFFFFFFFF
40 k = k + 1
41 go2 = 1
42 } } } }
43 }
44 if h == 0 { h = 1 }
45 return h
46}
47
48// cross-validate claim (tenths) against n sources. bufs[k]/lens[k]=evidence text, pats[k]=pattern the value
49// follows in THAT source, hosts[k]=caller-assigned host id (same id == same origin). out[0]=cross verdict,
50// out[1]=confirms, out[2]=discredits, out[3]=unverifiables, out[4]=distinct confirming hosts. returns out[0].
51func cvx_verify(bufs: *i64, lens: *i64, pats: *i64, hosts: *i64, n: i64, claim: i64, tol: i64, out: *i64) -> i64 {
52 var cf: i64 = 0
53 var ds: i64 = 0
54 var uv: i64 = 0
55 let chost: *i64 = sys_mmap((n + 1) * 8) as *i64 // hosts of the confirming sources
56 var k: i64 = 0
57 while k < n {
58 let code: i64 = cvc_verify_text(bufs[k] as *u8, lens[k], pats[k] as *u8, claim, tol)
59 if code == 0 { chost[cf] = hosts[k]; cf = cf + 1 } else {
60 if code == 3 { ds = ds + 1 } else { uv = uv + 1 }
61 }
62 k = k + 1
63 }
64 // distinct confirming hosts (n is small; exact O(n^2), no hashing)
65 var dh: i64 = 0
66 var i: i64 = 0
67 while i < cf {
68 var seen: i64 = 0
69 var j: i64 = 0
70 while j < i { if chost[j] == chost[i] { seen = 1 } j = j + 1 }
71 if seen == 0 { dh = dh + 1 }
72 i = i + 1
73 }
74 var v: i64 = 4 // UNVERIFIABLE = the n==0 / all-absent fail-closed default
75 if cf >= 1 {
76 if ds >= 1 { v = 3 } else { // sources DISAGREE -> CONFLICTED, never averaged
77 if dh >= 2 { v = 0 } else { v = 1 } // >=2 distinct hosts -> CORROBORATED; else single-source
78 }
79 } else {
80 if ds >= 1 { v = 5 } // only discredits -> REFUTED
81 }
82 out[0] = v
83 out[1] = cf
84 out[2] = ds
85 out[3] = uv
86 out[4] = dh
87 return v
88}
89
90// ---- ANSWER-LEVEL multi-source verification (the auto-invoke form for nx_research_unified) -----------------
91// PRIMARY verdict per numeric claim = EXACTLY rvs_verify_answer's semantics vs the CITED source (out[0..3]
92// bit-compatible -- a drop-in for the unified pipeline); PLUS the cross layer: a claim is CORROBORATED when its
93// value appears in >=2 DISTINCT-host sources (the independence discipline of cvx_verify at answer level).
94// hosts == 0 as *i64 -> index-as-host approximation: each srcv entry counts as its own origin. HONEST CAVEAT:
95// two docs fetched from the same real host then over-credit corroboration -- thread real host ids when the
96// caller has them (the follow-up). Conflict detection stays CITED-SOURCE-level (a non-cited source lacking the
97// number is weak evidence, not a discredit -- asymmetry preserved from rvs). out[4]=corroborated claims.
98func cvx_answer_verify(ans: *u8, alen: i64, srcv: *i64, nsrc: i64, hosts: *i64, tol: i64, out: *i64) -> i64 {
99 var numeric: i64 = 0
100 var cf: i64 = 0
101 var ds: i64 = 0
102 var uv: i64 = 0
103 var cb: i64 = 0
104 let op: *i64 = sys_mmap(32) as *i64
105 let hp: *i64 = sys_mmap(32) as *i64
106 let nearh: *i64 = sys_mmap((nsrc + 1) * 8) as *i64
107 let np: *i64 = sys_mmap(32) as *i64
108 var s: i64 = 0
109 while s < alen {
110 let e: i64 = txt_sentence_end(ans, s, alen)
111 let claimed: i64 = rvs_first_number(ans, s, e)
112 if claimed >= 0 {
113 numeric = numeric + 1
114 let c: i64 = rsq_sentence_cite(ans, s, e, nsrc, op)
115 var primary_cf: i64 = 0
116 if c >= 1 {
117 let src: *u8 = srcv[c-1] as *u8
118 let sl: i64 = rsq_len(src)
119 rvs_span_numbers_near(ans, s, e, src, sl, tol, hp, np) // EVERY number must be near (bench N6 laundering kill); rvs-compat: identical change both sides
120 if np[1] == 1 { cf = cf + 1; primary_cf = 1 } else { if hp[0] == 1 { ds = ds + 1 } else { uv = uv + 1 } }
121 } else { uv = uv + 1 }
122 // cross layer: distinct hosts among ALL sources carrying this value
123 var nh: i64 = 0
124 var k: i64 = 0
125 while k < nsrc {
126 let sk: *u8 = srcv[k] as *u8
127 if rvs_src_has_near(sk, rsq_len(sk), claimed, tol, hp) == 1 {
128 var hid: i64 = k
129 if (hosts as i64) != 0 { hid = hosts[k] }
130 var seen: i64 = 0
131 var j: i64 = 0
132 while j < nh { if nearh[j] == hid { seen = 1 } j = j + 1 }
133 if seen == 0 { nearh[nh] = hid; nh = nh + 1 }
134 }
135 k = k + 1
136 }
137 if primary_cf == 1 { if nh >= 2 { cb = cb + 1 } }
138 }
139 s = e + 1
140 }
141 out[0] = numeric
142 out[1] = cf
143 out[2] = ds
144 out[3] = uv
145 out[4] = cb
146 return numeric
147}