nx_artlicense.nx
buildroot/runtime/nx_artlicense.nx
about
nx_artlicense.nx -- THE LICENSE CHAIN AND THE ROYALTY LEDGER AS DATA (2026-08-24, /compare/phototwin PT4).
license_tier: ORIGINAL No hw writes (Rule 26).
nx_artlicense check <sku> [now_epoch] [territory] [conf] -> 0 SHIP-OK | 3 REVIEW | 4 REFUSE | 2 usage
nx_artlicense royalty <ledger.tsv> <sku> <sale_id> <sale_cents> [conf] -> appends ONE row (idempotent on sale_id)
nx_artlicense total <ledger.tsv> <sku> -> royalty cents owed for the sku
THE DEFECT IT PREVENTS. A garment print is a REPRODUCTION of the photograph, the gamut-mapped twin is a DERIVATIVE
work, and selling it is DISTRIBUTION -- three of the exclusive rights the copyright owner holds by default
(knowledge/fetched/cmp_phototwin_copyright.html). A SKU carries those rights only through a chain row that grants
all three, inside its term, inside its territory, with the artist's approval of the soft proof on record.
FAIL-CLOSED like nx_licgate: no chain, an expired or not-yet-started term, a missing right, or an unknown
territory against a restricted chain -> REFUSE (4). A chain without proof approval -> REVIEW (3): the artist,
not a machine, settles that. Silence is never permission. The exit vocabulary is nx_licgate's (0/3/4) so one
caller can compose both verdicts with one rule.
CHAIN ROWS (knowledge/artlicense.conf), pipe-separated, one per SKU:
chain|<sku>|<owner>|<rights letters from r d s>|<term_start_epoch>|<term_end_epoch>|<territories csv or *>|<royalty_permil>|<proof_approved yes or no>
ROYALTY LEDGER (tab-separated, APPEND-ONLY -- history is sacred, rule 13): epoch sku sale_id sale_cents royalty_cents owner
royalty = sale_cents * permil / 1000 in INTEGER CENTS (floor), never float.
dependencies 1 imports · 0 importers
imports: nx_syscalls.nx
imported by: nobody (leaf or entry point)
call flow from main pre-order; caps 40 nodes / depth 6 declared; ↻ = already shown
structs
| none |
consts
| 23 | const AL_EXIT_OK: i64 = 0 |
| 24 | const AL_EXIT_USAGE: i64 = 2 |
| 25 | const AL_EXIT_REVIEW: i64 = 3 |
| 26 | const AL_EXIT_REFUSE: i64 = 4 |
| 27 | const AL_CONF_DEFAULT: *u8 = "knowledge/artlicense.conf" |
| 28 | const AL_PIPE: i64 = 124 |
| 29 | const AL_NL: i64 = 10 |
| 30 | const AL_HASH: i64 = 35 |
| 31 | const AL_TAB: i64 = 9 |
| 32 | const AL_COMMA: i64 = 44 |
| 33 | const AL_STAR: i64 = 42 |
| 34 | const AL_ASCII_ZERO: i64 = 48 |
| 35 | const AL_ASCII_NINE: i64 = 57 |
| 36 | const AL_DECIMAL: i64 = 10 |
| 37 | const AL_F_SKU: i64 = 1 |
| 38 | const AL_F_OWNER: i64 = 2 |
| 39 | const AL_F_RIGHTS: i64 = 3 |
| 40 | const AL_F_START: i64 = 4 |
| 41 | const AL_F_END: i64 = 5 |
| 42 | const AL_F_TERR: i64 = 6 |
| 43 | const AL_F_PERMIL: i64 = 7 |
| 44 | const AL_F_APPROVED: i64 = 8 |
| 45 | const AL_FIELDS: i64 = 9 |
| 46 | const AL_RIGHT_REPRODUCE: i64 = 114 // r |
| 47 | const AL_RIGHT_DERIVE: i64 = 100 // d |
| 48 | const AL_RIGHT_DISTRIBUTE: i64 = 115 // s |
| 49 | const AL_PERMIL: i64 = 1000 |
| 50 | const AL_LINE_CAP: i64 = 1024 |
| 51 | const AL_MODE_0644: i64 = 420 |
| 52 | const AL_NOW_UNSET: i64 = 0 - 1 |
| 53 | const AL_LEDGER_F_SKU: i64 = 1 |
| 54 | const AL_LEDGER_F_SALE: i64 = 2 |
| 55 | const AL_LEDGER_F_ROYALTY: i64 = 4 |
| 56 | const AL_DUP: i64 = 0 - 1 |
| 58 | const AL_R_OK: i64 = 0 |
| 59 | const AL_R_NO_CHAIN: i64 = 1 |
| 60 | const AL_R_NOT_STARTED: i64 = 2 |
| 61 | const AL_R_EXPIRED: i64 = 3 |
| 62 | const AL_R_RIGHT_MISSING: i64 = 4 |
| 63 | const AL_R_TERRITORY: i64 = 5 |
| 64 | const AL_R_NOT_APPROVED: i64 = 6 |
| 65 | const AL_R_MALFORMED: i64 = 7 |
| 66 | const AL_R_NO_CONF: i64 = 8 |
| 67 | const AL_OUT_REASON: i64 = 0 |
| 68 | const AL_OUT_PERMIL: i64 = 1 |
| 69 | const AL_OUT_OWNER_OFF: i64 = 2 |
| 70 | const AL_OUT_OWNER_LEN: i64 = 3 |
| 71 | const AL_OUT_SLOTS: i64 = 8 |
| 72 | const AL_SLOT: i64 = 8 |
functions
| 74 | func al_w(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } sys_write(1, s, n); return 0 } |
| 75 | func al_wn(v: i64) -> i64 |
| 88 | func al_streq(a: *u8, b: *u8) -> i64 { var i: i64 = 0; while a[i] != (0 as u8) { if a[i] != b[i] { return 0 } i = i + 1 } if b[i] != (0 as u8) { return 0 } return 1 } called by 1: main |
| 89 | func al_slen(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n } |
| 90 | func al_atoi(s: *u8) -> i64 called by 1: main |
| 99 | func al_span_num(buf: *u8, off: i64, len: i64) -> i64 |
| 105 | func al_span_eq(buf: *u8, off: i64, len: i64, s: *u8) -> i64 |
| 112 | func al_field(buf: *u8, s: i64, e: i64, idx: i64, sep: i64, box: *i64) -> i64 |
| 128 | func al_span_has_char(buf: *u8, off: i64, len: i64, c: i64) -> i64 called by 1: al_license_chain |
| 134 | func al_territory_ok(buf: *u8, off: i64, len: i64, terr: *u8) -> i64 |
| 149 | func al_license_chain(buf: *u8, n: i64, sku: *u8, now: i64, terr: *u8, out: *i64) -> i64 |
| 195 | func al_reason_text(r: i64) -> *u8 called by 1: main |
| 209 | func al_royalty_ledger(ledger: *u8, sku: *u8, sale_id: *u8, sale_cents: i64, permil: i64, owner_buf: *u8, owner_off: i64, owner_len: i64, now: i64) -> i64 |
| 246 | func al_cat(d: *u8, o: i64, s: *u8) -> i64 { var i: i64 = 0; var p: i64 = o; while s[i] != (0 as u8) { d[p] = s[i]; p = p + 1; i = i + 1 } return p } called by 1: al_royalty_ledger |
| 247 | func al_catn(d: *u8, o: i64, v: i64) -> i64 |
| 259 | func al_total(ledger: *u8, sku: *u8, rows_out: *i64) -> i64 |
| 284 | func al_usage() -> i64 |
| 289 | func main(argc: i64, argv: *i64) -> i64 |