code wiki / _hdl_build / nx_work_pulse.nx
nx_work_pulse.nx source
↩ module page · 150 lines · 6582 B
1// nx_work_pulse.nx -- the team's STANDING WORK LOOP unit: parse the REAL research backlog file
2// (knowledge/library/research_backlog.txt -- until now a seed doc parsed by NOBODY), compute the
3// coverage-gap pick (the Researcher's own rb_next math over the live rows), and emit the next
4// marching order as a durable WORKNEXT line in knowledge/status/work_next.log. This turns "the
5// Researcher works the queue" from prose into a MECHANICAL, pulse-able decision: every beat, the
6// team re-derives what to research next from the file's current priorities/hits -- no human pick,
7// no Claude pick. RACI: RESEARCHER owns the pick (rb_next composed, not reimplemented); this organ
8// only parses the durable form and reports (Conductor's sequencing verb).
9// Row grammar: `topic | priority(1-9) | hits | PENDING/DONE`; '#' comments and prose lines (fewer
10// than 3 pipes) are skipped. LAWS: struct-free, integer-only, flat ifs, <=6 args. license_tier: ORIGINAL
11import "nx_research_backlog.nx"
12import "nx_itoa_lib.nx" // shared MSB-first emitter (zero-alloc)
13import "nx_syscalls.nx"
14const WP_MAGIC_2048: i64 = 2048
15
16const WP_TARGET_HITS: i64 = 10 // the backlog's stated depth bar (10 corroborated docs per topic)
17const WP_MAX_ROWS: i64 = 256
18
19func wp_w(fd: i64, s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(fd,s,n); return 0 }
20// MIGRATED to the shared emitter (debt 1785563586). The old body mmapped a scratch buffer
21// per call and never freed it. At PAGE granularity that is 4096B leaked PER CALL -- the
22// defect that took 28.5GB of a 36GB host in nx_ts_lumadiff (2MB input, ~3.66M calls).
23// nxi_* is MSB-first, allocates NOTHING, and emits identical bytes including the sign.
24func wp_wn(fd: i64, v: i64) -> i64 { nxi_fd(fd, v); return 0 }
25
26// parse the decimal run at j0; -1 if none before the field end e
27func wp_int_at(b: *u8, j0: i64, e: i64) -> i64 {
28 var j: i64 = j0
29 var v: i64 = 0 - 1
30 while j < e {
31 let c: i64 = b[j] as i64
32 if c < 48 { return v }
33 if c > 57 { return v }
34 if v < 0 { v = 0 }
35 v = v * 10 + (c - 48)
36 j = j + 1
37 }
38 return v
39}
40
41// next '|' at/after i (or e if none before line end)
42func wp_pipe(b: *u8, i: i64, e: i64) -> i64 {
43 var j: i64 = i
44 while j < e { if b[j] == (124 as u8) { return j } j = j + 1 }
45 return e
46}
47func wp_line_end(b: *u8, i: i64, n: i64) -> i64 {
48 var e: i64 = i
49 while e < n { if b[e] == (10 as u8) { return e } e = e + 1 }
50 return n
51}
52
53// parse one data row at [i,e) into the tables at slot r. st[0]=pri st[1]=hits st[2]=stat st[3]=tpos
54// st[4]=tlen (each a table base address). Returns 1 if the line was a valid data row.
55func wp_row(b: *u8, i: i64, e: i64, r: i64, st: *i64) -> i64 {
56 if i >= e { return 0 }
57 if b[i] == (35 as u8) { return 0 }
58 let p1: i64 = wp_pipe(b, i, e)
59 if p1 >= e { return 0 }
60 let p2: i64 = wp_pipe(b, p1 + 1, e)
61 if p2 >= e { return 0 }
62 let p3: i64 = wp_pipe(b, p2 + 1, e)
63 if p3 >= e { return 0 }
64 let pri: i64 = wp_int_at(b, wp_skip(b, p1 + 1, p2), p2)
65 let hits: i64 = wp_int_at(b, wp_skip(b, p2 + 1, p3), p3)
66 if pri < 0 { return 0 }
67 if hits < 0 { return 0 }
68 // status: first non-space after p3 -- 'P'=PENDING 'D'=DONE
69 let s0: i64 = wp_skip(b, p3 + 1, e)
70 var stv: i64 = 0 - 1
71 if s0 < e { if b[s0] == (80 as u8) { stv = RB_PENDING } }
72 if s0 < e { if b[s0] == (68 as u8) { stv = RB_DONE } }
73 if stv < 0 { return 0 }
74 // topic slice: line start to p1, right-trimmed (flat flag loop, no break tricks)
75 var te: i64 = p1
76 var trimming: i64 = 1
77 while trimming == 1 {
78 trimming = 0
79 if te > i { if b[te-1] == (32 as u8) { te = te - 1; trimming = 1 } }
80 }
81 let pri_t: *i64 = st[0] as *i64
82 let hit_t: *i64 = st[1] as *i64
83 let stat_t: *i64 = st[2] as *i64
84 let tpos_t: *i64 = st[3] as *i64
85 let tlen_t: *i64 = st[4] as *i64
86 pri_t[r] = pri; hit_t[r] = hits; stat_t[r] = stv; tpos_t[r] = i; tlen_t[r] = te - i
87 return 1
88}
89// first non-space index in [i,e)
90func wp_skip(b: *u8, i0: i64, e: i64) -> i64 {
91 var i: i64 = i0
92 while i < e { if b[i] != (32 as u8) { return i } i = i + 1 }
93 return e
94}
95
96// parse the whole backlog buffer -> row count
97func wp_parse(b: *u8, n: i64, st: *i64) -> i64 {
98 var r: i64 = 0
99 var i: i64 = 0
100 while i < n {
101 let e: i64 = wp_line_end(b, i, n)
102 if r < WP_MAX_ROWS { r = r + wp_row(b, i, e, r, st) }
103 i = e + 1
104 }
105 return r
106}
107
108// the unit: read backlog -> pick -> durable directive. out[0]=rows out[1]=pick idx out[2]=gap score
109// out[3]=progress permil out[4]=coverage permil. Returns 1 if a directive was written (or all done).
110func wp_run(backlogpath: *u8, logpath: *u8, out: *i64) -> i64 {
111 let lenp: *i64 = sys_mmap(16) as *i64
112 let b: *u8 = sys_read_file(backlogpath, lenp)
113 let n: i64 = lenp[0]
114 if n <= 0 { return 0 }
115 let st: *i64 = sys_mmap(64) as *i64
116 st[0] = sys_mmap(WP_MAGIC_2048) as i64; st[1] = sys_mmap(WP_MAGIC_2048) as i64; st[2] = sys_mmap(WP_MAGIC_2048) as i64
117 st[3] = sys_mmap(WP_MAGIC_2048) as i64; st[4] = sys_mmap(WP_MAGIC_2048) as i64
118 let rows: i64 = wp_parse(b, n, st)
119 out[0] = rows
120 if rows <= 0 { return 0 }
121 let pri_t: *i64 = st[0] as *i64
122 let hit_t: *i64 = st[1] as *i64
123 let stat_t: *i64 = st[2] as *i64
124 let tpos_t: *i64 = st[3] as *i64
125 let tlen_t: *i64 = st[4] as *i64
126 let pick: i64 = rb_next(pri_t, stat_t, hit_t, rows, WP_TARGET_HITS)
127 out[1] = pick
128 out[3] = rb_progress_permil(stat_t, rows)
129 out[4] = rb_library_coverage_permil(hit_t, rows, WP_TARGET_HITS)
130 let fd: i64 = sys_openat_append(logpath, 0x1a4)
131 if fd < 0 { return 0 }
132 if pick < 0 {
133 out[2] = 0
134 wp_w(fd, "WORKNEXT all-topics-done progress=1000 epoch=" as *u8); wp_wn(fd, sys_now_realtime_sec()); wp_w(fd, "\n" as *u8)
135 sys_close(fd)
136 return 1
137 }
138 out[2] = rb_gap_score(pri_t[pick], hit_t[pick], WP_TARGET_HITS)
139 wp_w(fd, "WORKNEXT topic=" as *u8)
140 sys_write(fd, (b as i64 + tpos_t[pick]) as *u8, tlen_t[pick])
141 wp_w(fd, " priority=" as *u8); wp_wn(fd, pri_t[pick])
142 wp_w(fd, " hits=" as *u8); wp_wn(fd, hit_t[pick])
143 wp_w(fd, " gap=" as *u8); wp_wn(fd, out[2])
144 wp_w(fd, " backlog_rows=" as *u8); wp_wn(fd, out[0])
145 wp_w(fd, " progress_permil=" as *u8); wp_wn(fd, out[3])
146 wp_w(fd, " library_coverage_permil=" as *u8); wp_wn(fd, out[4])
147 wp_w(fd, " verdict=RESEARCH-NEXT epoch=" as *u8); wp_wn(fd, sys_now_realtime_sec()); wp_w(fd, "\n" as *u8)
148 sys_close(fd)
149 return 1
150}