code wiki / _hdl_build / nx_ws_miner.nx
nx_ws_miner.nx source
↩ module page · 835 lines · 30956 B
1// nx_ws_miner.nx -- F217-class HISTORIC WORKSTREAM MINER (ws=ws-intel, 2026-07-20).
2// Mines the append-only ws_sync journal (the ecosystem's workstream HISTORY) into
3// machine-readable intelligence: per-lane lifecycle (kickoffs/beats/dones, first/last ts,
4// distinct actors, DONE|ACTIVE|STALE|ABANDONED), per-actor engagement, honest totals.
5// The journal IS the historic record -- this organ makes it QUERYABLE (JSON verb) and
6// PUBLISHABLE (HTML page verb) so monitoring parallel + historic workstreams is a live
7// ecosystem surface, not Claude-context archaeology. Sibling of nx_ws_kickoff_sync
8// (the writer) and nx_ws_cycle (evidence-derived phase). Composes -- does not duplicate.
9// SCALE LAW: reads windowed + envelope DECLARED in output (window_bytes / truncated /
10// lanes_capped / actors_capped) -- silent capping forbidden by construction.
11// license_tier: ORIGINAL No hw writes (Rule 26).
12// mine <journal> [stale_sec] [abandoned_sec] -> JSON to stdout
13// page <journal> <outfile> [stale_sec] [abandoned_sec] -> HTML file + marker line
14// selftest <scratch-journal> -> gate T1..T9 (caller pre-cleans path)
15import "nx_syscalls.nx"
16import "nx_gate_verdict.nx"
17const WM_MAGIC_4096: i64 = 4096
18const WM_MAGIC_2000: i64 = 2000
19const WM_MAGIC_3000: i64 = 3000
20const WM_MAGIC_7200: i64 = 7200
21
22const WM_WIN: i64 = 4194304
23const WM_OUT: i64 = 262144
24const WM_SOFT: i64 = 40960
25const WM_SOFT2: i64 = 57344
26const WM_PAGE_SOFT: i64 = 245760
27const WM_NOTE_MAX: i64 = 160
28const WM_NAME_MAX: i64 = 120
29const WM_STALE_DEF: i64 = 3600
30const WM_ABAND_DEF: i64 = 604800
31
32// ---------- buffer + parse helpers (proven ks_* idioms, nx_ws_kickoff_sync lineage) ----------
33func wm_cat(d: *u8, o: i64, s: *u8) -> i64 { var p: i64=o; var i: i64=0; while s[i]!=(0 as u8){ d[p]=s[i]; p=p+1; i=i+1 } return p }
34func wm_catn(d: *u8, o: i64, v: i64) -> i64 {
35 let t: *u8 = sys_mmap(28)
36 var m: i64 = v
37 var p: i64 = o
38 if m < 0 { d[p]=45 as u8; p=p+1; m=0-m }
39 var k: i64 = 0
40 if m == 0 { t[0]=48 as u8; k=1 }
41 while m > 0 { t[k]=(48+(m%10)) as u8; m=m/10; k=k+1 }
42 var i: i64 = 0
43 while i < k { d[p]=t[k-1-i]; p=p+1; i=i+1 }
44 return p
45}
46func wm_vlen(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} return n }
47func wm_atoi_z(s: *u8) -> i64 { var v: i64=0; var i: i64=0; while s[i]!=(0 as u8){ let c: i64=s[i] as i64; if c>=48 { if c<=57 { v=v*10+(c-48) } } i=i+1 } return v }
48func wm_read(path: *u8, buf: *u8, cap: i64) -> i64 {
49 let fd: i64 = sys_openat_rd(path)
50 if fd < 0 { return 0 }
51 var n: i64 = 0
52 var go: i64 = 1
53 while go == 1 { let r: i64 = sys_read(fd, ((buf as i64)+n) as *u8, cap-n); if r <= 0 { go = 0 } else { n = n + r } if n >= cap { go = 0 } }
54 sys_close(fd)
55 return n
56}
57// append one frame: <ts>\t<verb>\t<ws>\t<actor>\t<note>\n (ts<0 => real clock)
58func wm_append(journal: *u8, ts: i64, verb: *u8, ws: *u8, actor: *u8, note: *u8) -> i64 {
59 var t: i64 = ts
60 if t < 0 { t = sys_now_realtime_sec() }
61 let ln: *u8 = sys_mmap(WM_MAGIC_4096)
62 var o: i64 = 0
63 o = wm_catn(ln, o, t)
64 ln[o]=9 as u8; o=o+1
65 o = wm_cat(ln, o, verb)
66 ln[o]=9 as u8; o=o+1
67 o = wm_cat(ln, o, ws)
68 ln[o]=9 as u8; o=o+1
69 o = wm_cat(ln, o, actor)
70 ln[o]=9 as u8; o=o+1
71 o = wm_cat(ln, o, note)
72 ln[o]=10 as u8; o=o+1
73 let fd: i64 = sys_openat_append(journal, 0x1a4)
74 if fd < 0 { return -1 }
75 sys_write(fd, ln, o)
76 sys_close(fd)
77 return 0
78}
79func wm_le(q: *u8, i: i64, n: i64) -> i64 {
80 var le: i64 = i
81 var s: i64 = 1
82 while s==1 { if le>=n { s=0 } else { if q[le]==(10 as u8){s=0} else {le=le+1} } }
83 return le
84}
85func wm_col(q: *u8, ls: i64, le: i64, c: i64, out: *i64) -> i64 {
86 var col: i64 = 0
87 var p: i64 = ls
88 while col < c {
89 var s: i64 = 1
90 while s == 1 { if p >= le { return 0 } if q[p]==(9 as u8) { s = 0 } else { p = p+1 } }
91 p = p + 1
92 col = col + 1
93 }
94 var e: i64 = p
95 var s2: i64 = 1
96 while s2 == 1 { if e >= le { s2 = 0 } else { if q[e]==(9 as u8) { s2 = 0 } else { e = e+1 } } }
97 out[0] = p
98 out[1] = e
99 return 1
100}
101func wm_lit_eq(q: *u8, s: i64, e: i64, lit: *u8) -> i64 {
102 var i: i64 = 0
103 while s+i < e { if lit[i]==(0 as u8) { return 0 } if q[s+i]!=lit[i] { return 0 } i=i+1 }
104 if lit[i]!=(0 as u8) { return 0 }
105 return 1
106}
107func wm_span_eq(q: *u8, s1: i64, e1: i64, s2: i64, e2: i64) -> i64 {
108 if e1-s1 != e2-s2 { return 0 }
109 var i: i64 = 0
110 while s1+i < e1 { if q[s1+i]!=q[s2+i] { return 0 } i=i+1 }
111 return 1
112}
113func wm_atoi(q: *u8, s: i64, e: i64) -> i64 {
114 var v: i64 = 0
115 var i: i64 = s
116 while i < e { let c: i64 = q[i] as i64; if c>=48 { if c<=57 { v = v*10 + (c-48) } } i=i+1 }
117 return v
118}
119func wm_frames(q: *u8, n: i64) -> i64 {
120 var c: i64 = 0
121 var i: i64 = 0
122 while i < n { let le: i64 = wm_le(q,i,n); c=c+1; i = le + 1 }
123 return c
124}
125
126// ---------- lane scans (ws identified by col2 span; lanes = first-KICKOFF occurrences) ----------
127func wm_first_kick(q: *u8, upto: i64, ws_s: i64, ws_e: i64) -> i64 {
128 let cv: *i64 = sys_mmap(16) as *i64
129 let cw: *i64 = sys_mmap(16) as *i64
130 var i: i64 = 0
131 while i < upto {
132 let le: i64 = wm_le(q,i,upto)
133 if wm_col(q,i,le,1,cv)==1 { if wm_lit_eq(q,cv[0],cv[1],"KICKOFF" as *u8)==1 {
134 if wm_col(q,i,le,2,cw)==1 { if wm_span_eq(q,cw[0],cw[1],ws_s,ws_e)==1 { return 0 } }
135 } }
136 i = le + 1
137 }
138 return 1
139}
140func wm_has(q: *u8, n: i64, verb: *u8, ws_s: i64, ws_e: i64) -> i64 {
141 let cv: *i64 = sys_mmap(16) as *i64
142 let cw: *i64 = sys_mmap(16) as *i64
143 var i: i64 = 0
144 while i < n {
145 let le: i64 = wm_le(q,i,n)
146 if wm_col(q,i,le,1,cv)==1 { if wm_lit_eq(q,cv[0],cv[1],verb)==1 {
147 if wm_col(q,i,le,2,cw)==1 { if wm_span_eq(q,cw[0],cw[1],ws_s,ws_e)==1 { return 1 } }
148 } }
149 i = le + 1
150 }
151 return 0
152}
153func wm_count_verb(q: *u8, cx: *i64, verb: *u8, ws_s: i64, ws_e: i64) -> i64 {
154 let n: i64 = cx[0]
155 let cv: *i64 = sys_mmap(16) as *i64
156 let cw: *i64 = sys_mmap(16) as *i64
157 var c: i64 = 0
158 var i: i64 = 0
159 while i < n {
160 let le: i64 = wm_le(q,i,n)
161 if wm_col(q,i,le,1,cv)==1 { if wm_lit_eq(q,cv[0],cv[1],verb)==1 {
162 if wm_col(q,i,le,2,cw)==1 { if wm_span_eq(q,cw[0],cw[1],ws_s,ws_e)==1 { c=c+1 } }
163 } }
164 i = le + 1
165 }
166 return c
167}
168func wm_first_ts(q: *u8, cx: *i64, ws_s: i64, ws_e: i64) -> i64 {
169 let n: i64 = cx[0]
170 let cw: *i64 = sys_mmap(16) as *i64
171 let c0: *i64 = sys_mmap(16) as *i64
172 var i: i64 = 0
173 while i < n {
174 let le: i64 = wm_le(q,i,n)
175 if wm_col(q,i,le,2,cw)==1 { if wm_span_eq(q,cw[0],cw[1],ws_s,ws_e)==1 {
176 if wm_col(q,i,le,0,c0)==1 { return wm_atoi(q,c0[0],c0[1]) }
177 } }
178 i = le + 1
179 }
180 return -1
181}
182func wm_last_ts(q: *u8, cx: *i64, ws_s: i64, ws_e: i64) -> i64 {
183 let n: i64 = cx[0]
184 let cw: *i64 = sys_mmap(16) as *i64
185 let c0: *i64 = sys_mmap(16) as *i64
186 var last: i64 = -1
187 var i: i64 = 0
188 while i < n {
189 let le: i64 = wm_le(q,i,n)
190 if wm_col(q,i,le,2,cw)==1 { if wm_span_eq(q,cw[0],cw[1],ws_s,ws_e)==1 {
191 if wm_col(q,i,le,0,c0)==1 { last = wm_atoi(q,c0[0],c0[1]) }
192 } }
193 i = le + 1
194 }
195 return last
196}
197func wm_note_span(q: *u8, cx: *i64, ws_s: i64, ws_e: i64, out: *i64) -> i64 {
198 let n: i64 = cx[0]
199 let cw: *i64 = sys_mmap(16) as *i64
200 let cn: *i64 = sys_mmap(16) as *i64
201 var ns: i64 = -1
202 var ne: i64 = -1
203 var i: i64 = 0
204 while i < n {
205 let le: i64 = wm_le(q,i,n)
206 if wm_col(q,i,le,2,cw)==1 { if wm_span_eq(q,cw[0],cw[1],ws_s,ws_e)==1 {
207 if wm_col(q,i,le,4,cn)==1 { ns=cn[0]; ne=cn[1] }
208 } }
209 i = le + 1
210 }
211 if ns >= 0 { out[0]=ns; out[1]=ne; return 1 }
212 return 0
213}
214func wm_ws_actors(q: *u8, cx: *i64, ws_s: i64, ws_e: i64) -> i64 {
215 let n: i64 = cx[0]
216 let cw: *i64 = sys_mmap(16) as *i64
217 let ca: *i64 = sys_mmap(16) as *i64
218 let cw2: *i64 = sys_mmap(16) as *i64
219 let ca2: *i64 = sys_mmap(16) as *i64
220 var c: i64 = 0
221 var i: i64 = 0
222 while i < n {
223 let le: i64 = wm_le(q,i,n)
224 if wm_col(q,i,le,2,cw)==1 { if wm_span_eq(q,cw[0],cw[1],ws_s,ws_e)==1 {
225 if wm_col(q,i,le,3,ca)==1 {
226 var seen: i64 = 0
227 var j: i64 = 0
228 while j < i {
229 let je: i64 = wm_le(q,j,i)
230 if wm_col(q,j,je,2,cw2)==1 { if wm_span_eq(q,cw2[0],cw2[1],ws_s,ws_e)==1 {
231 if wm_col(q,j,je,3,ca2)==1 { if wm_span_eq(q,ca2[0],ca2[1],ca[0],ca[1])==1 { seen = 1 } }
232 } }
233 j = je + 1
234 }
235 if seen==0 { c=c+1 }
236 }
237 } }
238 i = le + 1
239 }
240 return c
241}
242// state: 0 DONE / 1 ACTIVE / 2 STALE / 3 ABANDONED (thresholds are DATA in cx, never magic)
243func wm_state(q: *u8, cx: *i64, ws_s: i64, ws_e: i64) -> i64 {
244 if wm_has(q,cx[0],"DONE" as *u8,ws_s,ws_e)==1 { return 0 }
245 let lt: i64 = wm_last_ts(q,cx,ws_s,ws_e)
246 if lt < 0 { return 3 }
247 let age: i64 = cx[1] - lt
248 if age > cx[3] { return 3 }
249 if age > cx[2] { return 2 }
250 return 1
251}
252func wm_state_name(st: i64) -> *u8 {
253 if st==0 { return "DONE" as *u8 }
254 if st==1 { return "ACTIVE" as *u8 }
255 if st==2 { return "STALE" as *u8 }
256 return "ABANDONED" as *u8
257}
258func wm_lanes_total(q: *u8, cx: *i64, t: *i64) -> i64 {
259 let n: i64 = cx[0]
260 let cv: *i64 = sys_mmap(16) as *i64
261 let cw: *i64 = sys_mmap(16) as *i64
262 t[0]=0; t[1]=0; t[2]=0; t[3]=0; t[4]=0
263 var i: i64 = 0
264 while i < n {
265 let le: i64 = wm_le(q,i,n)
266 if wm_col(q,i,le,1,cv)==1 { if wm_lit_eq(q,cv[0],cv[1],"KICKOFF" as *u8)==1 {
267 if wm_col(q,i,le,2,cw)==1 { if wm_first_kick(q,i,cw[0],cw[1])==1 {
268 t[0]=t[0]+1
269 let st: i64 = wm_state(q,cx,cw[0],cw[1])
270 t[1+st]=t[1+st]+1
271 } }
272 } }
273 i = le + 1
274 }
275 return 0
276}
277func wm_ws_span_lit(q: *u8, cx: *i64, ws: *u8, out: *i64) -> i64 {
278 let n: i64 = cx[0]
279 let cw: *i64 = sys_mmap(16) as *i64
280 var i: i64 = 0
281 while i < n {
282 let le: i64 = wm_le(q,i,n)
283 if wm_col(q,i,le,2,cw)==1 { if wm_lit_eq(q,cw[0],cw[1],ws)==1 { out[0]=cw[0]; out[1]=cw[1]; return 1 } }
284 i = le + 1
285 }
286 return 0
287}
288func wm_actor_span_lit(q: *u8, cx: *i64, actor: *u8, out: *i64) -> i64 {
289 let n: i64 = cx[0]
290 let ca: *i64 = sys_mmap(16) as *i64
291 var i: i64 = 0
292 while i < n {
293 let le: i64 = wm_le(q,i,n)
294 if wm_col(q,i,le,3,ca)==1 { if wm_lit_eq(q,ca[0],ca[1],actor)==1 { out[0]=ca[0]; out[1]=ca[1]; return 1 } }
295 i = le + 1
296 }
297 return 0
298}
299
300// ---------- actor scans ----------
301func wm_actor_seen(q: *u8, upto: i64, a_s: i64, a_e: i64) -> i64 {
302 let ca: *i64 = sys_mmap(16) as *i64
303 var i: i64 = 0
304 while i < upto {
305 let le: i64 = wm_le(q,i,upto)
306 if wm_col(q,i,le,3,ca)==1 { if wm_span_eq(q,ca[0],ca[1],a_s,a_e)==1 { return 1 } }
307 i = le + 1
308 }
309 return 0
310}
311func wm_actors_distinct(q: *u8, cx: *i64) -> i64 {
312 let n: i64 = cx[0]
313 let ca: *i64 = sys_mmap(16) as *i64
314 var c: i64 = 0
315 var i: i64 = 0
316 while i < n {
317 let le: i64 = wm_le(q,i,n)
318 if wm_col(q,i,le,3,ca)==1 { if wm_actor_seen(q,i,ca[0],ca[1])==0 { c=c+1 } }
319 i = le + 1
320 }
321 return c
322}
323func wm_actor_frames(q: *u8, cx: *i64, a_s: i64, a_e: i64) -> i64 {
324 let n: i64 = cx[0]
325 let ca: *i64 = sys_mmap(16) as *i64
326 var c: i64 = 0
327 var i: i64 = 0
328 while i < n {
329 let le: i64 = wm_le(q,i,n)
330 if wm_col(q,i,le,3,ca)==1 { if wm_span_eq(q,ca[0],ca[1],a_s,a_e)==1 { c=c+1 } }
331 i = le + 1
332 }
333 return c
334}
335func wm_actor_ws(q: *u8, cx: *i64, a_s: i64, a_e: i64) -> i64 {
336 let n: i64 = cx[0]
337 let ca: *i64 = sys_mmap(16) as *i64
338 let cw: *i64 = sys_mmap(16) as *i64
339 let ca2: *i64 = sys_mmap(16) as *i64
340 let cw2: *i64 = sys_mmap(16) as *i64
341 var c: i64 = 0
342 var i: i64 = 0
343 while i < n {
344 let le: i64 = wm_le(q,i,n)
345 if wm_col(q,i,le,3,ca)==1 { if wm_span_eq(q,ca[0],ca[1],a_s,a_e)==1 {
346 if wm_col(q,i,le,2,cw)==1 {
347 var seen: i64 = 0
348 var j: i64 = 0
349 while j < i {
350 let je: i64 = wm_le(q,j,i)
351 if wm_col(q,j,je,3,ca2)==1 { if wm_span_eq(q,ca2[0],ca2[1],a_s,a_e)==1 {
352 if wm_col(q,j,je,2,cw2)==1 { if wm_span_eq(q,cw2[0],cw2[1],cw[0],cw[1])==1 { seen=1 } }
353 } }
354 j = je + 1
355 }
356 if seen==0 { c=c+1 }
357 }
358 } }
359 i = le + 1
360 }
361 return c
362}
363
364// ---------- emit helpers (quotes/braces emitted as BYTES -- no escaped-quote literals) ----------
365func wm_jesc(d: *u8, o: i64, q: *u8, s: i64, e: i64, maxb: i64) -> i64 {
366 var p: i64 = o
367 var i: i64 = s
368 var used: i64 = 0
369 while i < e {
370 if used >= maxb { i = e } else {
371 let c: i64 = q[i] as i64
372 if c == 34 { d[p]=92 as u8; p=p+1; d[p]=34 as u8; p=p+1 } else { if c == 92 { d[p]=92 as u8; p=p+1; d[p]=92 as u8; p=p+1 } else { if c < 32 { d[p]=32 as u8; p=p+1 } else { d[p]=c as u8; p=p+1 } } }
373 used = used + 2
374 i = i + 1
375 }
376 }
377 return p
378}
379func wm_key(d: *u8, o: i64, name: *u8) -> i64 {
380 d[o]=34 as u8
381 var p: i64 = o + 1
382 p = wm_cat(d,p,name)
383 d[p]=34 as u8
384 p = p + 1
385 d[p]=58 as u8
386 p = p + 1
387 return p
388}
389func wm_qlit(d: *u8, o: i64, s: *u8) -> i64 {
390 var p: i64 = o
391 d[p]=34 as u8; p=p+1
392 p = wm_cat(d,p,s)
393 d[p]=34 as u8; p=p+1
394 return p
395}
396func wm_emit_lane(d: *u8, o: i64, q: *u8, cx: *i64, ws_s: i64, ws_e: i64) -> i64 {
397 var p: i64 = o
398 d[p]=123 as u8; p=p+1
399 p = wm_key(d,p,"ws" as *u8)
400 d[p]=34 as u8; p=p+1
401 p = wm_jesc(d,p,q,ws_s,ws_e,WM_NAME_MAX)
402 d[p]=34 as u8; p=p+1
403 d[p]=44 as u8; p=p+1
404 p = wm_key(d,p,"state" as *u8)
405 let st: i64 = wm_state(q,cx,ws_s,ws_e)
406 let sn: *u8 = wm_state_name(st)
407 p = wm_qlit(d,p,sn)
408 d[p]=44 as u8; p=p+1
409 p = wm_key(d,p,"kickoffs" as *u8)
410 let k: i64 = wm_count_verb(q,cx,"KICKOFF" as *u8,ws_s,ws_e)
411 p = wm_catn(d,p,k)
412 d[p]=44 as u8; p=p+1
413 p = wm_key(d,p,"beats" as *u8)
414 let b: i64 = wm_count_verb(q,cx,"BEAT" as *u8,ws_s,ws_e)
415 p = wm_catn(d,p,b)
416 d[p]=44 as u8; p=p+1
417 p = wm_key(d,p,"dones" as *u8)
418 let dn: i64 = wm_count_verb(q,cx,"DONE" as *u8,ws_s,ws_e)
419 p = wm_catn(d,p,dn)
420 d[p]=44 as u8; p=p+1
421 p = wm_key(d,p,"first_ts" as *u8)
422 let ft: i64 = wm_first_ts(q,cx,ws_s,ws_e)
423 p = wm_catn(d,p,ft)
424 d[p]=44 as u8; p=p+1
425 p = wm_key(d,p,"last_ts" as *u8)
426 let lt: i64 = wm_last_ts(q,cx,ws_s,ws_e)
427 p = wm_catn(d,p,lt)
428 d[p]=44 as u8; p=p+1
429 p = wm_key(d,p,"age_sec" as *u8)
430 var age: i64 = -1
431 if lt >= 0 { age = cx[1] - lt }
432 p = wm_catn(d,p,age)
433 d[p]=44 as u8; p=p+1
434 p = wm_key(d,p,"actors" as *u8)
435 let ac: i64 = wm_ws_actors(q,cx,ws_s,ws_e)
436 p = wm_catn(d,p,ac)
437 d[p]=44 as u8; p=p+1
438 p = wm_key(d,p,"last_note" as *u8)
439 d[p]=34 as u8; p=p+1
440 let no: *i64 = sys_mmap(16) as *i64
441 let hn: i64 = wm_note_span(q,cx,ws_s,ws_e,no)
442 if hn==1 { p = wm_jesc(d,p,q,no[0],no[1],WM_NOTE_MAX) }
443 d[p]=34 as u8; p=p+1
444 d[p]=125 as u8; p=p+1
445 return p
446}
447func wm_emit_actor(d: *u8, o: i64, q: *u8, cx: *i64, a_s: i64, a_e: i64) -> i64 {
448 var p: i64 = o
449 d[p]=123 as u8; p=p+1
450 p = wm_key(d,p,"actor" as *u8)
451 d[p]=34 as u8; p=p+1
452 p = wm_jesc(d,p,q,a_s,a_e,WM_NAME_MAX)
453 d[p]=34 as u8; p=p+1
454 d[p]=44 as u8; p=p+1
455 let fc: i64 = wm_actor_frames(q,cx,a_s,a_e)
456 p = wm_key(d,p,"frames" as *u8)
457 p = wm_catn(d,p,fc)
458 d[p]=44 as u8; p=p+1
459 let wc: i64 = wm_actor_ws(q,cx,a_s,a_e)
460 p = wm_key(d,p,"workstreams" as *u8)
461 p = wm_catn(d,p,wc)
462 d[p]=125 as u8; p=p+1
463 return p
464}
465func wm_mine_json(q: *u8, cx: *i64, d: *u8) -> i64 {
466 let n: i64 = cx[0]
467 var p: i64 = 0
468 d[p]=123 as u8; p=p+1
469 p = wm_key(d,p,"v" as *u8)
470 p = wm_catn(d,p,1)
471 d[p]=44 as u8; p=p+1
472 p = wm_key(d,p,"tool" as *u8)
473 p = wm_qlit(d,p,"nx_ws_miner" as *u8)
474 d[p]=44 as u8; p=p+1
475 p = wm_key(d,p,"journal" as *u8)
476 d[p]=34 as u8; p=p+1
477 let jp: *u8 = cx[5] as *u8
478 let jl: i64 = wm_vlen(jp)
479 p = wm_jesc(d,p,jp,0,jl,200)
480 d[p]=34 as u8; p=p+1
481 d[p]=44 as u8; p=p+1
482 p = wm_key(d,p,"journal_bytes" as *u8)
483 p = wm_catn(d,p,n)
484 d[p]=44 as u8; p=p+1
485 p = wm_key(d,p,"window_bytes" as *u8)
486 p = wm_catn(d,p,WM_WIN)
487 d[p]=44 as u8; p=p+1
488 p = wm_key(d,p,"truncated" as *u8)
489 p = wm_catn(d,p,cx[4])
490 d[p]=44 as u8; p=p+1
491 p = wm_key(d,p,"now" as *u8)
492 p = wm_catn(d,p,cx[1])
493 d[p]=44 as u8; p=p+1
494 p = wm_key(d,p,"stale_sec" as *u8)
495 p = wm_catn(d,p,cx[2])
496 d[p]=44 as u8; p=p+1
497 p = wm_key(d,p,"abandoned_sec" as *u8)
498 p = wm_catn(d,p,cx[3])
499 d[p]=44 as u8; p=p+1
500 p = wm_key(d,p,"note_max_bytes" as *u8)
501 p = wm_catn(d,p,WM_NOTE_MAX)
502 d[p]=44 as u8; p=p+1
503 let fr: i64 = wm_frames(q,n)
504 p = wm_key(d,p,"frames" as *u8)
505 p = wm_catn(d,p,fr)
506 d[p]=44 as u8; p=p+1
507 let t: *i64 = sys_mmap(64) as *i64
508 wm_lanes_total(q,cx,t)
509 let ad: i64 = wm_actors_distinct(q,cx)
510 p = wm_key(d,p,"totals" as *u8)
511 d[p]=123 as u8; p=p+1
512 p = wm_key(d,p,"workstreams" as *u8)
513 p = wm_catn(d,p,t[0])
514 d[p]=44 as u8; p=p+1
515 p = wm_key(d,p,"done" as *u8)
516 p = wm_catn(d,p,t[1])
517 d[p]=44 as u8; p=p+1
518 p = wm_key(d,p,"active" as *u8)
519 p = wm_catn(d,p,t[2])
520 d[p]=44 as u8; p=p+1
521 p = wm_key(d,p,"stale" as *u8)
522 p = wm_catn(d,p,t[3])
523 d[p]=44 as u8; p=p+1
524 p = wm_key(d,p,"abandoned" as *u8)
525 p = wm_catn(d,p,t[4])
526 d[p]=44 as u8; p=p+1
527 p = wm_key(d,p,"actors" as *u8)
528 p = wm_catn(d,p,ad)
529 d[p]=125 as u8; p=p+1
530 d[p]=44 as u8; p=p+1
531 p = wm_key(d,p,"lanes" as *u8)
532 d[p]=91 as u8; p=p+1
533 let cv: *i64 = sys_mmap(16) as *i64
534 let cw: *i64 = sys_mmap(16) as *i64
535 var capped: i64 = 0
536 var first: i64 = 1
537 var i: i64 = 0
538 while i < n {
539 let le: i64 = wm_le(q,i,n)
540 if wm_col(q,i,le,1,cv)==1 { if wm_lit_eq(q,cv[0],cv[1],"KICKOFF" as *u8)==1 {
541 if wm_col(q,i,le,2,cw)==1 { if wm_first_kick(q,i,cw[0],cw[1])==1 {
542 if p > WM_SOFT { capped=1 } else {
543 if first==0 { d[p]=44 as u8; p=p+1 }
544 first=0
545 p = wm_emit_lane(d,p,q,cx,cw[0],cw[1])
546 }
547 } }
548 } }
549 i = le + 1
550 }
551 d[p]=93 as u8; p=p+1
552 d[p]=44 as u8; p=p+1
553 p = wm_key(d,p,"lanes_capped" as *u8)
554 p = wm_catn(d,p,capped)
555 d[p]=44 as u8; p=p+1
556 p = wm_key(d,p,"actors_list" as *u8)
557 d[p]=91 as u8; p=p+1
558 let ca: *i64 = sys_mmap(16) as *i64
559 var acapped: i64 = 0
560 var afirst: i64 = 1
561 var j: i64 = 0
562 while j < n {
563 let je: i64 = wm_le(q,j,n)
564 if wm_col(q,j,je,3,ca)==1 { if wm_actor_seen(q,j,ca[0],ca[1])==0 {
565 if p > WM_SOFT2 { acapped=1 } else {
566 if afirst==0 { d[p]=44 as u8; p=p+1 }
567 afirst=0
568 p = wm_emit_actor(d,p,q,cx,ca[0],ca[1])
569 }
570 } }
571 j = je + 1
572 }
573 d[p]=93 as u8; p=p+1
574 d[p]=44 as u8; p=p+1
575 p = wm_key(d,p,"actors_capped" as *u8)
576 p = wm_catn(d,p,acapped)
577 d[p]=125 as u8; p=p+1
578 d[p]=10 as u8; p=p+1
579 return p
580}
581
582// ---------- HTML page (no CSS braces, no bang/hash literals -- emitted as bytes where needed) ----------
583func wm_hesc(d: *u8, o: i64, q: *u8, s: i64, e: i64, maxb: i64) -> i64 {
584 var p: i64 = o
585 var i: i64 = s
586 var used: i64 = 0
587 while i < e {
588 if used >= maxb { i = e } else {
589 let c: i64 = q[i] as i64
590 if c == 60 { p = wm_cat(d,p,"<" as *u8) } else { if c == 62 { p = wm_cat(d,p,">" as *u8) } else { if c == 38 { p = wm_cat(d,p,"&" as *u8) } else { if c < 32 { d[p]=32 as u8; p=p+1 } else { d[p]=c as u8; p=p+1 } } } }
591 used = used + 5
592 i = i + 1
593 }
594 }
595 return p
596}
597func wm_td_n(d: *u8, o: i64, v: i64) -> i64 {
598 var p: i64 = o
599 p = wm_cat(d,p,"<td>" as *u8)
600 p = wm_catn(d,p,v)
601 p = wm_cat(d,p,"</td>" as *u8)
602 return p
603}
604func wm_page_html(q: *u8, cx: *i64, d: *u8) -> i64 {
605 let n: i64 = cx[0]
606 var p: i64 = 0
607 p = wm_cat(d,p,"<" as *u8)
608 d[p]=33 as u8
609 p = p + 1
610 p = wm_cat(d,p,"doctype html><html><head><meta charset=utf-8><title>Nishi Workstream Miner</title></head><body>" as *u8)
611 p = wm_cat(d,p,"<h1>Nishi Workstream Miner -- historic + parallel lanes</h1>" as *u8)
612 let t: *i64 = sys_mmap(64) as *i64
613 wm_lanes_total(q,cx,t)
614 let ad: i64 = wm_actors_distinct(q,cx)
615 let fr: i64 = wm_frames(q,n)
616 p = wm_cat(d,p,"<p>workstreams=" as *u8)
617 p = wm_catn(d,p,t[0])
618 p = wm_cat(d,p," done=" as *u8)
619 p = wm_catn(d,p,t[1])
620 p = wm_cat(d,p," active=" as *u8)
621 p = wm_catn(d,p,t[2])
622 p = wm_cat(d,p," stale=" as *u8)
623 p = wm_catn(d,p,t[3])
624 p = wm_cat(d,p," abandoned=" as *u8)
625 p = wm_catn(d,p,t[4])
626 p = wm_cat(d,p," actors=" as *u8)
627 p = wm_catn(d,p,ad)
628 p = wm_cat(d,p," frames=" as *u8)
629 p = wm_catn(d,p,fr)
630 p = wm_cat(d,p,"</p>" as *u8)
631 p = wm_cat(d,p,"<table border=1><tr><th>workstream</th><th>state</th><th>kick</th><th>beat</th><th>done</th><th>age-min</th><th>actors</th><th>last checkpoint</th></tr>" as *u8)
632 let cv: *i64 = sys_mmap(16) as *i64
633 let cw: *i64 = sys_mmap(16) as *i64
634 let no: *i64 = sys_mmap(16) as *i64
635 var truncated_rows: i64 = 0
636 var i: i64 = 0
637 while i < n {
638 let le: i64 = wm_le(q,i,n)
639 if wm_col(q,i,le,1,cv)==1 { if wm_lit_eq(q,cv[0],cv[1],"KICKOFF" as *u8)==1 {
640 if wm_col(q,i,le,2,cw)==1 { if wm_first_kick(q,i,cw[0],cw[1])==1 {
641 if p > WM_PAGE_SOFT { truncated_rows = truncated_rows + 1 } else {
642 p = wm_cat(d,p,"<tr><td>" as *u8)
643 p = wm_hesc(d,p,q,cw[0],cw[1],WM_NAME_MAX)
644 p = wm_cat(d,p,"</td><td>" as *u8)
645 let st: i64 = wm_state(q,cx,cw[0],cw[1])
646 let sn: *u8 = wm_state_name(st)
647 p = wm_cat(d,p,sn)
648 p = wm_cat(d,p,"</td>" as *u8)
649 let k: i64 = wm_count_verb(q,cx,"KICKOFF" as *u8,cw[0],cw[1])
650 p = wm_td_n(d,p,k)
651 let b: i64 = wm_count_verb(q,cx,"BEAT" as *u8,cw[0],cw[1])
652 p = wm_td_n(d,p,b)
653 let dn: i64 = wm_count_verb(q,cx,"DONE" as *u8,cw[0],cw[1])
654 p = wm_td_n(d,p,dn)
655 let lt: i64 = wm_last_ts(q,cx,cw[0],cw[1])
656 var agem: i64 = -1
657 if lt >= 0 { agem = (cx[1] - lt) / 60 }
658 p = wm_td_n(d,p,agem)
659 let ac: i64 = wm_ws_actors(q,cx,cw[0],cw[1])
660 p = wm_td_n(d,p,ac)
661 p = wm_cat(d,p,"<td>" as *u8)
662 let hn: i64 = wm_note_span(q,cx,cw[0],cw[1],no)
663 if hn==1 { p = wm_hesc(d,p,q,no[0],no[1],WM_NOTE_MAX) }
664 p = wm_cat(d,p,"</td></tr>" as *u8)
665 }
666 } }
667 } }
668 i = le + 1
669 }
670 p = wm_cat(d,p,"</table>" as *u8)
671 if truncated_rows > 0 {
672 p = wm_cat(d,p,"<p>ENVELOPE: rows_truncated=" as *u8)
673 p = wm_catn(d,p,truncated_rows)
674 p = wm_cat(d,p,"</p>" as *u8)
675 }
676 p = wm_cat(d,p,"<p>envelope window_bytes=" as *u8)
677 p = wm_catn(d,p,WM_WIN)
678 p = wm_cat(d,p," journal_bytes=" as *u8)
679 p = wm_catn(d,p,n)
680 p = wm_cat(d,p," truncated=" as *u8)
681 p = wm_catn(d,p,cx[4])
682 p = wm_cat(d,p," generated=" as *u8)
683 p = wm_catn(d,p,cx[1])
684 p = wm_cat(d,p," | source=knowledge/status/ws_sync.jrnl | tool=nx_ws_miner (MCP) | <a href=/standup>standup</a> <a href=/frontier>frontier</a> <a href=/roi>roi</a></p>" as *u8)
685 p = wm_cat(d,p,"</body></html>" as *u8)
686 d[p]=10 as u8
687 p = p + 1
688 return p
689}
690
691// ---------- substring find (selftest smoke) ----------
692func wm_find(d: *u8, dn: i64, lit: *u8) -> i64 {
693 let ll: i64 = wm_vlen(lit)
694 if ll == 0 { return 0 }
695 var i: i64 = 0
696 while i + ll <= dn {
697 var k: i64 = 0
698 var ok: i64 = 1
699 while k < ll { if d[i+k]!=lit[k] { ok=0; k=ll } else { k=k+1 } }
700 if ok==1 { return 1 }
701 i = i + 1
702 }
703 return 0
704}
705
706// ---------- selftest gate (T1..T9, deterministic via injected timestamps) ----------
707func wm_selftest(journal: *u8) -> i64 {
708 let ctr: *i64 = gv_ctr()
709 gv_head("nx_ws_miner selftest -- historic workstream mining teeth (caller pre-cleans journal)" as *u8)
710 let q: *u8 = sys_mmap(WM_WIN)
711 let cx: *i64 = sys_mmap(64) as *i64
712 let t: *i64 = sys_mmap(64) as *i64
713 let sp: *i64 = sys_mmap(16) as *i64
714 let now: i64 = sys_now_realtime_sec()
715 let rcap: i64 = WM_WIN - 8
716 // T1 empty journal -> zero lanes, no fabrication
717 var n: i64 = wm_read(journal,q,rcap)
718 cx[0]=n; cx[1]=now; cx[2]=WM_STALE_DEF; cx[3]=WM_ABAND_DEF; cx[4]=0; cx[5]=journal as i64
719 wm_lanes_total(q,cx,t)
720 var ok1: i64 = 0
721 if t[0]==0 { if n==0 { ok1=1 } }
722 gv_check("T1 empty journal zero lanes no fabrication" as *u8, ok1, ctr)
723 // seed lane A: full lifecycle at fixed ancient timestamps
724 wm_append(journal, 1000, "KICKOFF" as *u8, "laneA" as *u8, "actor1" as *u8, "start-A" as *u8)
725 wm_append(journal, WM_MAGIC_2000, "BEAT" as *u8, "laneA" as *u8, "actor1" as *u8, "mid-A" as *u8)
726 wm_append(journal, WM_MAGIC_3000, "DONE" as *u8, "laneA" as *u8, "actor1" as *u8, "end-A" as *u8)
727 n = wm_read(journal,q,rcap)
728 cx[0]=n
729 wm_lanes_total(q,cx,t)
730 var ok2: i64 = 0
731 if t[0]==1 { if t[1]==1 { ok2=1 } }
732 gv_check("T2 lifecycle lane counted once and DONE" as *u8, ok2, ctr)
733 var ok3: i64 = 0
734 if wm_ws_span_lit(q,cx,"laneA" as *u8,sp)==1 {
735 let ka: i64 = wm_count_verb(q,cx,"KICKOFF" as *u8,sp[0],sp[1])
736 let ba: i64 = wm_count_verb(q,cx,"BEAT" as *u8,sp[0],sp[1])
737 let fa: i64 = wm_first_ts(q,cx,sp[0],sp[1])
738 let la: i64 = wm_last_ts(q,cx,sp[0],sp[1])
739 if ka==1 { if ba==1 { if fa==1000 { if la==WM_MAGIC_3000 { ok3=1 } } } }
740 }
741 gv_check("T3 per-lane counts and first/last ts exact" as *u8, ok3, ctr)
742 // T4 ancient kickoff without done -> ABANDONED
743 wm_append(journal, 1000, "KICKOFF" as *u8, "laneB" as *u8, "actor2" as *u8, "start-B" as *u8)
744 n = wm_read(journal,q,rcap)
745 cx[0]=n
746 var ok4: i64 = 0
747 if wm_ws_span_lit(q,cx,"laneB" as *u8,sp)==1 { let st4: i64 = wm_state(q,cx,sp[0],sp[1]); if st4==3 { ok4=1 } }
748 gv_check("T4 ancient undone lane detected ABANDONED" as *u8, ok4, ctr)
749 // T5 mid-age lane -> STALE
750 let ts5: i64 = now - WM_MAGIC_7200
751 wm_append(journal, ts5, "KICKOFF" as *u8, "laneD" as *u8, "actor3" as *u8, "start-D" as *u8)
752 n = wm_read(journal,q,rcap)
753 cx[0]=n
754 var ok5: i64 = 0
755 if wm_ws_span_lit(q,cx,"laneD" as *u8,sp)==1 { let st5: i64 = wm_state(q,cx,sp[0],sp[1]); if st5==2 { ok5=1 } }
756 gv_check("T5 hour-old undone lane detected STALE" as *u8, ok5, ctr)
757 // T6 fresh lane -> ACTIVE
758 let ts6: i64 = now - 10
759 wm_append(journal, ts6, "KICKOFF" as *u8, "laneC" as *u8, "actor2" as *u8, "start-C" as *u8)
760 n = wm_read(journal,q,rcap)
761 cx[0]=n
762 var ok6: i64 = 0
763 if wm_ws_span_lit(q,cx,"laneC" as *u8,sp)==1 { let st6: i64 = wm_state(q,cx,sp[0],sp[1]); if st6==1 { ok6=1 } }
764 gv_check("T6 fresh undone lane detected ACTIVE" as *u8, ok6, ctr)
765 // T7 distinct actors overall + per-actor workstream reach (actor2 touched laneB + laneC)
766 let adc: i64 = wm_actors_distinct(q,cx)
767 var ok7: i64 = 0
768 if adc==3 {
769 if wm_actor_span_lit(q,cx,"actor2" as *u8,sp)==1 {
770 let wc: i64 = wm_actor_ws(q,cx,sp[0],sp[1])
771 if wc==2 { ok7=1 }
772 }
773 }
774 gv_check("T7 distinct actors 3 and actor2 reach 2 lanes" as *u8, ok7, ctr)
775 // T8 neg-control: absent workstream honestly ABSENT (no fabricated span/ts)
776 var ok8: i64 = 0
777 if wm_ws_span_lit(q,cx,"laneNOPE" as *u8,sp)==0 { ok8=1 }
778 gv_check("T8 neg-control absent lane stays absent" as *u8, ok8, ctr)
779 // T9 JSON emit smoke: valid open brace + totals + envelope keys present
780 let d: *u8 = sys_mmap(WM_OUT)
781 let dl: i64 = wm_mine_json(q,cx,d)
782 var ok9: i64 = 0
783 if dl > 0 { if d[0]==(123 as u8) { if wm_find(d,dl,"workstreams" as *u8)==1 { if wm_find(d,dl,"lanes_capped" as *u8)==1 { if wm_find(d,dl,"ABANDONED" as *u8)==1 { ok9=1 } } } } }
784 gv_check("T9 JSON emit carries totals plus declared envelope" as *u8, ok9, ctr)
785 let rc: i64 = gv_verdict("WS-MINER-GATE" as *u8, ctr, "historic workstream miner teeth green" as *u8)
786 return rc
787}
788
789func main(argc: i64, argv: *i64) -> i64 {
790 if argc < 3 { gv_puts("usage: nx_ws_miner {mine <journal> [stale_sec] [abandoned_sec] | page <journal> <outfile> [stale_sec] [abandoned_sec] | selftest <journal>}\n" as *u8); sys_exit(2); return 2 }
791 let verb: *u8 = argv[1] as *u8
792 let journal: *u8 = argv[2] as *u8
793 let vl: i64 = wm_vlen(verb)
794 if wm_lit_eq(verb,0,vl,"selftest" as *u8)==1 { let rc: i64 = wm_selftest(journal); sys_exit(rc); return rc }
795 let q: *u8 = sys_mmap(WM_WIN)
796 let rcap: i64 = WM_WIN - 8
797 let n: i64 = wm_read(journal,q,rcap)
798 let cx: *i64 = sys_mmap(64) as *i64
799 cx[0]=n
800 cx[1]=sys_now_realtime_sec()
801 cx[2]=WM_STALE_DEF
802 cx[3]=WM_ABAND_DEF
803 cx[4]=0
804 if n >= rcap { cx[4]=1 }
805 cx[5]=journal as i64
806 if wm_lit_eq(verb,0,vl,"mine" as *u8)==1 {
807 if argc >= 4 { let sv: i64 = wm_atoi_z(argv[3] as *u8); if sv > 0 { cx[2]=sv } }
808 if argc >= 5 { let av: i64 = wm_atoi_z(argv[4] as *u8); if av > 0 { cx[3]=av } }
809 let d: *u8 = sys_mmap(WM_OUT)
810 let dl: i64 = wm_mine_json(q,cx,d)
811 sys_write(1,d,dl)
812 sys_exit(0)
813 return 0
814 }
815 if wm_lit_eq(verb,0,vl,"page" as *u8)==1 {
816 if argc < 4 { gv_puts("page needs <journal> <outfile>\n" as *u8); sys_exit(2); return 2 }
817 if argc >= 5 { let sv2: i64 = wm_atoi_z(argv[4] as *u8); if sv2 > 0 { cx[2]=sv2 } }
818 if argc >= 6 { let av2: i64 = wm_atoi_z(argv[5] as *u8); if av2 > 0 { cx[3]=av2 } }
819 let outfile: *u8 = argv[3] as *u8
820 let d: *u8 = sys_mmap(WM_OUT)
821 let dl: i64 = wm_page_html(q,cx,d)
822 let fd: i64 = sys_openat_wr(outfile, 0x1a4)
823 if fd < 0 { gv_puts("WSMINE-PAGE OPEN-FAIL\n" as *u8); sys_exit(1); return 1 }
824 sys_write(fd,d,dl)
825 sys_close(fd)
826 gv_puts("WSMINE-PAGE bytes=" as *u8)
827 gv_num(dl)
828 gv_puts("\n" as *u8)
829 sys_exit(0)
830 return 0
831 }
832 gv_puts("unknown verb\n" as *u8)
833 sys_exit(2)
834 return 2
835}