nx_research_report.nx source
↩ module page · 244 lines · 11230 B
1// nx_research_report.nx -- S3 of the Tesla ladder: the GROUNDED REPORT WRITER (low-resource analog of Paper
2// Orchestra's writing stage -- no LaTeX theatre, a rigorously-grounded Markdown report). It assembles multi-section
3// S1 synthesis into a report with a numbered References section, and ENFORCES a report-level grounding guarantee:
4// every non-empty sentence must carry >=1 citation [n], and every [n] must resolve to a real reference
5// (1..nsrc). A report with an uncited sentence or a dangling citation is NOT grounded -- the trustworthiness
6// guarantee FARS/PaperOrchestra prose can't make. Assembly + grounding are deterministic/$0; section synthesis
7// composes S1 (rsq_synth), model-gated. license_tier: ORIGINAL
8import "nx_syscalls.nx"
9import "nx_research_synth_qwen.nx"
10import "nx_text_sentences.nx"
11
12func rp_slen(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n }
13func rp_is_alnum(c: i64) -> i64 {
14 if c >= 48 { if c <= 57 { return 1 } }
15 if c >= 65 { if c <= 90 { return 1 } }
16 if c >= 97 { if c <= 122 { return 1 } }
17 return 0
18}
19func rp_cat(dst: *u8, off: i64, s: *u8, n: i64, cap: i64) -> i64 { var i: i64=0; var o: i64=off; while i<n { if o<cap { dst[o]=s[i]; o=o+1 } i=i+1 } return o }
20func rp_cats(dst: *u8, off: i64, s: *u8, cap: i64) -> i64 { var i: i64=0; var o: i64=off; while s[i]!=(0 as u8) { if o<cap { dst[o]=s[i]; o=o+1 } i=i+1 } return o }
21func rp_catn(dst: *u8, off: i64, v: i64, cap: i64) -> i64 {
22 if v == 0 { if off < cap { dst[off] = 48 as u8 } return off + 1 }
23 let tmp: *u8 = sys_mmap(24)
24 var m: i64 = v
25 var k: i64 = 0
26 while m > 0 { tmp[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 }
27 var o: i64 = off
28 var i: i64 = k - 1
29 while i >= 0 { if o < cap { dst[o] = tmp[i]; o = o + 1 } i = i - 1 }
30 return o
31}
32func rp_contains(buf: *u8, blen: i64, needle: *u8) -> i64 {
33 let nl: i64 = rp_slen(needle)
34 if nl == 0 { return 1 }
35 var i: i64 = 0
36 while i + nl <= blen {
37 var k: i64 = 0
38 var ok: i64 = 1
39 while k < nl { if ok == 1 { if buf[i+k] != needle[k] { ok = 0 } } k = k + 1 }
40 if ok == 1 { return 1 }
41 i = i + 1
42 }
43 return 0
44}
45// rp_has_content + rp_count_cites REMOVED (Consolidation STEP C 2026-07-14): dead code -- orphaned when
46// rp_report_grounded became the carry-aware state machine; grep-verified ZERO callers stack-wide. Citation-token
47// parsing now flows through the shared txt_parse_cite (nx_text_sentences); rp_parse_cite delegates to it.
48func rp_is_letter(c: i64) -> i64 {
49 if c >= 65 { if c <= 90 { return 1 } }
50 if c >= 97 { if c <= 122 { return 1 } }
51 return 0
52}
53func rp_is_digit(c: i64) -> i64 { if c >= 48 { if c <= 57 { return 1 } } return 0 }
54// parse one [number] token at body[i]=='['. outp[0]=val outp[1]=complete(1 if a ']' closed it). returns end offset.
55func rp_parse_cite(body: *u8, blen: i64, i: i64, outp: *i64) -> i64 {
56 return txt_parse_cite(body, blen, i, outp) // Consolidation STEP C: delegate to the shared canonical parser
57}
58// THE report-level grounding guarantee (single-pass state machine: a citation AFTER a sentence's period counts
59// for THAT sentence -- the model often writes "...Fair. [1]"). out[0]=sentences out[1]=uncited out[2]=dangling.
60// returns 1 if fully grounded (every content sentence has a citation and no dangling citation).
61func rp_report_grounded(body: *u8, blen: i64, nsrc: i64, out: *i64) -> i64 {
62 var sentences: i64 = 0
63 var uncited: i64 = 0
64 var dangling: i64 = 0
65 var in_sent: i64 = 0
66 var has_cite: i64 = 0
67 var has_dang: i64 = 0
68 var boundary: i64 = 0
69 var carry_cite: i64 = 0
70 var carry_dang: i64 = 0
71 let cp: *i64 = sys_mmap(32) as *i64
72 var i: i64 = 0
73 while i < blen {
74 let c: i64 = body[i] as i64 & 0xff
75 if rp_is_letter(c) == 1 {
76 if boundary == 1 {
77 sentences = sentences + 1
78 if has_cite == 0 { uncited = uncited + 1 }
79 if has_dang > 0 { dangling = dangling + 1 }
80 has_cite = carry_cite; has_dang = carry_dang; carry_cite = 0; carry_dang = 0; boundary = 0
81 }
82 in_sent = 1
83 i = i + 1
84 } else { if c == 91 {
85 let endp: i64 = rp_parse_cite(body, blen, i, cp)
86 if cp[1] == 1 {
87 has_cite = has_cite + 1
88 var isdang: i64 = 0
89 if cp[0] < 1 { isdang = 1 } else { if cp[0] > nsrc { isdang = 1 } }
90 if isdang == 1 { has_dang = has_dang + 1 }
91 if boundary == 1 { carry_cite = carry_cite + 1; if isdang == 1 { carry_dang = carry_dang + 1 } }
92 }
93 if endp > i { i = endp } else { i = i + 1 }
94 } else { if c == 46 {
95 var isdec: i64 = 0
96 if i > 0 { if rp_is_digit(body[i-1] as i64 & 0xff) == 1 { if i+1 < blen { if rp_is_digit(body[i+1] as i64 & 0xff) == 1 { isdec = 1 } } } }
97 if isdec == 0 { if in_sent == 1 { boundary = 1 } }
98 i = i + 1
99 } else { if c == 33 { if in_sent == 1 { boundary = 1 } i = i + 1 } else { if c == 63 { if in_sent == 1 { boundary = 1 } i = i + 1 } else { i = i + 1 } } } } }
100 }
101 if in_sent == 1 {
102 sentences = sentences + 1
103 if has_cite == 0 { uncited = uncited + 1 }
104 if has_dang > 0 { dangling = dangling + 1 }
105 }
106 out[0] = sentences
107 out[1] = uncited
108 out[2] = dangling
109 var grounded: i64 = 1
110 if uncited > 0 { grounded = 0 }
111 if dangling > 0 { grounded = 0 }
112 return grounded
113}
114// deterministically CLEAN a synthesized body: collapse each citation RUN to its first in-range citation, DROP
115// dangling ([n]>nsrc) and truncated ('[' with no ']') citations, then trim a trailing half-sentence (content
116// after the last terminator/']'). Turns 0.5B citation-spam into a groundable body. out must be caller-sized.
117func rp_clean_body(body: *u8, blen: i64, nsrc: i64, out: *u8, cap: i64) -> i64 {
118 var o: i64 = 0
119 var i: i64 = 0
120 let cp: *i64 = sys_mmap(32) as *i64
121 while i < blen {
122 let c: i64 = body[i] as i64 & 0xff
123 if c == 91 {
124 var first_valid: i64 = 0
125 var p: i64 = i
126 var run: i64 = 1
127 while run == 1 {
128 run = 0
129 if p < blen { if (body[p] as i64 & 0xff) == 91 {
130 let endp: i64 = rp_parse_cite(body, blen, p, cp)
131 if cp[1] == 1 {
132 if cp[0] >= 1 { if cp[0] <= nsrc { if first_valid == 0 { first_valid = cp[0] } } }
133 p = endp
134 if p < blen { if (body[p] as i64 & 0xff) == 32 { p = p + 1 } }
135 run = 1
136 } else { p = endp }
137 } }
138 }
139 if first_valid >= 1 {
140 if o < cap { out[o] = 91 as u8; o = o + 1 }
141 o = rp_catn(out, o, first_valid, cap)
142 if o < cap { out[o] = 93 as u8; o = o + 1 }
143 if o < cap { out[o] = 32 as u8; o = o + 1 } // space after citation for readability
144 }
145 i = p
146 } else {
147 if o < cap { out[o] = body[i]; o = o + 1 }
148 i = i + 1
149 }
150 }
151 var t: i64 = o - 1
152 var cut: i64 = 0 - 1
153 var found: i64 = 0
154 while t >= 0 {
155 if found == 0 {
156 let c2: i64 = out[t] as i64 & 0xff
157 if c2 == 46 { cut = t; found = 1 } else { if c2 == 33 { cut = t; found = 1 } else { if c2 == 63 { cut = t; found = 1 } else { if c2 == 93 { cut = t; found = 1 } } } }
158 }
159 t = t - 1
160 }
161 if found == 1 { o = cut + 1 }
162 out[o] = 0 as u8
163 return o
164}
165// NOTE (2026-07-14): a rp_emit_grounded "grounding-enforced emission" (drop uncited sentences) was PROTOTYPED and
166// REVERTED -- on the 0.5B's real demo output it dropped a PREFIX-cited claim ("[2] Human performance...": the [2]
167// absorbed into the prior sentence's trailing gap, leaving the claim looking uncited -> deleted = CONTENT LOSS).
168// The flag-based path (verdict=CONTINUE) is lossless + honest. A correct version needs carry-emission (a gap cite
169// counts for BOTH neighbours) AND a gate that asserts CONTENT SURVIVES, not just uncited==0. Deferred, gated.
170
171// assemble a Markdown report from pre-synthesized section bodies + numbered sources. deterministic. returns bytes.
172// heads[i]/bodies[i]/srcs[i] are (*u8 as i64).
173func rp_assemble(title: *u8, heads: *i64, bodies: *i64, nsec: i64, srcs: *i64, nsrc: i64, buf: *u8, cap: i64) -> i64 {
174 var o: i64 = 0
175 o = rp_cats(buf, o, "# " as *u8, cap)
176 o = rp_cats(buf, o, title, cap)
177 o = rp_cats(buf, o, "\n\n" as *u8, cap)
178 var i: i64 = 0
179 while i < nsec {
180 o = rp_cats(buf, o, "## " as *u8, cap)
181 o = rp_cats(buf, o, heads[i] as *u8, cap)
182 o = rp_cats(buf, o, "\n" as *u8, cap)
183 o = rp_cats(buf, o, bodies[i] as *u8, cap)
184 o = rp_cats(buf, o, "\n\n" as *u8, cap)
185 i = i + 1
186 }
187 o = rp_cats(buf, o, "## References\n" as *u8, cap)
188 var k: i64 = 0
189 while k < nsrc {
190 o = rp_cats(buf, o, "[" as *u8, cap)
191 o = rp_catn(buf, o, k + 1, cap)
192 o = rp_cats(buf, o, "] " as *u8, cap)
193 o = rp_cats(buf, o, srcs[k] as *u8, cap)
194 o = rp_cats(buf, o, "\n" as *u8, cap)
195 k = k + 1
196 }
197 return o
198}
199// model-gated: synthesize each section (S1 rsq_synth over the shared sources) then assemble + grounding-check.
200// out[0]=sentences out[1]=uncited out[2]=dangling (aggregated). returns report byte-length, or -1 if model unready.
201func rp_report(title: *u8, heads: *i64, questions: *i64, nsec: i64, srcs: *i64, nsrc: i64, buf: *u8, cap: i64, out: *i64) -> i64 {
202 if rsq_ready() == 0 { if rsq_load() != 0 { return 0-1 } }
203 var o: i64 = 0
204 o = rp_cats(buf, o, "# " as *u8, cap)
205 o = rp_cats(buf, o, title, cap)
206 o = rp_cats(buf, o, "\n\n" as *u8, cap)
207 var sentences: i64 = 0
208 var uncited: i64 = 0
209 var dangling: i64 = 0
210 let bodybuf: *u8 = sys_mmap(2048)
211 let cleanbuf: *u8 = sys_mmap(2048)
212 let g: *i64 = sys_mmap(32) as *i64
213 var i: i64 = 0
214 while i < nsec {
215 o = rp_cats(buf, o, "## " as *u8, cap)
216 o = rp_cats(buf, o, heads[i] as *u8, cap)
217 o = rp_cats(buf, o, "\n" as *u8, cap)
218 let bl: i64 = rsq_synth(questions[i] as *u8, srcs, nsrc, bodybuf)
219 if bl > 0 {
220 let cl: i64 = rp_clean_body(bodybuf, bl, nsrc, cleanbuf, 2048) // collapse citation-spam, drop dangling/truncated
221 o = rp_cat(buf, o, cleanbuf, cl, cap)
222 rp_report_grounded(cleanbuf, cl, nsrc, g)
223 sentences = sentences + g[0]
224 uncited = uncited + g[1]
225 dangling = dangling + g[2]
226 }
227 o = rp_cats(buf, o, "\n\n" as *u8, cap)
228 i = i + 1
229 }
230 o = rp_cats(buf, o, "## References\n" as *u8, cap)
231 var k: i64 = 0
232 while k < nsrc {
233 o = rp_cats(buf, o, "[" as *u8, cap)
234 o = rp_catn(buf, o, k + 1, cap)
235 o = rp_cats(buf, o, "] " as *u8, cap)
236 o = rp_cats(buf, o, srcs[k] as *u8, cap)
237 o = rp_cats(buf, o, "\n" as *u8, cap)
238 k = k + 1
239 }
240 out[0] = sentences
241 out[1] = uncited
242 out[2] = dangling
243 return o
244}