code wiki / _hdl_build / _t4b_closed_loop_authored.nx
_t4b_closed_loop_authored.nx source
↩ module page · 465 lines · 20156 B
1// _t4b_closed_loop_authored.nx -- T4b: the CLOSED-LOOP FIRST TURN. The first model trained
2// EXCLUSIVELY on team-generated, gate-verified data: the synthesis corpus
3// (knowledge/library/synth_corpus.log SYNTH rows). Task: expr -> spec (which spec does this
4// team-synthesized expression solve), an exact 7-class mapping (verified conflict-free).
5// Uses the NEW verified-gradient CE loss (tg_celoss op 6, gradcheck-gated) -- the one-hot-MSE
6// workaround is retired on its first outing. The T4 lesson set is APPLIED, not rediscovered:
7// centered features, inverse-frequency class weights, full-batch accumulation + gated AdamW,
8// deterministic early stop. Emits a machine-readable training report
9// (knowledge/status/train_report_t4b.log TRIAGE-* rows) for the nx_train_triage organ.
10// GATES: P parse+dict+consistency (identical features MUST agree on the label -- the
11// under-determined-data check) | Q trained to 100% (per-class pred counts == data counts,
12// loss decreased) | R BIT-EXACT two-run. Tamper hook: argv[1] corpus path override.
13// LAWS: struct-free, flat ifs, no &&/||, no unary-minus literals. license_tier: ORIGINAL
14import "nx_tgrad_core.nx"
15
16const B4_EPOCHS: i64 = 2000
17const B4_LOGEVERY: i64 = 100
18const B4_INB: i64 = 24
19const B4_HID: i64 = 16
20const B4_MAXCLS: i64 = 16
21const B4_MAXROWS: i64 = 256
22
23func b4_fp(fd: i64, s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(fd,s,n); return 0 }
24func b4_fn(fd: i64, v: i64) -> i64 { let bb: *u8=sys_mmap(28); var m: i64=v; if m<0{m=0-m;sys_write(fd,"-" as *u8,1)}; let t: *u8=sys_mmap(28); var k: i64=0; if m==0{t[0]=48;k=1}; while m>0{t[k]=48+(m%10);m=m/10;k=k+1}; var i: i64=0; while i<k{bb[i]=t[k-1-i];i=i+1}; sys_write(fd,bb,k); return 0 }
25func b4_bp(fd: i64, s: *u8) -> i64 { _tg_puts(s); b4_fp(fd, s); return 0 }
26func b4_bn(fd: i64, v: i64) -> i64 { _tg_num(v); b4_fn(fd, v); return 0 }
27
28func b4_match(b: *u8, i: i64, n: i64, lit: *u8) -> i64 {
29 var k: i64 = 0
30 while lit[k] != (0 as u8) {
31 if i + k >= n { return 0 }
32 if b[i+k] != lit[k] { return 0 }
33 k = k + 1
34 }
35 return 1
36}
37func b4_nameq(a: *u8, b: *u8) -> i64 {
38 var i: i64 = 0
39 while a[i] != (0 as u8) {
40 if a[i] != b[i] { return 0 }
41 i = i + 1
42 }
43 if b[i] == (0 as u8) { return 1 }
44 return 0
45}
46
47// parse SYNTH rows: spec dict (names 16x24) + per-row label + per-row expr window (rows x 28).
48// returns row count; nspecp[0] = dict size
49func b4_parse(cpath: *u8, dict: *u8, nspecp: *i64, labels: *i64, exprs: *u8) -> i64 {
50 let lenp: *i64 = sys_mmap(16) as *i64
51 let b: *u8 = sys_read_file(cpath, lenp)
52 let n: i64 = lenp[0]
53 if n <= 0 { return 0 - 1 }
54 var cnt: i64 = 0
55 var ls: i64 = 0
56 while ls < n {
57 var le: i64 = ls
58 var stop: i64 = 0
59 while stop == 0 {
60 if le >= n { stop = 1 } else { if b[le] == (10 as u8) { stop = 1 } else { le = le + 1 } }
61 }
62 if b4_match(b, ls, le, "SYNTH " as *u8) == 1 {
63 // spec= token
64 let tmp: *u8 = sys_mmap(32)
65 var got_spec: i64 = 0
66 var j: i64 = ls
67 while j < le {
68 if b4_match(b, j, le, "spec=" as *u8) == 1 {
69 var p: i64 = j + 5
70 var k: i64 = 0
71 var stop2: i64 = 0
72 while stop2 == 0 {
73 if p >= le { stop2 = 1 } else { if b[p] == (32 as u8) { stop2 = 1 } else {
74 if k < 23 { tmp[k] = b[p]; k = k + 1 }
75 p = p + 1
76 } }
77 }
78 tmp[k] = 0 as u8
79 if k > 0 { got_spec = 1 }
80 j = le
81 } else { j = j + 1 }
82 }
83 // expression field = expr= (search engines) OR step= (loop-synth fold rows), to EOL
84 var got_expr: i64 = 0
85 var ei: i64 = 0 - 1
86 j = ls
87 while j < le {
88 if b4_match(b, j, le, "expr=" as *u8) == 1 { ei = j + 5; got_expr = 1; j = le } else { j = j + 1 }
89 }
90 if got_expr == 0 {
91 j = ls
92 while j < le {
93 if b4_match(b, j, le, "step=" as *u8) == 1 { ei = j + 5; got_expr = 1; j = le } else { j = j + 1 }
94 }
95 }
96 if got_spec == 1 { if got_expr == 1 { if cnt < B4_MAXROWS {
97 // dict lookup/insert
98 var id: i64 = 0 - 1
99 var d: i64 = 0
100 while d < nspecp[0] {
101 let dp: *u8 = (dict as i64 + d*24) as *u8
102 if b4_nameq(tmp, dp) == 1 { id = d; d = nspecp[0] } else { d = d + 1 }
103 }
104 if id < 0 {
105 if nspecp[0] < B4_MAXCLS {
106 let dst: *u8 = (dict as i64 + nspecp[0]*24) as *u8
107 var k2: i64 = 0
108 var stop3: i64 = 0
109 while stop3 == 0 {
110 dst[k2] = tmp[k2]
111 if tmp[k2] == (0 as u8) { stop3 = 1 } else { k2 = k2 + 1 }
112 }
113 id = nspecp[0]
114 nspecp[0] = nspecp[0] + 1
115 }
116 }
117 if id >= 0 {
118 labels[cnt] = id
119 let xp: *u8 = (exprs as i64 + cnt*28) as *u8
120 var k3: i64 = 0
121 while k3 < B4_INB {
122 var bv: i64 = 0
123 if ei + k3 < le { bv = b[ei+k3] as i64 }
124 xp[k3] = bv
125 k3 = k3 + 1
126 }
127 xp[B4_INB] = 0 as u8
128 cnt = cnt + 1
129 }
130 } } }
131 }
132 ls = le + 1
133 }
134 return cnt
135}
136
137// plain forward, returns argmax over nspec logits
138func b4_fwd(w: *i64, x: *i64, nspec: i64, outv: *i64) -> i64 {
139 let b1o: i64 = B4_HID * B4_INB
140 let w2o: i64 = b1o + B4_HID
141 let b2o: i64 = w2o + nspec * B4_HID
142 let h: *i64 = sys_mmap(256) as *i64
143 var i: i64 = 0
144 while i < B4_HID {
145 var s: i64 = w[b1o + i]
146 var j: i64 = 0
147 while j < B4_INB { s = nx_f32_add(s, nx_f32_mul(w[i*B4_INB + j], x[j])); j = j + 1 }
148 if nx_f32_lt(s, 0) == 1 { s = 0 }
149 h[i] = s
150 i = i + 1
151 }
152 var c: i64 = 0
153 var best: i64 = 0
154 while c < nspec {
155 var o: i64 = w[b2o + c]
156 i = 0
157 while i < B4_HID { o = nx_f32_add(o, nx_f32_mul(w[w2o + c*B4_HID + i], h[i])); i = i + 1 }
158 outv[c] = o
159 if c > 0 { if nx_f32_gt(o, outv[best]) == 1 { best = c } }
160 c = c + 1
161 }
162 return best
163}
164
165func t4b_zero(w: *i64, b1o: i64, w2o: i64) -> i64 {
166 var z: i64 = b1o
167 while z < w2o { w[z] = 0; z = z + 1 }
168 return 0
169}
170// deterministic symmetry-breaking init (the gate-proven T4 pattern)
171func t4_initb(p: *i64, n: i64, salt: i64, den: i64) -> i64 {
172 var i: i64 = 0
173 while i < n {
174 let m: i64 = ((salt + i*7) % 13) - 6
175 if m < 0 { p[i] = nx_f32_neg(tg_q(0 - m, den)) } else { p[i] = tg_q(m, den) }
176 i = i + 1
177 }
178 return 0
179}
180
181// CE training: full-batch accumulation + gated ad_step, early stop; curve sampled into
182// curve buf (pairs ep,micro), curven[0] = entries, curven[1] = converged ep (or -1)
183func b4_train(tape: *i64, nb: *i64, arena: *i64, ab: *i64, xs: *i64, ts: *i64, wts: *i64, cnt: i64, nspec: i64, w: *i64, curve: *i64, curven: *i64, out2: *i64) -> i64 {
184 let w1n: i64 = B4_HID * B4_INB
185 let b1o: i64 = w1n
186 let w2o: i64 = b1o + B4_HID
187 let w2n: i64 = nspec * B4_HID
188 let b2o: i64 = w2o + w2n
189 t4b_zero(w, b1o, w2o)
190 t4_initb(w, w1n, 5, 16)
191 t4_initb((w as i64 + w2o*8) as *i64, w2n, 6, 16)
192 var z: i64 = b2o
193 while z < b2o + nspec { w[z] = 0; z = z + 1 }
194 let lr: i64 = tg_q(1, 20)
195 let b1c: i64 = tg_q(9, 10)
196 let b2c: i64 = tg_q(999, 1000)
197 let eps: i64 = tg_q(1, 100000)
198 let mw1: *i64 = sys_mmap(8192) as *i64
199 let vw1: *i64 = sys_mmap(8192) as *i64
200 let mb1: *i64 = sys_mmap(1024) as *i64
201 let vb1: *i64 = sys_mmap(1024) as *i64
202 let mw2: *i64 = sys_mmap(8192) as *i64
203 let vw2: *i64 = sys_mmap(8192) as *i64
204 let mb2: *i64 = sys_mmap(1024) as *i64
205 let vb2: *i64 = sys_mmap(1024) as *i64
206 let gaw1: *i64 = sys_mmap(8192) as *i64
207 let gab1: *i64 = sys_mmap(1024) as *i64
208 let gaw2: *i64 = sys_mmap(8192) as *i64
209 let gab2: *i64 = sys_mmap(1024) as *i64
210 let invn: i64 = nx_f32_div(nx_i32_to_f32(1), nx_i32_to_f32(cnt))
211 curven[0] = 0
212 curven[1] = 0 - 1
213 var ep: i64 = 0
214 while ep < B4_EPOCHS {
215 var epsum: i64 = 0
216 var z2: i64 = 0
217 while z2 < w1n { gaw1[z2] = 0; z2 = z2 + 1 }
218 z2 = 0
219 while z2 < B4_HID { gab1[z2] = 0; z2 = z2 + 1 }
220 z2 = 0
221 while z2 < w2n { gaw2[z2] = 0; z2 = z2 + 1 }
222 z2 = 0
223 while z2 < nspec { gab2[z2] = 0; z2 = z2 + 1 }
224 var s: i64 = 0
225 while s < cnt {
226 nb[0] = 0
227 ab[0] = 0
228 let lw1: i64 = tg_leaf(tape, nb, arena, ab, w, B4_HID, B4_INB)
229 let lb1: i64 = tg_leaf(tape, nb, arena, ab, (w as i64 + b1o*8) as *i64, B4_HID, 1)
230 let lw2: i64 = tg_leaf(tape, nb, arena, ab, (w as i64 + w2o*8) as *i64, nspec, B4_HID)
231 let lb2: i64 = tg_leaf(tape, nb, arena, ab, (w as i64 + b2o*8) as *i64, nspec, 1)
232 let lx: i64 = tg_leaf(tape, nb, arena, ab, (xs as i64 + s*B4_INB*8) as *i64, B4_INB, 1)
233 let lt: i64 = tg_leaf(tape, nb, arena, ab, (ts as i64 + s*B4_MAXCLS*8) as *i64, nspec, 1)
234 let hh: i64 = tg_reluvec(tape, nb, arena, ab, tg_addvec(tape, nb, arena, ab, tg_matvec(tape, nb, arena, ab, lw1, lx), lb1))
235 let oo: i64 = tg_addvec(tape, nb, arena, ab, tg_matvec(tape, nb, arena, ab, lw2, hh), lb2)
236 let lwt: i64 = tg_leaf(tape, nb, arena, ab, (wts as i64 + s*8) as *i64, 1, 1)
237 let loss: i64 = tg_smul(tape, nb, arena, ab, tg_celoss(tape, nb, arena, ab, oo, lt), lwt)
238 tg_backward(tape, nb[0], loss)
239 let lv: *i64 = tg_valp(tape, loss)
240 epsum = nx_f32_add(epsum, lv[0])
241 let pg1: *i64 = tg_gradp(tape, lw1)
242 var q: i64 = 0
243 while q < w1n { gaw1[q] = nx_f32_add(gaw1[q], pg1[q]); q = q + 1 }
244 let pb1: *i64 = tg_gradp(tape, lb1)
245 q = 0
246 while q < B4_HID { gab1[q] = nx_f32_add(gab1[q], pb1[q]); q = q + 1 }
247 let pg2: *i64 = tg_gradp(tape, lw2)
248 q = 0
249 while q < w2n { gaw2[q] = nx_f32_add(gaw2[q], pg2[q]); q = q + 1 }
250 let pb2: *i64 = tg_gradp(tape, lb2)
251 q = 0
252 while q < nspec { gab2[q] = nx_f32_add(gab2[q], pb2[q]); q = q + 1 }
253 s = s + 1
254 }
255 ad_step(w, gaw1, mw1, vw1, w1n, lr, b1c, b2c, eps, 0, ep + 1)
256 ad_step((w as i64 + b1o*8) as *i64, gab1, mb1, vb1, B4_HID, lr, b1c, b2c, eps, 0, ep + 1)
257 ad_step((w as i64 + w2o*8) as *i64, gaw2, mw2, vw2, w2n, lr, b1c, b2c, eps, 0, ep + 1)
258 ad_step((w as i64 + b2o*8) as *i64, gab2, mb2, vb2, nspec, lr, b1c, b2c, eps, 0, ep + 1)
259 let avg: i64 = nx_f32_mul(epsum, invn)
260 if ep == 0 { out2[0] = avg }
261 out2[1] = avg
262 let micro: i64 = tg_milli(nx_f32_mul(avg, nx_i32_to_f32(1000)))
263 if ep % B4_LOGEVERY == 0 {
264 if curven[0] < 120 {
265 curve[curven[0]*2+0] = ep
266 curve[curven[0]*2+1] = micro
267 curven[0] = curven[0] + 1
268 }
269 }
270 // deterministic early stop at convergence (the T4 lesson: post-convergence constant-lr
271 // Adam blows up; stop epoch = pure function of the losses, preserves bit-exactness)
272 if nx_f32_lt(avg, tg_q(1, 100000)) == 1 {
273 if curven[0] < 120 {
274 curve[curven[0]*2+0] = ep
275 curve[curven[0]*2+1] = micro
276 curven[0] = curven[0] + 1
277 }
278 curven[1] = ep
279 ep = B4_EPOCHS
280 } else { ep = ep + 1 }
281 }
282 return 0
283}
284
285func main(argc: i64, argv: *i64) -> i64 {
286 _tg_puts("=== T4b CLOSED-LOOP FIRST TURN (model trained ONLY on team-synthesized gate-verified data; CE loss) ===\n" as *u8)
287 var cpath: *u8 = "knowledge/library/synth_corpus.log" as *u8
288 if argc >= 2 { cpath = argv[1] as *u8 }
289 let lfd: i64 = sys_openat_append("knowledge/status/modelwright.log" as *u8, 0x1a4)
290 if lfd < 0 { _tg_puts(" modelwright log open FAILED\n" as *u8); sys_exit(1); return 1 }
291 b4_fp(lfd, "MODELWRIGHT T4B RUN epoch_unix=" as *u8); b4_fn(lfd, sys_now_realtime_sec()); b4_fp(lfd, "\n" as *u8)
292
293 let tape: *i64 = sys_mmap(32768) as *i64
294 let nb: *i64 = sys_mmap(16) as *i64
295 let arena: *i64 = sys_mmap(131072) as *i64
296 let ab: *i64 = sys_mmap(16) as *i64
297
298 // ---- GATE P: parse + dict + consistency ----
299 let dict: *u8 = sys_mmap(1024)
300 let nspecp: *i64 = sys_mmap(16) as *i64
301 let labels: *i64 = sys_mmap(4096) as *i64
302 let exprs: *u8 = sys_mmap(16384)
303 let cnt: i64 = b4_parse(cpath, dict, nspecp, labels, exprs)
304 let nspec: i64 = nspecp[0]
305 var pp: i64 = 1
306 if cnt < 20 { pp = 0 }
307 if nspec < 5 { pp = 0 }
308 if nspec > B4_MAXCLS { pp = 0 }
309 // consistency: identical feature windows MUST agree on the label (under-determined-data check)
310 var ii: i64 = 0
311 while ii < cnt {
312 var jj: i64 = ii + 1
313 while jj < cnt {
314 let xa: *u8 = (exprs as i64 + ii*28) as *u8
315 let xb: *u8 = (exprs as i64 + jj*28) as *u8
316 var same: i64 = 1
317 var k: i64 = 0
318 while k < B4_INB { if xa[k] != xb[k] { same = 0 } k = k + 1 }
319 if same == 1 { if labels[ii] != labels[jj] {
320 pp = 0
321 _tg_puts(" CONSISTENCY FAIL rows " as *u8); _tg_num(ii); _tg_puts(" vs " as *u8); _tg_num(jj); _tg_puts("\n" as *u8)
322 } }
323 jj = jj + 1
324 }
325 ii = ii + 1
326 }
327 let hist: *i64 = sys_mmap(256) as *i64
328 var s2: i64 = 0
329 while s2 < cnt { hist[labels[s2]] = hist[labels[s2]] + 1; s2 = s2 + 1 }
330 b4_bp(lfd, "MODELWRIGHT T4B DATA rows=" as *u8); b4_bn(lfd, cnt)
331 b4_bp(lfd, " specs=" as *u8); b4_bn(lfd, nspec)
332 var c2: i64 = 0
333 while c2 < nspec {
334 b4_bp(lfd, " " as *u8); b4_bp(lfd, (dict as i64 + c2*24) as *u8)
335 b4_bp(lfd, "=" as *u8); b4_bn(lfd, hist[c2])
336 c2 = c2 + 1
337 }
338 b4_bp(lfd, "\n" as *u8)
339 if pp == 1 { _tg_puts(" GATE P corpus parse + spec dict + consistency: PASS\n" as *u8) } else { _tg_puts(" GATE P: FAIL\n" as *u8) }
340
341 // ---- features (centered bytes, the T4 lesson) + one-hot + inverse-frequency weights ----
342 let xs: *i64 = sys_mmap(65536) as *i64
343 let ts: *i64 = sys_mmap(65536) as *i64
344 s2 = 0
345 while s2 < cnt {
346 let xp: *u8 = (exprs as i64 + s2*28) as *u8
347 var j: i64 = 0
348 while j < B4_INB {
349 let bv: i64 = xp[j] as i64
350 let m: i64 = bv - 84
351 if m < 0 { xs[s2*B4_INB + j] = nx_f32_neg(tg_q(0 - m, 32)) } else { xs[s2*B4_INB + j] = tg_q(m, 32) }
352 j = j + 1
353 }
354 var c3: i64 = 0
355 while c3 < B4_MAXCLS {
356 if c3 == labels[s2] { ts[s2*B4_MAXCLS + c3] = nx_i32_to_f32(1) } else { ts[s2*B4_MAXCLS + c3] = 0 }
357 c3 = c3 + 1
358 }
359 s2 = s2 + 1
360 }
361 let wts: *i64 = sys_mmap(4096) as *i64
362 s2 = 0
363 while s2 < cnt { wts[s2] = nx_f32_div(nx_f32_div(nx_i32_to_f32(1), nx_i32_to_f32(nspec)), nx_i32_to_f32(hist[labels[s2]])); s2 = s2 + 1 }
364
365 // ---- GATE Q: train to 100% with CE ----
366 let w1: *i64 = sys_mmap(8192) as *i64
367 let curve: *i64 = sys_mmap(4096) as *i64
368 let curven: *i64 = sys_mmap(32) as *i64
369 let o1: *i64 = sys_mmap(64) as *i64
370 b4_train(tape, nb, arena, ab, xs, ts, wts, cnt, nspec, w1, curve, curven, o1)
371 var ci: i64 = 0
372 while ci < curven[0] {
373 b4_bp(lfd, "MODELWRIGHT T4B LOSSCURVE ep=" as *u8); b4_bn(lfd, curve[ci*2+0])
374 b4_bp(lfd, " loss_micro=" as *u8); b4_bn(lfd, curve[ci*2+1]); b4_bp(lfd, "\n" as *u8)
375 ci = ci + 1
376 }
377 if curven[1] >= 0 { b4_bp(lfd, "MODELWRIGHT T4B CONVERGED ep=" as *u8); b4_bn(lfd, curven[1]); b4_bp(lfd, "\n" as *u8) }
378 let outv: *i64 = sys_mmap(256) as *i64
379 let pcount: *i64 = sys_mmap(256) as *i64
380 var acc: i64 = 0
381 s2 = 0
382 while s2 < cnt {
383 let pred: i64 = b4_fwd(w1, (xs as i64 + s2*B4_INB*8) as *i64, nspec, outv)
384 pcount[pred] = pcount[pred] + 1
385 if pred == labels[s2] { acc = acc + 1 } else {
386 _tg_puts(" MISS row=" as *u8); _tg_num(s2)
387 _tg_puts(" label=" as *u8); _tg_num(labels[s2])
388 _tg_puts(" pred=" as *u8); _tg_num(pred); _tg_puts("\n" as *u8)
389 }
390 s2 = s2 + 1
391 }
392 var pq: i64 = 1
393 if acc != cnt { pq = 0 }
394 c2 = 0
395 while c2 < nspec {
396 if pcount[c2] != hist[c2] { pq = 0 }
397 c2 = c2 + 1
398 }
399 if nx_f32_lt(o1[1], o1[0]) == 0 { pq = 0 }
400 b4_bp(lfd, "MODELWRIGHT T4B ACC right=" as *u8); b4_bn(lfd, acc)
401 b4_bp(lfd, " total=" as *u8); b4_bn(lfd, cnt); b4_bp(lfd, "\n" as *u8)
402 if pq == 1 { _tg_puts(" GATE Q 100% on the synthesis corpus (per-class counts == data, CE loss decreased): PASS\n" as *u8) } else { _tg_puts(" GATE Q: FAIL\n" as *u8) }
403
404 // ---- GATE R: bit-exact two-run ----
405 let w2b: *i64 = sys_mmap(8192) as *i64
406 let curve2: *i64 = sys_mmap(4096) as *i64
407 let curven2: *i64 = sys_mmap(32) as *i64
408 let o2: *i64 = sys_mmap(64) as *i64
409 b4_train(tape, nb, arena, ab, xs, ts, wts, cnt, nspec, w2b, curve2, curven2, o2)
410 let tot: i64 = B4_HID*B4_INB + B4_HID + nspec*B4_HID + nspec
411 var pr: i64 = 1
412 var k4: i64 = 0
413 while k4 < tot { if w1[k4] != w2b[k4] { pr = 0 } k4 = k4 + 1 }
414 b4_bp(lfd, "MODELWRIGHT T4B BITEXACT cells=" as *u8); b4_bn(lfd, tot)
415 b4_bp(lfd, " identical=" as *u8); b4_bn(lfd, pr); b4_bp(lfd, "\n" as *u8)
416 if pr == 1 { _tg_puts(" GATE R bit-exact two-run CE training: PASS\n" as *u8) } else { _tg_puts(" GATE R: FAIL\n" as *u8) }
417
418 // ---- machine-readable training report for nx_train_triage ----
419 // tamper/override runs (argc>=2) must NEVER clobber the durable report -- the live
420 // triage row reads it (lesson: the first tamper run overwrote it and turned the gate red)
421 var rpath: *u8 = "knowledge/status/train_report_t4b.log" as *u8
422 if argc >= 2 { rpath = "/tmp/_t4b_report_override.log" as *u8 }
423 let rfd: i64 = sys_openat_wr(rpath, 0x1a4)
424 if rfd >= 0 {
425 c2 = 0
426 while c2 < nspec {
427 b4_fp(rfd, "TRIAGE-CLASS id=" as *u8); b4_fn(rfd, c2)
428 b4_fp(rfd, " count=" as *u8); b4_fn(rfd, hist[c2]); b4_fp(rfd, "\n" as *u8)
429 c2 = c2 + 1
430 }
431 c2 = 0
432 while c2 < nspec {
433 b4_fp(rfd, "TRIAGE-PRED id=" as *u8); b4_fn(rfd, c2)
434 b4_fp(rfd, " count=" as *u8); b4_fn(rfd, pcount[c2]); b4_fp(rfd, "\n" as *u8)
435 c2 = c2 + 1
436 }
437 b4_fp(rfd, "TRIAGE-ACC right=" as *u8); b4_fn(rfd, acc)
438 b4_fp(rfd, " total=" as *u8); b4_fn(rfd, cnt); b4_fp(rfd, "\n" as *u8)
439 ci = 0
440 while ci < curven[0] {
441 b4_fp(rfd, "TRIAGE-LOSS ep=" as *u8); b4_fn(rfd, curve[ci*2+0])
442 b4_fp(rfd, " micro=" as *u8); b4_fn(rfd, curve[ci*2+1]); b4_fp(rfd, "\n" as *u8)
443 ci = ci + 1
444 }
445 sys_close(rfd)
446 _tg_puts(" training report written: " as *u8); _tg_puts(rpath); _tg_puts("\n" as *u8)
447 }
448
449 var gates: i64 = 0
450 if pp == 1 { gates = gates + 1 }
451 if pq == 1 { gates = gates + 1 }
452 if pr == 1 { gates = gates + 1 }
453 b4_bp(lfd, "MODELWRIGHT T4B VERDICT gates=" as *u8); b4_bn(lfd, gates)
454 b4_bp(lfd, "/3" as *u8)
455 if gates == 3 { b4_bp(lfd, " pass=1\n" as *u8) } else { b4_bp(lfd, " pass=0\n" as *u8) }
456 sys_close(lfd)
457 if gates == 3 {
458 _tg_puts(" T4B CLOSED-LOOP GATE: PASS (first model trained exclusively on team-generated gate-verified data)\n" as *u8)
459 sys_exit(0)
460 return 0
461 }
462 _tg_puts(" T4B CLOSED-LOOP GATE: FAIL\n" as *u8)
463 sys_exit(1)
464 return 1
465}