code wiki / _hdl_build / nx_research_gaps.nx
nx_research_gaps.nx source
↩ module page · 96 lines · 4830 B
1// nx_research_gaps.nx -- THE CLEAN OPEN-GAPS DIGEST (the actionable feedback signal to operator + Claude). The
2// raw research_gaps.txt is append-only history (cluttered with resolved + duplicate flags); the research_queue is
3// the SOURCE OF TRUTH (live statuses). This reads the queue, collects the DISTINCT topics whose status is still
4// INADEQUATE, and writes knowledge/index/research_open_gaps.txt -- the precise, deduped list of what the
5// researcher still cannot serve = where to improve / fetch deeper to unblock the auto-builder. Loose coupling:
6// consumes the queue artifact, writes a digest artifact. expect_exit: 0 license_tier: ORIGINAL
7import "nx_search_inverted_persist.nx" // brings syscalls
8import "nx_itoa_lib.nx" // shared MSB-first emitter (zero-alloc)
9
10const RGP_CAP: i64 = 8192
11
12func rgp_puts(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 }
13// MIGRATED to the shared emitter (debt 1785563586). The old body mmapped a scratch buffer
14// per call and never freed it. At PAGE granularity that is 4096B leaked PER CALL -- the
15// defect that took 28.5GB of a 36GB host in nx_ts_lumadiff (2MB input, ~3.66M calls).
16// nxi_* is MSB-first, allocates NOTHING, and emits identical bytes including the sign.
17func rgp_num(v: i64) -> i64 { nxi_out(v); return 0 }
18func rgp_line_end(buf: *u8, i: i64, end: i64) -> i64 {
19 var p: i64=i; var stop: i64=0
20 while stop==0 { if p>=end { stop=1 } else { if buf[p]==(10 as u8) { stop=1 } else { p=p+1 } } }
21 return p
22}
23func rgp_scan(buf: *u8, i: i64, end: i64) -> i64 {
24 var p: i64=i; var stop: i64=0
25 while stop==0 { if p>=end { stop=1 } else { if buf[p]==(32 as u8) { stop=1 } else { if buf[p]==(10 as u8) { stop=1 } else { p=p+1 } } } }
26 return p
27}
28// equal-range compare: buf[a_off..a_off+a_len) vs buf[b_off..b_off+b_len)
29func rgp_eq(buf: *u8, a_off: i64, a_len: i64, b_off: i64, b_len: i64) -> i64 {
30 if a_len != b_len { return 0 }
31 var i: i64=0
32 while i < a_len { if buf[a_off+i] != buf[b_off+i] { return 0 } i=i+1 }
33 return 1
34}
35
36func main() -> i64 {
37 rgp_puts("=== nx_research_gaps: clean open-gaps digest (currently INADEQUATE topics) ===\n" as *u8)
38 let qbox: *i64 = sys_mmap(16) as *i64
39 let q: *u8 = sys_read_file("knowledge/index/research_queue.txt" as *u8, qbox)
40 if q == 0 as *u8 { rgp_puts(" queue empty -- no requests\n" as *u8); sys_exit(0); return 0 }
41 let qlen: i64 = qbox[0]
42
43 let off: *i64 = sys_mmap(8*RGP_CAP) as *i64 // distinct open-gap topic offsets into q
44 let len: *i64 = sys_mmap(8*RGP_CAP) as *i64
45 var nopen: i64 = 0
46 var served: i64 = 0
47 var i: i64 = 0
48 while i < qlen {
49 let ls: i64 = i
50 let le: i64 = rgp_line_end(q, i, qlen)
51 if le > ls {
52 // <id> <status> <topic>
53 let e1: i64 = rgp_scan(q, ls, le)
54 var j: i64 = e1; if j<le { if q[j]==(32 as u8) { j=j+1 } }
55 let e2: i64 = rgp_scan(q, j, le)
56 let st_off: i64 = j; let st_len: i64 = e2 - j
57 var p: i64 = e2; if p<le { if q[p]==(32 as u8) { p=p+1 } }
58 let topic_off: i64 = p; let topic_len: i64 = le - p
59 // status == SERVED ? (6 chars, 'S')
60 if st_len == 6 { if q[st_off]==(83 as u8) { served = served + 1 } }
61 // status == INADEQUATE ? (10 chars, 'I')
62 if st_len == 10 { if q[st_off]==(73 as u8) {
63 if topic_len > 0 {
64 // dedup against already-collected open topics
65 var dup: i64 = 0
66 var k: i64 = 0
67 while k < nopen { if rgp_eq(q, off[k], len[k], topic_off, topic_len)==1 { dup=1 } k=k+1 }
68 if dup == 0 { if nopen < RGP_CAP { off[nopen]=topic_off; len[nopen]=topic_len; nopen=nopen+1 } }
69 }
70 } }
71 }
72 i = le; if i < qlen { i = i + 1 }
73 }
74
75 // write the clean digest
76 let fd: i64 = sys_openat_wr("knowledge/index/research_open_gaps.txt" as *u8, 0x1a4)
77 var w: i64 = 0
78 while w < nopen {
79 if fd >= 0 { sys_write(fd, ((q as i64)+off[w]) as *u8, len[w]); sys_write(fd, "\n" as *u8, 1) }
80 w = w + 1
81 }
82 if fd >= 0 { sys_close(fd) }
83
84 rgp_puts(" served="); rgp_num(served); rgp_puts(" OPEN GAPS (distinct, still inadequate)="); rgp_num(nopen)
85 rgp_puts(" -> knowledge/index/research_open_gaps.txt\n" as *u8)
86 if nopen > 0 {
87 rgp_puts(" IMPROVE THE RESEARCHER / FETCH DEEPER for:\n" as *u8)
88 var r: i64 = 0
89 while r < nopen {
90 rgp_puts(" - "); sys_write(1, ((q as i64)+off[r]) as *u8, len[r]); rgp_puts("\n" as *u8)
91 r = r + 1
92 }
93 } else { rgp_puts(" no open gaps -- the researcher currently serves every requested topic\n" as *u8) }
94 rgp_puts(" GAPS-OK\n" as *u8)
95 sys_exit(0); return 0
96}