nx_artlicense_gate.nx source
↩ module page · 125 lines · 8023 B
1// nx_artlicense_gate.nx -- THE GATE FOR THE LICENSE CHAIN AND ROYALTY LEDGER (nx_artlicense), 2026-08-24.
2//
3// SUBJECT: the nx_artlicense ELF forked for real; its exit code IS the contract (0 SHIP-OK / 3 REVIEW / 4 REFUSE)
4// and every REFUSE must NAME its conjunct. Fixture chain rows in /tmp/nx_artlicense_gate/chain.conf cover one
5// row per refusal reason plus the positive control; the ledger is unlinked at SETUP so idempotency is measured
6// against a state this run established. A guard that refuses everything passes every deny-test, so the ALLOW
7// case (ok / DE-territory) is load-bearing, not decoration.
8// license_tier: ORIGINAL No hw writes (Rule 26). expect_exit: 0
9import "nx_syscalls.nx"
10import "nx_gate_verdict.nx"
11import "nx_tool_run.nx"
12
13const AG_SUBJECT_DEFAULT: *u8 = "nx_artlicense.elf"
14const AG_DIR: *u8 = "/tmp/nx_artlicense_gate"
15const AG_CONF: *u8 = "/tmp/nx_artlicense_gate/chain.conf"
16const AG_LEDGER: *u8 = "/tmp/nx_artlicense_gate/royalty.tsv"
17const AG_MODE_DIR: i64 = 493
18const AG_MODE_0644: i64 = 420
19const AG_CAPTURE_CAP: i64 = 65536
20const AG_ARGV_SLOTS: i64 = 10
21const AG_SLOT: i64 = 8
22const AG_EXIT_OK: i64 = 0
23const AG_EXIT_REVIEW: i64 = 3
24const AG_EXIT_REFUSE: i64 = 4
25const AG_NOW_INSIDE: *u8 = "1600"
26
27func ag_write_text(path: *u8, s: *u8) -> i64 {
28 var n: i64 = 0
29 while s[n] != (0 as u8) { n = n + 1 }
30 let fd: i64 = sys_openat_wr(path, AG_MODE_0644)
31 if fd < 0 { return 0 - 1 }
32 let wr: i64 = sys_write(fd, s, n)
33 sys_close(fd)
34 if wr != n { return 0 - 1 }
35 return n
36}
37func ag_exists(path: *u8) -> i64 {
38 let lp: *i64 = sys_mmap(AG_SLOT * 2) as *i64
39 let b: *u8 = sys_read_file(path, lp)
40 if (b as i64) == 0 { return 0 }
41 return 1
42}
43// run the subject with up to 6 args
44func ag_run(subject: *u8, a1: *u8, a2: *u8, a3: *u8, a4: *u8, a5: *u8, a6: *u8, out: *u8, outlen: *i64) -> i64 {
45 let av: *i64 = sys_mmap(AG_SLOT * AG_ARGV_SLOTS) as *i64
46 av[0] = subject as i64
47 av[1] = a1 as i64
48 av[2] = a2 as i64
49 av[3] = a3 as i64
50 av[4] = a4 as i64
51 av[5] = a5 as i64
52 av[6] = a6 as i64
53 av[7] = 0
54 return tr_run_capture(subject, av, out, AG_CAPTURE_CAP, outlen)
55}
56
57func main(argc: i64, argv: *i64) -> i64 {
58 let ctr: *i64 = gv_ctr()
59 gv_head("nx_artlicense gate -- the license chain refuses by NAMED conjunct, allows the granted case, and the ledger is append-only and idempotent" as *u8)
60 var subject: *u8 = AG_SUBJECT_DEFAULT
61 if argc >= 2 { subject = argv[1] as *u8 }
62 gv_puts(" subject: " as *u8); gv_puts(subject); gv_puts("\n\n" as *u8)
63 sys_mkdir(AG_DIR, AG_MODE_DIR)
64 sys_unlinkat(AG_LEDGER)
65 let w1: i64 = ag_write_text(AG_CONF, "# fixture chains\nchain|ok|Owner A|rds|1000|4102444800|*|100|yes\nchain|noright|Owner B|rs|1000|4102444800|*|100|yes\nchain|expired|Owner C|rds|1000|1500|*|100|yes\nchain|future|Owner D|rds|1800|2000|*|100|yes\nchain|terr|Owner E|rds|1000|2000|NL,DE|100|yes\nchain|review|Owner F|rds|1000|2000|*|100|no\n" as *u8)
66 gv_check("setup-fixture-chain-written" as *u8, (w1 > 0) as i64, ctr)
67 gv_check("setup-ledger-absent-before-measuring (gate is idempotent)" as *u8, (ag_exists(AG_LEDGER) == 0) as i64, ctr)
68 let cap: *u8 = sys_mmap(AG_CAPTURE_CAP)
69 let olen: *i64 = sys_mmap(AG_SLOT * 2) as *i64
70
71 let rc_ok: i64 = ag_run(subject, "check" as *u8, "ok" as *u8, AG_NOW_INSIDE, "NL" as *u8, AG_CONF, 0 as *u8, cap, olen)
72 gv_puts(" [ok] rc=" as *u8); gv_num(rc_ok); gv_puts(" " as *u8); sys_write(1, cap, olen[0])
73 gv_check("granted-chain-inside-term-and-territory-is-SHIP-OK (exit 0)" as *u8, (rc_ok == AG_EXIT_OK) as i64, ctr)
74 gv_check("granted-chain-prints-its-royalty-permil" as *u8, tr_contains(cap, olen[0], "royalty_permil=100 verdict=SHIP-OK" as *u8), ctr)
75
76 let rc_nr: i64 = ag_run(subject, "check" as *u8, "noright" as *u8, AG_NOW_INSIDE, "NL" as *u8, AG_CONF, 0 as *u8, cap, olen)
77 gv_puts(" [noright] rc=" as *u8); gv_num(rc_nr); gv_puts(" " as *u8); sys_write(1, cap, olen[0])
78 var t: i64 = 0
79 if rc_nr == AG_EXIT_REFUSE { if tr_contains(cap, olen[0], "reason=RIGHT-MISSING" as *u8) == 1 { t = 1 } }
80 gv_check("missing-derivative-right-REFUSES-and-names-RIGHT-MISSING" as *u8, t, ctr)
81 gv_bite("neg-control-refuses-missing-right-allows-granted" as *u8, (rc_nr == AG_EXIT_REFUSE) as i64, (rc_ok != AG_EXIT_OK) as i64, ctr)
82
83 let rc_ex: i64 = ag_run(subject, "check" as *u8, "expired" as *u8, AG_NOW_INSIDE, "NL" as *u8, AG_CONF, 0 as *u8, cap, olen)
84 t = 0
85 if rc_ex == AG_EXIT_REFUSE { if tr_contains(cap, olen[0], "reason=EXPIRED" as *u8) == 1 { t = 1 } }
86 gv_check("expired-term-REFUSES-and-names-EXPIRED" as *u8, t, ctr)
87 let rc_fu: i64 = ag_run(subject, "check" as *u8, "future" as *u8, AG_NOW_INSIDE, "NL" as *u8, AG_CONF, 0 as *u8, cap, olen)
88 t = 0
89 if rc_fu == AG_EXIT_REFUSE { if tr_contains(cap, olen[0], "reason=NOT-STARTED" as *u8) == 1 { t = 1 } }
90 gv_check("future-term-REFUSES-and-names-NOT-STARTED" as *u8, t, ctr)
91 let rc_tf: i64 = ag_run(subject, "check" as *u8, "terr" as *u8, AG_NOW_INSIDE, "FR" as *u8, AG_CONF, 0 as *u8, cap, olen)
92 t = 0
93 if rc_tf == AG_EXIT_REFUSE { if tr_contains(cap, olen[0], "reason=TERRITORY" as *u8) == 1 { t = 1 } }
94 gv_check("ungranted-territory-REFUSES-and-names-TERRITORY" as *u8, t, ctr)
95 let rc_td: i64 = ag_run(subject, "check" as *u8, "terr" as *u8, AG_NOW_INSIDE, "DE" as *u8, AG_CONF, 0 as *u8, cap, olen)
96 gv_check("granted-territory-in-a-restricted-chain-is-SHIP-OK" as *u8, (rc_td == AG_EXIT_OK) as i64, ctr)
97 let rc_rv: i64 = ag_run(subject, "check" as *u8, "review" as *u8, AG_NOW_INSIDE, "NL" as *u8, AG_CONF, 0 as *u8, cap, olen)
98 t = 0
99 if rc_rv == AG_EXIT_REVIEW { if tr_contains(cap, olen[0], "reason=NOT-APPROVED" as *u8) == 1 { t = 1 } }
100 gv_check("unapproved-proof-is-REVIEW (exit 3), a person settles it" as *u8, t, ctr)
101 let rc_no: i64 = ag_run(subject, "check" as *u8, "nosuch" as *u8, AG_NOW_INSIDE, "NL" as *u8, AG_CONF, 0 as *u8, cap, olen)
102 t = 0
103 if rc_no == AG_EXIT_REFUSE { if tr_contains(cap, olen[0], "reason=NO-CHAIN" as *u8) == 1 { t = 1 } }
104 gv_check("absent-chain-REFUSES-and-names-NO-CHAIN (silence is never permission)" as *u8, t, ctr)
105
106 // ---- ledger: append, idempotent on sale_id, refused sales book nothing, totals sum ----
107 let rc_r1: i64 = ag_run(subject, "royalty" as *u8, AG_LEDGER, "ok" as *u8, "S1" as *u8, "12345" as *u8, AG_CONF, cap, olen)
108 gv_puts(" [royalty S1] rc=" as *u8); gv_num(rc_r1); gv_puts(" " as *u8); sys_write(1, cap, olen[0])
109 t = 0
110 if rc_r1 == AG_EXIT_OK { if tr_contains(cap, olen[0], "ledger=APPENDED sale_cents=12345 royalty_cents=1234" as *u8) == 1 { t = 1 } }
111 gv_check("royalty-appends-integer-cents (12345 * 100 permil = 1234, floor)" as *u8, t, ctr)
112 let rc_r2: i64 = ag_run(subject, "royalty" as *u8, AG_LEDGER, "ok" as *u8, "S1" as *u8, "12345" as *u8, AG_CONF, cap, olen)
113 gv_check("royalty-repeat-of-the-same-sale_id-is-DUPLICATE-not-a-second-row" as *u8, tr_contains(cap, olen[0], "ledger=DUPLICATE" as *u8), ctr)
114 let rc_r3: i64 = ag_run(subject, "royalty" as *u8, AG_LEDGER, "noright" as *u8, "S2" as *u8, "1000" as *u8, AG_CONF, cap, olen)
115 t = 0
116 if rc_r3 == AG_EXIT_REFUSE { if tr_contains(cap, olen[0], "ledger=UNCHANGED" as *u8) == 1 { t = 1 } }
117 gv_check("royalty-on-a-refused-chain-books-nothing" as *u8, t, ctr)
118 let rc_r4: i64 = ag_run(subject, "royalty" as *u8, AG_LEDGER, "ok" as *u8, "S3" as *u8, "5000" as *u8, AG_CONF, cap, olen)
119 let rc_t: i64 = ag_run(subject, "total" as *u8, AG_LEDGER, "ok" as *u8, 0 as *u8, 0 as *u8, 0 as *u8, cap, olen)
120 gv_puts(" [total ok] " as *u8); sys_write(1, cap, olen[0])
121 gv_check("total-sums-only-this-sku (1234 + 500 = 1734 over 2 rows)" as *u8, tr_contains(cap, olen[0], "rows=2 royalty_cents=1734" as *u8), ctr)
122
123 sys_unlinkat(AG_LEDGER)
124 return gv_verdict("artlicense" as *u8, ctr, "every refusal names its conjunct, the granted case ships, the ledger is idempotent integer cents" as *u8)
125}