code wiki / (root) / nx_licgate_lib.nx

nx_licgate_lib.nx source

↩ module page · 364 lines · 15985 B

1// nx_licgate_lib.nx -- the SHIPPABILITY verdict as a LIBRARY: may I SELL what this generation chain 2// produced? Split out of nx_licgate.nx so the EMIT PATH can call it in-process. 3// 4// WHY A LIB (the same unblock as nx_swarm_endpoint_lib): a gate nothing calls is DARK, and the one 5// consumer that MUST call this is the generator itself -- it has to refuse BEFORE bytes hit disk, 6// not after. An organ with main() cannot be imported (double-main), so the verdict had to leave the 7// CLI. The CLI is now a thin caller of this, which means the command line and the emit path prove 8// the SAME code. 9// 10// THE DEFECT IT PREVENTS: output rights and weight rights are DIFFERENT RIGHTS. NoobAI-XL is freely 11// downloadable, freely mergeable, and forbids commercialising model-GENERATED PRODUCTS -- so a game 12// built entirely from "open" checkpoints can be in breach on every frame. And a generation's rights 13// are the INTERSECTION over its whole provenance chain: one non-commercial LoRA in a forty-node 14// graph poisons everything downstream of it. 15// 16// FAIL-CLOSED: unknown model, unresolved licence, or an EMPTY chain -> REFUSE. Silence is never 17// permission. Rights table is DATA (knowledge/model_license.conf) -- a new checkpoint costs a row. 18// 19// Rights are encoded ORDERED (0 NO < 1 CONDITIONAL < 2 YES) so "most restrictive wins" is a plain 20// MIN; deriv_must_open is an OBLIGATION, so it takes the MAX instead. 21// license_tier: ORIGINAL 22import "nx_syscalls.nx" 23 24// RIGHTS ENCODING, NAMED (rule 11). The table's own header defines the order 0 NO < 1 CONDITIONAL 25// < 2 YES, so "most restrictive wins" is a plain MIN. Every comparison site below used bare 0/1/2 26// literals -- a magic number carrying a domain meaning, which no reader can tell from a count and 27// no gate can check. 28const LG_NO: i64 = 0 29const LG_COND: i64 = 1 30const LG_YES: i64 = 2 31// verified (lic field 6): 1 = the licence text was READ; 0 = transcribed but UNCONFIRMED. 32const LG_UNVERIFIED: i64 = 0 33const LG_WORD: i64 = 8 34const LG_CTX_SLOTS: i64 = 8 35// K_MAGIC_262144 / K_MAGIC_262143 REMOVED 2026-08-25. A constant whose own NAME says "magic" is the 36// defect admitting itself in the one place it cannot be greppped away: they sized the rights-table 37// read. Both call sites now derive the size from the file. Nothing in this lib is a guessed bound. 38 39func lg_len(s: *u8) -> i64 { var i: i64 = 0; while s[i] != (0 as u8) { i = i + 1 } return i } 40 41func lg_put(o: *u8, at: i64, s: *u8) -> i64 { 42 var i: i64 = 0 43 var a: i64 = at 44 while s[i] != (0 as u8) { o[a] = s[i]; a = a + 1; i = i + 1 } 45 return a 46} 47 48func lg_putn(o: *u8, at: i64, buf: *u8, off: i64, n: i64) -> i64 { 49 var i: i64 = 0 50 var a: i64 = at 51 while i < n { o[a] = buf[off + i]; a = a + 1; i = i + 1 } 52 return a 53} 54 55func lg_putd(o: *u8, at: i64, v: i64) -> i64 { 56 if v == 0 { o[at] = (48 as u8); return at + 1 } 57 let tmp: *u8 = sys_mmap(32) 58 var x: i64 = v 59 var k: i64 = 0 60 while x > 0 { tmp[k] = ((48 + (x - ((x / 10) * 10))) as u8); x = x / 10; k = k + 1 } 61 var a: i64 = at 62 var j: i64 = k - 1 63 while j >= 0 { o[a] = tmp[j]; a = a + 1; j = j - 1 } 64 return a 65} 66 67func lg_ceq(a: *u8, b: *u8) -> i64 { 68 var i: i64 = 0 69 var ok: i64 = 1 70 var go: i64 = 1 71 while go == 1 { 72 if a[i] != b[i] { ok = 0; go = 0 } 73 else { if a[i] == (0 as u8) { go = 0 } else { i = i + 1 } } 74 } 75 return ok 76} 77 78func lg_seq(buf: *u8, off: i64, n: i64, s: *u8) -> i64 { 79 if lg_len(s) != n { return 0 } 80 var i: i64 = 0 81 var ok: i64 = 1 82 while i < n { if buf[off + i] != s[i] { ok = 0; i = n } else { i = i + 1 } } 83 return ok 84} 85 86func lg_sseq(buf: *u8, a: i64, an: i64, b: i64, bn: i64) -> i64 { 87 if an != bn { return 0 } 88 var i: i64 = 0 89 var ok: i64 = 1 90 while i < an { if buf[a + i] != buf[b + i] { ok = 0; i = an } else { i = i + 1 } } 91 return ok 92} 93 94func lg_field(buf: *u8, s: i64, e: i64, idx: i64, box: *i64) -> i64 { 95 var p: i64 = s 96 var f: i64 = 0 97 while f < idx { 98 var go: i64 = 1 99 while go == 1 { 100 if p >= e { go = 0 } 101 else { if buf[p] == (9 as u8) { p = p + 1; go = 0 } else { p = p + 1 } } 102 } 103 f = f + 1 104 } 105 if p >= e { box[0] = 0; box[1] = 0; return 0 } 106 var q: i64 = p 107 var g2: i64 = 1 108 while g2 == 1 { 109 if q >= e { g2 = 0 } 110 else { if buf[q] == (9 as u8) { g2 = 0 } else { q = q + 1 } } 111 } 112 box[0] = p 113 box[1] = q - p 114 return 1 115} 116 117func lg_num(buf: *u8, off: i64, n: i64) -> i64 { 118 var v: i64 = 0 119 var i: i64 = 0 120 while i < n { 121 let c: i64 = buf[off + i] as i64 122 if c >= 48 { if c <= 57 { v = v * 10 + (c - 48) } } 123 i = i + 1 124 } 125 return v 126} 127 128// lg_slurp REMOVED 2026-08-25 together with its cap: its only caller (lg_ctx, proven the only one -- 129// nx_absent corpus_complete=1) now composes sys_read_file, which sizes from the file and cannot 130// short-read. Keeping a capped reader beside an uncapped one is a second ruler waiting to be picked. 131 132// ctx layout (plain i64 slots, never struct fields): 133// ctx[0]=buf ctx[1]=n ctx[2]=lic rows ctx[3]=nlic ctx[4]=mod rows ctx[5]=nmod 134// ctx[3] = 0-1 means the rights table was unreadable 135// lic stride 7: off,len,out_commercial,weights_redist,paid_service,deriv_must_open,verified 136// mod stride 5: off,len,lic_index,kind_off,kind_len 137func lg_ctx() -> *i64 { 138 let ctx: *i64 = sys_mmap(LG_CTX_SLOTS * LG_WORD) as *i64 139 // A CAP THAT MUST BE GUESSED IS A DEFECT GENERATOR, and this one guarded the RIGHTS TABLE: past 140 // 262143 bytes a grown table SHORT-READS and licence rows vanish silently. Fail-closed makes the 141 // consequence REFUSE rather than a wrong permission -- safe, but unexplainable: it would read as 142 // "this model is unknown" forever, with nothing pointing at the buffer. sys_read_file sizes its 143 // buffer from the file itself (lseek END) and cannot short-read, so there is no number to tune 144 // and no cap to raise. Removing the guess beats raising it. 145 let lp: *i64 = sys_mmap(LG_WORD * 2) as *i64 146 let buf: *u8 = sys_read_file("knowledge/model_license.conf" as *u8, lp) 147 var n: i64 = 0 148 if (buf as i64) != 0 { n = lp[0] } 149 ctx[0] = buf as i64 150 ctx[1] = n 151 ctx[3] = 0 - 1 152 ctx[5] = 0 153 if n <= 0 { return ctx } 154 let lic: *i64 = sys_mmap(128 * 7 * 8) as *i64 155 let mods: *i64 = sys_mmap(512 * 5 * 8) as *i64 156 let box: *i64 = sys_mmap(32) as *i64 157 var nlic: i64 = 0 158 var nmod: i64 = 0 159 var p: i64 = 0 160 while p < n { 161 var q: i64 = p 162 var g: i64 = 1 163 while g == 1 { 164 if q >= n { g = 0 } 165 else { if buf[q] == (10 as u8) { g = 0 } else { q = q + 1 } } 166 } 167 if q > p + 1 { 168 if buf[p + 1] == (9 as u8) { 169 if buf[p] == (76 as u8) { 170 if nlic < 128 { 171 lg_field(buf, p, q, 1, box); lic[nlic * 7 + 0] = box[0]; lic[nlic * 7 + 1] = box[1] 172 lg_field(buf, p, q, 2, box); lic[nlic * 7 + 2] = lg_num(buf, box[0], box[1]) 173 lg_field(buf, p, q, 3, box); lic[nlic * 7 + 3] = lg_num(buf, box[0], box[1]) 174 lg_field(buf, p, q, 4, box); lic[nlic * 7 + 4] = lg_num(buf, box[0], box[1]) 175 lg_field(buf, p, q, 5, box); lic[nlic * 7 + 5] = lg_num(buf, box[0], box[1]) 176 lg_field(buf, p, q, 6, box); lic[nlic * 7 + 6] = lg_num(buf, box[0], box[1]) 177 nlic = nlic + 1 178 } 179 } 180 if buf[p] == (77 as u8) { 181 if nmod < 512 { 182 lg_field(buf, p, q, 1, box); mods[nmod * 5 + 0] = box[0]; mods[nmod * 5 + 1] = box[1] 183 lg_field(buf, p, q, 2, box) 184 var li: i64 = 0 - 1 185 var k: i64 = 0 186 while k < nlic { 187 if lg_sseq(buf, lic[k * 7 + 0], lic[k * 7 + 1], box[0], box[1]) == 1 { li = k; k = nlic } 188 else { k = k + 1 } 189 } 190 mods[nmod * 5 + 2] = li 191 lg_field(buf, p, q, 3, box); mods[nmod * 5 + 3] = box[0]; mods[nmod * 5 + 4] = box[1] 192 nmod = nmod + 1 193 } 194 } 195 } 196 } 197 p = q + 1 198 } 199 ctx[2] = lic as i64 200 ctx[3] = nlic 201 ctx[4] = mods as i64 202 ctx[5] = nmod 203 return ctx 204} 205 206func lg_find_model(ctx: *i64, want: *u8) -> i64 { 207 if ctx[3] < 0 { return 0 - 1 } 208 let buf: *u8 = ctx[0] as *u8 209 let mods: *i64 = ctx[4] as *i64 210 let nmod: i64 = ctx[5] 211 var i: i64 = 0 212 var hit: i64 = 0 - 1 213 while i < nmod { 214 if lg_seq(buf, mods[i * 5 + 0], mods[i * 5 + 1], want) == 1 { hit = i; i = nmod } 215 else { i = i + 1 } 216 } 217 return hit 218} 219 220// FIND A LICENCE ROW BY ITS OWN ID, not via a model. Added 2026-08-25 for the librarian: an external 221// code repository or dataset has a LICENCE but is not a "model", so lg_find_model cannot reach it and 222// the alternative was a SECOND rights table keyed differently. There is one rights table in this 223// estate and this is how the non-model callers read it. 224// Returns the lic row index, or -1 when the table is unreadable or the id is absent -- and ABSENT 225// MUST STAY FAIL-CLOSED at the caller: silence is never permission. 226func lg_find_license(ctx: *i64, want: *u8) -> i64 { 227 if ctx[3] < 0 { return 0 - 1 } 228 let buf: *u8 = ctx[0] as *u8 229 let lic: *i64 = ctx[2] as *i64 230 let nlic: i64 = ctx[3] 231 var i: i64 = 0 232 var hit: i64 = 0 - 1 233 while i < nlic { 234 if lg_seq(buf, lic[i * 7 + 0], lic[i * 7 + 1], want) == 1 { hit = i; i = nlic } 235 else { i = i + 1 } 236 } 237 return hit 238} 239 240// the four numeric columns of a licence row, read by INDEX so no caller re-derives the stride. 241func lg_lic_redist(ctx: *i64, li: i64) -> i64 { let lic: *i64 = ctx[2] as *i64; return lic[li * 7 + 3] } 242func lg_lic_verified(ctx: *i64, li: i64) -> i64 { let lic: *i64 = ctx[2] as *i64; return lic[li * 7 + 6] } 243 244// intersect rights over cnt model names held as pointers in names[]. 245// res: 0 out_commercial, 1 weights_redist, 2 paid_service, 3 deriv_must_open, 4 unknown, 5 binding idx 246func lg_eval(ctx: *i64, names: *i64, cnt: i64, res: *i64) -> i64 { 247 var outc: i64 = 2 248 var wred: i64 = 2 249 var psvc: i64 = 2 250 var dopen: i64 = 0 251 var unk: i64 = 0 252 var bind: i64 = 0 - 1 253 if ctx[3] < 0 { unk = unk + 1 } 254 else { 255 let lic: *i64 = ctx[2] as *i64 256 let mods: *i64 = ctx[4] as *i64 257 var i: i64 = 0 258 while i < cnt { 259 let mi: i64 = lg_find_model(ctx, names[i] as *u8) 260 if mi < 0 { unk = unk + 1 } 261 else { 262 let li: i64 = mods[mi * 5 + 2] 263 if li < 0 { unk = unk + 1 } 264 else { 265 // AN UNREAD LICENCE CANNOT GRANT AN OUTRIGHT YES. verified (field 6) was parsed 266 // into the table, printed verbatim by `list`, and never consulted by the verdict 267 // -- so a row this very file marks UNCONFIRMED returned the same SHIP_OK as one 268 // whose text had actually been read. MEASURED 2026-08-25 before this fix: 269 // `nx_licgate chain sdxl-base-1.0` -> openrail-pp, verified=0, verdict=SHIP_OK, 270 // exit=0 -- while that row's own note reads "READ IT". 271 // DECLARED MUST NEVER BE SERVED AS MEASURED. 272 // Capping an unverified row at CONDITIONAL is a strict TIGHTENING: a verdict can 273 // only move toward REVIEW, never toward permission, so this can never bless 274 // anything it did not already bless. deriv_must_open is an OBLIGATION (MAX, not 275 // MIN) and lg_rc never reads it, so it is deliberately left uncapped -- capping 276 // it would change no verdict and would only obscure the blast radius of this fix. 277 var r_out: i64 = lic[li * 7 + 2] 278 var r_wts: i64 = lic[li * 7 + 3] 279 var r_svc: i64 = lic[li * 7 + 4] 280 if lic[li * 7 + 6] == LG_UNVERIFIED { 281 if r_out > LG_COND { r_out = LG_COND } 282 if r_wts > LG_COND { r_wts = LG_COND } 283 if r_svc > LG_COND { r_svc = LG_COND } 284 } 285 if r_out < outc { outc = r_out; bind = i } 286 if r_wts < wred { wred = r_wts } 287 if r_svc < psvc { psvc = r_svc } 288 if lic[li * 7 + 5] > dopen { dopen = lic[li * 7 + 5] } 289 } 290 } 291 i = i + 1 292 } 293 } 294 if cnt <= 0 { unk = unk + 1 } 295 res[0] = outc 296 res[1] = wred 297 res[2] = psvc 298 res[3] = dopen 299 res[4] = unk 300 res[5] = bind 301 return 0 302} 303 304// 0 SHIP_OK | 3 REVIEW (a conditional term a machine may not settle) | 4 REFUSE 305const LG_RC_OK: i64 = 0 306const LG_RC_REVIEW: i64 = 3 307const LG_RC_REFUSE: i64 = 4 308 309func lg_rc(res: *i64) -> i64 { 310 if res[4] > 0 { return LG_RC_REFUSE } 311 if res[0] == LG_NO { return LG_RC_REFUSE } 312 if res[0] == LG_COND { return LG_RC_REVIEW } 313 return LG_RC_OK 314} 315 316// EVERY AXIS, NOT JUST THE ONE. lg_rc above answers exactly ONE question -- may I SELL the output -- 317// and that IS its documented contract, so it is deliberately NOT widened: a caller already branching 318// on it must keep the meaning it has (rule 19, adding is safe and changing breaks consumers). 319// 320// THE DEFECT THAT MOTIVATES THIS: lg_eval computes FOUR axes and lg_rc consults TWO of them 321// (res[4] unknown, res[0] out_commercial). weights_redist, paid_service and deriv_must_open are 322// computed, returned, printed in the JSON and printed in the dossier -- and reach no exit code at 323// all. So a caller that reads exit 0 as "all clear" is answering only "may I sell the pixels" while 324// silently discarding three answers. 325// MEASURED 2026-08-25 on the live binary: `nx_licgate chain illustrious-xl` returns verdict=SHIP_OK 326// exit=0 with paid_service=0 -- DENIED, the model may NOT power a paid service -- and 327// deriv_must_open=1, an obligation nobody has discharged. Standing a paid service up on that exit 328// code would breach the licence while every printed number sat right there saying so. 329// 330// AN OBLIGATION IS NOT A RIGHT. deriv_must_open=1 means a DUTY attaches (derivatives must stay open), 331// which a machine cannot discharge and must not silently accept, so it yields REVIEW -- a human's 332// decision, unmade -- and never REFUSE. Refusing would conflate "you owe something" with "you may not". 333func lg_rc_axes(res: *i64) -> i64 { 334 if res[4] > 0 { return LG_RC_REFUSE } 335 var worst: i64 = LG_YES 336 if res[0] < worst { worst = res[0] } 337 if res[1] < worst { worst = res[1] } 338 if res[2] < worst { worst = res[2] } 339 if worst == LG_NO { return LG_RC_REFUSE } 340 if worst == LG_COND { return LG_RC_REVIEW } 341 if res[3] > 0 { return LG_RC_REVIEW } 342 return LG_RC_OK 343} 344 345// which axis bound the all-axis verdict, so a refusal NAMES its cause instead of being a bare code. 346func lg_axis_name(res: *i64) -> *u8 { 347 if res[4] > 0 { return "unknown-component" as *u8 } 348 if res[0] == LG_NO { return "out_commercial" as *u8 } 349 if res[1] == LG_NO { return "weights_redist" as *u8 } 350 if res[2] == LG_NO { return "paid_service" as *u8 } 351 if res[0] == LG_COND { return "out_commercial" as *u8 } 352 if res[1] == LG_COND { return "weights_redist" as *u8 } 353 if res[2] == LG_COND { return "paid_service" as *u8 } 354 if res[3] > 0 { return "deriv_must_open" as *u8 } 355 return "none" as *u8 356} 357 358// THE ONE CALL THE EMIT PATH MAKES: names+count -> exit-code verdict. Anything non-zero must not ship. 359func lg_verdict(names: *i64, cnt: i64) -> i64 { 360 let ctx: *i64 = lg_ctx() 361 let res: *i64 = sys_mmap(64) as *i64 362 lg_eval(ctx, names, cnt, res) 363 return lg_rc(res) 364}