code wiki / _hdl_build / nx_train_triage.nx

nx_train_triage.nx source

↩ module page · 181 lines · 7831 B

1// nx_train_triage.nx -- TRAINING-DYNAMICS TRIAGE library (the team organ that handles what 2// Claude diagnosed BY HAND during T4, 2026-06-10). Reads a machine-readable training report 3// (TRIAGE-CLASS/TRIAGE-PRED/TRIAGE-ACC/TRIAGE-LOSS rows, emitted by training lanes like 4// _t4b_closed_loop_authored) and NAMES the failure mode + the gate-proven fix, mechanically. 5// The five lessons it encodes were each MEASURED on real failed gate runs: 6// MAJORITY-COLLAPSE per-sample Adam on 88:2 imbalance -> all preds one class (88/149) 7// POST-CONVERGENCE-BLOWUP constant-lr Adam after convergence: grads->0 => v->0 => mh/eps spike 8// RARE-CLASS-LOSS unweighted loss loses exactly the smallest classes (util+mon) 9// PLATEAU uncentered all-positive features froze relu nets across 3 optimizers 10// CONVERGED-HEALTHY what T4/T4b look like when the lessons are applied 11// Pure integer math on micro-loss values -- no f32 needed to judge a curve. 12// RACI: Doctor owns the DIAGNOSIS verb here (names the heal); the Engineer owns the gate. 13// LAWS: struct-free, flat ifs, no &&/||, loud verdicts. license_tier: ORIGINAL 14import "nx_syscalls.nx" 15const TT_MAGIC_8192: i64 = 8192 16 17const TT_HEALTHY: i64 = 0 18const TT_COLLAPSE: i64 = 1 19const TT_BLOWUP: i64 = 2 20const TT_RARE: i64 = 3 21const TT_PLATEAU: i64 = 4 22const TT_UNDIAG: i64 = 5 23const TT_BROKEN: i64 = 6 24const TT_MAXCLS: i64 = 16 25const TT_MAXLOSS: i64 = 512 26 27func tt_w(fd: i64, s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(fd,s,n); return 0 } 28func tt_wn(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 } 29 30func tt_match(b: *u8, i: i64, n: i64, lit: *u8) -> i64 { 31 var k: i64 = 0 32 while lit[k] != (0 as u8) { 33 if i + k >= n { return 0 } 34 if b[i+k] != lit[k] { return 0 } 35 k = k + 1 36 } 37 return 1 38} 39func tt_keynum(b: *u8, ls: i64, le: i64, key: *u8) -> i64 { 40 var i: i64 = ls 41 while i < le { 42 if tt_match(b, i, le, key) == 1 { 43 var k: i64 = 0 44 while key[k] != (0 as u8) { k = k + 1 } 45 var j: i64 = i + k 46 var v: i64 = 0 47 var got: i64 = 0 48 while j < le { 49 let c: i64 = b[j] as i64 50 if c < 48 { j = le } else { if c > 57 { j = le } else { v = v*10 + (c - 48); got = 1; j = j + 1 } } 51 } 52 if got == 1 { return v } 53 } 54 i = i + 1 55 } 56 return 0 - 1 57} 58 59// parse a report. out layout: classes[0..15], preds[16..31], [32]=right [33]=total [34]=got_acc 60// [35]=ncls [36]=nloss, losses at [40..] (micro values only, epoch order) 61func tt_read(path: *u8, out: *i64) -> i64 { 62 var z: i64 = 0 63 while z < 40 + TT_MAXLOSS { out[z] = 0; z = z + 1 } 64 out[32] = 0 - 1 65 out[33] = 0 - 1 66 let lenp: *i64 = sys_mmap(16) as *i64 67 let b: *u8 = sys_read_file(path, lenp) 68 let n: i64 = lenp[0] 69 if n <= 0 { return 0 } 70 var ls: i64 = 0 71 while ls < n { 72 var le: i64 = ls 73 var stop: i64 = 0 74 while stop == 0 { 75 if le >= n { stop = 1 } else { if b[le] == (10 as u8) { stop = 1 } else { le = le + 1 } } 76 } 77 if tt_match(b, ls, le, "TRIAGE-CLASS " as *u8) == 1 { 78 let id: i64 = tt_keynum(b, ls, le, "id=" as *u8) 79 let c: i64 = tt_keynum(b, ls, le, "count=" as *u8) 80 if id >= 0 { if id < TT_MAXCLS { if c >= 0 { 81 out[id] = c 82 if id + 1 > out[35] { out[35] = id + 1 } 83 } } } 84 } 85 if tt_match(b, ls, le, "TRIAGE-PRED " as *u8) == 1 { 86 let id2: i64 = tt_keynum(b, ls, le, "id=" as *u8) 87 let c2: i64 = tt_keynum(b, ls, le, "count=" as *u8) 88 if id2 >= 0 { if id2 < TT_MAXCLS { if c2 >= 0 { out[16 + id2] = c2 } } } 89 } 90 if tt_match(b, ls, le, "TRIAGE-ACC " as *u8) == 1 { 91 out[32] = tt_keynum(b, ls, le, "right=" as *u8) 92 out[33] = tt_keynum(b, ls, le, "total=" as *u8) 93 out[34] = 1 94 } 95 if tt_match(b, ls, le, "TRIAGE-LOSS " as *u8) == 1 { 96 let mv: i64 = tt_keynum(b, ls, le, "micro=" as *u8) 97 if mv >= 0 { if out[36] < TT_MAXLOSS { 98 out[40 + out[36]] = mv 99 out[36] = out[36] + 1 100 } } 101 } 102 ls = le + 1 103 } 104 return 1 105} 106 107// the diagnosis: priority order matters (collapse > blowup > rare-class > plateau > healthy) 108func tt_diagnose(path: *u8) -> i64 { 109 let out: *i64 = sys_mmap(TT_MAGIC_8192) as *i64 110 let ok: i64 = tt_read(path, out) 111 if ok == 0 { return TT_BROKEN } 112 let ncls: i64 = out[35] 113 let nloss: i64 = out[36] 114 let right: i64 = out[32] 115 let total: i64 = out[33] 116 if out[34] == 0 { return TT_BROKEN } 117 if ncls == 0 { return TT_BROKEN } 118 if nloss == 0 { return TT_BROKEN } 119 if total <= 0 { return TT_BROKEN } 120 let first: i64 = out[40] 121 let final: i64 = out[40 + nloss - 1] 122 var minv: i64 = first 123 var li: i64 = 1 124 while li < nloss { if out[40 + li] < minv { minv = out[40 + li] } li = li + 1 } 125 // 1: MAJORITY-COLLAPSE -- every prediction is one class and acc == that class's true count 126 var c: i64 = 0 127 while c < ncls { 128 if out[16 + c] == total { if right == out[c] { if ncls > 1 { return TT_COLLAPSE } } } 129 c = c + 1 130 } 131 // 2: POST-CONVERGENCE-BLOWUP -- loss converged (min << first) then rose >= 10x above the min 132 if final > minv * 10 { if minv < first { if final >= 50 { return TT_BLOWUP } } } 133 // 3: RARE-CLASS-LOSS -- misses exist and EVERY under-predicted class is a small class 134 if right < total { 135 var maxcls: i64 = 0 136 c = 0 137 while c < ncls { if out[c] > maxcls { maxcls = out[c] } c = c + 1 } 138 var under: i64 = 0 139 var allsmall: i64 = 1 140 c = 0 141 while c < ncls { 142 if out[16 + c] < out[c] { 143 under = under + 1 144 if out[c] * 4 > maxcls { allsmall = 0 } 145 } 146 c = c + 1 147 } 148 if under > 0 { if allsmall == 1 { return TT_RARE } } 149 } 150 // 4: PLATEAU -- misses exist and the last quarter of the curve improved < 5% 151 if right < total { 152 if nloss >= 4 { 153 let a: i64 = out[40 + (nloss * 3) / 4] 154 if a > 0 { 155 if (a - final) * 20 < a { return TT_PLATEAU } 156 } 157 } 158 } 159 // 0: CONVERGED-HEALTHY -- 100% and the final loss sits at the curve minimum 160 if right == total { if final <= minv * 2 { return TT_HEALTHY } } 161 return TT_UNDIAG 162} 163 164func tt_name(id: i64) -> *u8 { 165 if id == 0 { return "CONVERGED-HEALTHY" as *u8 } 166 if id == 1 { return "MAJORITY-COLLAPSE" as *u8 } 167 if id == 2 { return "POST-CONVERGENCE-BLOWUP" as *u8 } 168 if id == 3 { return "RARE-CLASS-LOSS" as *u8 } 169 if id == 4 { return "PLATEAU" as *u8 } 170 if id == 6 { return "BROKEN-REPORT" as *u8 } 171 return "UNDIAGNOSED" as *u8 172} 173func tt_fix(id: i64) -> *u8 { 174 if id == 0 { return "NONE" as *u8 } 175 if id == 1 { return "FULL-BATCH-GRAD-ACCUMULATION (per-sample updates collapse to the majority on imbalanced streams)" as *u8 } 176 if id == 2 { return "EARLY-STOP-AT-CONVERGENCE (grads->0 => v->0 => mh/eps spike jumps basins)" as *u8 } 177 if id == 3 { return "INVERSE-FREQ-CLASS-WEIGHTS (rare-class gradients vanish in unweighted sums)" as *u8 } 178 if id == 4 { return "CENTER-FEATURES then capacity then optimizer (all-positive features kill relu nets)" as *u8 } 179 if id == 6 { return "report is missing CLASS/ACC/LOSS rows -- fix the emitting lane" as *u8 } 180 return "new failure shape: name it, add its KAT to the triage gate" as *u8 181}