code wiki / _hdl_build / nx_harnessmine.nx
nx_harnessmine.nx source
↩ module page · 324 lines · 15422 B
1// nx_harnessmine.nx -- HARNESS-CLASS MINER over the gate-outcome journal (miner-sota F1012, 2026-07-23).
2// The census (nx_minecov MC09) measured the harness class at ZERO evidence: 953+ gates run constantly
3// and NOTHING recorded an outcome, so flake and erosion were structurally invisible. nx_gate_verdict
4// now self-records one actlog-grammar frame per verdict (fail-soft); this mines that history for the
5// two signals a pass/fail count cannot give:
6// FLAKE = the same gate has produced BOTH outcomes (non-determinism -- the gate cannot be trusted)
7// EROSION = a gate that was GREEN later went RED (a BANKED WIN LOST -- the ratchet law's RED). A gate
8// that went RED then GREEN is a FIX, explicitly NOT erosion; the distinction is the point.
9// Order matters, so frames are walked in journal order per gate. now INJECTABLE for deterministic tests.
10// Composes nx_sovjson_lib (sj_*). Read-only. No hw writes (Rule 26).
11// mine <journal> [minruns] [now] -> JSON per-gate + totals (green_permil, flaky, eroded)
12// selftest <scratch-prefix> -> gate T1..T8
13// frame cols: ts TAB ws TAB gate TAB verb TAB outcome(GREEN|RED) TAB passed/total
14// license_tier: ORIGINAL
15import "nx_sovjson_lib.nx"
16import "nx_syscalls.nx"
17import "nx_gate_verdict.nx"
18const HM_MAGIC_1785000000: i64 = 1785000000
19const HM_MAGIC_4088: i64 = 4088
20
21const HM_WIN: i64 = 4194304
22const HM_OUT: i64 = 65536
23const HM_PATH: i64 = 512
24const HM_GATES: i64 = 512
25const HM_TOPN: i64 = 30
26const HM_PERMIL: i64 = 1000
27const HM_DAY: i64 = 86400
28const HM_NAME_MAX: i64 = 120
29const HM_MODE_644: i64 = 420
30
31func hm_read(path: *u8, buf: *u8, cap: i64) -> i64 {
32 let fd: i64 = sys_openat_rd(path)
33 if fd < 0 { return -1 }
34 var n: i64 = 0
35 var go: i64 = 1
36 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 } }
37 sys_close(fd)
38 return n
39}
40func hm_find(q: *u8, n: i64, lit: *u8) -> i64 {
41 let ll: i64 = sj_vlen(lit)
42 if ll == 0 { return 0 }
43 var i: i64 = 0
44 while i + ll <= n {
45 var k: i64 = 0
46 var ok: i64 = 1
47 while k < ll { if q[i+k] != lit[k] { ok = 0; k = ll } else { k = k + 1 } }
48 if ok == 1 { return 1 }
49 i = i + 1
50 }
51 return 0
52}
53func hm_key(d: *u8, o: i64, name: *u8) -> i64 {
54 d[o] = 34 as u8
55 var p: i64 = o + 1
56 p = sj_cat(d, p, name)
57 d[p] = 34 as u8
58 p = p + 1
59 d[p] = 58 as u8
60 p = p + 1
61 return p
62}
63func hm_digits(q: *u8, s: i64, e: i64) -> i64 {
64 if e <= s { return 0 }
65 var i: i64 = s
66 while i < e { let c: i64 = q[i] as i64; if c < 48 { return 0 } if c > 57 { return 0 } i = i + 1 }
67 return 1
68}
69func hm_mine_json(jpath: *u8, minruns: i64, now: i64, d: *u8) -> i64 {
70 let q: *u8 = sys_mmap(HM_WIN)
71 let n: i64 = hm_read(jpath, q, HM_WIN - 8)
72 if n <= 0 { return -1 }
73 var trunc: i64 = 0
74 if n >= HM_WIN - 8 { trunc = 1 }
75 let gs: *i64 = sys_mmap(8 * HM_GATES) as *i64
76 let ge: *i64 = sys_mmap(8 * HM_GATES) as *i64
77 let runs: *i64 = sys_mmap(8 * HM_GATES) as *i64
78 let green: *i64 = sys_mmap(8 * HM_GATES) as *i64
79 let red: *i64 = sys_mmap(8 * HM_GATES) as *i64
80 let eroded: *i64 = sys_mmap(8 * HM_GATES) as *i64
81 let lastg: *i64 = sys_mmap(8 * HM_GATES) as *i64
82 let lastts: *i64 = sys_mmap(8 * HM_GATES) as *i64
83 let done: *i64 = sys_mmap(8 * HM_GATES) as *i64
84 let sp: *i64 = sys_mmap(16) as *i64
85 var ng: i64 = 0
86 var gcapped: i64 = 0
87 var frames: i64 = 0
88 var malformed: i64 = 0
89 var i: i64 = 0
90 while i < n {
91 let le: i64 = sj_le(q, i, n)
92 var ok: i64 = 0
93 var cmt: i64 = 0
94 if le > i { if q[i] == (35 as u8) { cmt = 1 } }
95 if le > i { if cmt == 0 { if sj_col(q, i, le, 4, sp) == 1 { ok = 1 } } }
96 if ok == 0 { if le > i { if cmt == 0 { malformed = malformed + 1 } } } else {
97 var isgreen: i64 = 0
98 var isred: i64 = 0
99 if sj_lit_eq(q, sp[0], sp[1], "GREEN" as *u8) == 1 { isgreen = 1 }
100 if sj_lit_eq(q, sp[0], sp[1], "RED" as *u8) == 1 { isred = 1 }
101 if isgreen + isred == 0 { malformed = malformed + 1 } else {
102 frames = frames + 1
103 sj_col(q, i, le, 2, sp)
104 let cs: i64 = sp[0]
105 let ce: i64 = sp[1]
106 var idx: i64 = 0 - 1
107 var k: i64 = 0
108 while k < ng {
109 if ce - cs == ge[k] - gs[k] {
110 var m: i64 = 0
111 var eq: i64 = 1
112 while m < ce - cs { if q[cs+m] != q[gs[k]+m] { eq = 0; m = ce - cs } else { m = m + 1 } }
113 if eq == 1 { idx = k; k = ng }
114 }
115 k = k + 1
116 }
117 if idx < 0 {
118 if ng >= HM_GATES { gcapped = 1 } else {
119 gs[ng] = cs
120 ge[ng] = ce
121 lastg[ng] = 0 - 1
122 idx = ng
123 ng = ng + 1
124 }
125 }
126 if idx >= 0 {
127 runs[idx] = runs[idx] + 1
128 if isgreen == 1 { green[idx] = green[idx] + 1 } else { red[idx] = red[idx] + 1 }
129 // EROSION: previously GREEN, now RED. A RED->GREEN transition is a FIX, not erosion.
130 if isred == 1 { if lastg[idx] == 1 { eroded[idx] = 1 } }
131 if isgreen == 1 { lastg[idx] = 1 } else { lastg[idx] = 0 }
132 sj_col(q, i, le, 0, sp)
133 if hm_digits(q, sp[0], sp[1]) == 1 { lastts[idx] = sj_atoi_span(q, sp[0], sp[1]) }
134 }
135 }
136 }
137 i = le + 1
138 }
139 var tgreen: i64 = 0
140 var tred: i64 = 0
141 var flaky: i64 = 0
142 var nerod: i64 = 0
143 var k3: i64 = 0
144 while k3 < ng {
145 tgreen = tgreen + green[k3]
146 tred = tred + red[k3]
147 if green[k3] > 0 { if red[k3] > 0 { flaky = flaky + 1 } }
148 nerod = nerod + eroded[k3]
149 k3 = k3 + 1
150 }
151 var p: i64 = 0
152 d[p] = 123 as u8; p = p + 1
153 p = hm_key(d, p, "v" as *u8); p = sj_catn(d, p, 1); d[p] = 44 as u8; p = p + 1
154 p = hm_key(d, p, "tool" as *u8)
155 d[p] = 34 as u8; p = p + 1
156 p = sj_cat(d, p, "nx_harnessmine" as *u8)
157 d[p] = 34 as u8; p = p + 1
158 d[p] = 44 as u8; p = p + 1
159 p = hm_key(d, p, "averb" as *u8)
160 d[p] = 34 as u8; p = p + 1
161 p = sj_cat(d, p, "mine" as *u8)
162 d[p] = 34 as u8; p = p + 1
163 d[p] = 44 as u8; p = p + 1
164 p = hm_key(d, p, "journal" as *u8)
165 d[p] = 34 as u8; p = p + 1
166 p = sj_cat_esc(d, p, jpath, 0, sj_vlen(jpath), HM_NAME_MAX)
167 d[p] = 34 as u8; p = p + 1
168 d[p] = 44 as u8; p = p + 1
169 p = hm_key(d, p, "journal_bytes" as *u8); p = sj_catn(d, p, n); d[p] = 44 as u8; p = p + 1
170 p = hm_key(d, p, "truncated" as *u8); p = sj_catn(d, p, trunc); d[p] = 44 as u8; p = p + 1
171 p = hm_key(d, p, "minruns" as *u8); p = sj_catn(d, p, minruns); d[p] = 44 as u8; p = p + 1
172 p = hm_key(d, p, "frames" as *u8); p = sj_catn(d, p, frames); d[p] = 44 as u8; p = p + 1
173 p = hm_key(d, p, "malformed" as *u8); p = sj_catn(d, p, malformed); d[p] = 44 as u8; p = p + 1
174 p = hm_key(d, p, "gates" as *u8); p = sj_catn(d, p, ng); d[p] = 44 as u8; p = p + 1
175 p = hm_key(d, p, "flaky" as *u8); p = sj_catn(d, p, flaky); d[p] = 44 as u8; p = p + 1
176 p = hm_key(d, p, "eroded" as *u8); p = sj_catn(d, p, nerod); d[p] = 44 as u8; p = p + 1
177 var gperm: i64 = 0 - 1
178 if frames > 0 { gperm = tgreen * HM_PERMIL / frames }
179 p = hm_key(d, p, "green_permil" as *u8); p = sj_catn(d, p, gperm); d[p] = 44 as u8; p = p + 1
180 // per-gate, ranked by RED desc (the ones that need attention first)
181 p = hm_key(d, p, "by_gate" as *u8)
182 d[p] = 91 as u8; p = p + 1
183 var shown: i64 = 0
184 var below: i64 = 0
185 var efirst: i64 = 1
186 var pass: i64 = 0
187 while pass < ng {
188 var mi: i64 = 0 - 1
189 var mx: i64 = 0 - 1
190 var k4: i64 = 0
191 while k4 < ng {
192 if done[k4] == 0 { if red[k4] > mx { mx = red[k4]; mi = k4 } }
193 k4 = k4 + 1
194 }
195 if mi >= 0 {
196 done[mi] = 1
197 if runs[mi] < minruns { below = below + 1 } else {
198 if shown < HM_TOPN {
199 if efirst == 0 { d[p] = 44 as u8; p = p + 1 }
200 efirst = 0
201 d[p] = 123 as u8; p = p + 1
202 p = hm_key(d, p, "gate" as *u8)
203 d[p] = 34 as u8; p = p + 1
204 p = sj_cat_esc(d, p, q, gs[mi], ge[mi], HM_NAME_MAX)
205 d[p] = 34 as u8; p = p + 1
206 d[p] = 44 as u8; p = p + 1
207 p = hm_key(d, p, "runs" as *u8); p = sj_catn(d, p, runs[mi]); d[p] = 44 as u8; p = p + 1
208 p = hm_key(d, p, "green" as *u8); p = sj_catn(d, p, green[mi]); d[p] = 44 as u8; p = p + 1
209 p = hm_key(d, p, "red" as *u8); p = sj_catn(d, p, red[mi]); d[p] = 44 as u8; p = p + 1
210 var fl: i64 = 0
211 if green[mi] > 0 { if red[mi] > 0 { fl = 1 } }
212 p = hm_key(d, p, "flaky" as *u8); p = sj_catn(d, p, fl); d[p] = 44 as u8; p = p + 1
213 p = hm_key(d, p, "eroded" as *u8); p = sj_catn(d, p, eroded[mi]); d[p] = 44 as u8; p = p + 1
214 p = hm_key(d, p, "last" as *u8)
215 d[p] = 34 as u8; p = p + 1
216 if lastg[mi] == 1 { p = sj_cat(d, p, "GREEN" as *u8) } else { p = sj_cat(d, p, "RED" as *u8) }
217 d[p] = 34 as u8; p = p + 1
218 d[p] = 44 as u8; p = p + 1
219 var agd: i64 = 0 - 1
220 if lastts[mi] > 0 { agd = (now - lastts[mi]) / HM_DAY }
221 p = hm_key(d, p, "last_run_days" as *u8); p = sj_catn(d, p, agd)
222 d[p] = 125 as u8; p = p + 1
223 shown = shown + 1
224 }
225 }
226 }
227 pass = pass + 1
228 }
229 d[p] = 93 as u8; p = p + 1
230 d[p] = 44 as u8; p = p + 1
231 p = hm_key(d, p, "gates_shown" as *u8); p = sj_catn(d, p, shown); d[p] = 44 as u8; p = p + 1
232 p = hm_key(d, p, "gates_below_minruns" as *u8); p = sj_catn(d, p, below); d[p] = 44 as u8; p = p + 1
233 p = hm_key(d, p, "gates_capped" as *u8); p = sj_catn(d, p, gcapped)
234 d[p] = 125 as u8; p = p + 1
235 d[p] = 10 as u8; p = p + 1
236 return p
237}
238func hm_selftest(prefix: *u8) -> i64 {
239 let ctr: *i64 = gv_ctr()
240 gv_head("nx_harnessmine selftest -- flake vs EROSION teeth (order matters; a fix is not erosion)" as *u8)
241 let now: i64 = HM_MAGIC_1785000000
242 let fx: *u8 = sys_mmap(HM_PATH)
243 var o: i64 = sj_cat(fx, 0, prefix)
244 o = sj_catn(fx, o, sys_now_realtime_sec())
245 o = sj_cat(fx, o, ".hm" as *u8)
246 fx[o] = 0 as u8
247 let miss: *u8 = sys_mmap(HM_PATH)
248 o = sj_cat(miss, 0, fx)
249 o = sj_cat(miss, o, ".absent" as *u8)
250 miss[o] = 0 as u8
251 // GA: GREEN then RED = ERODED + flaky. GB: RED then GREEN = a FIX, flaky but NOT eroded.
252 // GC: GREEN x3 = stable. GD: 1 run only (below minruns 2). plus a malformed + a bogus outcome.
253 let fd: i64 = sys_openat_wr(fx, HM_MODE_644)
254 let lb: *u8 = sys_mmap(HM_MAGIC_4088)
255 var lo: i64 = sj_cat(lb, 0, "# fixture\n" as *u8)
256 lo = sj_cat(lb, lo, "1784900000\tharness\tGA-GATE\trun\tGREEN\t8/8\n" as *u8)
257 lo = sj_cat(lb, lo, "1784910000\tharness\tGB-GATE\trun\tRED\t5/8\n" as *u8)
258 lo = sj_cat(lb, lo, "1784920000\tharness\tGA-GATE\trun\tRED\t7/8\n" as *u8)
259 lo = sj_cat(lb, lo, "1784930000\tharness\tGB-GATE\trun\tGREEN\t8/8\n" as *u8)
260 lo = sj_cat(lb, lo, "1784940000\tharness\tGC-GATE\trun\tGREEN\t4/4\n" as *u8)
261 lo = sj_cat(lb, lo, "1784950000\tharness\tGC-GATE\trun\tGREEN\t4/4\n" as *u8)
262 lo = sj_cat(lb, lo, "1784960000\tharness\tGC-GATE\trun\tGREEN\t4/4\n" as *u8)
263 lo = sj_cat(lb, lo, "1784970000\tharness\tGD-GATE\trun\tGREEN\t2/2\n" as *u8)
264 lo = sj_cat(lb, lo, "1784980000\tharness\tGE-GATE\trun\tPURPLE\t1/1\n" as *u8)
265 lo = sj_cat(lb, lo, "nocolumns\n" as *u8)
266 sys_write(fd, lb, lo)
267 sys_close(fd)
268 let d: *u8 = sys_mmap(HM_OUT)
269 let r1: i64 = hm_mine_json(miss, 1, now, d)
270 var ok1: i64 = 0
271 if r1 < 0 { ok1 = 1 }
272 gv_check("T1 missing journal refused fail closed" as *u8, ok1, ctr)
273 let dl: i64 = hm_mine_json(fx, 1, now, d)
274 var ok2: i64 = 0
275 if dl > 0 { if hm_find(d, dl, "\"frames\":8,\"malformed\":2,\"gates\":4" as *u8) == 1 { ok2 = 1 } }
276 gv_check("T2 exact frames 8, BOTH bad lines counted malformed, 4 gates" as *u8, ok2, ctr)
277 var ok3: i64 = 0
278 if hm_find(d, dl, "\"gate\":\"GA-GATE\",\"runs\":2,\"green\":1,\"red\":1,\"flaky\":1,\"eroded\":1,\"last\":\"RED\"" as *u8) == 1 { ok3 = 1 }
279 gv_check("T3 GREEN then RED = ERODED (a banked win lost)" as *u8, ok3, ctr)
280 var ok4: i64 = 0
281 if hm_find(d, dl, "\"gate\":\"GB-GATE\",\"runs\":2,\"green\":1,\"red\":1,\"flaky\":1,\"eroded\":0,\"last\":\"GREEN\"" as *u8) == 1 { ok4 = 1 }
282 gv_check("T4 RED then GREEN is a FIX: flaky yes, eroded NO (order respected)" as *u8, ok4, ctr)
283 var ok5: i64 = 0
284 if hm_find(d, dl, "\"gate\":\"GC-GATE\",\"runs\":3,\"green\":3,\"red\":0,\"flaky\":0,\"eroded\":0" as *u8) == 1 { ok5 = 1 }
285 gv_check("T5 stable gate is neither flaky nor eroded" as *u8, ok5, ctr)
286 var ok6: i64 = 0
287 if hm_find(d, dl, "\"flaky\":2,\"eroded\":1" as *u8) == 1 { if hm_find(d, dl, "\"green_permil\":750" as *u8) == 1 { ok6 = 1 } }
288 gv_check("T6 totals exact: 2 flaky, only 1 eroded, green_permil 750" as *u8, ok6, ctr)
289 var ok7: i64 = 0
290 if hm_find(d, dl, "\"last_run_days\":0" as *u8) == 1 { if hm_find(d, dl, "\"gate\":\"GE-GATE\"" as *u8) == 0 { ok7 = 1 } }
291 gv_check("T7 unknown outcome PURPLE never becomes a gate; recency derived" as *u8, ok7, ctr)
292 let dl8: i64 = hm_mine_json(fx, 2, now, d)
293 var ok8: i64 = 0
294 if dl8 > 0 { if hm_find(d, dl8, "\"gate\":\"GD-GATE\"" as *u8) == 0 { if hm_find(d, dl8, "\"gates_below_minruns\":1" as *u8) == 1 { ok8 = 1 } } }
295 gv_check("T8 minruns 2 suppresses the single-run gate and DECLARES it" as *u8, ok8, ctr)
296 let rc: i64 = gv_verdict("HARNESSMINE-GATE" as *u8, ctr, "harness mining: flake vs erosion distinguished by ORDER, malformed counted, suppression declared" as *u8)
297 return rc
298}
299
300func main(argc: i64, argv: *i64) -> i64 {
301 if argc < 3 { sj_puts("usage: nx_harnessmine {mine <journal> [minruns] [now] | selftest <scratch-prefix>}\n" as *u8); sys_exit(2); return 2 }
302 let verb: *u8 = argv[1] as *u8
303 let vl: i64 = sj_vlen(verb)
304 if sj_lit_eq(verb, 0, vl, "selftest" as *u8) == 1 {
305 let rc: i64 = hm_selftest(argv[2] as *u8)
306 sys_exit(rc)
307 return rc
308 }
309 if sj_lit_eq(verb, 0, vl, "mine" as *u8) == 1 {
310 var minruns: i64 = 1
311 if argc >= 4 { let mz: i64 = sj_atoi_z(argv[3] as *u8); if mz > 0 { minruns = mz } }
312 var now: i64 = sys_now_realtime_sec()
313 if argc >= 5 { let nz: i64 = sj_atoi_z(argv[4] as *u8); if nz > 0 { now = nz } }
314 let d: *u8 = sys_mmap(HM_OUT)
315 let dl: i64 = hm_mine_json(argv[2] as *u8, minruns, now, d)
316 if dl < 0 { sj_puts("REFUSED journal missing or empty (no gate has recorded an outcome yet)\n" as *u8); sys_exit(3); return 3 }
317 sys_write(1, d, dl)
318 sys_exit(0)
319 return 0
320 }
321 sj_puts("unknown verb\n" as *u8)
322 sys_exit(2)
323 return 2
324}