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}