code wiki / (root) / nx_extllm_lib.nx

nx_extllm_lib.nx source

↩ module page · 292 lines · 13085 B

1// nx_extllm_lib.nx -- THE EGRESS DECISION LIBRARY: may THESE BYTES leave, to THIS PROVIDER, for THIS USE? 2// The CODE half of two conf files authored 2026-08-24 that have had no reader since (measured 2026-08-25: 3// xl_egress matches=0 over 61,475 files, coverage_complete=1 corpus_complete=1). 4// xl_class_of -- CLASSIFY AT THE DOOR over the operator's release manifest. C by default; U only on an 5// explicit row whose sha256 still matches the file. A STALE row admits NOTHING. 6// xl_use_verdict -- the provider terms ledger as data. UNKNOWN is a VALUE and REFUSES every gated use. 7// xl_budget_* -- CUMULATIVE disclosure per provider. Splitting work into parts defeats a SINGLE call 8// and NOT aggregation across calls: a provider holding a perpetual licence retains every 9// fragment and reassembles at leisure. The bound is on the SUM, never on the call. 10// WHY A NEW LIB RATHER THAN EXTENDING AN INCUMBENT (checked before building, 2026-08-25): the estate's three 11// shipping classifiers cannot answer an OBJECT-side release question. ag_uid_to_level grades a READER (a 0..3 12// RBAC ladder, never a byte's sensitivity); nx_site_lock_lib slk_resolve returns 0 for an unmatched path and 13// ag_allow turns that into ALLOW for everyone ("no match => PUBLIC"); the docportal consent bit is OPT-OUT 14// (keep initialises to 1, so an undeclared document is SERVED). Two of the three default to release, so this 15// decision must fail closed INDEPENDENTLY of all of them rather than compose one. 16// Verdicts are exit-code shaped so a caller can branch without parsing. license_tier: ORIGINAL. No hw writes (Rule 26). 17import "nx_syscalls.nx" 18import "nx_sovjson_lib.nx" 19 20// ---- the three states. UNKNOWN is NOT allow: an axis that cannot see must abstain, never acquit. ---- 21const XL_ALLOW: i64 = 0 22const XL_REFUSE: i64 = 1 23const XL_UNKNOWN: i64 = 3 24 25// ---- classification (no-write-down: a provider is a sink cleared to U) ---- 26const XL_CLASS_U: i64 = 0 27const XL_CLASS_C: i64 = 1 28 29// ---- use classes, as spelled in the allowed_uses column ---- 30const XL_USE_WORKER: i64 = 1 31const XL_USE_JUDGE: i64 = 2 32const XL_USE_DISTILL: i64 = 3 33 34// ---- bytes we must construct rather than spell: the nx_cc lexer forbids these inside a string literal ---- 35const XL_BYTE_HASH: i64 = 35 36const XL_BYTE_PIPE: i64 = 124 37const XL_BYTE_NL: i64 = 10 38 39// ---- extllm_terms.conf: 12 pipe-separated columns, declared in the file's own header ---- 40const XL_TC_PROVIDER: i64 = 0 41const XL_TC_TIER: i64 = 1 42const XL_TC_TRAINS_IN: i64 = 2 43const XL_TC_OUT_OURS: i64 = 3 44const XL_TC_PUBRESTRICT: i64 = 4 45const XL_TC_USES: i64 = 9 46const XL_TC_REFKEY: i64 = 10 47const XL_TC_PIN: i64 = 11 48const XL_TC_COLS: i64 = 12 49 50// ---- extllm_release.conf: release|<path>|<sha256>|<declared by>|<date>|<why> ---- 51const XL_RC_PATH: i64 = 1 52const XL_RC_SHA: i64 = 2 53const XL_RC_COLS: i64 = 6 54 55// A pin is the sha256 of the mirrored contract, spelled h then 64 hex. The terms conf's own header requires 56// a pin check, so a row that was never pinned to a mirror ADMITS NOTHING: PIN-PENDING is a refusal, not a 57// placeholder that quietly passes. We do not get to assert a provider's posture we have not pinned to evidence. 58const XL_PIN_MIN: i64 = 65 59const XL_BYTE_H: i64 = 104 60 61// A column span is TWO i64 slots (start, end), so its scratch is 2 x 8 bytes. Named for that PURPOSE, 62// not for its value: nx_magic would hoist this to XL_MAGIC_16, and a constant named after its own value 63// is still a magic number -- it has only moved. The tool says so itself: its generated names are 64// mechanical and the rename to a domain term is the owner judgment rule 11 actually asks for. 65const XL_SPAN_SLOTS: i64 = 2 66const XL_SPAN_BYTES: i64 = 16 67 68func xl_terms_path() -> *u8 { return "knowledge/extllm_terms.conf" as *u8 } 69func xl_release_path() -> *u8 { return "knowledge/extllm_release.conf" as *u8 } 70 71// A conf comment. Spelled as a byte because the lexer will not carry the character in a literal. 72func xl_is_comment(q: *u8, ls: i64, le: i64) -> i64 { 73 if ls >= le { return 1 } 74 if (q[ls] as i64) == XL_BYTE_HASH { return 1 } 75 return 0 76} 77 78// Column c of a PIPE-separated row. sj_col is TAB-only by construction, so the separator travels here. 79func xl_col(q: *u8, ls: i64, le: i64, c: i64, out: *i64) -> i64 { 80 var col: i64 = 0 81 var p: i64 = ls 82 while col < c { 83 var s: i64 = 1 84 while s == 1 { if p >= le { return 0 } if (q[p] as i64) == XL_BYTE_PIPE { s = 0 } else { p = p + 1 } } 85 p = p + 1 86 col = col + 1 87 } 88 var e: i64 = p 89 var s2: i64 = 1 90 while s2 == 1 { if e >= le { s2 = 0 } else { if (q[e] as i64) == XL_BYTE_PIPE { s2 = 0 } else { e = e + 1 } } } 91 out[0] = p 92 out[1] = e 93 return 1 94} 95 96// How many columns does this row actually have? A row of the wrong width is MALFORMED, never silently short. 97func xl_ncols(q: *u8, ls: i64, le: i64) -> i64 { 98 var n: i64 = 1 99 var i: i64 = ls 100 while i < le { if (q[i] as i64) == XL_BYTE_PIPE { n = n + 1 } i = i + 1 } 101 return n 102} 103 104// The literal spelled in the allowed_uses column for a use class. 105func xl_use_name(use: i64) -> *u8 { 106 if use == XL_USE_WORKER { return "WORKER" as *u8 } 107 if use == XL_USE_JUDGE { return "JUDGE" as *u8 } 108 if use == XL_USE_DISTILL { return "DISTILL" as *u8 } 109 return "" as *u8 110} 111 112func xl_verdict_name(v: i64) -> *u8 { 113 if v == XL_ALLOW { return "ALLOW" as *u8 } 114 if v == XL_REFUSE { return "REFUSE" as *u8 } 115 return "UNKNOWN-REFUSED" as *u8 116} 117 118func xl_class_name(c: i64) -> *u8 { 119 if c == XL_CLASS_U { return "U" as *u8 } 120 return "C" as *u8 121} 122 123// Find the terms row for provider+tier. Returns 1 and writes row start/end into out, else 0. 124func xl_row_find(q: *u8, n: i64, provider: *u8, tier: *u8, out: *i64) -> i64 { 125 let c: *i64 = sys_mmap(XL_SPAN_BYTES) as *i64 126 var i: i64 = 0 127 while i < n { 128 let le: i64 = sj_le(q, i, n) 129 if xl_is_comment(q, i, le) == 0 { 130 if xl_col(q, i, le, XL_TC_PROVIDER, c) == 1 { 131 if sj_lit_eq(q, c[0], c[1], provider) == 1 { 132 if xl_col(q, i, le, XL_TC_TIER, c) == 1 { 133 if sj_lit_eq(q, c[0], c[1], tier) == 1 { 134 out[0] = i 135 out[1] = le 136 return 1 137 } 138 } 139 } 140 } 141 } 142 i = le + 1 143 } 144 return 0 145} 146 147// Is a terms cell exactly this token? Used for YES / NO / CONDITIONAL / UNKNOWN. 148func xl_cell_is(q: *u8, ls: i64, le: i64, col: i64, lit: *u8) -> i64 { 149 let c: *i64 = sys_mmap(XL_SPAN_BYTES) as *i64 150 if xl_col(q, ls, le, col, c) == 0 { return 0 } 151 return sj_lit_eq(q, c[0], c[1], lit) 152} 153 154// Is this use listed in allowed_uses? An empty list lists nothing (github/models, retired). 155func xl_use_listed(q: *u8, ls: i64, le: i64, use: i64) -> i64 { 156 let c: *i64 = sys_mmap(XL_SPAN_BYTES) as *i64 157 if xl_col(q, ls, le, XL_TC_USES, c) == 0 { return 0 } 158 if c[0] >= c[1] { return 0 } 159 return sj_span_has(q, c[0], c[1], xl_use_name(use)) 160} 161 162func xl_pin_ok(q: *u8, ls: i64, le: i64) -> i64 { 163 let c: *i64 = sys_mmap(XL_SPAN_BYTES) as *i64 164 if xl_col(q, ls, le, XL_TC_PIN, c) == 0 { return 0 } 165 if c[1] - c[0] < XL_PIN_MIN { return 0 } 166 if (q[c[0]] as i64) != XL_BYTE_H { return 0 } 167 return 1 168} 169 170// THE TERMS DECISION. Every refusal is attributable to exactly one named conjunct, so a caller is never 171// told "no" without being told which rule said it. 172// 0 row absent -> UNKNOWN (a provider with no mirrored row must never read ALLOW) 173// 1 row malformed -> UNKNOWN 174// 2 use not listed -> REFUSE 175// 3 DISTILL demands outputs_train_ours=YES; anything else, including UNKNOWN, REFUSES 176func xl_use_verdict(q: *u8, n: i64, provider: *u8, tier: *u8, use: i64) -> i64 { 177 let r: *i64 = sys_mmap(XL_SPAN_BYTES) as *i64 178 if xl_row_find(q, n, provider, tier, r) == 0 { return XL_UNKNOWN } 179 if xl_ncols(q, r[0], r[1]) != XL_TC_COLS { return XL_UNKNOWN } 180 if xl_pin_ok(q, r[0], r[1]) == 0 { return XL_UNKNOWN } 181 if xl_use_listed(q, r[0], r[1], use) == 0 { return XL_REFUSE } 182 if use == XL_USE_DISTILL { 183 if xl_cell_is(q, r[0], r[1], XL_TC_OUT_OURS, "YES" as *u8) == 0 { return XL_REFUSE } 184 } 185 return XL_ALLOW 186} 187 188// Does this provider train on what we send it? Reported separately from the verdict because it does not 189// refuse a WORKER use -- it decides whether a fragment sent is a fragment donated permanently. 190func xl_trains_on_input(q: *u8, n: i64, provider: *u8, tier: *u8) -> i64 { 191 let r: *i64 = sys_mmap(XL_SPAN_BYTES) as *i64 192 if xl_row_find(q, n, provider, tier, r) == 0 { return XL_UNKNOWN } 193 if xl_cell_is(q, r[0], r[1], XL_TC_TRAINS_IN, "NO" as *u8) == 1 { return XL_ALLOW } 194 if xl_cell_is(q, r[0], r[1], XL_TC_TRAINS_IN, "YES" as *u8) == 1 { return XL_REFUSE } 195 return XL_UNKNOWN 196} 197 198// ---- CLASSIFY AT THE DOOR ------------------------------------------------------------------------- 199// A path is U only when the operator's manifest carries a row for it AND the declared sha256 still equals 200// the file's bytes at call time. Absent row -> C. Stale row -> C, which is the whole point of the hash: 201// a file that changed since it was declared has NOT been declared. 202func xl_release_row(q: *u8, n: i64, path: *u8, out: *i64) -> i64 { 203 let c: *i64 = sys_mmap(XL_SPAN_BYTES) as *i64 204 var i: i64 = 0 205 while i < n { 206 let le: i64 = sj_le(q, i, n) 207 if xl_is_comment(q, i, le) == 0 { 208 if xl_ncols(q, i, le) == XL_RC_COLS { 209 if xl_col(q, i, le, XL_RC_PATH, c) == 1 { 210 if sj_lit_eq(q, c[0], c[1], path) == 1 { out[0] = i; out[1] = le; return 1 } 211 } 212 } 213 } 214 i = le + 1 215 } 216 return 0 217} 218 219// actual_sha is supplied by the caller (nx_filehash of the file at call time), never trusted from the row. 220func xl_class_of(q: *u8, n: i64, path: *u8, actual_sha: *u8) -> i64 { 221 let r: *i64 = sys_mmap(XL_SPAN_BYTES) as *i64 222 if xl_release_row(q, n, path, r) == 0 { return XL_CLASS_C } 223 let c: *i64 = sys_mmap(XL_SPAN_BYTES) as *i64 224 if xl_col(q, r[0], r[1], XL_RC_SHA, c) == 0 { return XL_CLASS_C } 225 if sj_lit_eq(q, c[0], c[1], actual_sha) == 0 { return XL_CLASS_C } 226 return XL_CLASS_U 227} 228 229// How many rows has the operator actually declared? Zero is the correct answer today and the caller must 230// be able to SEE that, because a manifest with no rows admits nothing and that is not a malfunction. 231func xl_release_rows(q: *u8, n: i64) -> i64 { 232 var rows: i64 = 0 233 var i: i64 = 0 234 while i < n { 235 let le: i64 = sj_le(q, i, n) 236 if xl_is_comment(q, i, le) == 0 { if xl_ncols(q, i, le) == XL_RC_COLS { rows = rows + 1 } } 237 i = le + 1 238 } 239 return rows 240} 241 242// ---- CUMULATIVE DISCLOSURE ------------------------------------------------------------------------ 243// The ledger row is: <unix>|<provider>|<tier>|<subsystem>|<bytes>|<class>|<prompt-sha>|<verdict> 244const XL_LC_PROVIDER: i64 = 1 245const XL_LC_SUBSYSTEM: i64 = 3 246const XL_LC_BYTES: i64 = 4 247const XL_LC_COLS: i64 = 8 248 249// Total bytes this provider has EVER been shown, optionally narrowed to one subsystem. This is the number 250// a per-call check structurally cannot compute, and it is the only number that bounds reassembly. 251func xl_spent(q: *u8, n: i64, provider: *u8, subsystem: *u8, all_subsystems: i64) -> i64 { 252 let c: *i64 = sys_mmap(XL_SPAN_BYTES) as *i64 253 var tot: i64 = 0 254 var i: i64 = 0 255 while i < n { 256 let le: i64 = sj_le(q, i, n) 257 if xl_is_comment(q, i, le) == 0 { 258 if xl_ncols(q, i, le) == XL_LC_COLS { 259 if xl_col(q, i, le, XL_LC_PROVIDER, c) == 1 { 260 if sj_lit_eq(q, c[0], c[1], provider) == 1 { 261 var take: i64 = all_subsystems 262 if take == 0 { 263 if xl_col(q, i, le, XL_LC_SUBSYSTEM, c) == 1 { 264 if sj_lit_eq(q, c[0], c[1], subsystem) == 1 { take = 1 } 265 } 266 } 267 if take == 1 { 268 if xl_col(q, i, le, XL_LC_BYTES, c) == 1 { tot = tot + sj_atoi_span(q, c[0], c[1]) } 269 } 270 } 271 } 272 } 273 } 274 i = le + 1 275 } 276 return tot 277} 278 279// The budget refuses on the SUM, which is what makes fragmenting honest rather than theatre. A bound of 0 280// is UNKNOWN, not unlimited -- an unconfigured budget must not read as permission. 281func xl_budget_verdict(spent: i64, add: i64, bound: i64) -> i64 { 282 if bound <= 0 { return XL_UNKNOWN } 283 if spent + add > bound { return XL_REFUSE } 284 return XL_ALLOW 285} 286 287// Remaining headroom, clamped at 0 so a caller never sees a negative budget and reads it as a large one. 288func xl_budget_left(spent: i64, bound: i64) -> i64 { 289 if bound <= 0 { return 0 } 290 if spent >= bound { return 0 } 291 return bound - spent 292}