code wiki / _hdl_build / nx_ledger_data.nx

nx_ledger_data.nx source

↩ module page · 317 lines · 12322 B

1// nx_ledger_data.nx -- LEDGER-AS-DATA (rung AN1): an Analyst case is a .led FILE, not code. 2// New question = new file, NO recompile (the vizsla archetype-matrix lesson). The file carries 3// SOURCE COLUMNS so the strict source-criticism re-grade is data too: every MEASURED leaf must 4// be backed by >=2 DISTINCT incentive classes or it is DEMOTED to DERIVED before the verdict. 5// Grammar (one record per line; '#'/blank = comment; integers only, space-separated): 6// T <tol_ppm> <min_traced_permil> <max_residual_permil> (exactly one) 7// C <class_a> <class_b> (opposed pair; 0..4 rows) 8// S <rel 1-6> <cred 1-6> <party 1-3> <method 1-5> <class> (source; idx = order) 9// N <parent> <value_cents> <kind 0/1/2> (node; idx = order; node 0 = root) 10// B <node> <src> (backing edge) 11// Any other line, bad field, bad grade, or bad reference fails LOUD (parse returns 0) -- a 12// ledger that cannot be read exactly is never half-answered. Composes nx_analyst (verdict math) 13// + nx_source_grade (grades, independence, confidence). LAWS: struct-free, integer-only, flat 14// ifs, <=6 args (st-table for the parse state). license_tier: ORIGINAL 15import "nx_analyst.nx" 16import "nx_source_grade.nx" 17import "nx_syscalls.nx" 18 19const LD_MAX_SRC: i64 = 64 20const LD_MAX_NODE: i64 = 64 21const LD_MAX_EDGE: i64 = 256 22const LD_MAX_OPP: i64 = 4 23 24// st-table slots (base addresses of parallel arrays, then counts + thresholds) 25const LD_REL: i64 = 0 // *i64[LD_MAX_SRC] 26const LD_CRED: i64 = 1 27const LD_PARTY: i64 = 2 28const LD_METHOD: i64 = 3 29const LD_CLASS: i64 = 4 30const LD_PARENT: i64 = 5 // *i64[LD_MAX_NODE] 31const LD_VALUE: i64 = 6 32const LD_KIND: i64 = 7 33const LD_BNODE: i64 = 8 // *i64[LD_MAX_EDGE] 34const LD_BSRC: i64 = 9 35const LD_OPPA: i64 = 10 // *i64[LD_MAX_OPP] 36const LD_OPPB: i64 = 11 37const LD_NS: i64 = 12 // counts 38const LD_NN: i64 = 13 39const LD_NB: i64 = 14 40const LD_NC: i64 = 15 41const LD_TOL: i64 = 16 // thresholds 42const LD_MINTP: i64 = 17 43const LD_MAXRP: i64 = 18 44const LD_NT: i64 = 19 // how many T rows seen (must end at exactly 1) 45 46func ld_alloc(st: *i64) -> i64 { 47 st[LD_REL] = sys_mmap(8*LD_MAX_SRC) as i64 48 st[LD_CRED] = sys_mmap(8*LD_MAX_SRC) as i64 49 st[LD_PARTY] = sys_mmap(8*LD_MAX_SRC) as i64 50 st[LD_METHOD] = sys_mmap(8*LD_MAX_SRC) as i64 51 st[LD_CLASS] = sys_mmap(8*LD_MAX_SRC) as i64 52 st[LD_PARENT] = sys_mmap(8*LD_MAX_NODE) as i64 53 st[LD_VALUE] = sys_mmap(8*LD_MAX_NODE) as i64 54 st[LD_KIND] = sys_mmap(8*LD_MAX_NODE) as i64 55 st[LD_BNODE] = sys_mmap(8*LD_MAX_EDGE) as i64 56 st[LD_BSRC] = sys_mmap(8*LD_MAX_EDGE) as i64 57 st[LD_OPPA] = sys_mmap(8*LD_MAX_OPP) as i64 58 st[LD_OPPB] = sys_mmap(8*LD_MAX_OPP) as i64 59 st[LD_NS]=0; st[LD_NN]=0; st[LD_NB]=0; st[LD_NC]=0; st[LD_NT]=0 60 st[LD_TOL]=0; st[LD_MINTP]=0; st[LD_MAXRP]=0 61 return 0 62} 63 64func ld_line_end(b: *u8, i: i64, n: i64) -> i64 { 65 var e: i64 = i 66 while e < n { if b[e] == (10 as u8) { return e } e = e + 1 } 67 return n 68} 69func ld_skip(b: *u8, i0: i64, e: i64) -> i64 { 70 var i: i64 = i0 71 while i < e { if b[i] != (32 as u8) { return i } i = i + 1 } 72 return e 73} 74 75// parse the decimal run at the first non-space >= j0; out[0]=value out[1]=index-after. 76// returns 1 ok, 0 = no digits (loud at the caller). Flat loop (4-deep-if landmine). 77func ld_int(b: *u8, j0: i64, e: i64, out: *i64) -> i64 { 78 var j: i64 = ld_skip(b, j0, e) 79 var v: i64 = 0 80 var got: i64 = 0 81 var go: i64 = 1 82 while go == 1 { 83 go = 0 84 var c: i64 = 0 - 1 85 if j < e { c = b[j] as i64 } 86 var isd: i64 = 0 87 if c >= 48 { if c <= 57 { isd = 1 } } 88 if isd == 1 { v = v * 10 + (c - 48); got = 1; j = j + 1; go = 1 } 89 } 90 out[0] = v 91 out[1] = j 92 return got 93} 94 95// parse k integers after position i into out[0..k); returns 1 ok / 0 loud 96func ld_ints(b: *u8, i0: i64, e: i64, k: i64, out: *i64) -> i64 { 97 let tmp: *i64 = sys_mmap(8*4) as *i64 98 var i: i64 = i0 99 var f: i64 = 0 100 while f < k { 101 if ld_int(b, i, e, tmp) == 0 { return 0 } 102 out[f] = tmp[0] 103 i = tmp[1] 104 f = f + 1 105 } 106 return 1 107} 108 109// parse one line; returns 1 ok (or skipped), 0 = loud malformed 110func ld_line(b: *u8, i: i64, e: i64, st: *i64) -> i64 { 111 let s: i64 = ld_skip(b, i, e) 112 if s >= e { return 1 } // blank 113 let c: i64 = b[s] as i64 114 if c == 35 { return 1 } // '#' 115 let v: *i64 = sys_mmap(8*8) as *i64 116 if c == 84 { // 'T' 117 if ld_ints(b, s+1, e, 3, v) == 0 { return 0 } 118 st[LD_TOL]=v[0]; st[LD_MINTP]=v[1]; st[LD_MAXRP]=v[2] 119 st[LD_NT] = st[LD_NT] + 1 120 return 1 121 } 122 if c == 67 { // 'C' 123 if ld_ints(b, s+1, e, 2, v) == 0 { return 0 } 124 if st[LD_NC] >= LD_MAX_OPP { return 0 } 125 let oa: *i64 = st[LD_OPPA] as *i64 126 let ob: *i64 = st[LD_OPPB] as *i64 127 oa[st[LD_NC]] = v[0]; ob[st[LD_NC]] = v[1] 128 st[LD_NC] = st[LD_NC] + 1 129 return 1 130 } 131 if c == 83 { // 'S' 132 if ld_ints(b, s+1, e, 5, v) == 0 { return 0 } 133 if st[LD_NS] >= LD_MAX_SRC { return 0 } 134 if sg_valid(v[0], v[1], v[2], v[3]) == 0 { return 0 } // bad grades fail LOUD at parse 135 let a0: *i64 = st[LD_REL] as *i64 136 let a1: *i64 = st[LD_CRED] as *i64 137 let a2: *i64 = st[LD_PARTY] as *i64 138 let a3: *i64 = st[LD_METHOD] as *i64 139 let a4: *i64 = st[LD_CLASS] as *i64 140 a0[st[LD_NS]]=v[0]; a1[st[LD_NS]]=v[1]; a2[st[LD_NS]]=v[2]; a3[st[LD_NS]]=v[3]; a4[st[LD_NS]]=v[4] 141 st[LD_NS] = st[LD_NS] + 1 142 return 1 143 } 144 if c == 78 { // 'N' 145 if ld_ints(b, s+1, e, 3, v) == 0 { return 0 } 146 if st[LD_NN] >= LD_MAX_NODE { return 0 } 147 if v[2] > 2 { return 0 } // kind 0/1/2 only 148 let p: *i64 = st[LD_PARENT] as *i64 149 let vl: *i64 = st[LD_VALUE] as *i64 150 let kd: *i64 = st[LD_KIND] as *i64 151 var par: i64 = v[0] 152 if st[LD_NN] == 0 { par = 0 - 1 } // node 0 = root by convention 153 if st[LD_NN] > 0 { if par >= st[LD_NN] { return 0 } } // parent must precede child 154 p[st[LD_NN]]=par; vl[st[LD_NN]]=v[1]; kd[st[LD_NN]]=v[2] 155 st[LD_NN] = st[LD_NN] + 1 156 return 1 157 } 158 if c == 66 { // 'B' 159 if ld_ints(b, s+1, e, 2, v) == 0 { return 0 } 160 if st[LD_NB] >= LD_MAX_EDGE { return 0 } 161 if v[0] >= st[LD_NN] { return 0 } // node must exist already 162 if v[1] >= st[LD_NS] { return 0 } // source must exist already 163 let bn: *i64 = st[LD_BNODE] as *i64 164 let bs: *i64 = st[LD_BSRC] as *i64 165 bn[st[LD_NB]]=v[0]; bs[st[LD_NB]]=v[1] 166 st[LD_NB] = st[LD_NB] + 1 167 return 1 168 } 169 return 0 // unknown record letter = LOUD 170} 171 172// parse a whole .led buffer. 1 = ok, 0 = loud-fail (malformed anywhere = no answer at all) 173func ld_parse(b: *u8, n: i64, st: *i64) -> i64 { 174 ld_alloc(st) 175 var i: i64 = 0 176 while i < n { 177 let e: i64 = ld_line_end(b, i, n) 178 if ld_line(b, i, e, st) == 0 { return 0 } 179 i = e + 1 180 } 181 if st[LD_NT] != 1 { return 0 } // exactly one threshold row 182 if st[LD_NN] < 2 { return 0 } // a root and at least one child 183 return 1 184} 185 186func ld_parse_file(path: *u8, st: *i64) -> i64 { 187 let lenp: *i64 = sys_mmap(16) as *i64 188 let b: *u8 = sys_read_file(path, lenp) 189 if lenp[0] <= 0 { return 0 } 190 return ld_parse(b, lenp[0], st) 191} 192 193// ---- strict evaluation (the independence rule applied to the parsed case) ---- 194 195// best composed score among `node`'s backers of class c (-1 if none). Flat scan. 196func ld_class_best(st: *i64, node: i64, c: i64) -> i64 { 197 let bn: *i64 = st[LD_BNODE] as *i64 198 let bs: *i64 = st[LD_BSRC] as *i64 199 let cl: *i64 = st[LD_CLASS] as *i64 200 let a0: *i64 = st[LD_REL] as *i64 201 let a1: *i64 = st[LD_CRED] as *i64 202 let a2: *i64 = st[LD_PARTY] as *i64 203 let a3: *i64 = st[LD_METHOD] as *i64 204 var cb: i64 = 0 - 1 205 var k: i64 = 0 206 while k < st[LD_NB] { 207 var hit: i64 = 0 208 if bn[k] == node { if cl[bs[k]] == c { hit = 1 } } 209 if hit == 1 { 210 let sc: i64 = sg_score_permil(a0[bs[k]], a1[bs[k]], a2[bs[k]], a3[bs[k]]) 211 if sc > cb { cb = sc } 212 } 213 k = k + 1 214 } 215 return cb 216} 217 218// distinct backing classes of `node`; also reports via out: out[0]=has_opposed out[1]=leg 219// (leg = min of the two best per-class scores -- the row stands on its weaker leg) 220func ld_node_support(st: *i64, node: i64, out: *i64) -> i64 { 221 let bn: *i64 = st[LD_BNODE] as *i64 222 let bs: *i64 = st[LD_BSRC] as *i64 223 let cl: *i64 = st[LD_CLASS] as *i64 224 let cls: *i64 = sys_mmap(8*(LD_MAX_EDGE+2)) as *i64 225 var nc: i64 = 0 226 var best1: i64 = 0 - 1 // best per-class score, top two 227 var best2: i64 = 0 - 1 228 var i: i64 = 0 229 while i < st[LD_NB] { 230 var hit: i64 = 0 231 var c: i64 = 0 232 if bn[i] == node { hit = 1; c = cl[bs[i]] } 233 var fresh: i64 = 0 234 if hit == 1 { 235 var seen: i64 = 0 236 var j: i64 = 0 237 while j < nc { if cls[j] == c { seen = 1 } j = j + 1 } 238 if seen == 0 { fresh = 1 } 239 } 240 if fresh == 1 { 241 cls[nc] = c 242 nc = nc + 1 243 let cb: i64 = ld_class_best(st, node, c) 244 if cb > best1 { best2 = best1; best1 = cb } else { if cb > best2 { best2 = cb } } 245 } 246 i = i + 1 247 } 248 // opposed pair present among the distinct classes? 249 let oa: *i64 = st[LD_OPPA] as *i64 250 let ob: *i64 = st[LD_OPPB] as *i64 251 var op: i64 = 0 252 var q: i64 = 0 253 while q < st[LD_NC] { 254 if sg_has_opposed(cls, nc, oa[q], ob[q]) == 1 { op = 1 } 255 q = q + 1 256 } 257 out[0] = op 258 out[1] = best2 // the weaker of the two best legs (-1 if <2 classes) 259 return nc 260} 261 262// build the STRICT kind array: a MEASURED leaf keeps MEASURED only with >=2 distinct classes. 263// returns the number of demotions. skind must hold LD_MAX_NODE slots. 264func ld_strict_kinds(st: *i64, skind: *i64) -> i64 { 265 let kd: *i64 = st[LD_KIND] as *i64 266 let p: *i64 = st[LD_PARENT] as *i64 267 let sup: *i64 = sys_mmap(8*4) as *i64 268 var dem: i64 = 0 269 var i: i64 = 0 270 while i < st[LD_NN] { 271 skind[i] = kd[i] 272 if kd[i] == AN_MEASURED { 273 if an_is_leaf(p, st[LD_NN], i) == 1 { 274 let nc: i64 = ld_node_support(st, i, sup) 275 if nc < 2 { skind[i] = AN_DERIVED; dem = dem + 1 } 276 } 277 } 278 i = i + 1 279 } 280 return dem 281} 282 283// full strict evaluation. out: 0=traced 1=tp 2=rp 3=verdict 4=worst_leg 5=confidence 6=demotions 284// 7=closure_fails. returns 1 ok / 0 = parse-level refusal already happened upstream. 285func ld_eval(st: *i64, out: *i64) -> i64 { 286 let skind: *i64 = sys_mmap(8*LD_MAX_NODE) as *i64 287 let dem: i64 = ld_strict_kinds(st, skind) 288 let p: *i64 = st[LD_PARENT] as *i64 289 let vl: *i64 = st[LD_VALUE] as *i64 290 let nn: i64 = st[LD_NN] 291 let cf: i64 = an_closure_fails(p, vl, nn, st[LD_TOL]) 292 let na: i64 = an_narrative_admitted(skind, vl, nn) 293 let tc: i64 = an_traced_cents(p, vl, skind, nn) 294 let tp: i64 = an_traced_permil(vl[0], tc) 295 let rp: i64 = an_residual_permil(vl[0], tc) 296 let vd: i64 = an_verdict(cf, na, tp, rp, st[LD_MINTP], st[LD_MAXRP]) 297 // confidence: weakest admitted leg across surviving measured leaves 298 let sup: *i64 = sys_mmap(8*4) as *i64 299 var worst: i64 = 1000 300 var any: i64 = 0 301 var i: i64 = 1 302 while i < nn { 303 if skind[i] == AN_MEASURED { 304 if an_is_leaf(p, nn, i) == 1 { 305 ld_node_support(st, i, sup) 306 any = 1 307 if sup[1] < worst { worst = sup[1] } 308 } 309 } 310 i = i + 1 311 } 312 var conf: i64 = SG_CONF_LOW 313 if any == 1 { conf = sg_confidence(SG_CORROB, worst) } 314 if any == 0 { worst = 0 } 315 out[0]=tc; out[1]=tp; out[2]=rp; out[3]=vd; out[4]=worst; out[5]=conf; out[6]=dem; out[7]=cf 316 return 1 317}