code wiki / _hdl_build / nx_actlog.nx
nx_actlog.nx source
↩ module page · 1750 lines · 85350 B
1// nx_actlog.nx -- ACTION LOG + WORKFLOW SEQUENCE MINER (ws=ws-intel3, 2026-07-20).
2// F217 completion (loop design-of-record R3): every cycle action journaled (ws/tool/verb/
3// outcome) + the nx_workflow_mine half = n-gram mining over per-workstream action sequences.
4// Recurring tool:verb bigrams/trigrams with support >= minsup are the EMPIRICAL workflow
5// candidates (executed patterns, not combinatorial proposals -- the complement of
6// nx_atlas_discover). The loop: sessions/seats/plans LOG actions -> mine surfaces patterns
7// -> proposals enter nx_pm_intake -> PM/LLM seat triages -> catalog verb. Sequences NEVER
8// cross workstream boundaries (per-ws successor chains). State derived, append-only,
9// conflict-free (O_APPEND; ws_sync lineage).
10// Frame: <ts>\t<ws>\t<tool>\t<verb>\t<outcome>\t<note>
11// SCALE LAW: windowed reads + declared envelope (window_bytes/truncated/bigrams_capped/
12// trigrams_capped); O(n^3) pair scan honest for journal-window scale, declared.
13// license_tier: ORIGINAL No hw writes (Rule 26).
14// log <journal> <ws> <tool> <verb> <outcome> <note> -> ACTLOG OK
15// mine <journal> [minsup] -> JSON (default minsup 2)
16// freq <journal> [topn] -> JSON per-tool:verb counts, ranked (topn: rows emitted, default 30; distinct is always the whole population)
17// (the fallback-log ranking verb; F872 rung 2)
18// harden <journal> [minsup] [filer] -> every tool:verb recurring >= minsup
19// auto-files a hardening debt via the
20// ALLOWLIST-RESOLVED filer (default nx_debt;
21// count-free canonical desc => idempotent)
22// selftest <scratch-journal> -> gate T1..T9 (caller pre-cleans)
23// steps <journal> [minsup] [conf] [topn] [now] -> ES26 STEPS-TO-SOLVE (2026-09-06): recurring adjacent
24// bigrams/trigrams joined to knowledge/stepsolve.conf and
25// classified ONE-STEP-AVAILABLE / DEPENDENCY / REDUCIBLE /
26// UNDECLARED; support-weighted partition, the reason or the
27// composed verb per ritual, the UNDECLARED worklist most
28// common first; spine knowledge/status/stepsolve.spine +
29// gauge stamp knowledge/status/stepsolve.stamp (gauge_pass)
30import "nx_sovjson_lib.nx"
31import "nx_syscalls.nx"
32import "nx_gate_verdict.nx"
33import "nx_tool_run.nx"
34import "nx_stepsolve_lib.nx" // ES26 (2026-09-06): THE ONE steps-to-solve ruler -- the `steps` verb below joins this miner's n-grams to knowledge/stepsolve.conf
35const AL_MAGIC_5381: i64 = 5381
36const AL_MAGIC_1100: i64 = 1100
37const AL_MAGIC_1101: i64 = 1101
38const AL_MAGIC_1102: i64 = 1102
39const AL_MAGIC_1103: i64 = 1103
40const AL_MAGIC_1104: i64 = 1104
41const AL_MAGIC_1105: i64 = 1105
42const AL_MAGIC_1106: i64 = 1106
43const AL_MAGIC_1107: i64 = 1107
44const AL_MAGIC_1108: i64 = 1108
45const AL_MAGIC_1110: i64 = 1110
46const AL_MAGIC_1111: i64 = 1111
47const AL_MAGIC_1112: i64 = 1112
48const AL_MAGIC_1113: i64 = 1113
49const AL_MAGIC_1114: i64 = 1114
50const AL_MAGIC_1115: i64 = 1115
51const AL_MAGIC_4096: i64 = 4096
52const AL_MAGIC_1500: i64 = 1500
53const AL_MAGIC_1024: i64 = 1024
54const AL_MAGIC_4090: i64 = 4090
55
56const AL_WIN: i64 = 4194304
57const AL_SEEK_SET: i64 = 0
58const AL_SEEK_END: i64 = 2
59const AL_OUT: i64 = 262144
60const AL_SOFT: i64 = 49152
61const AL_NAME_MAX: i64 = 120
62const AL_MINSUP_DEF: i64 = 2
63const AL_BIGRAM_CAP: i64 = 30
64const AL_TRIGRAM_CAP: i64 = 15
65const AL_FREQ_CAP: i64 = 30
66const AL_FREQ_SLOTS: i64 = 256
67const AL_HARDEN_SEV: i64 = 5
68const AL_HARDEN_CAP: i64 = 10
69const AL_ALLOW_BUF: i64 = 131072
70const AL_IX_TVMAX: i64 = 4096
71const AL_IX_HSLOTS: i64 = 8193
72const AL_IX_GMAX: i64 = 16384
73const AL_IX_GHSLOTS: i64 = 32771
74const AL_IX_ARENA: i64 = 1048576
75const AL_IX_HMOD: i64 = 1000003
76const AL_IX_KEYB: i64 = 8192
77const AL_IX_RING: i64 = 9
78const AL_IX_MAXGAP: i64 = 8
79
80// al_cat/al_catn/al_vlen/al_le/al_col DELEGATE to the shared nx_sovjson_lib (sj_*) -- dup logic eaten (TS04-family)
81func al_cat(d: *u8, o: i64, s: *u8) -> i64 { return sj_cat(d, o, s) }
82func al_catn(d: *u8, o: i64, v: i64) -> i64 { return sj_catn(d, o, v) }
83func al_vlen(s: *u8) -> i64 { return sj_vlen(s) }
84func al_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 }
85// TAIL-ANCHORED (2026-08-20, Lane I). This read filled from offset 0 and stopped at AL_WIN, so once
86// the journal passed 4 MiB every reader kept the OLDEST bytes and dropped the NEWEST. MEASURED at the
87// time of this fix: knowledge/status/actlog.jrnl was 23,221,549 B against a 4,194,304 B window, so
88// mine/freq/harden answered "what do we do repeatedly" from the OLDEST 18.1% of the record -- a
89// recurrence miner blind to recent work proposes hardening for behaviour already superseded.
90// The identical defect was fixed in the siblings on 2026-08-07 (nx_trajscan tj_read, nx_toolatency
91// tl_read_tail, nx_wirecensus) and nx_actlog was MISSED: a fix that lives in one organ and not its
92// sibling is half a fix, and the missing half is invisible until something runs it. Deliberately the
93// SAME shape as tj_read, not a variant -- two spellings of one rule is the duplicate-ruler defect.
94// ANCHORED, not RAISED: a cap that can be crossed in silence will be crossed again.
95// DECLARED IMPRECISION (shared with tj_read, NOT introduced here): a tail read can begin mid-frame,
96// so the first line may be a partial frame -- bounded at <=1 malformed frame per read. Worth eating
97// in ONE place across all four organs rather than diverging here.
98func al_read(path: *u8, buf: *u8, cap: i64) -> i64 {
99 let fd: i64 = sys_openat_rd(path)
100 if fd < 0 { return 0 }
101 let sz: i64 = sys_lseek(fd, 0, AL_SEEK_END)
102 if sz > cap { sys_lseek(fd, sz - cap, AL_SEEK_SET) } else { sys_lseek(fd, 0, AL_SEEK_SET) }
103 var n: i64 = 0
104 var go: i64 = 1
105 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 } }
106 sys_close(fd)
107 return n
108}
109func al_append(journal: *u8, ts: i64, ws: *u8, tool: *u8, verb: *u8, outcome: *u8, note: *u8) -> i64 {
110 var t: i64 = ts
111 if t < 0 { t = sys_now_realtime_sec() }
112 let ln: *u8 = sys_mmap(AL_MAGIC_4096)
113 var o: i64 = 0
114 o = al_catn(ln, o, t)
115 ln[o]=9 as u8; o=o+1
116 o = al_cat(ln, o, ws)
117 ln[o]=9 as u8; o=o+1
118 o = al_cat(ln, o, tool)
119 ln[o]=9 as u8; o=o+1
120 o = al_cat(ln, o, verb)
121 ln[o]=9 as u8; o=o+1
122 o = al_cat(ln, o, outcome)
123 ln[o]=9 as u8; o=o+1
124 var i: i64 = 0
125 var used: i64 = 0
126 while note[i]!=(0 as u8) {
127 if used < AL_MAGIC_1500 {
128 let c: i64 = note[i] as i64
129 if c==9 { ln[o]=32 as u8; o=o+1 } else { if c==10 { ln[o]=32 as u8; o=o+1 } else { if c==13 { ln[o]=32 as u8; o=o+1 } else { ln[o]=c as u8; o=o+1 } } }
130 used = used + 1
131 }
132 i = i + 1
133 }
134 ln[o]=10 as u8; o=o+1
135 let fd: i64 = sys_openat_append(journal, 0x1a4)
136 if fd < 0 { return -1 }
137 sys_write(fd, ln, o)
138 sys_close(fd)
139 return 0
140}
141func al_le(q: *u8, i: i64, n: i64) -> i64 { return sj_le(q, i, n) }
142func al_col(q: *u8, ls: i64, le: i64, c: i64, out: *i64) -> i64 { return sj_col(q, ls, le, c, out) }
143func al_span_eq(q: *u8, s1: i64, e1: i64, s2: i64, e2: i64) -> i64 {
144 if e1-s1 != e2-s2 { return 0 }
145 var i: i64 = 0
146 while s1+i < e1 { if q[s1+i]!=q[s2+i] { return 0 } i=i+1 }
147 return 1
148}
149func al_lit_eq(q: *u8, s: i64, e: i64, lit: *u8) -> i64 {
150 var i: i64 = 0
151 while s+i < e { if lit[i]==(0 as u8) { return 0 } if q[s+i]!=lit[i] { return 0 } i=i+1 }
152 if lit[i]!=(0 as u8) { return 0 }
153 return 1
154}
155func al_frames(q: *u8, n: i64) -> i64 {
156 var c: i64 = 0
157 var i: i64 = 0
158 while i < n { let le: i64 = al_le(q,i,n); c=c+1; i = le + 1 }
159 return c
160}
161// successor of frame at ls: next frame (after this line) whose ws (col1) equals this frame's ws.
162// returns line-start or -1.
163func al_succ(q: *u8, cx: *i64, ls: i64) -> i64 {
164 let n: i64 = cx[0]
165 let w1: *i64 = sys_mmap(16) as *i64
166 let w2: *i64 = sys_mmap(16) as *i64
167 let le0: i64 = al_le(q,ls,n)
168 if al_col(q,ls,le0,1,w1)==0 { return -1 }
169 var i: i64 = le0 + 1
170 while i < n {
171 let le: i64 = al_le(q,i,n)
172 if al_col(q,i,le,1,w2)==1 { if al_span_eq(q,w2[0],w2[1],w1[0],w1[1])==1 { return i } }
173 i = le + 1
174 }
175 return -1
176}
177// tool:verb of frame at l1 equals frame at l2?
178func al_tv_eq(q: *u8, cx: *i64, l1: i64, l2: i64) -> i64 {
179 let n: i64 = cx[0]
180 let a: *i64 = sys_mmap(16) as *i64
181 let b: *i64 = sys_mmap(16) as *i64
182 let e1: i64 = al_le(q,l1,n)
183 let e2: i64 = al_le(q,l2,n)
184 if al_col(q,l1,e1,2,a)==0 { return 0 }
185 if al_col(q,l2,e2,2,b)==0 { return 0 }
186 if al_span_eq(q,a[0],a[1],b[0],b[1])==0 { return 0 }
187 if al_col(q,l1,e1,3,a)==0 { return 0 }
188 if al_col(q,l2,e2,3,b)==0 { return 0 }
189 if al_span_eq(q,a[0],a[1],b[0],b[1])==0 { return 0 }
190 return 1
191}
192// bigram at (i,j) content-equal to bigram at (i2,j2)?
193func al_bg_eq(q: *u8, cx: *i64, i: i64, j: i64, i2: i64, j2: i64) -> i64 {
194 if al_tv_eq(q,cx,i,i2)==0 { return 0 }
195 if al_tv_eq(q,cx,j,j2)==0 { return 0 }
196 return 1
197}
198// is (i,j) the FIRST occurrence of its bigram content? scan earlier frames' successor pairs.
199func al_bg_first(q: *u8, cx: *i64, i: i64, j: i64) -> i64 {
200 let n: i64 = cx[0]
201 var k: i64 = 0
202 while k < i {
203 let ke: i64 = al_le(q,k,n)
204 let m: i64 = al_succ(q,cx,k)
205 if m >= 0 { if al_bg_eq(q,cx,k,m,i,j)==1 { return 0 } }
206 k = ke + 1
207 }
208 return 1
209}
210func al_bg_support(q: *u8, cx: *i64, i: i64, j: i64) -> i64 {
211 let n: i64 = cx[0]
212 var c: i64 = 0
213 var k: i64 = 0
214 while k < n {
215 let ke: i64 = al_le(q,k,n)
216 let m: i64 = al_succ(q,cx,k)
217 if m >= 0 { if al_bg_eq(q,cx,k,m,i,j)==1 { c=c+1 } }
218 k = ke + 1
219 }
220 return c
221}
222// trigram (i,j,k2) first + support
223func al_tg_first(q: *u8, cx: *i64, i: i64, j: i64, k2: i64) -> i64 {
224 let n: i64 = cx[0]
225 var a: i64 = 0
226 while a < i {
227 let ae: i64 = al_le(q,a,n)
228 let b: i64 = al_succ(q,cx,a)
229 if b >= 0 {
230 let c: i64 = al_succ(q,cx,b)
231 if c >= 0 { if al_bg_eq(q,cx,a,b,i,j)==1 { if al_tv_eq(q,cx,c,k2)==1 { return 0 } } }
232 }
233 a = ae + 1
234 }
235 return 1
236}
237func al_tg_support(q: *u8, cx: *i64, i: i64, j: i64, k2: i64) -> i64 {
238 let n: i64 = cx[0]
239 var cnt: i64 = 0
240 var a: i64 = 0
241 while a < n {
242 let ae: i64 = al_le(q,a,n)
243 let b: i64 = al_succ(q,cx,a)
244 if b >= 0 {
245 let c: i64 = al_succ(q,cx,b)
246 if c >= 0 { if al_bg_eq(q,cx,a,b,i,j)==1 { if al_tv_eq(q,cx,c,k2)==1 { cnt=cnt+1 } } }
247 }
248 a = ae + 1
249 }
250 return cnt
251}
252func al_jesc(d: *u8, o: i64, q: *u8, s: i64, e: i64, maxb: i64) -> i64 {
253 var p: i64 = o
254 var i: i64 = s
255 var used: i64 = 0
256 while i < e {
257 if used >= maxb { i = e } else {
258 let c: i64 = q[i] as i64
259 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 } } }
260 used = used + 2
261 i = i + 1
262 }
263 }
264 return p
265}
266func al_key(d: *u8, o: i64, name: *u8) -> i64 {
267 d[o]=34 as u8
268 var p: i64 = o + 1
269 p = al_cat(d,p,name)
270 d[p]=34 as u8
271 p = p + 1
272 d[p]=58 as u8
273 p = p + 1
274 return p
275}
276func al_qlit(d: *u8, o: i64, s: *u8) -> i64 {
277 var p: i64 = o
278 d[p]=34 as u8; p=p+1
279 p = al_cat(d,p,s)
280 d[p]=34 as u8; p=p+1
281 return p
282}
283// emit "tool:verb" of frame at l as an escaped json string
284func al_emit_tv(d: *u8, o: i64, q: *u8, cx: *i64, l: i64) -> i64 {
285 let n: i64 = cx[0]
286 let sp: *i64 = sys_mmap(16) as *i64
287 var p: i64 = o
288 let le: i64 = al_le(q,l,n)
289 d[p]=34 as u8; p=p+1
290 if al_col(q,l,le,2,sp)==1 { p = al_jesc(d,p,q,sp[0],sp[1],AL_NAME_MAX) }
291 d[p]=58 as u8; p=p+1
292 if al_col(q,l,le,3,sp)==1 { p = al_jesc(d,p,q,sp[0],sp[1],AL_NAME_MAX) }
293 d[p]=34 as u8; p=p+1
294 return p
295}
296func al_mine_json(q: *u8, cx: *i64, minsup: i64, d: *u8) -> i64 {
297 let n: i64 = cx[0]
298 var p: i64 = 0
299 d[p]=123 as u8; p=p+1
300 p = al_key(d,p,"v" as *u8)
301 p = al_catn(d,p,1)
302 d[p]=44 as u8; p=p+1
303 p = al_key(d,p,"tool" as *u8)
304 p = al_qlit(d,p,"nx_actlog" as *u8)
305 d[p]=44 as u8; p=p+1
306 p = al_key(d,p,"journal" as *u8)
307 d[p]=34 as u8; p=p+1
308 let jp: *u8 = cx[5] as *u8
309 let jl: i64 = al_vlen(jp)
310 p = al_jesc(d,p,jp,0,jl,200)
311 d[p]=34 as u8; p=p+1
312 d[p]=44 as u8; p=p+1
313 p = al_key(d,p,"journal_bytes" as *u8)
314 p = al_catn(d,p,n)
315 d[p]=44 as u8; p=p+1
316 p = al_key(d,p,"window_bytes" as *u8)
317 p = al_catn(d,p,AL_WIN)
318 d[p]=44 as u8; p=p+1
319 p = al_key(d,p,"truncated" as *u8)
320 p = al_catn(d,p,cx[4])
321 d[p]=44 as u8; p=p+1
322 p = al_key(d,p,"minsup" as *u8)
323 p = al_catn(d,p,minsup)
324 d[p]=44 as u8; p=p+1
325 let fr: i64 = al_frames(q,n)
326 p = al_key(d,p,"frames" as *u8)
327 p = al_catn(d,p,fr)
328 d[p]=44 as u8; p=p+1
329 // bigrams
330 p = al_key(d,p,"bigrams" as *u8)
331 d[p]=91 as u8; p=p+1
332 var bcount: i64 = 0
333 var bcapped: i64 = 0
334 var bfirst: i64 = 1
335 var i: i64 = 0
336 while i < n {
337 let le: i64 = al_le(q,i,n)
338 let j: i64 = al_succ(q,cx,i)
339 if j >= 0 { if al_bg_first(q,cx,i,j)==1 {
340 let sup: i64 = al_bg_support(q,cx,i,j)
341 if sup >= minsup {
342 if bcount >= AL_BIGRAM_CAP { bcapped=1 } else { if p > AL_SOFT { bcapped=1 } else {
343 if bfirst==0 { d[p]=44 as u8; p=p+1 }
344 bfirst=0
345 d[p]=123 as u8; p=p+1
346 p = al_key(d,p,"a" as *u8)
347 p = al_emit_tv(d,p,q,cx,i)
348 d[p]=44 as u8; p=p+1
349 p = al_key(d,p,"b" as *u8)
350 p = al_emit_tv(d,p,q,cx,j)
351 d[p]=44 as u8; p=p+1
352 p = al_key(d,p,"support" as *u8)
353 p = al_catn(d,p,sup)
354 d[p]=125 as u8; p=p+1
355 bcount = bcount + 1
356 } }
357 }
358 } }
359 i = le + 1
360 }
361 d[p]=93 as u8; p=p+1
362 d[p]=44 as u8; p=p+1
363 p = al_key(d,p,"bigrams_capped" as *u8)
364 p = al_catn(d,p,bcapped)
365 d[p]=44 as u8; p=p+1
366 // trigrams
367 p = al_key(d,p,"trigrams" as *u8)
368 d[p]=91 as u8; p=p+1
369 var tcount: i64 = 0
370 var tcapped: i64 = 0
371 var tfirst: i64 = 1
372 var a: i64 = 0
373 while a < n {
374 let ae: i64 = al_le(q,a,n)
375 let b: i64 = al_succ(q,cx,a)
376 if b >= 0 {
377 let c: i64 = al_succ(q,cx,b)
378 if c >= 0 { if al_tg_first(q,cx,a,b,c)==1 {
379 let sup2: i64 = al_tg_support(q,cx,a,b,c)
380 if sup2 >= minsup {
381 if tcount >= AL_TRIGRAM_CAP { tcapped=1 } else { if p > AL_SOFT { tcapped=1 } else {
382 if tfirst==0 { d[p]=44 as u8; p=p+1 }
383 tfirst=0
384 d[p]=123 as u8; p=p+1
385 p = al_key(d,p,"a" as *u8)
386 p = al_emit_tv(d,p,q,cx,a)
387 d[p]=44 as u8; p=p+1
388 p = al_key(d,p,"b" as *u8)
389 p = al_emit_tv(d,p,q,cx,b)
390 d[p]=44 as u8; p=p+1
391 p = al_key(d,p,"c" as *u8)
392 p = al_emit_tv(d,p,q,cx,c)
393 d[p]=44 as u8; p=p+1
394 p = al_key(d,p,"support" as *u8)
395 p = al_catn(d,p,sup2)
396 d[p]=125 as u8; p=p+1
397 tcount = tcount + 1
398 } }
399 }
400 } }
401 }
402 a = ae + 1
403 }
404 d[p]=93 as u8; p=p+1
405 d[p]=44 as u8; p=p+1
406 p = al_key(d,p,"trigrams_capped" as *u8)
407 p = al_catn(d,p,tcapped)
408 d[p]=125 as u8; p=p+1
409 d[p]=10 as u8; p=p+1
410 return p
411}
412func al_find(d: *u8, dn: i64, lit: *u8) -> i64 {
413 let ll: i64 = al_vlen(lit)
414 if ll == 0 { return 0 }
415 var i: i64 = 0
416 while i + ll <= dn {
417 var k: i64 = 0
418 var ok: i64 = 1
419 while k < ll { if d[i+k]!=lit[k] { ok=0; k=ll } else { k=k+1 } }
420 if ok==1 { return 1 }
421 i = i + 1
422 }
423 return 0
424}
425
426// per-tool:verb FREQUENCY over the WHOLE journal (ws-agnostic) -- the fallback-log RANKING verb.
427// "which primary/backup engages most" is a frequency question the sequence miner structurally
428// cannot answer (a lone fallback row has no successor bigram). Ranked by bounded selection
429// (exact, no sort infra), capped + declared like every emitter (scale-law envelope).
430func al_tv_count(q: *u8, cx: *i64, l: i64) -> i64 {
431 let n: i64 = cx[0]
432 var c: i64 = 0
433 var k: i64 = 0
434 while k < n {
435 let ke: i64 = al_le(q,k,n)
436 if al_tv_eq(q,cx,l,k)==1 { c=c+1 }
437 k = ke + 1
438 }
439 return c
440}
441func al_tv_first(q: *u8, cx: *i64, l: i64) -> i64 {
442 var k: i64 = 0
443 while k < l {
444 let ke: i64 = al_le(q,k,cx[0])
445 if al_tv_eq(q,cx,l,k)==1 { return 0 }
446 k = ke + 1
447 }
448 return 1
449}
450func al_freq_json(q: *u8, cx: *i64, d: *u8) -> i64 {
451 let n: i64 = cx[0]
452 let starts: *i64 = sys_mmap(8 * AL_FREQ_SLOTS) as *i64
453 let counts: *i64 = sys_mmap(8 * AL_FREQ_SLOTS) as *i64
454 let done: *i64 = sys_mmap(8 * AL_FREQ_SLOTS) as *i64
455 var nf: i64 = 0
456 var fcapped: i64 = 0
457 var i: i64 = 0
458 while i < n {
459 let le: i64 = al_le(q,i,n)
460 if al_tv_first(q,cx,i)==1 {
461 if nf >= AL_FREQ_SLOTS { fcapped=1 } else {
462 starts[nf]=i
463 counts[nf]=al_tv_count(q,cx,i)
464 nf=nf+1
465 }
466 }
467 i = le + 1
468 }
469 var p: i64 = 0
470 d[p]=123 as u8; p=p+1
471 p = al_key(d,p,"v" as *u8); p = al_catn(d,p,1); d[p]=44 as u8; p=p+1
472 p = al_key(d,p,"tool" as *u8); p = al_qlit(d,p,"nx_actlog" as *u8); d[p]=44 as u8; p=p+1
473 p = al_key(d,p,"averb" as *u8); p = al_qlit(d,p,"freq" as *u8); d[p]=44 as u8; p=p+1
474 p = al_key(d,p,"journal" as *u8)
475 d[p]=34 as u8; p=p+1
476 let jp: *u8 = cx[5] as *u8
477 let jl: i64 = al_vlen(jp)
478 p = al_jesc(d,p,jp,0,jl,200)
479 d[p]=34 as u8; p=p+1
480 d[p]=44 as u8; p=p+1
481 p = al_key(d,p,"journal_bytes" as *u8); p = al_catn(d,p,n); d[p]=44 as u8; p=p+1
482 p = al_key(d,p,"truncated" as *u8); p = al_catn(d,p,cx[4]); d[p]=44 as u8; p=p+1
483 p = al_key(d,p,"frames" as *u8); p = al_catn(d,p,al_frames(q,n)); d[p]=44 as u8; p=p+1
484 p = al_key(d,p,"distinct" as *u8); p = al_catn(d,p,nf); d[p]=44 as u8; p=p+1
485 p = al_key(d,p,"freq" as *u8)
486 d[p]=91 as u8; p=p+1
487 var shown: i64 = 0
488 var efirst: i64 = 1
489 var pass: i64 = 0
490 while pass < nf {
491 if shown < AL_FREQ_CAP { if p <= AL_SOFT {
492 var mi: i64 = 0 - 1
493 var mx: i64 = 0 - 1
494 var k: i64 = 0
495 while k < nf {
496 if done[k]==0 { if counts[k] > mx { mx = counts[k]; mi = k } }
497 k = k + 1
498 }
499 if mi >= 0 {
500 done[mi] = 1
501 if efirst==0 { d[p]=44 as u8; p=p+1 }
502 efirst = 0
503 d[p]=123 as u8; p=p+1
504 p = al_key(d,p,"tv" as *u8)
505 p = al_emit_tv(d,p,q,cx,starts[mi])
506 d[p]=44 as u8; p=p+1
507 p = al_key(d,p,"count" as *u8)
508 p = al_catn(d,p,mx)
509 d[p]=125 as u8; p=p+1
510 shown = shown + 1
511 }
512 } }
513 pass = pass + 1
514 }
515 d[p]=93 as u8; p=p+1
516 d[p]=44 as u8; p=p+1
517 p = al_key(d,p,"shown" as *u8); p = al_catn(d,p,shown); d[p]=44 as u8; p=p+1
518 p = al_key(d,p,"freq_capped" as *u8); p = al_catn(d,p,fcapped)
519 d[p]=125 as u8; p=p+1
520 d[p]=10 as u8; p=p+1
521 return p
522}
523
524// harden: the F872 rung-3 CLOSER -- every tool:verb recurring >= minsup auto-files a hardening
525// debt through the ALLOWLIST-RESOLVED filer (never a hardcoded sibling path -- the execve-127
526// lesson: allowlist rows are not name-derivable). The desc is CANONICAL and COUNT-FREE so
527// nx_debt's content-idempotent add (F868) makes every re-run a NO-OP for already-filed
528// recurrences: a beat cannot spam. The filer is INJECTABLE (argecho in the gate) so the
529// selftest never writes the production debt plane.
530// DELEGATES to the shared base (rule-15 extraction 2026-07-23) -- the ORIGINAL of the 7 copies
531func al_allow_path(name: *u8, outp: *u8) -> i64 { return sj_allow_path(name, outp) }
532func al_harden_json(q: *u8, cx: *i64, minsup: i64, sev: i64, filer: *u8, d: *u8) -> i64 {
533 let n: i64 = cx[0]
534 let starts: *i64 = sys_mmap(8 * AL_FREQ_SLOTS) as *i64
535 let counts: *i64 = sys_mmap(8 * AL_FREQ_SLOTS) as *i64
536 var nf: i64 = 0
537 var i: i64 = 0
538 while i < n {
539 let le: i64 = al_le(q,i,n)
540 if al_tv_first(q,cx,i)==1 { if nf < AL_FREQ_SLOTS {
541 starts[nf]=i
542 counts[nf]=al_tv_count(q,cx,i)
543 nf=nf+1
544 } }
545 i = le + 1
546 }
547 let fpath: *u8 = sys_mmap(512)
548 let fok: i64 = al_allow_path(filer, fpath)
549 var p: i64 = 0
550 d[p]=123 as u8; p=p+1
551 p = al_key(d,p,"v" as *u8); p = al_catn(d,p,1); d[p]=44 as u8; p=p+1
552 p = al_key(d,p,"tool" as *u8); p = al_qlit(d,p,"nx_actlog" as *u8); d[p]=44 as u8; p=p+1
553 p = al_key(d,p,"averb" as *u8); p = al_qlit(d,p,"harden" as *u8); d[p]=44 as u8; p=p+1
554 p = al_key(d,p,"minsup" as *u8); p = al_catn(d,p,minsup); d[p]=44 as u8; p=p+1
555 p = al_key(d,p,"sev" as *u8); p = al_catn(d,p,sev); d[p]=44 as u8; p=p+1
556 p = al_key(d,p,"filer" as *u8)
557 d[p]=34 as u8; p=p+1
558 p = al_jesc(d,p,filer,0,al_vlen(filer),120)
559 d[p]=34 as u8; p=p+1
560 d[p]=44 as u8; p=p+1
561 p = al_key(d,p,"filer_resolved" as *u8); p = al_catn(d,p,fok); d[p]=44 as u8; p=p+1
562 p = al_key(d,p,"filed" as *u8)
563 d[p]=91 as u8; p=p+1
564 var recur: i64 = 0
565 var attempted: i64 = 0
566 var hcapped: i64 = 0
567 var efirst: i64 = 1
568 var k: i64 = 0
569 while k < nf {
570 if counts[k] >= minsup {
571 recur = recur + 1
572 if attempted >= AL_HARDEN_CAP { hcapped=1 } else { if fok==1 {
573 let tvb: *u8 = sys_mmap(256)
574 let sp2: *i64 = sys_mmap(16) as *i64
575 let le2: i64 = al_le(q,starts[k],n)
576 var to: i64 = 0
577 if al_col(q,starts[k],le2,2,sp2)==1 { var z: i64=sp2[0]; while z<sp2[1] { if to<100 { tvb[to]=q[z]; to=to+1 } z=z+1 } }
578 tvb[to]=58 as u8
579 to=to+1
580 if al_col(q,starts[k],le2,3,sp2)==1 { var z2: i64=sp2[0]; while z2<sp2[1] { if to<220 { tvb[to]=q[z2]; to=to+1 } z2=z2+1 } }
581 tvb[to]=0 as u8
582 let desc: *u8 = sys_mmap(AL_MAGIC_1024)
583 var dso: i64 = 0
584 dso = al_cat(desc,dso,"FALLBACK-RECURRENCE " as *u8)
585 dso = al_cat(desc,dso,tvb)
586 dso = al_cat(desc,dso," (auto-filed by nx_actlog harden): this backup method engages repeatedly -- root-cause and HARDEN THE PRIMARY; current counts via nx_actlog freq, per-engagement why/evidence in the journal rows" as *u8)
587 desc[dso]=0 as u8
588 let sevs: *u8 = sys_mmap(8)
589 var so: i64 = al_catn(sevs,0,sev)
590 sevs[so]=0 as u8
591 let av: *i64 = sys_mmap(64) as *i64
592 av[0]=fpath as i64
593 av[1]="add" as *u8 as i64
594 av[2]=sevs as i64
595 av[3]="fallback" as *u8 as i64
596 av[4]=desc as i64
597 av[5]=0
598 let cout: *u8 = sys_mmap(AL_MAGIC_4096)
599 let colen: *i64 = sys_mmap(8) as *i64
600 let ex: i64 = tr_run_capture(fpath, av, cout, AL_MAGIC_4090, colen)
601 if efirst==0 { d[p]=44 as u8; p=p+1 }
602 efirst=0
603 d[p]=123 as u8; p=p+1
604 p = al_key(d,p,"tv" as *u8)
605 d[p]=34 as u8; p=p+1
606 p = al_jesc(d,p,tvb,0,al_vlen(tvb),240)
607 d[p]=34 as u8; p=p+1
608 d[p]=44 as u8; p=p+1
609 p = al_key(d,p,"exit" as *u8); p = al_catn(d,p,ex); d[p]=44 as u8; p=p+1
610 p = al_key(d,p,"out" as *u8)
611 d[p]=34 as u8; p=p+1
612 var ce: i64 = colen[0]
613 if ce > 400 { ce = 400 }
614 p = al_jesc(d,p,cout,0,ce,800)
615 d[p]=34 as u8; p=p+1
616 d[p]=125 as u8; p=p+1
617 attempted = attempted + 1
618 } }
619 }
620 k = k + 1
621 }
622 d[p]=93 as u8; p=p+1
623 d[p]=44 as u8; p=p+1
624 p = al_key(d,p,"recurring" as *u8); p = al_catn(d,p,recur); d[p]=44 as u8; p=p+1
625 p = al_key(d,p,"attempted" as *u8); p = al_catn(d,p,attempted); d[p]=44 as u8; p=p+1
626 p = al_key(d,p,"harden_capped" as *u8); p = al_catn(d,p,hcapped)
627 d[p]=125 as u8; p=p+1
628 d[p]=10 as u8; p=p+1
629 return p
630}
631
632// ---------- seq626 O(F) INDEXED MINER ----------
633// One hash-interned pass replaces the O(F^2/F^3) pair scans that died (rc=-1) on the first
634// real-scale journal (8184 frames, F964 backfill). The slow al_succ/al_bg_*/al_tg_*/al_tv_*
635// primitives above are KEPT: the selftest computes supports through them (T4/T5) while the
636// fast emitters produce the JSON (T6/T7/T8) -- fast path must agree with the slow oracle on
637// the fixture. Emission order preserved: first-occurrence, count-desc selection for freq.
638func al_z_eq(a: *u8, b: *u8) -> i64 {
639 var i: i64 = 0
640 while a[i] != (0 as u8) { if a[i] != b[i] { return 0 } i = i + 1 }
641 if b[i] != (0 as u8) { return 0 }
642 return 1
643}
644func al_z_hash(s: *u8) -> i64 {
645 var h: i64 = AL_MAGIC_5381
646 var i: i64 = 0
647 while s[i] != (0 as u8) { h = (h * 31 + (s[i] as i64)) % AL_IX_HMOD; i = i + 1 }
648 return h
649}
650// string intern: open-addressing hash holds id+1; ids are first-seen order; strings in arena.
651func al_ix_sintern(z: *u8, hash: *i64, off: *i64, hslots: i64, maxn: i64, ar: *u8, an: *i64, nn: *i64) -> i64 {
652 var h: i64 = al_z_hash(z) % hslots
653 var probes: i64 = 0
654 while probes < hslots {
655 let v: i64 = hash[h]
656 if v == 0 {
657 if nn[0] >= maxn { return -1 }
658 let zl: i64 = al_vlen(z)
659 if an[0] + zl + 1 >= AL_IX_ARENA { return -1 }
660 let id: i64 = nn[0]
661 off[id] = an[0]
662 var k: i64 = 0
663 while k <= zl { ar[an[0] + k] = z[k]; k = k + 1 }
664 an[0] = an[0] + zl + 1
665 hash[h] = id + 1
666 nn[0] = id + 1
667 return id
668 }
669 if al_z_eq(((ar as i64) + off[v-1]) as *u8, z) == 1 { return v - 1 }
670 h = h + 1
671 if h >= hslots { h = 0 }
672 probes = probes + 1
673 }
674 return -1
675}
676// numeric-key intern (bigram/trigram packed keys)
677func al_ix_kintern(key: i64, hash: *i64, keys: *i64, hslots: i64, maxn: i64, nn: *i64) -> i64 {
678 var h: i64 = key % hslots
679 if h < 0 { h = 0 - h }
680 var probes: i64 = 0
681 while probes < hslots {
682 let v: i64 = hash[h]
683 if v == 0 {
684 if nn[0] >= maxn { return -1 }
685 let id: i64 = nn[0]
686 keys[id] = key
687 hash[h] = id + 1
688 nn[0] = id + 1
689 return id
690 }
691 if keys[v-1] == key { return v - 1 }
692 h = h + 1
693 if h >= hslots { h = 0 }
694 probes = probes + 1
695 }
696 return -1
697}
698// ix ptr slots: 0 tvhash 1 tvoff 2 tvcnt 3 ntv 4 arena 5 aused 6 wshash 7 wsoff 8 wslast 9 wslast2
699// 10 nws 11 bghash 12 bgkey 13 bgcnt 14 nbg 15 tghash 16 tgkey 17 tgcnt 18 ntg 19 frames 20 overflow
700func al_ix_build(q: *u8, cx: *i64, ix: *i64, maxgap: i64) -> i64 {
701 ix[0] = sys_mmap(8 * AL_IX_HSLOTS) as i64
702 ix[1] = sys_mmap(8 * AL_IX_TVMAX) as i64
703 ix[2] = sys_mmap(8 * AL_IX_TVMAX) as i64
704 ix[3] = sys_mmap(16) as i64
705 ix[4] = sys_mmap(AL_IX_ARENA) as i64
706 ix[5] = sys_mmap(16) as i64
707 ix[6] = sys_mmap(8 * AL_IX_HSLOTS) as i64
708 ix[7] = sys_mmap(8 * AL_IX_TVMAX) as i64
709 ix[8] = sys_mmap(8 * AL_IX_TVMAX * AL_IX_RING) as i64
710 ix[9] = sys_mmap(8 * AL_IX_TVMAX) as i64
711 ix[10] = sys_mmap(16) as i64
712 // INDEX SIZED FROM THE INPUT (2026-09-05): distinct bigrams and trigrams can never exceed the frame
713 // count, so the gram tables are DERIVED from a newline census of the journal; AL_IX_GMAX / AL_IX_GHSLOTS
714 // remain only as FLOORS. Measured on the live 54 MB journal the fixed cap read index_overflow=1: every
715 // pair past the 16,384th was silently uncounted while the miner still published a ranking. mmap faults
716 // pages in on demand, so a large table costs address space, not resident memory (a cap is not a number
717 // to tune -- derive it). ix[21]=gmax ix[22]=ghslots are VALUES (the other slots are pointers).
718 let n: i64 = cx[0]
719 var frames: i64 = 0
720 var fi: i64 = 0
721 while fi < n { if q[fi] == (10 as u8) { frames = frames + 1 } fi = fi + 1 }
722 if n > 0 { if q[n - 1] != (10 as u8) { frames = frames + 1 } }
723 var gmax: i64 = frames + 1
724 if gmax < AL_IX_GMAX { gmax = AL_IX_GMAX }
725 var ghslots: i64 = 2 * gmax + 1
726 if ghslots < AL_IX_GHSLOTS { ghslots = AL_IX_GHSLOTS }
727 ix[21] = gmax
728 ix[22] = ghslots
729 ix[11] = sys_mmap(8 * ghslots) as i64
730 ix[12] = sys_mmap(8 * gmax) as i64
731 ix[13] = sys_mmap(8 * gmax) as i64
732 ix[14] = sys_mmap(16) as i64
733 ix[15] = sys_mmap(8 * ghslots) as i64
734 ix[16] = sys_mmap(8 * gmax) as i64
735 ix[17] = sys_mmap(8 * gmax) as i64
736 ix[18] = sys_mmap(16) as i64
737 ix[19] = sys_mmap(16) as i64
738 // ov[0] any overflow (the contract every reader holds) ov[1] string-intern overflows ov[2] gram-table overflows
739 ix[20] = sys_mmap(32) as i64
740 // ES27 QUALITY AXIS: a failure count beside every gram count (a frame whose outcome column is not ok taints the
741 // grams it closes), and a per-workstream ring of frame badness beside the tool-id ring: ix[23] bgfail ix[24] tgfail ix[25] badring
742 ix[23] = sys_mmap(8 * gmax) as i64
743 ix[24] = sys_mmap(8 * gmax) as i64
744 ix[25] = sys_mmap(8 * AL_IX_TVMAX * AL_IX_RING) as i64
745 let sp: *i64 = sys_mmap(16) as *i64
746 let tvb: *u8 = sys_mmap(512)
747 let wsb: *u8 = sys_mmap(256)
748 let fp: *i64 = ix[19] as *i64
749 let ov: *i64 = ix[20] as *i64
750 var i: i64 = 0
751 while i < n {
752 let le: i64 = al_le(q,i,n)
753 fp[0] = fp[0] + 1
754 var ok: i64 = 0
755 var wl: i64 = 0
756 var to: i64 = 0
757 if al_col(q,i,le,1,sp)==1 {
758 var z: i64 = sp[0]
759 while z < sp[1] { if wl < 200 { wsb[wl] = q[z]; wl = wl + 1 } z = z + 1 }
760 wsb[wl] = 0 as u8
761 if al_col(q,i,le,2,sp)==1 {
762 var z2: i64 = sp[0]
763 while z2 < sp[1] { if to < 240 { tvb[to] = q[z2]; to = to + 1 } z2 = z2 + 1 }
764 tvb[to] = 58 as u8
765 to = to + 1
766 if al_col(q,i,le,3,sp)==1 {
767 var z3: i64 = sp[0]
768 while z3 < sp[1] { if to < 480 { tvb[to] = q[z3]; to = to + 1 } z3 = z3 + 1 }
769 tvb[to] = 0 as u8
770 ok = 1
771 }
772 }
773 }
774 var bad: i64 = 0
775 if al_col(q,i,le,4,sp)==1 { if sp[1] - sp[0] != 2 { bad = 1 } else { if q[sp[0]] != (111 as u8) { bad = 1 } else { if q[sp[0]+1] != (107 as u8) { bad = 1 } } } }
776 if ok == 1 {
777 let tid: i64 = al_ix_sintern(tvb, ix[0] as *i64, ix[1] as *i64, AL_IX_HSLOTS, AL_IX_TVMAX, ix[4] as *u8, ix[5] as *i64, ix[3] as *i64)
778 let wid: i64 = al_ix_sintern(wsb, ix[6] as *i64, ix[7] as *i64, AL_IX_HSLOTS, AL_IX_TVMAX, ix[4] as *u8, ix[5] as *i64, ix[10] as *i64)
779 if tid >= 0 { if wid >= 0 {
780 let tvcnt: *i64 = ix[2] as *i64
781 tvcnt[tid] = tvcnt[tid] + 1
782 let ring: *i64 = ix[8] as *i64
783 let wln: *i64 = ix[9] as *i64
784 let cnt: i64 = wln[wid]
785 var dd: i64 = 1
786 while dd <= maxgap + 1 {
787 if dd <= cnt {
788 let pv: i64 = ring[wid * AL_IX_RING + ((cnt - dd) % AL_IX_RING)]
789 if pv > 0 {
790 let bkey: i64 = (pv - 1) * AL_IX_KEYB + tid
791 let bid: i64 = al_ix_kintern(bkey, ix[11] as *i64, ix[12] as *i64, ix[22], ix[21], ix[14] as *i64)
792 if bid >= 0 { let bc: *i64 = ix[13] as *i64; bc[bid] = bc[bid] + 1; let bf: *i64 = ix[23] as *i64; let badr: *i64 = ix[25] as *i64; if bad == 1 { bf[bid] = bf[bid] + 1 } else { if badr[wid * AL_IX_RING + ((cnt - dd) % AL_IX_RING)] == 1 { bf[bid] = bf[bid] + 1 } } } else { ov[0] = 1; ov[2] = ov[2] + 1 }
793 if dd == 1 { if cnt >= 2 {
794 let p2v: i64 = ring[wid * AL_IX_RING + ((cnt - 2) % AL_IX_RING)]
795 if p2v > 0 {
796 let tkey: i64 = ((p2v - 1) * AL_IX_KEYB + (pv - 1)) * AL_IX_KEYB + tid
797 let tgid: i64 = al_ix_kintern(tkey, ix[15] as *i64, ix[16] as *i64, ix[22], ix[21], ix[18] as *i64)
798 if tgid >= 0 { let tc: *i64 = ix[17] as *i64; tc[tgid] = tc[tgid] + 1; let tf: *i64 = ix[24] as *i64; let badr2: *i64 = ix[25] as *i64; var tb: i64 = bad; if badr2[wid * AL_IX_RING + ((cnt - 1) % AL_IX_RING)] == 1 { tb = 1 } if badr2[wid * AL_IX_RING + ((cnt - 2) % AL_IX_RING)] == 1 { tb = 1 } if tb == 1 { tf[tgid] = tf[tgid] + 1 } } else { ov[0] = 1; ov[2] = ov[2] + 1 }
799 }
800 } }
801 }
802 }
803 dd = dd + 1
804 }
805 ring[wid * AL_IX_RING + (cnt % AL_IX_RING)] = tid + 1
806 let badw: *i64 = ix[25] as *i64
807 badw[wid * AL_IX_RING + (cnt % AL_IX_RING)] = bad
808 wln[wid] = cnt + 1
809 } else { ov[0] = 1; ov[1] = ov[1] + 1 } } else { ov[0] = 1; ov[1] = ov[1] + 1 }
810 }
811 i = le + 1
812 }
813 return 0
814}
815func al_ix_tv_emit(d: *u8, o: i64, ar: *u8, off: i64) -> i64 {
816 var p: i64 = o
817 d[p]=34 as u8; p=p+1
818 let zl: i64 = al_vlen(((ar as i64) + off) as *u8)
819 p = al_jesc(d,p,ar,off,off+zl,240)
820 d[p]=34 as u8; p=p+1
821 return p
822}
823func al_freq_fast(q: *u8, cx: *i64, d: *u8, fcap: i64) -> i64 {
824 let n: i64 = cx[0]
825 let ix: *i64 = sys_mmap(256) as *i64
826 al_ix_build(q, cx, ix, 0)
827 let ntvp: *i64 = ix[3] as *i64
828 let nf: i64 = ntvp[0]
829 let cnts: *i64 = ix[2] as *i64
830 let offs: *i64 = ix[1] as *i64
831 let ar: *u8 = ix[4] as *u8
832 let fp: *i64 = ix[19] as *i64
833 let ov: *i64 = ix[20] as *i64
834 let done: *i64 = sys_mmap(8 * AL_IX_TVMAX) as *i64
835 var p: i64 = 0
836 d[p]=123 as u8; p=p+1
837 p = al_key(d,p,"v" as *u8); p = al_catn(d,p,1); d[p]=44 as u8; p=p+1
838 p = al_key(d,p,"tool" as *u8); p = al_qlit(d,p,"nx_actlog" as *u8); d[p]=44 as u8; p=p+1
839 p = al_key(d,p,"averb" as *u8); p = al_qlit(d,p,"freq" as *u8); d[p]=44 as u8; p=p+1
840 p = al_key(d,p,"journal" as *u8)
841 d[p]=34 as u8; p=p+1
842 let jp: *u8 = cx[5] as *u8
843 p = al_jesc(d,p,jp,0,al_vlen(jp),200)
844 d[p]=34 as u8; p=p+1
845 d[p]=44 as u8; p=p+1
846 p = al_key(d,p,"journal_bytes" as *u8); p = al_catn(d,p,n); d[p]=44 as u8; p=p+1
847 p = al_key(d,p,"truncated" as *u8); p = al_catn(d,p,cx[4]); d[p]=44 as u8; p=p+1
848 p = al_key(d,p,"frames" as *u8); p = al_catn(d,p,fp[0]); d[p]=44 as u8; p=p+1
849 p = al_key(d,p,"distinct" as *u8); p = al_catn(d,p,nf); d[p]=44 as u8; p=p+1
850 p = al_key(d,p,"freq" as *u8)
851 d[p]=91 as u8; p=p+1
852 var shown: i64 = 0
853 var efirst: i64 = 1
854 var pass: i64 = 0
855 while pass < nf {
856 if shown < fcap { if p <= AL_SOFT {
857 var mi: i64 = 0 - 1
858 var mx: i64 = 0 - 1
859 var k: i64 = 0
860 while k < nf {
861 if done[k]==0 { if cnts[k] > mx { mx = cnts[k]; mi = k } }
862 k = k + 1
863 }
864 if mi >= 0 {
865 done[mi] = 1
866 if efirst==0 { d[p]=44 as u8; p=p+1 }
867 efirst = 0
868 d[p]=123 as u8; p=p+1
869 p = al_key(d,p,"tv" as *u8)
870 p = al_ix_tv_emit(d,p,ar,offs[mi])
871 d[p]=44 as u8; p=p+1
872 p = al_key(d,p,"count" as *u8)
873 p = al_catn(d,p,mx)
874 d[p]=125 as u8; p=p+1
875 shown = shown + 1
876 }
877 } }
878 pass = pass + 1
879 }
880 d[p]=93 as u8; p=p+1
881 d[p]=44 as u8; p=p+1
882 p = al_key(d,p,"shown" as *u8); p = al_catn(d,p,shown); d[p]=44 as u8; p=p+1
883 p = al_key(d,p,"index_overflow" as *u8); p = al_catn(d,p,ov[0]); d[p]=44 as u8; p=p+1
884 p = al_key(d,p,"index_overflow_strings" as *u8); p = al_catn(d,p,ov[1]); d[p]=44 as u8; p=p+1
885 p = al_key(d,p,"index_overflow_grams" as *u8); p = al_catn(d,p,ov[2]); d[p]=44 as u8; p=p+1
886 p = al_key(d,p,"index_gmax" as *u8); p = al_catn(d,p,ix[21]); d[p]=44 as u8; p=p+1
887 p = al_key(d,p,"index_ghslots" as *u8); p = al_catn(d,p,ix[22]); d[p]=44 as u8; p=p+1
888 p = al_key(d,p,"freq_capped" as *u8); p = al_catn(d,p,ov[0])
889 d[p]=125 as u8; p=p+1
890 d[p]=10 as u8; p=p+1
891 return p
892}
893// al_bg_is_closed: CLOSED-PATTERN test (CloSpan/BIDE class, the research standard for NON-REDUNDANT
894// sequential mining). A bigram (a,b) is NON-closed (redundant) if some trigram containing it
895// CONTIGUOUSLY -- as prefix (a,b,*) or suffix (*,a,b) -- has the SAME support: its count is fully
896// explained by a longer pattern, so reporting it adds noise. Trigrams are maximal here (no 4-grams)
897// => emitted as closed-up-to-length-3 (declared). Returns 1 closed, 0 subsumed.
898func al_bg_is_closed(a: i64, b: i64, sup: i64, tgkey: *i64, tgcnt: *i64, ntg: i64) -> i64 {
899 var i: i64 = 0
900 while i < ntg {
901 if tgcnt[i] == sup {
902 let ta: i64 = tgkey[i] / (AL_IX_KEYB * AL_IX_KEYB)
903 let tb: i64 = (tgkey[i] / AL_IX_KEYB) % AL_IX_KEYB
904 let tc: i64 = tgkey[i] % AL_IX_KEYB
905 if ta == a { if tb == b { return 0 } }
906 if tb == a { if tc == b { return 0 } }
907 }
908 i = i + 1
909 }
910 return 1
911}
912func al_mine_fast(q: *u8, cx: *i64, minsup: i64, maxgap: i64, closed: i64, d: *u8) -> i64 {
913 let n: i64 = cx[0]
914 let ix: *i64 = sys_mmap(256) as *i64
915 al_ix_build(q, cx, ix, maxgap)
916 let offs: *i64 = ix[1] as *i64
917 let ar: *u8 = ix[4] as *u8
918 let fp: *i64 = ix[19] as *i64
919 let ov: *i64 = ix[20] as *i64
920 let nbgp: *i64 = ix[14] as *i64
921 let bgkey: *i64 = ix[12] as *i64
922 let bgcnt: *i64 = ix[13] as *i64
923 let ntgp: *i64 = ix[18] as *i64
924 let tgkey: *i64 = ix[16] as *i64
925 let tgcnt: *i64 = ix[17] as *i64
926 let tvcnt: *i64 = ix[2] as *i64
927 var p: i64 = 0
928 d[p]=123 as u8; p=p+1
929 p = al_key(d,p,"v" as *u8)
930 p = al_catn(d,p,1)
931 d[p]=44 as u8; p=p+1
932 p = al_key(d,p,"tool" as *u8)
933 p = al_qlit(d,p,"nx_actlog" as *u8)
934 d[p]=44 as u8; p=p+1
935 p = al_key(d,p,"journal" as *u8)
936 d[p]=34 as u8; p=p+1
937 let jp: *u8 = cx[5] as *u8
938 p = al_jesc(d,p,jp,0,al_vlen(jp),200)
939 d[p]=34 as u8; p=p+1
940 d[p]=44 as u8; p=p+1
941 p = al_key(d,p,"journal_bytes" as *u8)
942 p = al_catn(d,p,n)
943 d[p]=44 as u8; p=p+1
944 p = al_key(d,p,"window_bytes" as *u8)
945 p = al_catn(d,p,AL_WIN)
946 d[p]=44 as u8; p=p+1
947 p = al_key(d,p,"truncated" as *u8)
948 p = al_catn(d,p,cx[4])
949 d[p]=44 as u8; p=p+1
950 p = al_key(d,p,"minsup" as *u8)
951 p = al_catn(d,p,minsup)
952 d[p]=44 as u8; p=p+1
953 p = al_key(d,p,"maxgap" as *u8)
954 p = al_catn(d,p,maxgap)
955 d[p]=44 as u8; p=p+1
956 p = al_key(d,p,"closed" as *u8)
957 p = al_catn(d,p,closed)
958 d[p]=44 as u8; p=p+1
959 p = al_key(d,p,"frames" as *u8)
960 p = al_catn(d,p,fp[0])
961 d[p]=44 as u8; p=p+1
962 p = al_key(d,p,"bigrams" as *u8)
963 d[p]=91 as u8; p=p+1
964 var bcount: i64 = 0
965 var bcapped: i64 = 0
966 var bfirst: i64 = 1
967 var bi: i64 = 0
968 while bi < nbgp[0] {
969 var bg_ok: i64 = 0
970 if bgcnt[bi] >= minsup { bg_ok = 1 }
971 if bg_ok == 1 { if closed == 1 { if al_bg_is_closed(bgkey[bi] / AL_IX_KEYB, bgkey[bi] % AL_IX_KEYB, bgcnt[bi], tgkey, tgcnt, ntgp[0]) == 0 { bg_ok = 0 } } }
972 if bg_ok == 1 {
973 if bcount >= AL_BIGRAM_CAP { bcapped=1 } else { if p > AL_SOFT { bcapped=1 } else {
974 if bfirst==0 { d[p]=44 as u8; p=p+1 }
975 bfirst=0
976 d[p]=123 as u8; p=p+1
977 p = al_key(d,p,"a" as *u8)
978 p = al_ix_tv_emit(d,p,ar,offs[bgkey[bi] / AL_IX_KEYB])
979 d[p]=44 as u8; p=p+1
980 p = al_key(d,p,"b" as *u8)
981 p = al_ix_tv_emit(d,p,ar,offs[bgkey[bi] % AL_IX_KEYB])
982 d[p]=44 as u8; p=p+1
983 p = al_key(d,p,"support" as *u8)
984 p = al_catn(d,p,bgcnt[bi])
985 d[p]=44 as u8; p=p+1
986 // association-rule CONFIDENCE = P(b follows a) = support / freq(a). Total-independent
987 // strength: surfaces STRONG transitions vs frequent-by-chance ones (Agrawal et al.).
988 p = al_key(d,p,"confidence_permil" as *u8)
989 var conf: i64 = 0
990 let ca: i64 = bgkey[bi] / AL_IX_KEYB
991 if tvcnt[ca] > 0 { conf = bgcnt[bi] * 1000 / tvcnt[ca] }
992 p = al_catn(d,p,conf)
993 d[p]=125 as u8; p=p+1
994 bcount = bcount + 1
995 } }
996 }
997 bi = bi + 1
998 }
999 d[p]=93 as u8; p=p+1
1000 d[p]=44 as u8; p=p+1
1001 p = al_key(d,p,"bigrams_capped" as *u8)
1002 p = al_catn(d,p,bcapped)
1003 d[p]=44 as u8; p=p+1
1004 p = al_key(d,p,"trigrams" as *u8)
1005 d[p]=91 as u8; p=p+1
1006 var tcount: i64 = 0
1007 var tcapped: i64 = 0
1008 var tfirst: i64 = 1
1009 var ti: i64 = 0
1010 while ti < ntgp[0] {
1011 if tgcnt[ti] >= minsup {
1012 if tcount >= AL_TRIGRAM_CAP { tcapped=1 } else { if p > AL_SOFT { tcapped=1 } else {
1013 if tfirst==0 { d[p]=44 as u8; p=p+1 }
1014 tfirst=0
1015 d[p]=123 as u8; p=p+1
1016 p = al_key(d,p,"a" as *u8)
1017 p = al_ix_tv_emit(d,p,ar,offs[tgkey[ti] / (AL_IX_KEYB * AL_IX_KEYB)])
1018 d[p]=44 as u8; p=p+1
1019 p = al_key(d,p,"b" as *u8)
1020 p = al_ix_tv_emit(d,p,ar,offs[(tgkey[ti] / AL_IX_KEYB) % AL_IX_KEYB])
1021 d[p]=44 as u8; p=p+1
1022 p = al_key(d,p,"c" as *u8)
1023 p = al_ix_tv_emit(d,p,ar,offs[tgkey[ti] % AL_IX_KEYB])
1024 d[p]=44 as u8; p=p+1
1025 p = al_key(d,p,"support" as *u8)
1026 p = al_catn(d,p,tgcnt[ti])
1027 d[p]=125 as u8; p=p+1
1028 tcount = tcount + 1
1029 } }
1030 }
1031 ti = ti + 1
1032 }
1033 d[p]=93 as u8; p=p+1
1034 d[p]=44 as u8; p=p+1
1035 p = al_key(d,p,"trigrams_capped" as *u8)
1036 p = al_catn(d,p,tcapped)
1037 d[p]=44 as u8; p=p+1
1038 p = al_key(d,p,"index_overflow" as *u8)
1039 p = al_catn(d,p,ov[0])
1040 d[p]=44 as u8; p=p+1
1041 p = al_key(d,p,"index_overflow_strings" as *u8); p = al_catn(d,p,ov[1]); d[p]=44 as u8; p=p+1
1042 p = al_key(d,p,"index_overflow_grams" as *u8); p = al_catn(d,p,ov[2]); d[p]=44 as u8; p=p+1
1043 p = al_key(d,p,"index_gmax" as *u8); p = al_catn(d,p,ix[21]); d[p]=44 as u8; p=p+1
1044 p = al_key(d,p,"index_bigrams" as *u8); p = al_catn(d,p,nbgp[0]); d[p]=44 as u8; p=p+1
1045 p = al_key(d,p,"index_trigrams" as *u8); p = al_catn(d,p,ntgp[0])
1046 d[p]=125 as u8; p=p+1
1047 d[p]=10 as u8; p=p+1
1048 return p
1049}
1050
1051// ---------- F968 BENCH: miner accuracy vs CONSTRUCTED ground truth ----------
1052// Synthetic journals with PLANTED patterns = an exact oracle by construction (no external dep):
1053// expected supports are known arithmetic facts about the plant. Adversarial families: gapped plants
1054// (found ONLY at sufficient maxgap, never at gap 0), ws-split decoys (never cross), pure-noise
1055// (nothing fabricated), self-loops + trigrams (exact counts). A wrong support ANYWHERE = RED.
1056// ---------- ES26 STEPS-TO-SOLVE (2026-09-06) ----------
1057// The operator's one-step goal as a verb on THIS organ (the action journal's own miner), never a new tool: the same
1058// indexed pass as `mine` at maxgap 0 (a ritual is CONSECUTIVE calls), bigrams closed against trigrams (a bigram fully
1059// explained by a longer pattern is not a second ritual), every recurring signature joined to knowledge/stepsolve.conf
1060// through nx_stepsolve_lib and classified ONE-STEP-AVAILABLE / DEPENDENCY / REDUCIBLE / UNDECLARED. Totals are the
1061// WHOLE candidate population (never the shown prefix); the top-N by support carry each row's declared reason or
1062// composed verb; the UNDECLARED worklist follows, most common first; a spine row and the gauge stamp (EXPLAINED
1063// permil in the CE9 heartbeat shape, so a stale stamp reads STALE never zero) are written only when something recurs.
1064// signature text: tool:verb>tool:verb[>tool:verb], chronological (the miner keys are prev*KEYB+cur).
1065func al_steps_sig(sig: *u8, ar: *u8, offs: *i64, kind: i64, idx: i64, bgkey: *i64, tgkey: *i64) -> i64 {
1066 var a: i64 = 0
1067 var b: i64 = 0
1068 var c: i64 = 0 - 1
1069 if kind == 2 { a = bgkey[idx] / AL_IX_KEYB; b = bgkey[idx] % AL_IX_KEYB } else {
1070 a = tgkey[idx] / (AL_IX_KEYB * AL_IX_KEYB); b = (tgkey[idx] / AL_IX_KEYB) % AL_IX_KEYB; c = tgkey[idx] % AL_IX_KEYB
1071 }
1072 var o: i64 = al_cat(sig, 0, ((ar as i64) + offs[a]) as *u8)
1073 sig[o] = SS_GT as u8; o = o + 1
1074 o = al_cat(sig, o, ((ar as i64) + offs[b]) as *u8)
1075 if c >= 0 { sig[o] = SS_GT as u8; o = o + 1; o = al_cat(sig, o, ((ar as i64) + offs[c]) as *u8) }
1076 sig[o] = 0 as u8
1077 return o
1078}
1079func al_steps_emit_one(d: *u8, p0: i64, sig: *u8, ar: *u8, offs: *i64, bgkey: *i64, tgkey: *i64, cq: *u8, tab: *i64, rt: *i64, kind: i64, idx: i64, sup: i64, fail: i64, cls: i64, row: i64, rule: i64) -> i64 {
1080 var p: i64 = p0
1081 let sl: i64 = al_steps_sig(sig, ar, offs, kind, idx, bgkey, tgkey)
1082 d[p]=123 as u8; p=p+1
1083 p = al_key(d,p,"signature" as *u8); d[p]=34 as u8; p=p+1; p = al_jesc(d,p,sig,0,sl,480); d[p]=34 as u8; p=p+1; d[p]=44 as u8; p=p+1
1084 p = al_key(d,p,"steps" as *u8); p = al_catn(d,p,kind); d[p]=44 as u8; p=p+1
1085 p = al_key(d,p,"support" as *u8); p = al_catn(d,p,sup); d[p]=44 as u8; p=p+1
1086 p = al_key(d,p,"fail" as *u8); p = al_catn(d,p,fail); d[p]=44 as u8; p=p+1
1087 p = al_key(d,p,"fail_permil" as *u8); p = al_catn(d,p,ss_fail_permil(sup, fail)); d[p]=44 as u8; p=p+1
1088 p = al_key(d,p,"risk" as *u8); p = al_catn(d,p,ss_risk(sup, fail)); d[p]=44 as u8; p=p+1
1089 p = al_key(d,p,"class" as *u8); p = al_qlit(d,p,ss_class_name(cls)); d[p]=44 as u8; p=p+1
1090 if row >= 0 {
1091 let b: i64 = row * SS_R_SLOTS
1092 p = al_key(d,p,"min_steps" as *u8); p = al_catn(d,p,tab[b + SS_R_MIN]); d[p]=44 as u8; p=p+1
1093 p = al_key(d,p,"gap" as *u8); p = al_catn(d,p,kind - tab[b + SS_R_MIN]); d[p]=44 as u8; p=p+1
1094 let rs: *u8 = ((cq as i64) + tab[b + SS_R_REASON]) as *u8
1095 p = al_key(d,p,"reason" as *u8); d[p]=34 as u8; p=p+1; p = al_jesc(d,p,rs,0,al_vlen(rs),600); d[p]=34 as u8; p=p+1; d[p]=44 as u8; p=p+1
1096 let vs: *u8 = ((cq as i64) + tab[b + SS_R_VERB]) as *u8
1097 p = al_key(d,p,"one_step_verb" as *u8); d[p]=34 as u8; p=p+1; p = al_jesc(d,p,vs,0,al_vlen(vs),120); d[p]=34 as u8; p=p+1
1098 } else {
1099 if rule >= 0 {
1100 // BY-RULE: every step is one whole organ run; the rule's verb and reason travel with the row, gap is zero
1101 let ub: i64 = rule * SS_U_SLOTS
1102 p = al_key(d,p,"min_steps" as *u8); p = al_catn(d,p,kind); d[p]=44 as u8; p=p+1
1103 p = al_key(d,p,"gap" as *u8); p = al_catn(d,p,0); d[p]=44 as u8; p=p+1
1104 let rv: *u8 = ((cq as i64) + rt[ub + SS_U_VERB]) as *u8
1105 p = al_key(d,p,"rule_verb" as *u8); d[p]=34 as u8; p=p+1; p = al_jesc(d,p,rv,0,al_vlen(rv),64); d[p]=34 as u8; p=p+1; d[p]=44 as u8; p=p+1
1106 let rr: *u8 = ((cq as i64) + rt[ub + SS_U_REASON]) as *u8
1107 p = al_key(d,p,"reason" as *u8); d[p]=34 as u8; p=p+1; p = al_jesc(d,p,rr,0,al_vlen(rr),600); d[p]=34 as u8; p=p+1
1108 } else {
1109 p = al_key(d,p,"min_steps" as *u8); p = al_qlit(d,p,"UNDECLARED" as *u8); d[p]=44 as u8; p=p+1
1110 p = al_key(d,p,"remedy" as *u8); p = al_qlit(d,p,"declare a steps row in knowledge/stepsolve.conf: the logical minimum with its reason, or the composed verb on the canonical organ" as *u8)
1111 }
1112 }
1113 d[p]=125 as u8; p=p+1
1114 return p
1115}
1116// the rules array: per-rule support and signature count beside its reason, so a rule can never hide what it absorbed
1117// (an unused rule reports zero, it never invents support)
1118func al_steps_emit_rules(d: *u8, p0: i64, cq: *u8, rt: *i64, nrules: i64) -> i64 {
1119 var p: i64 = p0
1120 d[p]=91 as u8; p=p+1
1121 var r: i64 = 0
1122 while r < nrules {
1123 let ub: i64 = r * SS_U_SLOTS
1124 if r > 0 { d[p]=44 as u8; p=p+1 }
1125 d[p]=123 as u8; p=p+1
1126 let rv: *u8 = ((cq as i64) + rt[ub + SS_U_VERB]) as *u8
1127 p = al_key(d,p,"verb" as *u8); d[p]=34 as u8; p=p+1; p = al_jesc(d,p,rv,0,al_vlen(rv),64); d[p]=34 as u8; p=p+1; d[p]=44 as u8; p=p+1
1128 p = al_key(d,p,"support" as *u8); p = al_catn(d,p,rt[ub + SS_U_SUP]); d[p]=44 as u8; p=p+1
1129 p = al_key(d,p,"signatures" as *u8); p = al_catn(d,p,rt[ub + SS_U_CNT]); d[p]=44 as u8; p=p+1
1130 let rr: *u8 = ((cq as i64) + rt[ub + SS_U_REASON]) as *u8
1131 p = al_key(d,p,"reason" as *u8); d[p]=34 as u8; p=p+1; p = al_jesc(d,p,rr,0,al_vlen(rr),600); d[p]=34 as u8; p=p+1
1132 d[p]=125 as u8; p=p+1
1133 r = r + 1
1134 }
1135 d[p]=93 as u8; p=p+1
1136 return p
1137}
1138func al_steps(q: *u8, cx: *i64, minsup: i64, confpath: *u8, topn: i64, now: i64, d: *u8) -> i64 {
1139 let n: i64 = cx[0]
1140 let ix: *i64 = sys_mmap(256) as *i64
1141 al_ix_build(q, cx, ix, 0)
1142 let offs: *i64 = ix[1] as *i64
1143 let ar: *u8 = ix[4] as *u8
1144 let fp: *i64 = ix[19] as *i64
1145 let ov: *i64 = ix[20] as *i64
1146 let nbgp: *i64 = ix[14] as *i64
1147 let bgkey: *i64 = ix[12] as *i64
1148 let bgcnt: *i64 = ix[13] as *i64
1149 let ntgp: *i64 = ix[18] as *i64
1150 let tgkey: *i64 = ix[16] as *i64
1151 let tgcnt: *i64 = ix[17] as *i64
1152 let nbg: i64 = nbgp[0]
1153 let ntg: i64 = ntgp[0]
1154 let bgfail: *i64 = ix[23] as *i64
1155 let tgfail: *i64 = ix[24] as *i64
1156 // the conf: an unreadable conf is an ABSTAINING AXIS -- every signature then reads UNDECLARED and the stamp says BLIND
1157 let t: *i64 = sys_mmap(SS_T_SLOTS * SS_WORD) as *i64
1158 ss_totals_zero(t)
1159 let cln: *i64 = sys_mmap(16) as *i64
1160 let cq: *u8 = sys_read_file(confpath, cln)
1161 var crows: i64 = 0
1162 var tab: *i64 = sys_mmap(SS_R_SLOTS * SS_WORD) as *i64
1163 var rt: *i64 = sys_mmap(SS_U_SLOTS * SS_WORD) as *i64
1164 if (cq as i64) != 0 { if cln[0] > 0 {
1165 t[SS_T_CONF_READ] = 1
1166 let ccap: i64 = ss_capacity(cq, cln[0])
1167 tab = sys_mmap(ccap * SS_R_SLOTS * SS_WORD) as *i64
1168 rt = sys_mmap(ccap * SS_U_SLOTS * SS_WORD) as *i64
1169 crows = ss_conf_load(cq, cln[0], tab, rt, t)
1170 } }
1171 let nrules: i64 = t[SS_T_CONF_RULES]
1172 // candidates sized from the index (never a picked cap): kind, index, support, class, conf row, rule
1173 let cap: i64 = nbg + ntg + 1
1174 let ckind: *i64 = sys_mmap(cap * SS_WORD) as *i64
1175 let cidx: *i64 = sys_mmap(cap * SS_WORD) as *i64
1176 let csup: *i64 = sys_mmap(cap * SS_WORD) as *i64
1177 let ccls: *i64 = sys_mmap(cap * SS_WORD) as *i64
1178 let crow: *i64 = sys_mmap(cap * SS_WORD) as *i64
1179 let crule: *i64 = sys_mmap(cap * SS_WORD) as *i64
1180 let cfail: *i64 = sys_mmap(cap * SS_WORD) as *i64
1181 var nc: i64 = 0
1182 var nb2: i64 = 0
1183 var nt3: i64 = 0
1184 let sig: *u8 = sys_mmap(AL_MAGIC_1024)
1185 var i: i64 = 0
1186 while i < nbg {
1187 if bgcnt[i] >= minsup {
1188 let a: i64 = bgkey[i] / AL_IX_KEYB
1189 let b: i64 = bgkey[i] % AL_IX_KEYB
1190 if al_bg_is_closed(a, b, bgcnt[i], tgkey, tgcnt, ntg) == 1 { ckind[nc] = 2; cidx[nc] = i; csup[nc] = bgcnt[i]; cfail[nc] = bgfail[i]; nc = nc + 1; nb2 = nb2 + 1 }
1191 }
1192 i = i + 1
1193 }
1194 var j: i64 = 0
1195 while j < ntg {
1196 if tgcnt[j] >= minsup { ckind[nc] = 3; cidx[nc] = j; csup[nc] = tgcnt[j]; cfail[nc] = tgfail[j]; nc = nc + 1; nt3 = nt3 + 1 }
1197 j = j + 1
1198 }
1199 // pass 1: classify the WHOLE population into the totals (the shown prefix below is never the denominator)
1200 var c: i64 = 0
1201 while c < nc {
1202 let sl: i64 = al_steps_sig(sig, ar, offs, ckind[c], cidx[c], bgkey, tgkey)
1203 var row: i64 = 0 - 1
1204 if crows > 0 { row = ss_conf_find(cq, tab, crows, sig, sl) }
1205 var minv: i64 = 0
1206 var hv: i64 = 0
1207 if row >= 0 { minv = tab[row * SS_R_SLOTS + SS_R_MIN]; hv = tab[row * SS_R_SLOTS + SS_R_HASVERB] }
1208 var rule: i64 = 0 - 1
1209 if row < 0 { if nrules > 0 { rule = ss_rule_find(cq, rt, nrules, sig, sl) } }
1210 let cl: i64 = ss_class_of(row, minv, hv, ckind[c], rule)
1211 ccls[c] = cl
1212 crow[c] = row
1213 crule[c] = rule
1214 if cl == SS_C_RULE { ss_rule_add(rt, rule, csup[c]) }
1215 ss_totals_add(t, cl, csup[c], cfail[c])
1216 c = c + 1
1217 }
1218 var p: i64 = 0
1219 d[p]=123 as u8; p=p+1
1220 p = al_key(d,p,"v" as *u8); p = al_catn(d,p,1); d[p]=44 as u8; p=p+1
1221 p = al_key(d,p,"tool" as *u8); p = al_qlit(d,p,"nx_actlog" as *u8); d[p]=44 as u8; p=p+1
1222 p = al_key(d,p,"averb" as *u8); p = al_qlit(d,p,"steps" as *u8); d[p]=44 as u8; p=p+1
1223 p = al_key(d,p,"journal" as *u8); d[p]=34 as u8; p=p+1
1224 let jp: *u8 = cx[5] as *u8
1225 p = al_jesc(d,p,jp,0,al_vlen(jp),200)
1226 d[p]=34 as u8; p=p+1; d[p]=44 as u8; p=p+1
1227 p = al_key(d,p,"journal_bytes" as *u8); p = al_catn(d,p,n); d[p]=44 as u8; p=p+1
1228 p = al_key(d,p,"truncated" as *u8); p = al_catn(d,p,cx[4]); d[p]=44 as u8; p=p+1
1229 p = al_key(d,p,"frames" as *u8); p = al_catn(d,p,fp[0]); d[p]=44 as u8; p=p+1
1230 p = al_key(d,p,"minsup" as *u8); p = al_catn(d,p,minsup); d[p]=44 as u8; p=p+1
1231 p = al_key(d,p,"maxgap" as *u8); p = al_catn(d,p,0); d[p]=44 as u8; p=p+1
1232 p = al_key(d,p,"index_overflow" as *u8); p = al_catn(d,p,ov[0]); d[p]=44 as u8; p=p+1
1233 p = al_key(d,p,"conf" as *u8); p = al_qlit(d,p,confpath); d[p]=44 as u8; p=p+1
1234 p = al_key(d,p,"conf_read" as *u8); p = al_catn(d,p,t[SS_T_CONF_READ]); d[p]=44 as u8; p=p+1
1235 p = al_key(d,p,"conf_rows" as *u8); p = al_catn(d,p,t[SS_T_CONF_ROWS]); d[p]=44 as u8; p=p+1
1236 p = al_key(d,p,"conf_malformed" as *u8); p = al_catn(d,p,t[SS_T_CONF_MALFORMED]); d[p]=44 as u8; p=p+1
1237 p = al_key(d,p,"conf_rules" as *u8); p = al_catn(d,p,t[SS_T_CONF_RULES]); d[p]=44 as u8; p=p+1
1238 p = al_key(d,p,"bigrams_closed" as *u8); p = al_catn(d,p,nb2); d[p]=44 as u8; p=p+1
1239 p = al_key(d,p,"trigrams" as *u8); p = al_catn(d,p,nt3); d[p]=44 as u8; p=p+1
1240 p = al_key(d,p,"totals" as *u8); p = ss_emit_totals(d,p,t); d[p]=44 as u8; p=p+1
1241 p = al_key(d,p,"rules" as *u8); p = al_steps_emit_rules(d,p,cq,rt,nrules); d[p]=44 as u8; p=p+1
1242 // top-N by support over every class (bounded selection, exact, no sort infra)
1243 p = al_key(d,p,"signatures" as *u8); d[p]=91 as u8; p=p+1
1244 let done: *i64 = sys_mmap(cap * SS_WORD) as *i64
1245 var shown: i64 = 0
1246 var efirst: i64 = 1
1247 var pass: i64 = 0
1248 while pass < nc {
1249 if shown < topn { if p <= AL_SOFT {
1250 var mi: i64 = 0 - 1
1251 var mx: i64 = 0 - 1
1252 var k: i64 = 0
1253 while k < nc { if done[k]==0 { if csup[k] > mx { mx = csup[k]; mi = k } } k = k + 1 }
1254 if mi >= 0 {
1255 done[mi] = 1
1256 if efirst==0 { d[p]=44 as u8; p=p+1 }
1257 efirst = 0
1258 p = al_steps_emit_one(d, p, sig, ar, offs, bgkey, tgkey, cq, tab, rt, ckind[mi], cidx[mi], csup[mi], cfail[mi], ccls[mi], crow[mi], crule[mi])
1259 shown = shown + 1
1260 }
1261 } }
1262 pass = pass + 1
1263 }
1264 d[p]=93 as u8; p=p+1; d[p]=44 as u8; p=p+1
1265 p = al_key(d,p,"signatures_shown" as *u8); p = al_catn(d,p,shown); d[p]=44 as u8; p=p+1
1266 p = al_key(d,p,"signatures_of" as *u8); p = al_catn(d,p,nc); d[p]=44 as u8; p=p+1
1267 // the UNDECLARED worklist, most common first: the rows the operator's order asks the estate to explain next
1268 p = al_key(d,p,"worklist_undeclared" as *u8); d[p]=91 as u8; p=p+1
1269 let done2: *i64 = sys_mmap(cap * SS_WORD) as *i64
1270 var wshown: i64 = 0
1271 var wfirst: i64 = 1
1272 var wpass: i64 = 0
1273 while wpass < nc {
1274 if wshown < topn { if p <= AL_SOFT {
1275 var wi: i64 = 0 - 1
1276 var wx: i64 = 0 - 1
1277 var wk: i64 = 0
1278 while wk < nc { if done2[wk]==0 { if ccls[wk] == SS_C_UNDECLARED { if csup[wk] > wx { wx = csup[wk]; wi = wk } } } wk = wk + 1 }
1279 if wi >= 0 {
1280 done2[wi] = 1
1281 if wfirst==0 { d[p]=44 as u8; p=p+1 }
1282 wfirst = 0
1283 let wl: i64 = al_steps_sig(sig, ar, offs, ckind[wi], cidx[wi], bgkey, tgkey)
1284 d[p]=123 as u8; p=p+1
1285 p = al_key(d,p,"signature" as *u8); d[p]=34 as u8; p=p+1; p = al_jesc(d,p,sig,0,wl,480); d[p]=34 as u8; p=p+1; d[p]=44 as u8; p=p+1
1286 p = al_key(d,p,"steps" as *u8); p = al_catn(d,p,ckind[wi]); d[p]=44 as u8; p=p+1
1287 p = al_key(d,p,"support" as *u8); p = al_catn(d,p,csup[wi])
1288 d[p]=125 as u8; p=p+1
1289 wshown = wshown + 1
1290 }
1291 } }
1292 wpass = wpass + 1
1293 }
1294 d[p]=93 as u8; p=p+1; d[p]=44 as u8; p=p+1
1295 p = al_key(d,p,"worklist_shown" as *u8); p = al_catn(d,p,wshown); d[p]=44 as u8; p=p+1
1296 p = al_key(d,p,"worklist_of" as *u8); p = al_catn(d,p,t[SS_T_CNT + SS_C_UNDECLARED]); d[p]=44 as u8; p=p+1
1297 // ES27: the RISK worklist over EVERY class, support x failure permil, most dangerous first, only rituals whose frames
1298 // failed -- a common bad one-step outranks a rare rigorous long one (operator 2026-09-06: a bad 1 step not rigorously
1299 // evaluated is worse than a 40 step perfect deliverable). A FLAG ends the selection, never a sentinel in the cursor.
1300 p = al_key(d,p,"worklist_risk" as *u8); d[p]=91 as u8; p=p+1
1301 let done3: *i64 = sys_mmap(cap * SS_WORD) as *i64
1302 var rshown: i64 = 0
1303 var rfirst: i64 = 1
1304 var rgo: i64 = 1
1305 while rgo == 1 {
1306 if rshown >= topn { rgo = 0 } else { if p > AL_SOFT { rgo = 0 } else {
1307 var ri: i64 = 0 - 1
1308 var rx: i64 = 0
1309 var rk: i64 = 0
1310 while rk < nc { if done3[rk]==0 { let rv: i64 = ss_risk(csup[rk], cfail[rk]); if rv > rx { rx = rv; ri = rk } } rk = rk + 1 }
1311 if ri < 0 { rgo = 0 } else {
1312 done3[ri] = 1
1313 if rfirst==0 { d[p]=44 as u8; p=p+1 }
1314 rfirst = 0
1315 let rl: i64 = al_steps_sig(sig, ar, offs, ckind[ri], cidx[ri], bgkey, tgkey)
1316 d[p]=123 as u8; p=p+1
1317 p = al_key(d,p,"signature" as *u8); d[p]=34 as u8; p=p+1; p = al_jesc(d,p,sig,0,rl,480); d[p]=34 as u8; p=p+1; d[p]=44 as u8; p=p+1
1318 p = al_key(d,p,"steps" as *u8); p = al_catn(d,p,ckind[ri]); d[p]=44 as u8; p=p+1
1319 p = al_key(d,p,"class" as *u8); p = al_qlit(d,p,ss_class_name(ccls[ri])); d[p]=44 as u8; p=p+1
1320 p = al_key(d,p,"support" as *u8); p = al_catn(d,p,csup[ri]); d[p]=44 as u8; p=p+1
1321 p = al_key(d,p,"fail" as *u8); p = al_catn(d,p,cfail[ri]); d[p]=44 as u8; p=p+1
1322 p = al_key(d,p,"fail_permil" as *u8); p = al_catn(d,p,ss_fail_permil(csup[ri], cfail[ri])); d[p]=44 as u8; p=p+1
1323 p = al_key(d,p,"risk" as *u8); p = al_catn(d,p,rx)
1324 d[p]=125 as u8; p=p+1
1325 rshown = rshown + 1
1326 }
1327 } }
1328 }
1329 d[p]=93 as u8; p=p+1; d[p]=44 as u8; p=p+1
1330 p = al_key(d,p,"worklist_risk_shown" as *u8); p = al_catn(d,p,rshown); d[p]=44 as u8; p=p+1
1331 p = ss_publish_json(d, p, jp, now, t)
1332 d[p]=125 as u8; p=p+1
1333 d[p]=10 as u8; p=p+1
1334 return p
1335}
1336func al_bench_path(dst: *u8, prefix: *u8, now: i64, sfx: *u8) -> i64 {
1337 var o: i64 = al_cat(dst, 0, prefix)
1338 o = al_catn(dst, o, now)
1339 o = al_cat(dst, o, sfx)
1340 dst[o] = 0 as u8
1341 // seq672 FIX: TRUNCATE the bench fixture so two selftest runs in the SAME second (now collides)
1342 // start empty instead of doubling appended rows -> the exact-support bench assertions stay idempotent.
1343 let fd: i64 = sys_openat_wr(dst, 0x1a4)
1344 if fd >= 0 { sys_close(fd) }
1345 return 0
1346}
1347func al_bench_case(ctr: *i64, name: *u8, jr: *u8, minsup: i64, maxgap: i64, needle: *u8, want: i64) -> i64 {
1348 let q: *u8 = sys_mmap(AL_WIN)
1349 let cx: *i64 = sys_mmap(64) as *i64
1350 let n: i64 = al_read(jr, q, AL_WIN - 8)
1351 cx[0]=n
1352 cx[1]=0
1353 cx[2]=0
1354 cx[3]=0
1355 cx[4]=0
1356 cx[5]=jr as i64
1357 let d: *u8 = sys_mmap(AL_OUT)
1358 let dl: i64 = al_mine_fast(q,cx,minsup,maxgap,0,d)
1359 var got: i64 = 0
1360 if dl > 0 { got = al_find(d,dl,needle) }
1361 var ok: i64 = 0
1362 if got == want { ok = 1 }
1363 gv_check(name, ok, ctr)
1364 return ok
1365}
1366func al_bench(prefix: *u8) -> i64 {
1367 let ctr: *i64 = gv_ctr()
1368 gv_head("nx_actlog bench -- miner accuracy vs planted-pattern EXACT oracle (F968)" as *u8)
1369 let now: i64 = sys_now_realtime_sec()
1370 let jA: *u8 = sys_mmap(512)
1371 al_bench_path(jA, prefix, now, ".bA" as *u8)
1372 let jB: *u8 = sys_mmap(512)
1373 al_bench_path(jB, prefix, now, ".bB" as *u8)
1374 let jC: *u8 = sys_mmap(512)
1375 al_bench_path(jC, prefix, now, ".bC" as *u8)
1376 let jD: *u8 = sys_mmap(512)
1377 al_bench_path(jD, prefix, now, ".bD" as *u8)
1378 let jE: *u8 = sys_mmap(512)
1379 al_bench_path(jE, prefix, now, ".bE" as *u8)
1380 let jF: *u8 = sys_mmap(512)
1381 al_bench_path(jF, prefix, now, ".bF" as *u8)
1382 // jA: X:a Y:b alternating x3 in w1 (contiguous plant, K=3)
1383 al_append(jA, 900, "w1" as *u8, "X" as *u8, "a" as *u8, "ok" as *u8, "-" as *u8)
1384 al_append(jA, 901, "w1" as *u8, "Y" as *u8, "b" as *u8, "ok" as *u8, "-" as *u8)
1385 al_append(jA, 902, "w1" as *u8, "X" as *u8, "a" as *u8, "ok" as *u8, "-" as *u8)
1386 al_append(jA, 903, "w1" as *u8, "Y" as *u8, "b" as *u8, "ok" as *u8, "-" as *u8)
1387 al_append(jA, 904, "w1" as *u8, "X" as *u8, "a" as *u8, "ok" as *u8, "-" as *u8)
1388 al_append(jA, 905, "w1" as *u8, "Y" as *u8, "b" as *u8, "ok" as *u8, "-" as *u8)
1389 al_bench_case(ctr, "C1 contiguous plant support exact 3 at maxgap 0" as *u8, jA, 2, 0, "\"a\":\"X:a\",\"b\":\"Y:b\",\"support\":3" as *u8, 1)
1390 al_bench_case(ctr, "C2 gap window never inflates the adjacent plant (still 3 at maxgap 1)" as *u8, jA, 2, 1, "\"a\":\"X:a\",\"b\":\"Y:b\",\"support\":3" as *u8, 1)
1391 // jB: X:a N:z Y:b x3 in w1 (gapped plant, gap=1, K=3)
1392 al_append(jB, 910, "w1" as *u8, "X" as *u8, "a" as *u8, "ok" as *u8, "-" as *u8)
1393 al_append(jB, 911, "w1" as *u8, "N" as *u8, "z" as *u8, "ok" as *u8, "-" as *u8)
1394 al_append(jB, 912, "w1" as *u8, "Y" as *u8, "b" as *u8, "ok" as *u8, "-" as *u8)
1395 al_append(jB, 913, "w1" as *u8, "X" as *u8, "a" as *u8, "ok" as *u8, "-" as *u8)
1396 al_append(jB, 914, "w1" as *u8, "N" as *u8, "z" as *u8, "ok" as *u8, "-" as *u8)
1397 al_append(jB, 915, "w1" as *u8, "Y" as *u8, "b" as *u8, "ok" as *u8, "-" as *u8)
1398 al_append(jB, 916, "w1" as *u8, "X" as *u8, "a" as *u8, "ok" as *u8, "-" as *u8)
1399 al_append(jB, 917, "w1" as *u8, "N" as *u8, "z" as *u8, "ok" as *u8, "-" as *u8)
1400 al_append(jB, 918, "w1" as *u8, "Y" as *u8, "b" as *u8, "ok" as *u8, "-" as *u8)
1401 al_bench_case(ctr, "C3 gapped plant INVISIBLE at maxgap 0 (no fabrication)" as *u8, jB, 2, 0, "\"a\":\"X:a\",\"b\":\"Y:b\"" as *u8, 0)
1402 al_bench_case(ctr, "C4 gapped plant found exact 3 at maxgap 1" as *u8, jB, 2, 1, "\"a\":\"X:a\",\"b\":\"Y:b\",\"support\":3" as *u8, 1)
1403 al_bench_case(ctr, "C5 wider window stays exact (3 at maxgap 2, no overcount)" as *u8, jB, 2, 2, "\"a\":\"X:a\",\"b\":\"Y:b\",\"support\":3" as *u8, 1)
1404 // jC: X:a in w1 / Y:b in w2 alternating x3 (ws-split decoy)
1405 al_append(jC, 920, "w1" as *u8, "X" as *u8, "a" as *u8, "ok" as *u8, "-" as *u8)
1406 al_append(jC, 921, "w2" as *u8, "Y" as *u8, "b" as *u8, "ok" as *u8, "-" as *u8)
1407 al_append(jC, 922, "w1" as *u8, "X" as *u8, "a" as *u8, "ok" as *u8, "-" as *u8)
1408 al_append(jC, 923, "w2" as *u8, "Y" as *u8, "b" as *u8, "ok" as *u8, "-" as *u8)
1409 al_append(jC, 924, "w1" as *u8, "X" as *u8, "a" as *u8, "ok" as *u8, "-" as *u8)
1410 al_append(jC, 925, "w2" as *u8, "Y" as *u8, "b" as *u8, "ok" as *u8, "-" as *u8)
1411 al_bench_case(ctr, "C6 ws-split decoy never counted even at maxgap 2 (isolation)" as *u8, jC, 2, 2, "\"a\":\"X:a\",\"b\":\"Y:b\"" as *u8, 0)
1412 // jD: 5 distinct singleton tvs (pure noise)
1413 al_append(jD, 930, "w1" as *u8, "T1" as *u8, "v" as *u8, "ok" as *u8, "-" as *u8)
1414 al_append(jD, 931, "w1" as *u8, "T2" as *u8, "v" as *u8, "ok" as *u8, "-" as *u8)
1415 al_append(jD, 932, "w1" as *u8, "T3" as *u8, "v" as *u8, "ok" as *u8, "-" as *u8)
1416 al_append(jD, 933, "w1" as *u8, "T4" as *u8, "v" as *u8, "ok" as *u8, "-" as *u8)
1417 al_append(jD, 934, "w1" as *u8, "T5" as *u8, "v" as *u8, "ok" as *u8, "-" as *u8)
1418 al_bench_case(ctr, "C7 pure noise yields ZERO patterns at minsup 2" as *u8, jD, 2, 2, "\"support\"" as *u8, 0)
1419 // jE: P:p Q:q R:r x2 (trigram plant, K=2)
1420 al_append(jE, 940, "w1" as *u8, "P" as *u8, "p" as *u8, "ok" as *u8, "-" as *u8)
1421 al_append(jE, 941, "w1" as *u8, "Q" as *u8, "q" as *u8, "ok" as *u8, "-" as *u8)
1422 al_append(jE, 942, "w1" as *u8, "R" as *u8, "r" as *u8, "ok" as *u8, "-" as *u8)
1423 al_append(jE, 943, "w1" as *u8, "P" as *u8, "p" as *u8, "ok" as *u8, "-" as *u8)
1424 al_append(jE, 944, "w1" as *u8, "Q" as *u8, "q" as *u8, "ok" as *u8, "-" as *u8)
1425 al_append(jE, 945, "w1" as *u8, "R" as *u8, "r" as *u8, "ok" as *u8, "-" as *u8)
1426 al_bench_case(ctr, "C8 trigram plant support exact 2" as *u8, jE, 2, 0, "\"a\":\"P:p\",\"b\":\"Q:q\",\"c\":\"R:r\",\"support\":2" as *u8, 1)
1427 // jF: S:s x4 (self-loop, 3 adjacent pairs)
1428 al_append(jF, 950, "w1" as *u8, "S" as *u8, "s" as *u8, "ok" as *u8, "-" as *u8)
1429 al_append(jF, 951, "w1" as *u8, "S" as *u8, "s" as *u8, "ok" as *u8, "-" as *u8)
1430 al_append(jF, 952, "w1" as *u8, "S" as *u8, "s" as *u8, "ok" as *u8, "-" as *u8)
1431 al_append(jF, 953, "w1" as *u8, "S" as *u8, "s" as *u8, "ok" as *u8, "-" as *u8)
1432 al_bench_case(ctr, "C9 self-loop support exact 3 (4 frames, 3 adjacent pairs)" as *u8, jF, 2, 0, "\"a\":\"S:s\",\"b\":\"S:s\",\"support\":3" as *u8, 1)
1433 let rc: i64 = gv_verdict("ACTLOG-BENCH" as *u8, ctr, "planted-pattern oracle: exact supports, honest gaps, ws isolation, zero fabrication" as *u8)
1434 return rc
1435}
1436
1437// ---------- selftest gate (T1..T9, deterministic) ----------
1438func al_selftest(journal: *u8) -> i64 {
1439 let ctr: *i64 = gv_ctr()
1440 gv_head("nx_actlog selftest -- action journal + sequence mining teeth (SELF-cleans scratch)" as *u8)
1441 // seq672 FIX: truncate the scratch journal to empty so a RE-RUN is idempotent (T1 empty-journal
1442 // held on every run). Was "caller pre-cleans" -> a 2nd run failed T1 -> FALSE erosion in the
1443 // harness miner. Truncate-open (O_WRONLY_CT) not unlinkat (the AT_FDCWD dirfd=0 relative-path bug).
1444 let tfd: i64 = sys_openat_wr(journal, 0x1a4)
1445 if tfd >= 0 { sys_close(tfd) }
1446 let q: *u8 = sys_mmap(AL_WIN)
1447 let cx: *i64 = sys_mmap(64) as *i64
1448 let rcap: i64 = AL_WIN - 8
1449 // T1 empty -> zero frames
1450 var n: i64 = al_read(journal,q,rcap)
1451 cx[0]=n; cx[1]=0; cx[2]=0; cx[3]=0; cx[4]=0; cx[5]=journal as i64
1452 var ok1: i64 = 0
1453 if n==0 { ok1=1 }
1454 gv_check("T1 empty journal zero frames" as *u8, ok1, ctr)
1455 // seed w1: A:x -> B:y -> A:x -> B:y interleaved with w2: C:z after the first frame
1456 al_append(journal, 1000, "w1" as *u8, "A" as *u8, "x" as *u8, "ok" as *u8, "n1" as *u8)
1457 al_append(journal, 1001, "w2" as *u8, "C" as *u8, "z" as *u8, "ok" as *u8, "n2" as *u8)
1458 al_append(journal, 1002, "w1" as *u8, "B" as *u8, "y" as *u8, "ok" as *u8, "n3" as *u8)
1459 al_append(journal, 1003, "w1" as *u8, "A" as *u8, "x" as *u8, "ok" as *u8, "n4" as *u8)
1460 al_append(journal, 1004, "w1" as *u8, "B" as *u8, "y" as *u8, "ok" as *u8, "n5" as *u8)
1461 n = al_read(journal,q,rcap)
1462 cx[0]=n
1463 var ok2: i64 = 0
1464 let fr: i64 = al_frames(q,n)
1465 if fr==5 { ok2=1 }
1466 gv_check("T2 five frames logged" as *u8, ok2, ctr)
1467 // T3 ws isolation: successor of frame0 (w1 A:x) is the w1 B:y frame, NOT the w2 C:z frame
1468 var ok3: i64 = 0
1469 let s0: i64 = al_succ(q,cx,0)
1470 if s0 >= 0 {
1471 let sp: *i64 = sys_mmap(16) as *i64
1472 let se: i64 = al_le(q,s0,n)
1473 if al_col(q,s0,se,2,sp)==1 { if al_lit_eq(q,sp[0],sp[1],"B" as *u8)==1 { ok3=1 } }
1474 }
1475 gv_check("T3 successor stays inside workstream" as *u8, ok3, ctr)
1476 // T4 bigram support: (A:x -> B:y) in w1 occurs twice
1477 var ok4: i64 = 0
1478 let s0b: i64 = al_succ(q,cx,0)
1479 if s0b >= 0 { let sup: i64 = al_bg_support(q,cx,0,s0b); if sup==2 { ok4=1 } }
1480 gv_check("T4 repeated bigram support exact 2" as *u8, ok4, ctr)
1481 // T5 trigram support: (A:x -> B:y -> A:x) occurs once
1482 var ok5: i64 = 0
1483 if s0b >= 0 {
1484 let s1: i64 = al_succ(q,cx,s0b)
1485 if s1 >= 0 { let sup3: i64 = al_tg_support(q,cx,0,s0b,s1); if sup3==1 { ok5=1 } }
1486 }
1487 gv_check("T5 trigram support exact 1" as *u8, ok5, ctr)
1488 // T6 threshold honesty: mine with minsup=99 emits zero bigrams
1489 let d: *u8 = sys_mmap(AL_OUT)
1490 let dl6: i64 = al_mine_fast(q,cx,99,0,0,d)
1491 var ok6: i64 = 0
1492 if dl6 > 0 { if al_find(d,dl6,"\"support\"" as *u8)==0 { ok6=1 } }
1493 gv_check("T6 minsup 99 yields no patterns no fabrication" as *u8, ok6, ctr)
1494 // T7 real mine JSON: support-2 bigram present + envelope keys
1495 let dl7: i64 = al_mine_fast(q,cx,2,0,0,d)
1496 var ok7: i64 = 0
1497 if dl7 > 0 { if d[0]==(123 as u8) { if al_find(d,dl7,"bigrams_capped" as *u8)==1 { if al_find(d,dl7,"A:x" as *u8)==1 { if al_find(d,dl7,"support" as *u8)==1 { ok7=1 } } } } }
1498 gv_check("T7 mine JSON carries pattern plus declared envelope" as *u8, ok7, ctr)
1499 // T8 freq: per-tool:verb frequency over the seeded journal -- A:x 2, B:y 2, C:z 1, distinct 3.
1500 // Non-vacuous two ways: C:z has NO successor so a sequence-only regression cannot emit it, and
1501 // a dedup regression (first-check broken) reads distinct 5 not 3.
1502 let dl8: i64 = al_freq_fast(q,cx,d,AL_FREQ_CAP)
1503 var ok8: i64 = 0
1504 if dl8 > 0 { if al_find(d,dl8,"\"distinct\":3" as *u8)==1 { if al_find(d,dl8,"\"tv\":\"C:z\",\"count\":1" as *u8)==1 { if al_find(d,dl8,"\"tv\":\"A:x\",\"count\":2" as *u8)==1 { ok8=1 } } } }
1505 gv_check("T8 freq ranks per-tool:verb counts (A:x 2, C:z 1, distinct 3 -- dedup + non-sequence coverage)" as *u8, ok8, ctr)
1506 // T9 harden: A:x and B:y recur (count 2 >= minsup 2), C:z does not. With the INJECTED argecho
1507 // filer, exactly those two file -- their echoed argv must carry the REAL canonical desc (a fork
1508 // that never ran leaves out empty), and C:z must be absent (a broken recurrence filter files 3).
1509 let dl9: i64 = al_harden_json(q,cx,2,5,"argecho" as *u8,d)
1510 var ok9: i64 = 0
1511 if dl9 > 0 { if al_find(d,dl9,"\"recurring\":2" as *u8)==1 { if al_find(d,dl9,"FALLBACK-RECURRENCE A:x" as *u8)==1 { if al_find(d,dl9,"FALLBACK-RECURRENCE B:y" as *u8)==1 { if al_find(d,dl9,"C:z" as *u8)==0 { ok9=1 } } } } }
1512 gv_check("T9 harden files EXACTLY the recurring tvs through the injected filer (canonical desc echoed back; C:z absent)" as *u8, ok9, ctr)
1513 // T10/T11 gap-constrained mining (F966 rung 1): w3 = A:x, C:z, B:y -- A->B has ONE intervening frame
1514 al_append(journal, 1010, "w3" as *u8, "A" as *u8, "x" as *u8, "ok" as *u8, "g1" as *u8)
1515 al_append(journal, 1011, "w3" as *u8, "C" as *u8, "z" as *u8, "ok" as *u8, "g2" as *u8)
1516 al_append(journal, 1012, "w3" as *u8, "B" as *u8, "y" as *u8, "ok" as *u8, "g3" as *u8)
1517 n = al_read(journal,q,rcap)
1518 cx[0]=n
1519 let dl10: i64 = al_mine_fast(q,cx,2,0,0,d)
1520 var ok10: i64 = 0
1521 if dl10 > 0 { if al_find(d,dl10,"\"a\":\"A:x\",\"b\":\"B:y\",\"support\":2" as *u8)==1 { ok10=1 } }
1522 gv_check("T10 maxgap 0 never counts the gapped pair (support stays 2)" as *u8, ok10, ctr)
1523 let dl11: i64 = al_mine_fast(q,cx,2,1,0,d)
1524 var ok11: i64 = 0
1525 if dl11 > 0 { if al_find(d,dl11,"\"a\":\"A:x\",\"b\":\"B:y\",\"support\":3" as *u8)==1 { if al_find(d,dl11,"\"maxgap\":1" as *u8)==1 { ok11=1 } } }
1526 gv_check("T11 maxgap 1 finds the interleaved pair (support 3, declared)" as *u8, ok11, ctr)
1527 // T12: the F968 bench itself must be all-exact (accuracy measured, not asserted)
1528 let rb: i64 = al_bench(journal)
1529 var ok12: i64 = 0
1530 if rb == 0 { ok12 = 1 }
1531 gv_check("T12 bench: planted-pattern accuracy harness all-exact" as *u8, ok12, ctr)
1532 // T13/T14 CLOSED PATTERNS (CloSpan/BIDE, benchmarked vs a hand-computed closure oracle). w4 = G:x
1533 // H:y I:z x3 (contiguous) so G:x->H:y and H:y->I:z are SUBSUMED by the trigram G:x->H:y->I:z (equal
1534 // support 3) = NON-closed. w5 = P:x Q:y R:z / P:x Q:y S:z so P:x->Q:y (sup 2) has NO equal-support
1535 // trigram (both P:x->Q:y->{R,S} are sup 1) = CLOSED. Fresh tvs (G/H/I/P/Q/R/S) avoid main-journal collisions.
1536 al_append(journal, AL_MAGIC_1100, "w4" as *u8, "G" as *u8, "x" as *u8, "ok" as *u8, "-" as *u8)
1537 al_append(journal, AL_MAGIC_1101, "w4" as *u8, "H" as *u8, "y" as *u8, "ok" as *u8, "-" as *u8)
1538 al_append(journal, AL_MAGIC_1102, "w4" as *u8, "I" as *u8, "z" as *u8, "ok" as *u8, "-" as *u8)
1539 al_append(journal, AL_MAGIC_1103, "w4" as *u8, "G" as *u8, "x" as *u8, "ok" as *u8, "-" as *u8)
1540 al_append(journal, AL_MAGIC_1104, "w4" as *u8, "H" as *u8, "y" as *u8, "ok" as *u8, "-" as *u8)
1541 al_append(journal, AL_MAGIC_1105, "w4" as *u8, "I" as *u8, "z" as *u8, "ok" as *u8, "-" as *u8)
1542 al_append(journal, AL_MAGIC_1106, "w4" as *u8, "G" as *u8, "x" as *u8, "ok" as *u8, "-" as *u8)
1543 al_append(journal, AL_MAGIC_1107, "w4" as *u8, "H" as *u8, "y" as *u8, "ok" as *u8, "-" as *u8)
1544 al_append(journal, AL_MAGIC_1108, "w4" as *u8, "I" as *u8, "z" as *u8, "ok" as *u8, "-" as *u8)
1545 al_append(journal, AL_MAGIC_1110, "w5" as *u8, "P" as *u8, "x" as *u8, "ok" as *u8, "-" as *u8)
1546 al_append(journal, AL_MAGIC_1111, "w5" as *u8, "Q" as *u8, "y" as *u8, "ok" as *u8, "-" as *u8)
1547 al_append(journal, AL_MAGIC_1112, "w5" as *u8, "R" as *u8, "z" as *u8, "ok" as *u8, "-" as *u8)
1548 al_append(journal, AL_MAGIC_1113, "w5" as *u8, "P" as *u8, "x" as *u8, "ok" as *u8, "-" as *u8)
1549 al_append(journal, AL_MAGIC_1114, "w5" as *u8, "Q" as *u8, "y" as *u8, "ok" as *u8, "-" as *u8)
1550 al_append(journal, AL_MAGIC_1115, "w5" as *u8, "S" as *u8, "z" as *u8, "ok" as *u8, "-" as *u8)
1551 n = al_read(journal,q,rcap)
1552 cx[0]=n
1553 let dlnc: i64 = al_mine_fast(q,cx,2,0,0,d)
1554 var ok13: i64 = 0
1555 if dlnc > 0 { if al_find(d,dlnc,"\"a\":\"G:x\",\"b\":\"H:y\",\"support\":3" as *u8)==1 { if al_find(d,dlnc,"\"closed\":0" as *u8)==1 { ok13=1 } } }
1556 gv_check("T13 non-closed mode emits the subsumed bigram G:x->H:y (support 3)" as *u8, ok13, ctr)
1557 let dlc: i64 = al_mine_fast(q,cx,2,0,1,d)
1558 var ok14: i64 = 0
1559 // the SUBSUMED bigram's specific form ("support" right after "b") must be gone; the trigram
1560 // G:x->H:y->I:z ("c" after "b") legitimately remains and must NOT be matched as the bigram.
1561 if dlc > 0 { if al_find(d,dlc,"\"a\":\"G:x\",\"b\":\"H:y\",\"support\"" as *u8)==0 { if al_find(d,dlc,"\"a\":\"P:x\",\"b\":\"Q:y\",\"support\":2" as *u8)==1 { if al_find(d,dlc,"\"closed\":1" as *u8)==1 { ok14=1 } } } }
1562 gv_check("T14 closed mode DROPS the subsumed bigram, KEEPS the closed P:x->Q:y (CloSpan/BIDE)" as *u8, ok14, ctr)
1563 // T15 CONFIDENCE (association-rule strength, EXACT + total-independent). w6 = M N M N M P => M appears
1564 // 3x, M->N 2x, M->P 1x => confidence(M:x->N:y)=support(2)/freq(M)(3)=666 permil regardless of journal size.
1565 al_append(journal, AL_MAGIC_1100, "w6" as *u8, "M" as *u8, "x" as *u8, "ok" as *u8, "-" as *u8)
1566 al_append(journal, AL_MAGIC_1100, "w6" as *u8, "N" as *u8, "y" as *u8, "ok" as *u8, "-" as *u8)
1567 al_append(journal, AL_MAGIC_1100, "w6" as *u8, "M" as *u8, "x" as *u8, "ok" as *u8, "-" as *u8)
1568 al_append(journal, AL_MAGIC_1100, "w6" as *u8, "N" as *u8, "y" as *u8, "ok" as *u8, "-" as *u8)
1569 al_append(journal, AL_MAGIC_1100, "w6" as *u8, "M" as *u8, "x" as *u8, "ok" as *u8, "-" as *u8)
1570 al_append(journal, AL_MAGIC_1100, "w6" as *u8, "P" as *u8, "z" as *u8, "ok" as *u8, "-" as *u8)
1571 n = al_read(journal,q,rcap)
1572 cx[0]=n
1573 let dlcf: i64 = al_mine_fast(q,cx,2,0,0,d)
1574 var ok15: i64 = 0
1575 if dlcf > 0 { if al_find(d,dlcf,"\"a\":\"M:x\",\"b\":\"N:y\",\"support\":2,\"confidence_permil\":666" as *u8)==1 { ok15=1 } }
1576 gv_check("T15 confidence(M:x->N:y)=666 permil (support 2 / freq(M) 3 -- association-rule strength, exact)" as *u8, ok15, ctr)
1577 // T16/T17 INDEX SIZED FROM THE FRAME COUNT (2026-09-05). Fixture: 130 tools, every ordered pair (Ta,Tb)
1578 // emitted as consecutive frames in one workspace => EXACTLY 130*130 = 16,900 distinct bigrams, which is
1579 // ABOVE the old fixed AL_IX_GMAX (16,384): under the fixed cap this journal read index_overflow=1 with 516
1580 // pairs silently uncounted. The tooth asserts the exact count (a floor-sized table cannot reach it) and that
1581 // the table was DERIVED (gmax = frames + 1 = 33,801, not the 16,384 floor). Written to its own file so the
1582 // capped selftest read buffer cannot truncate the fixture into passing for the wrong reason.
1583 let ovj: *u8 = sys_mmap(512)
1584 var oo: i64 = al_cat(ovj, 0, journal)
1585 oo = al_cat(ovj, oo, ".ovf" as *u8)
1586 ovj[oo] = 0 as u8
1587 let tfd: i64 = sys_openat_wr(ovj, 420)
1588 if tfd >= 0 { sys_close(tfd) }
1589 let ta: *u8 = sys_mmap(32)
1590 let tb: *u8 = sys_mmap(32)
1591 var fa: i64 = 0
1592 while fa < 130 {
1593 var fb: i64 = 0
1594 while fb < 130 {
1595 var ao: i64 = al_cat(ta, 0, "T" as *u8); ao = al_catn(ta, ao, fa); ta[ao] = 0 as u8
1596 var bo: i64 = al_cat(tb, 0, "T" as *u8); bo = al_catn(tb, bo, fb); tb[bo] = 0 as u8
1597 al_append(ovj, AL_MAGIC_1100, "wo" as *u8, ta, "v" as *u8, "ok" as *u8, "-" as *u8)
1598 al_append(ovj, AL_MAGIC_1100, "wo" as *u8, tb, "v" as *u8, "ok" as *u8, "-" as *u8)
1599 fb = fb + 1
1600 }
1601 fa = fa + 1
1602 }
1603 let nn16: *i64 = sys_mmap(16) as *i64
1604 let q16: *u8 = sys_read_file(ovj, nn16)
1605 let cx16: *i64 = sys_mmap(64) as *i64
1606 cx16[0] = nn16[0]
1607 cx16[1] = 0
1608 cx16[2] = 0
1609 cx16[3] = 0
1610 cx16[4] = 0
1611 cx16[5] = ovj as i64
1612 let dl16: i64 = al_mine_fast(q16, cx16, 1, 0, 0, d)
1613 var ok16: i64 = 0
1614 if dl16 > 0 { if al_find(d,dl16,"\"index_bigrams\":16900" as *u8)==1 { if al_find(d,dl16,"\"index_overflow\":0" as *u8)==1 { if al_find(d,dl16,"\"index_overflow_grams\":0" as *u8)==1 { ok16=1 } } } }
1615 gv_check("T16 index sized from the frame count: 16,900 distinct bigrams (above the old 16,384 fixed cap) counted EXACTLY, index_overflow 0" as *u8, ok16, ctr)
1616 var ok17: i64 = 0
1617 if dl16 > 0 { if al_find(d,dl16,"\"index_gmax\":33801" as *u8)==1 { ok17=1 } }
1618 gv_check("T17 fixture-reached-the-condition: the gram table was DERIVED (gmax = 33,800 frames + 1), not the floor" as *u8, ok17, ctr)
1619 let rc: i64 = gv_verdict("ACTLOG-GATE" as *u8, ctr, "action journal + sequence + frequency + harden + gap + bench + closed-pattern + confidence + derived-index teeth green" as *u8)
1620 return rc
1621}
1622
1623func main(argc: i64, argv: *i64) -> i64 {
1624 if argc < 3 { gv_puts("usage: nx_actlog {log <journal> <ws> <tool> <verb> <outcome> <note> | mine <journal> [minsup] [maxgap] [closed] | freq <journal> | harden <journal> [minsup] [filer] | bench <scratch-prefix> | selftest <journal>}\n" as *u8); sys_exit(2); return 2 }
1625 let verb: *u8 = argv[1] as *u8
1626 let journal: *u8 = argv[2] as *u8
1627 let vl: i64 = al_vlen(verb)
1628 if al_lit_eq(verb,0,vl,"selftest" as *u8)==1 { let rc: i64 = al_selftest(journal); sys_exit(rc); return rc }
1629 if al_lit_eq(verb,0,vl,"log" as *u8)==1 {
1630 if argc < 8 { gv_puts("log needs <journal> <ws> <tool> <verb> <outcome> <note>\n" as *u8); sys_exit(2); return 2 }
1631 let ws: *u8 = argv[3] as *u8
1632 let tool: *u8 = argv[4] as *u8
1633 let averb: *u8 = argv[5] as *u8
1634 let outcome: *u8 = argv[6] as *u8
1635 let note: *u8 = argv[7] as *u8
1636 let rc: i64 = al_append(journal, -1, ws, tool, averb, outcome, note)
1637 if rc==0 { gv_puts("ACTLOG OK ws=" as *u8); gv_puts(ws); gv_puts(" " as *u8); gv_puts(tool); gv_puts(":" as *u8); gv_puts(averb); gv_puts("\n" as *u8); sys_exit(0); return 0 }
1638 gv_puts("append FAILED\n" as *u8)
1639 sys_exit(1)
1640 return 1
1641 }
1642 // ES26: steps <journal> [minsup] [conf] [topn] [now] -- the one-step-solve ruler over this journal (prints JSON; writes
1643 // the spine row and gauge stamp only when something recurs; an unreadable journal fails closed, nothing published)
1644 if al_lit_eq(verb,0,vl,"steps" as *u8)==1 {
1645 let snn: *i64 = sys_mmap(16) as *i64
1646 let sq: *u8 = sys_read_file(journal, snn)
1647 if (sq as i64) == 0 { gv_puts("nx_actlog steps: journal unreadable (fail closed, nothing published)\n" as *u8); sys_exit(3); return 3 }
1648 let sn: i64 = snn[0]
1649 let scx: *i64 = sys_mmap(64) as *i64
1650 scx[0]=sn
1651 scx[1]=sys_now_realtime_sec()
1652 scx[2]=0
1653 scx[3]=0
1654 scx[4]=0
1655 scx[5]=journal as i64
1656 var sminsup: i64 = AL_MINSUP_DEF
1657 if argc > 3 { let sm: i64 = al_atoi_z(argv[3] as *u8); if sm > 0 { sminsup = sm } }
1658 var sconf: *u8 = SS_CONF_PROD
1659 if argc > 4 { sconf = argv[4] as *u8 }
1660 var stopn: i64 = AL_FREQ_CAP
1661 if argc > 5 { let stn: i64 = al_atoi_z(argv[5] as *u8); if stn > 0 { stopn = stn } }
1662 var snow: i64 = sys_now_realtime_sec()
1663 if argc > 6 { let snz: i64 = al_atoi_z(argv[6] as *u8); if snz > 0 { snow = snz } }
1664 let sd: *u8 = sys_mmap(AL_OUT)
1665 let sdl: i64 = al_steps(sq, scx, sminsup, sconf, stopn, snow, sd)
1666 sys_write(1, sd, sdl)
1667 sys_exit(0)
1668 return 0
1669 }
1670 if al_lit_eq(verb,0,vl,"mine" as *u8)==1 {
1671 let nn: *i64 = sys_mmap(16) as *i64
1672 let q: *u8 = sys_read_file(journal, nn)
1673 let n: i64 = nn[0]
1674 let rcap: i64 = n + 8
1675 let cx: *i64 = sys_mmap(64) as *i64
1676 cx[0]=n
1677 cx[1]=sys_now_realtime_sec()
1678 cx[2]=0
1679 cx[3]=0
1680 cx[4]=0
1681 if n >= rcap { cx[4]=1 }
1682 cx[5]=journal as i64
1683 var minsup: i64 = AL_MINSUP_DEF
1684 if argc >= 4 { let mz: i64 = al_atoi_z(argv[3] as *u8); if mz > 0 { minsup = mz } }
1685 var maxgap: i64 = 0
1686 if argc >= 5 { let gz: i64 = al_atoi_z(argv[4] as *u8); if gz > 0 { maxgap = gz } }
1687 if maxgap > AL_IX_MAXGAP { maxgap = AL_IX_MAXGAP }
1688 var closed: i64 = 0
1689 if argc >= 6 { let cz: i64 = al_atoi_z(argv[5] as *u8); if cz > 0 { closed = 1 } }
1690 let d: *u8 = sys_mmap(AL_OUT)
1691 let dl: i64 = al_mine_fast(q,cx,minsup,maxgap,closed,d)
1692 sys_write(1,d,dl)
1693 sys_exit(0)
1694 return 0
1695 }
1696 if al_lit_eq(verb,0,vl,"freq" as *u8)==1 {
1697 let nn: *i64 = sys_mmap(16) as *i64
1698 let q: *u8 = sys_read_file(journal, nn)
1699 let n: i64 = nn[0]
1700 let rcap: i64 = n + 8
1701 let cx: *i64 = sys_mmap(64) as *i64
1702 cx[0]=n
1703 cx[1]=0
1704 cx[2]=0
1705 cx[3]=0
1706 cx[4]=0
1707 if n >= rcap { cx[4]=1 }
1708 cx[5]=journal as i64
1709 var fcap: i64 = AL_FREQ_CAP
1710 if argc >= 4 { let fz: i64 = al_atoi_z(argv[3] as *u8); if fz > 0 { fcap = fz } }
1711 let d: *u8 = sys_mmap(AL_OUT)
1712 let dl: i64 = al_freq_fast(q,cx,d,fcap)
1713 sys_write(1,d,dl)
1714 sys_exit(0)
1715 return 0
1716 }
1717 if al_lit_eq(verb,0,vl,"harden" as *u8)==1 {
1718 let nn: *i64 = sys_mmap(16) as *i64
1719 let q: *u8 = sys_read_file(journal, nn)
1720 let n: i64 = nn[0]
1721 let rcap: i64 = n + 8
1722 let cx: *i64 = sys_mmap(64) as *i64
1723 cx[0]=n
1724 cx[1]=0
1725 cx[2]=0
1726 cx[3]=0
1727 cx[4]=0
1728 if n >= rcap { cx[4]=1 }
1729 cx[5]=journal as i64
1730 var minsup: i64 = AL_MINSUP_DEF
1731 if argc >= 4 { let mz: i64 = al_atoi_z(argv[3] as *u8); if mz > 0 { minsup = mz } }
1732 let filer: *u8 = sys_mmap(128)
1733 var fo2: i64 = 0
1734 if argc >= 5 { fo2 = al_cat(filer,0,argv[4] as *u8) } else { fo2 = al_cat(filer,0,"nx_debt" as *u8) }
1735 filer[fo2]=0 as u8
1736 let d: *u8 = sys_mmap(AL_OUT)
1737 let dl: i64 = al_harden_json(q,cx,minsup,AL_HARDEN_SEV,filer,d)
1738 sys_write(1,d,dl)
1739 sys_exit(0)
1740 return 0
1741 }
1742 if al_lit_eq(verb,0,vl,"bench" as *u8)==1 {
1743 let rb: i64 = al_bench(journal)
1744 sys_exit(rb)
1745 return rb
1746 }
1747 gv_puts("unknown verb\n" as *u8)
1748 sys_exit(2)
1749 return 2
1750}