nx_research_synth_qwen.nx source
↩ module page · 369 lines · 15708 B
1// nx_research_synth_qwen.nx -- S1 of the Tesla growth ladder: SOVEREIGN GROUNDED SYNTHESIS.
2// Given a question + N retrieved source passages, the pretrained sovereign Qwen (nsv_generate, in-process,
3// no HTTP, $0, integer-deterministic) generates a MULTI-SENTENCE answer that cites each claim [n] back to a
4// numbered source. The organ's RESONANT property (Tesla law #1) is not the generation -- it is the
5// DETERMINISTIC GROUNDING CHECK that runs at $0 with NO model: every content word of the answer must trace
6// to a cited source, and every citation must be in range. A hallucinated claim (word absent from all sources)
7// or a fabricated citation ([5] when 2 sources exist) is caught mechanically. This is the anti-hallucination
8// discipline FARS lacked (its own audit: 5.7% hallucinated citations, 7.4% fabricated results).
9//
10// Composes: nx_nofloat_serve_core (nsv_init/nsv_generate). Model-call pattern mirrors nx_qwen_extract (proven).
11// The grounding functions (rsq_ground_report / rsq_parse_cites / rsq_is_refusal) need NO model -> the gate
12// proves the mechanism in miniature (law #3), and the generative path is marker-gated for NAS measurement.
13// NEXT (S2): each ungrounded claim -> nx_evidence_verify_gate for external confirm/discredit. license_tier: ORIGINAL
14import "nx_syscalls.nx"
15import "nx_nofloat_serve_core.nx"
16import "nx_text_sentences.nx"
17
18const RSQ_MODEL: *u8 = "/home/elderwesto/nx_stage/nx_real_model.gguf"
19const RSQ_SRCCAP: i64 = 600 // per-source byte cap inside the prompt
20const RSQ_MAXPROMPT: i64 = 4000 // hard byte guard (<< NSV_MAXIN=16384 tok-scratch; ~1600 tok < NSV_MAXT=2048)
21const RSQ_MAXNEW: i64 = 64 // synthesis needs a 2-4 sentence answer (extraction used 16)
22const RSQ_MODE: i64 = 0 // 0 = i32 lossless (faithful default)
23const RSQ_MINWORD: i64 = 5 // a content word is len>=5 (filters most function words)
24
25static g_rsq_ready: i64 // 0 until nsv_init succeeds (BSS-zero, safe to read pre-init)
26static g_rsq_pr: *u8 // preallocated prompt buffer
27static g_rsq_out: *u8 // model output buffer
28static g_rsq_meta: *i64 // nsv meta block
29static g_rsq_gp: *i64 // nsv generate-params block
30static g_rsq_ctp: *i64 // one-time scratch for txt_parse_cite (Consolidation STEP C; lazy-init, NOT mmap-per-call)
31static g_rsq_ctp_init: i64
32
33// ---- small byte helpers (declared before use; fwd static-ref would miscompile) ----
34func rsq_len(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n }
35func rsq_lc(c: i64) -> i64 { if c >= 65 { if c <= 90 { return c + 32 } } return c }
36func rsq_is_alnum(c: i64) -> i64 {
37 if c >= 48 { if c <= 57 { return 1 } }
38 if c >= 65 { if c <= 90 { return 1 } }
39 if c >= 97 { if c <= 122 { return 1 } }
40 return 0
41}
42func rsq_cat(dst: *u8, off: i64, s: *u8, n: i64, cap: i64) -> i64 {
43 var i: i64 = 0; var o: i64 = off
44 while i < n { if o < cap { dst[o] = s[i]; o = o + 1 } i = i + 1 }
45 return o
46}
47func rsq_cats(dst: *u8, off: i64, s: *u8, cap: i64) -> i64 {
48 var i: i64 = 0; var o: i64 = off
49 while s[i] != (0 as u8) { if o < cap { dst[o] = s[i]; o = o + 1 } i = i + 1 }
50 return o
51}
52func rsq_catd(dst: *u8, off: i64, d: i64, cap: i64) -> i64 {
53 var o: i64 = off
54 if o < cap { dst[o] = (48 + d) as u8; o = o + 1 }
55 return o
56}
57
58// case-insensitive: does the (ptr,wlen) word occur anywhere in buf[0,blen)?
59func rsq_ci_match_at(buf: *u8, pos: i64, blen: i64, word: *u8, wlen: i64) -> i64 {
60 var k: i64 = 0
61 while k < wlen {
62 if pos + k >= blen { return 0 }
63 if rsq_lc(buf[pos+k] as i64 & 0xff) != rsq_lc(word[k] as i64 & 0xff) { return 0 }
64 k = k + 1
65 }
66 return 1
67}
68func rsq_ci_contains(buf: *u8, blen: i64, word: *u8, wlen: i64) -> i64 {
69 if wlen == 0 { return 0 }
70 var i: i64 = 0
71 while i + wlen <= blen {
72 if rsq_ci_match_at(buf, i, blen, word, wlen) == 1 { return 1 }
73 i = i + 1
74 }
75 return 0
76}
77// end of the alnum run starting at i (i points at an alnum byte); always returns > i
78func rsq_word_end(ans: *u8, i: i64, alen: i64) -> i64 {
79 var j: i64 = i
80 var go: i64 = 1
81 while go == 1 {
82 go = 0
83 if j < alen { if rsq_is_alnum(ans[j] as i64 & 0xff) == 1 { j = j + 1; go = 1 } }
84 }
85 return j
86}
87// case-insensitive equality of answer span [off,off+wlen) to a NUL-terminated word
88func rsq_eqword(ans: *u8, off: i64, wlen: i64, w: *u8) -> i64 {
89 var k: i64 = 0
90 while k < wlen {
91 if w[k] == (0 as u8) { return 0 }
92 if rsq_lc(ans[off+k] as i64 & 0xff) != rsq_lc(w[k] as i64 & 0xff) { return 0 }
93 k = k + 1
94 }
95 if w[wlen] != (0 as u8) { return 0 }
96 return 1
97}
98// a small len>=5 function-word list so the hallucination signal is about CONTENT, not grammar
99func rsq_is_stop(ans: *u8, off: i64, wlen: i64) -> i64 {
100 if rsq_eqword(ans, off, wlen, "which" as *u8) == 1 { return 1 }
101 if rsq_eqword(ans, off, wlen, "there" as *u8) == 1 { return 1 }
102 if rsq_eqword(ans, off, wlen, "these" as *u8) == 1 { return 1 }
103 if rsq_eqword(ans, off, wlen, "those" as *u8) == 1 { return 1 }
104 if rsq_eqword(ans, off, wlen, "their" as *u8) == 1 { return 1 }
105 if rsq_eqword(ans, off, wlen, "would" as *u8) == 1 { return 1 }
106 if rsq_eqword(ans, off, wlen, "could" as *u8) == 1 { return 1 }
107 if rsq_eqword(ans, off, wlen, "should" as *u8) == 1 { return 1 }
108 if rsq_eqword(ans, off, wlen, "about" as *u8) == 1 { return 1 }
109 if rsq_eqword(ans, off, wlen, "after" as *u8) == 1 { return 1 }
110 if rsq_eqword(ans, off, wlen, "other" as *u8) == 1 { return 1 }
111 if rsq_eqword(ans, off, wlen, "being" as *u8) == 1 { return 1 }
112 if rsq_eqword(ans, off, wlen, "where" as *u8) == 1 { return 1 }
113 if rsq_eqword(ans, off, wlen, "while" as *u8) == 1 { return 1 }
114 if rsq_eqword(ans, off, wlen, "first" as *u8) == 1 { return 1 }
115 return 0
116}
117// is a content word (ptr at ans+off, wlen) present in ANY of the nsrc sources?
118func rsq_present_in_sources(ans: *u8, off: i64, wlen: i64, srcv: *i64, nsrc: i64) -> i64 {
119 var k: i64 = 0
120 while k < nsrc {
121 let sp: *u8 = srcv[k] as *u8
122 let sl: i64 = rsq_len(sp)
123 if rsq_ci_contains(sp, sl, (ans as i64 + off) as *u8, wlen) == 1 { return 1 }
124 k = k + 1
125 }
126 return 0
127}
128// THE grounding report: out[0]=content words, out[1]=hallucinated (present in NO source). returns halluc.
129func rsq_ground_report(ans: *u8, alen: i64, srcv: *i64, nsrc: i64, out: *i64) -> i64 {
130 var content: i64 = 0
131 var halluc: i64 = 0
132 var i: i64 = 0
133 while i < alen {
134 let c: i64 = ans[i] as i64 & 0xff
135 if rsq_is_alnum(c) == 1 {
136 let je: i64 = rsq_word_end(ans, i, alen)
137 let wlen: i64 = je - i
138 if wlen >= RSQ_MINWORD {
139 if rsq_is_stop(ans, i, wlen) == 0 {
140 content = content + 1
141 if rsq_present_in_sources(ans, i, wlen, srcv, nsrc) == 0 { halluc = halluc + 1 }
142 }
143 }
144 i = je
145 } else {
146 i = i + 1
147 }
148 }
149 out[0] = content
150 out[1] = halluc
151 return halluc
152}
153// parse [n] citations: out[0]=count out[1]=in-range out[2]=out-of-range. returns count.
154func rsq_parse_cites(ans: *u8, alen: i64, cites: *i64, maxc: i64, srcrange: i64, out: *i64) -> i64 {
155 var nc: i64 = 0; var inr: i64 = 0; var outr: i64 = 0
156 var i: i64 = 0
157 while i < alen {
158 if (ans[i] as i64 & 0xff) == 91 { // '['
159 var j: i64 = i + 1
160 var val: i64 = 0
161 var got: i64 = 0
162 var go: i64 = 1
163 while go == 1 {
164 go = 0
165 if j < alen {
166 let d: i64 = ans[j] as i64 & 0xff
167 if d >= 48 { if d <= 57 { val = val*10 + (d-48); got = got + 1; j = j + 1; go = 1 } }
168 }
169 }
170 if got > 0 { if j < alen { if (ans[j] as i64 & 0xff) == 93 { // ']'
171 if nc < maxc { cites[nc] = val; nc = nc + 1 }
172 if val >= 1 { if val <= srcrange { inr = inr + 1 } else { outr = outr + 1 } } else { outr = outr + 1 }
173 i = j
174 } } }
175 }
176 i = i + 1
177 }
178 out[0] = nc; out[1] = inr; out[2] = outr
179 return nc
180}
181// did the model decline (grounded refusal, the DeepResearcher honesty-refusal behavior)?
182func rsq_is_refusal(ans: *u8, alen: i64) -> i64 {
183 if rsq_ci_contains(ans, alen, "not supported" as *u8, 13) == 1 { return 1 }
184 return 0
185}
186// COMBINED grounded verdict (the complete S1 check). out[0]=content out[1]=halluc out[2]=ncites
187// out[3]=inrange out[4]=outrange. Returns 1 GROUNDED iff halluc<=htol AND no out-of-range citation
188// AND (has content OR is an explicit refusal). Catches BOTH hallucinated claims and fabricated citations
189// (the real 0.5B over-cites -- Tier-2 emitted a [3] with 2 sources; this rejects it). Not a hot path.
190func rsq_verdict(ans: *u8, alen: i64, srcv: *i64, nsrc: i64, htol: i64, out: *i64) -> i64 {
191 let gr: *i64 = sys_mmap(64) as *i64
192 let cr: *i64 = sys_mmap(64) as *i64
193 let cbuf: *i64 = sys_mmap(256) as *i64
194 rsq_ground_report(ans, alen, srcv, nsrc, gr)
195 rsq_parse_cites(ans, alen, cbuf, 24, nsrc, cr)
196 out[0] = gr[0]
197 out[1] = gr[1]
198 out[2] = cr[0]
199 out[3] = cr[1]
200 out[4] = cr[2]
201 var grounded: i64 = 1
202 if gr[1] > htol { grounded = 0 }
203 if cr[2] > 0 { grounded = 0 }
204 if gr[0] == 0 { if rsq_is_refusal(ans, alen) == 0 { grounded = 0 } }
205 return grounded
206}
207
208// ---- per-claim attribution (the S1->S2 bridge: each sentence-claim independently checkable) ----
209// first IN-RANGE [c] citation in sentence [s,e) (1..nsrc), or 0 if none; outp[0]=1 if any OUT-OF-RANGE cite.
210func rsq_sentence_cite(ans: *u8, s: i64, e: i64, nsrc: i64, outp: *i64) -> i64 {
211 if g_rsq_ctp_init == 0 { g_rsq_ctp = sys_mmap(32) as *i64; g_rsq_ctp_init = 1 }
212 let tp: *i64 = g_rsq_ctp
213 var c: i64 = 0
214 var oor: i64 = 0
215 var i: i64 = s
216 while i < e {
217 var adv: i64 = 1
218 if (ans[i] as i64 & 0xff) == 91 { // '['
219 let endp: i64 = txt_parse_cite(ans, e, i, tp) // shared canonical parser (Consolidation STEP C)
220 if tp[1] == 1 { // complete [n] token
221 let val: i64 = tp[0]
222 if val >= 1 { if val <= nsrc { if c == 0 { c = val } } else { oor = 1 } } else { oor = 1 }
223 i = endp
224 adv = 0
225 }
226 }
227 if adv == 1 { i = i + 1 }
228 }
229 outp[0] = oor
230 return c
231}
232// does any content word of ans[s,e) appear in the SPECIFICALLY cited source srcv[c-1]? (mis-citation catcher)
233func rsq_span_overlaps_src(ans: *u8, s: i64, e: i64, srcv: *i64, c: i64) -> i64 {
234 if c < 1 { return 0 }
235 let sp: *u8 = srcv[c-1] as *u8
236 let sl: i64 = rsq_len(sp)
237 var i: i64 = s
238 while i < e {
239 if rsq_is_alnum(ans[i] as i64 & 0xff) == 1 {
240 let je: i64 = rsq_word_end(ans, i, e)
241 let wlen: i64 = je - i
242 if wlen >= RSQ_MINWORD { if rsq_is_stop(ans, i, wlen) == 0 {
243 if rsq_ci_contains(sp, sl, (ans as i64 + i) as *u8, wlen) == 1 { return 1 }
244 } }
245 i = je
246 } else { i = i + 1 }
247 }
248 return 0
249}
250// per-claim (sentence) verdict. out[0]=nclaims out[1]=grounded out[2]=ungrounded. A claim is grounded iff it
251// has an in-range citation AND >=1 content word present in THAT cited source. returns nclaims.
252func rsq_claim_verdict(ans: *u8, alen: i64, srcv: *i64, nsrc: i64, out: *i64) -> i64 {
253 var nclaims: i64 = 0
254 var ng: i64 = 0
255 var nu: i64 = 0
256 let op: *i64 = sys_mmap(32) as *i64
257 var s: i64 = 0
258 while s < alen {
259 let e: i64 = txt_sentence_end(ans, s, alen)
260 var content: i64 = 0
261 var i: i64 = s
262 while i < e {
263 if rsq_is_alnum(ans[i] as i64 & 0xff) == 1 {
264 let je: i64 = rsq_word_end(ans, i, e)
265 let wlen: i64 = je - i
266 if wlen >= RSQ_MINWORD { if rsq_is_stop(ans, i, wlen) == 0 { content = content + 1 } }
267 i = je
268 } else { i = i + 1 }
269 }
270 if content > 0 {
271 nclaims = nclaims + 1
272 let c: i64 = rsq_sentence_cite(ans, s, e, nsrc, op)
273 var grounded: i64 = 0
274 if c >= 1 { if op[0] == 0 { if rsq_span_overlaps_src(ans, s, e, srcv, c) == 1 { grounded = 1 } } }
275 if grounded == 1 { ng = ng + 1 } else { nu = nu + 1 }
276 }
277 s = e + 1
278 }
279 out[0] = nclaims
280 out[1] = ng
281 out[2] = nu
282 return nclaims
283}
284// build the synthesis prompt: instruction + numbered sources + question. returns byte length.
285func rsq_build_prompt(q: *u8, srcv: *i64, nsrc: i64, pr: *u8, cap: i64) -> i64 {
286 var po: i64 = 0
287 po = rsq_cats(pr, po, "Answer the question using ONLY the numbered sources. After each sentence cite the source in brackets like [1]. If the sources do not contain the answer, reply exactly: NOT SUPPORTED.\n\n" as *u8, cap)
288 var k: i64 = 0
289 while k < nsrc {
290 let sp: *u8 = srcv[k] as *u8
291 po = rsq_cat(pr, po, "[" as *u8, 1, cap)
292 po = rsq_catd(pr, po, k + 1, cap)
293 po = rsq_cats(pr, po, "] " as *u8, cap)
294 var sl: i64 = rsq_len(sp)
295 if sl > RSQ_SRCCAP { sl = RSQ_SRCCAP }
296 po = rsq_cat(pr, po, sp, sl, cap)
297 po = rsq_cats(pr, po, "\n" as *u8, cap)
298 k = k + 1
299 }
300 po = rsq_cats(pr, po, "\nQuestion: " as *u8, cap)
301 var qc: i64 = rsq_len(q)
302 if qc > 200 { qc = 200 }
303 po = rsq_cat(pr, po, q, qc, cap)
304 po = rsq_cats(pr, po, "\nAnswer:" as *u8, cap)
305 return po
306}
307
308// ---- model boot (idempotent; path override like nx_qwen_extract) ----
309func rsq_load() -> i64 {
310 if g_rsq_ready == 1 { return 0 }
311 var mp: *u8 = RSQ_MODEL
312 let pfd: i64 = sys_openat_rd("knowledge/index/qwen_model_path.txt" as *u8)
313 if pfd >= 0 {
314 let pb: *u8 = sys_mmap(512)
315 let pn: i64 = sys_read(pfd, pb, 511)
316 sys_close(pfd)
317 var pe: i64 = pn
318 var trim: i64 = 1
319 while trim == 1 {
320 trim = 0
321 if pe > 0 {
322 let c: i64 = pb[pe-1] as i64
323 if c == 10 { pe = pe - 1; trim = 1 } else { if c == 13 { pe = pe - 1; trim = 1 } else { if c == 32 { pe = pe - 1; trim = 1 } } }
324 }
325 }
326 if pe > 0 { pb[pe] = 0 as u8; mp = pb }
327 }
328 let rc: i64 = nsv_init(mp)
329 if rc != 0 { return rc }
330 g_rsq_pr = sys_mmap(8192)
331 g_rsq_out = sys_mmap(4096)
332 g_rsq_meta = sys_mmap(8*8) as *i64
333 g_rsq_gp = sys_mmap(12*8) as *i64
334 g_rsq_ready = 1
335 return 0
336}
337func rsq_ready() -> i64 { return g_rsq_ready }
338
339// generate a grounded synthesis for q over nsrc sources; first-block answer into ans (NUL-term).
340// returns answer byte length, or <=0 on not-ready / too-long / empty.
341func rsq_synth(q: *u8, srcv: *i64, nsrc: i64, ans: *u8) -> i64 {
342 if g_rsq_ready == 0 { return 0 }
343 let pr: *u8 = g_rsq_pr
344 let po: i64 = rsq_build_prompt(q, srcv, nsrc, pr, 8192)
345 if po > RSQ_MAXPROMPT { return 0 }
346 let out: *u8 = g_rsq_out
347 let gp: *i64 = g_rsq_gp
348 gp[0] = pr as i64
349 gp[1] = po
350 gp[2] = RSQ_MAXNEW
351 gp[3] = RSQ_MODE
352 gp[4] = out as i64
353 gp[5] = 4096
354 gp[6] = g_rsq_meta as i64
355 gp[7] = 0 - 1
356 gp[8] = 0
357 gp[9] = 0
358 gp[10] = 0
359 gp[11] = 0
360 let tlen: i64 = nsv_generate(gp)
361 if tlen <= 0 { return 0 }
362 var st: i64 = 0
363 if (out[0] as i64) == 32 { st = 1 } // trim leading space
364 var w: i64 = 0
365 var k: i64 = st
366 while k < tlen { if w < 1000 { ans[w] = out[k]; w = w + 1 } k = k + 1 }
367 ans[w] = 0 as u8
368 return w
369}