nx_wiki_license.nx source
↩ module page · 153 lines · 7527 B
1// nx_wiki_license.nx -- PER-SOURCE LICENSE LAYER for the no-link-rot archive.
2//
3// THE EXCEED OVER WIKIPEDIA (anti-pushout, done RIGHT):
4// We render a cited supporting source INLINE in the wiki -- but ONLY when the
5// license permits us to host/redistribute it. This module is the gate that
6// decides hostable vs link-only. Getting this WRONG is the one unacceptable
7// failure: inlining content we are not licensed to host. So the rule is sealed
8// here, data-driven (per-source tag in the archive store), and the cite-render
9// asks THIS module -- never guesses.
10//
11// LICENSE CLASSES (sealed enum; values are stable on-disk so a stored tag keeps
12// meaning forever -- additive-only, never renumber):
13// 0 UNKNOWN not hostable (we don't know -> we don't inline)
14// 1 PUBLIC_DOMAIN hostable, no attribution required
15// 2 CC0 hostable, no attribution required (PD-equivalent dedication)
16// 3 CC_BY hostable, attribution required
17// 4 CC_BY_SA hostable, attribution required (share-alike)
18// 5 CC_BY_NC hostable, attribution required (non-commercial)
19// 6 CC_BY_ND hostable, attribution required (no-derivatives -- verbatim
20// redistribution, which inline display IS, is permitted)
21// 7 CC_BY_NC_SA hostable, attribution required
22// 8 PROPRIETARY NOT hostable (all-rights-reserved -> link only)
23//
24// HOSTABLE = "the license permits us to redistribute / display the verbatim
25// source bytes to a reader". Public-domain + CC0 + every Creative-Commons
26// variant grant redistribution (the NC/ND/SA conditions constrain commercial
27// use / derivatives / relicensing, NOT verbatim display, which is exactly what
28// an inline read is). PROPRIETARY and UNKNOWN are the deny set.
29//
30// STORE: the per-source tag lives in the SAME content-addressed seg_store the
31// archive uses (prefix WAR_PREFIX from nx_wiki_archive.nx), under key
32// wikilic:<cid> -> one byte = the license class (0..8)
33// keyed by the SOURCE's CID so the license travels with the content address.
34// Absent tag => UNKNOWN (fail-closed: an un-tagged source is never inlined).
35//
36// IMPORTS: nx_wiki_archive.nx (for WAR_PREFIX + the seg_store API it re-exports
37// transitively). NishiLang's resolver de-dups imports by module identity (the
38// archive itself imports nx_seg_store + nx_canon_cid; importing the archive here
39// splices each ONCE), so no double-import nxasm-rc6 landmine. Pure NishiLang,
40// NO SQL, NO .sh/.py/.js, no new .tsv/.conf. license_tier: ORIGINAL
41import "nx_wiki_archive.nx"
42
43// ===== sealed license-class enum (stable on-disk values) =====================
44const NXLIC_UNKNOWN: i64 = 0
45const NXLIC_PUBLIC_DOMAIN: i64 = 1
46const NXLIC_CC0: i64 = 2
47const NXLIC_CC_BY: i64 = 3
48const NXLIC_CC_BY_SA: i64 = 4
49const NXLIC_CC_BY_NC: i64 = 5
50const NXLIC_CC_BY_ND: i64 = 6
51const NXLIC_CC_BY_NC_SA: i64 = 7
52const NXLIC_PROPRIETARY: i64 = 8
53
54// manifest segment-scan cap for license-tag reads (matches archive callers;
55// the archive is a handful of committed segments, this is generous headroom).
56const NXLIC_CAP: i64 = 64
57
58// ---- human-readable class name (for the inline card's attribution footer) ----
59// Returns a NUL-terminated literal. Unknown/out-of-range -> "Unknown license".
60func nx_wiki_license_name(cls: i64) -> *u8 {
61 if cls == NXLIC_PUBLIC_DOMAIN { return "Public Domain" as *u8 }
62 if cls == NXLIC_CC0 { return "CC0 1.0" as *u8 }
63 if cls == NXLIC_CC_BY { return "CC BY 4.0" as *u8 }
64 if cls == NXLIC_CC_BY_SA { return "CC BY-SA 4.0" as *u8 }
65 if cls == NXLIC_CC_BY_NC { return "CC BY-NC 4.0" as *u8 }
66 if cls == NXLIC_CC_BY_ND { return "CC BY-ND 4.0" as *u8 }
67 if cls == NXLIC_CC_BY_NC_SA { return "CC BY-NC-SA 4.0" as *u8 }
68 if cls == NXLIC_PROPRIETARY { return "Proprietary - all rights reserved" as *u8 }
69 return "Unknown license" as *u8
70}
71
72// ---- THE LIAR-KILL DECISION: may we host/inline this source's bytes? ----
73// 1 = yes (PD, CC0, every CC variant -- redistribution/display granted)
74// 0 = no (PROPRIETARY, UNKNOWN -- fail-closed deny set)
75// This is the ONLY place the hostable rule lives; cite-render calls it and
76// trusts it (Cardinal 12: trust internal, validate boundaries).
77func nx_wiki_license_hostable(cls: i64) -> i64 {
78 if cls == NXLIC_PUBLIC_DOMAIN { return 1 }
79 if cls == NXLIC_CC0 { return 1 }
80 if cls == NXLIC_CC_BY { return 1 }
81 if cls == NXLIC_CC_BY_SA { return 1 }
82 if cls == NXLIC_CC_BY_NC { return 1 }
83 if cls == NXLIC_CC_BY_ND { return 1 }
84 if cls == NXLIC_CC_BY_NC_SA { return 1 }
85 // NXLIC_UNKNOWN, NXLIC_PROPRIETARY, and anything else -> deny
86 return 0
87}
88
89// ---- does this license require attribution when we display it? ----
90// PD + CC0 dedicate to the public domain / waive attribution; every BY-* CC
91// license requires it. Non-hostable classes return 0 (moot -- never displayed).
92func nx_wiki_license_attribution_required(cls: i64) -> i64 {
93 if cls == NXLIC_CC_BY { return 1 }
94 if cls == NXLIC_CC_BY_SA { return 1 }
95 if cls == NXLIC_CC_BY_NC { return 1 }
96 if cls == NXLIC_CC_BY_ND { return 1 }
97 if cls == NXLIC_CC_BY_NC_SA { return 1 }
98 return 0
99}
100
101// ---- build the "wikilic:<cid>" tag key into out (NUL-terminated) ----
102// cid is NUL-terminated; reuses war_cat (the archive's concat helper).
103func nx_wiki_lickey(cid: *u8, out: *u8) -> i64 {
104 var o: i64 = 0
105 o = war_cat(out, o, "wikilic:" as *u8)
106 o = war_cat(out, o, cid)
107 out[o] = 0 as u8
108 return o
109}
110
111// ---- SETTER: tag a source CID with a license class ----
112// Appends wikilic:<cid> -> 1 byte (cls) into an OPEN writer; the caller commits
113// (same temp->rename discipline as war_archive_page; idempotent by last-writer).
114// Validates cls into the sealed range at the boundary (UNKNOWN if out of range,
115// so a garbage class can never become "hostable"). Returns ss_add rc (0 ok).
116func nx_wiki_license_set_w(w: *i64, cid: *u8, cls: i64) -> i64 {
117 var c: i64 = cls
118 if c < 0 { c = NXLIC_UNKNOWN }
119 if c > NXLIC_PROPRIETARY { c = NXLIC_UNKNOWN }
120 let lk: *u8 = sys_mmap(128)
121 nx_wiki_lickey(cid, lk)
122 let vb: *u8 = sys_mmap(8)
123 vb[0] = c as u8
124 return ss_add(w, 1, lk, vb, 1)
125}
126
127// ---- SETTER (self-contained): begin+set+commit in one call ----
128// Convenience for callers that just want to stamp one source's license.
129// segid lets the caller pick a fresh segment id (additive). Returns commit rc.
130func nx_wiki_license_set(prefix: *u8, cid: *u8, cls: i64, segid: i64) -> i64 {
131 let w: *i64 = ss_begin()
132 let r: i64 = nx_wiki_license_set_w(w, cid, cls)
133 if r != 0 { return r }
134 return ss_commit(prefix, w, segid)
135}
136
137// ---- GETTER: read a source CID's license class from the committed store ----
138// Returns the stored class (0..8), or NXLIC_UNKNOWN if no tag exists
139// (fail-closed). prefix = the archive store prefix (production: WAR_PREFIX).
140func nx_wiki_license_get(prefix: *u8, cid: *u8) -> i64 {
141 let lk: *u8 = sys_mmap(128)
142 nx_wiki_lickey(cid, lk)
143 let pp: *i64 = sys_mmap(16) as *i64
144 let ll: *i64 = sys_mmap(16) as *i64
145 let r: i64 = ss_get_cap(prefix, lk, pp, ll, NXLIC_CAP)
146 if r != 1 { return NXLIC_UNKNOWN }
147 if ll[0] < 1 { return NXLIC_UNKNOWN }
148 let src: *u8 = pp[0] as *u8
149 let v: i64 = src[0]
150 if v < 0 { return NXLIC_UNKNOWN }
151 if v > NXLIC_PROPRIETARY { return NXLIC_UNKNOWN }
152 return v
153}