nx_provclass_lib.nx source
↩ module page · 251 lines · 9251 B
1// nx_provclass_lib.nx -- THE PROVENANCE-CLASS RULER. One classifier, read by every organ that
2// admits a measured fact, so a class can never mean one thing to the writer and another to the reader.
3//
4// WHAT IT ADDS TO nx_refcorpus, AND WHAT IT DELIBERATELY DOES NOT TOUCH. rc_admit already walls off
5// asset PAYLOAD (length + plain alphabet) and enforces a global k-floor RC_KMIN=8. Both are properties
6// of the VALUE. Neither looks at WHERE the measured assets came from: rc_put_row bounds `provenance`
7// and `license` by LENGTH ONLY, so `unverified` and `cc0` pass identically. This lib is the missing
8// axis, and it is STRICTLY ADDITIVE -- it can only ever REFUSE something rc_admit would have taken.
9// It never loosens rc_admit and it is not a second copy of it.
10//
11// TWO REASONS THE `use` COLUMN EXISTS, and the second is the one that matters:
12// 1. `shipped` -- provenance is verifiable, the class may inform artifacts we ship.
13// 2. `reference-only` -- AGGREGATE STATISTICS ONLY. Never a shape target, never a fitted generator
14// axis, never resolved from a build closure.
15// Keeping an asset out of the build path stops us shipping its BYTES. It does not stop its IDENTITY
16// propagating through a generator fitted to it -- and that output IS shipped. The build-path rule is
17// structurally blind to that path; `reference-only` is what makes it enforceable rather than promised.
18//
19// FAIL CLOSED, IN BOTH DIRECTIONS THAT MATTER:
20// * an UNKNOWN tag refuses. It does not fall through to the permissive value. The estate has already
21// measured that cost: pr_mode returned BUFFERED for any unrecognised token, silently downgrading a
22// fail-closed route to an open one with no diagnostic.
23// * an UNREADABLE conf refuses too, with its own named code. A classifier that cannot read its table
24// must ABSTAIN, never acquit -- an admission wall that opens when its rules go missing is worse
25// than no wall, because its existence is counted as coverage.
26//
27// TWO-ROOT PROBE, ON PURPOSE. `knowledge/...` is a CWD-RELATIVE EXPRESSION and this estate has already
28// paid for that: the same literal names a different tree depending on the forking process's CWD.
29// pc_load probes the bare path FIRST, then the buildroot twin, and RECORDS WHICH ONE RESOLVED
30// (pc_conf_which) -- a resolver that returns bytes without saying where they came from reproduces the
31// original defect one layer up.
32//
33// NO LOOP-EXIT SENTINELS. The scanners below return early from helpers instead of writing a sentinel
34// into the cursor. The estate has recorded that defect four times in one day ("a loop-exit sentinel
35// written into the search cursor erases the answer"), and the first draft of THIS file committed it.
36//
37// license_tier: ORIGINAL
38import "nx_syscalls.nx"
39
40const PC_CONF_PRIMARY: *u8 = "knowledge/asset_provenance.conf"
41const PC_CONF_SECONDARY: *u8 = "buildroot/knowledge/asset_provenance.conf"
42
43const PC_USE_UNKNOWN: i64 = 0
44const PC_USE_SHIPPED: i64 = 1
45const PC_USE_REFERENCE_ONLY: i64 = 2
46
47const PC_OK: i64 = 0
48const PC_ERR_UNKNOWN_CLASS: i64 = 0 - 1
49const PC_ERR_BELOW_KMIN: i64 = 0 - 2
50const PC_ERR_NO_CONF: i64 = 0 - 3
51
52const PC_MAX_CLASSES: i64 = 64
53const PC_TAG_BYTES: i64 = 64
54const PC_TAB_BYTES: i64 = 4096
55const PC_IDX_BYTES: i64 = 512
56const PC_CH_SP: i64 = 32
57const PC_CH_TAB: i64 = 9
58const PC_CH_NL: i64 = 10
59const PC_CH_CR: i64 = 13
60const PC_CH_SEMI: i64 = 59
61const PC_D0: i64 = 48
62const PC_D9: i64 = 57
63
64static pc_loaded_g: i64
65static pc_n_g: i64
66static pc_which_g: i64
67static pc_tags_g: *u8
68static pc_kmin_g: *i64
69static pc_use_g: *i64
70
71func pc_is_space(c: i64) -> i64 {
72 if c == PC_CH_SP { return 1 }
73 if c == PC_CH_TAB { return 1 }
74 return 0
75}
76
77func pc_streq(a: *u8, b: *u8) -> i64 {
78 var i: i64 = 0
79 while a[i] != (0 as u8) {
80 if b[i] != a[i] { return 0 }
81 i = i + 1
82 }
83 if b[i] != (0 as u8) { return 0 }
84 return 1
85}
86
87func pc_eol(buf: *u8, n: i64, from: i64) -> i64 {
88 var j: i64 = from
89 while j < n {
90 if (buf[j] as i64) == PC_CH_NL { return j }
91 j = j + 1
92 }
93 return n
94}
95
96func pc_skip_sp(buf: *u8, end: i64, from: i64) -> i64 {
97 var j: i64 = from
98 while j < end {
99 if pc_is_space(buf[j] as i64) == 0 { return j }
100 j = j + 1
101 }
102 return end
103}
104
105func pc_tok_end(buf: *u8, end: i64, from: i64) -> i64 {
106 var j: i64 = from
107 while j < end {
108 let c: i64 = buf[j] as i64
109 if pc_is_space(c) == 1 { return j }
110 if c == PC_CH_CR { return j }
111 j = j + 1
112 }
113 return end
114}
115
116func pc_tok_is(buf: *u8, s: i64, e: i64, lit: *u8) -> i64 {
117 var k: i64 = 0
118 while lit[k] != (0 as u8) {
119 if s + k >= e { return 0 }
120 if buf[s + k] != lit[k] { return 0 }
121 k = k + 1
122 }
123 if s + k != e { return 0 }
124 return 1
125}
126
127func pc_tok_num(buf: *u8, s: i64, e: i64) -> i64 {
128 var v: i64 = 0
129 var k: i64 = s
130 var any: i64 = 0
131 while k < e {
132 let d: i64 = buf[k] as i64
133 if d < PC_D0 { return 0 - 1 }
134 if d > PC_D9 { return 0 - 1 }
135 v = v * 10 + (d - PC_D0)
136 any = 1
137 k = k + 1
138 }
139 if any == 0 { return 0 - 1 }
140 return v
141}
142
143func pc_conf_which() -> i64 { return pc_which_g }
144func pc_count() -> i64 { return pc_n_g }
145
146func pc_parse(buf: *u8, n: i64) -> i64 {
147 var count: i64 = 0
148 var i: i64 = 0
149 while i < n {
150 let eol: i64 = pc_eol(buf, n, i)
151 let a: i64 = pc_skip_sp(buf, eol, i)
152 if a < eol {
153 if (buf[a] as i64) != PC_CH_SEMI {
154 let e0: i64 = pc_tok_end(buf, eol, a)
155 if pc_tok_is(buf, a, e0, "class" as *u8) == 1 {
156 if count < PC_MAX_CLASSES {
157 let b: i64 = pc_skip_sp(buf, eol, e0)
158 let e1: i64 = pc_tok_end(buf, eol, b)
159 let c: i64 = pc_skip_sp(buf, eol, e1)
160 let e2: i64 = pc_tok_end(buf, eol, c)
161 let d: i64 = pc_skip_sp(buf, eol, e2)
162 let e3: i64 = pc_tok_end(buf, eol, d)
163 let kv: i64 = pc_tok_num(buf, c, e2)
164 var uv: i64 = PC_USE_UNKNOWN
165 if pc_tok_is(buf, d, e3, "shipped" as *u8) == 1 { uv = PC_USE_SHIPPED }
166 if pc_tok_is(buf, d, e3, "reference-only" as *u8) == 1 { uv = PC_USE_REFERENCE_ONLY }
167 if kv >= 0 {
168 if uv != PC_USE_UNKNOWN {
169 var glen: i64 = e1 - b
170 if glen > PC_TAG_BYTES - 1 { glen = PC_TAG_BYTES - 1 }
171 if glen > 0 {
172 var k: i64 = 0
173 while k < glen { pc_tags_g[count * PC_TAG_BYTES + k] = buf[b + k]; k = k + 1 }
174 pc_tags_g[count * PC_TAG_BYTES + glen] = 0 as u8
175 pc_kmin_g[count] = kv
176 pc_use_g[count] = uv
177 count = count + 1
178 }
179 }
180 }
181 }
182 }
183 }
184 }
185 i = eol + 1
186 }
187 return count
188}
189
190func pc_load() -> i64 {
191 if pc_loaded_g == 1 {
192 if pc_which_g == 0 { return PC_ERR_NO_CONF }
193 return pc_n_g
194 }
195 pc_tags_g = sys_mmap(PC_TAB_BYTES)
196 pc_kmin_g = sys_mmap(PC_IDX_BYTES) as *i64
197 pc_use_g = sys_mmap(PC_IDX_BYTES) as *i64
198 let lp: *i64 = sys_mmap(8) as *i64
199 lp[0] = 0
200 var buf: *u8 = sys_read_file(PC_CONF_PRIMARY, lp)
201 var which: i64 = 1
202 if (buf as i64) == 0 {
203 lp[0] = 0
204 buf = sys_read_file(PC_CONF_SECONDARY, lp)
205 which = 2
206 }
207 pc_loaded_g = 1
208 if (buf as i64) == 0 { pc_which_g = 0; pc_n_g = 0; return PC_ERR_NO_CONF }
209 if lp[0] <= 0 { pc_which_g = 0; pc_n_g = 0; return PC_ERR_NO_CONF }
210 pc_n_g = pc_parse(buf, lp[0])
211 pc_which_g = which
212 return pc_n_g
213}
214
215func pc_find(tag: *u8) -> i64 {
216 if pc_load() < 0 { return PC_ERR_NO_CONF }
217 var i: i64 = 0
218 while i < pc_n_g {
219 if pc_streq(((pc_tags_g as i64) + i * PC_TAG_BYTES) as *u8, tag) == 1 { return i }
220 i = i + 1
221 }
222 return PC_ERR_UNKNOWN_CLASS
223}
224
225func pc_kmin(tag: *u8) -> i64 {
226 let idx: i64 = pc_find(tag)
227 if idx < 0 { return idx }
228 return pc_kmin_g[idx]
229}
230
231func pc_use(tag: *u8) -> i64 {
232 let idx: i64 = pc_find(tag)
233 if idx < 0 { return PC_USE_UNKNOWN }
234 return pc_use_g[idx]
235}
236
237func pc_admit(tag: *u8, n: i64) -> i64 {
238 let idx: i64 = pc_find(tag)
239 if idx == PC_ERR_NO_CONF { return PC_ERR_NO_CONF }
240 if idx < 0 { return PC_ERR_UNKNOWN_CLASS }
241 if n < pc_kmin_g[idx] { return PC_ERR_BELOW_KMIN }
242 return PC_OK
243}
244
245// May a class inform a fitted generator axis / shape target? ONLY `shipped` may. This is the query
246// the build-path rule cannot answer, so it gets its own name rather than being left to a caller's
247// reading of pc_use.
248func pc_may_fit_axis(tag: *u8) -> i64 {
249 if pc_use(tag) == PC_USE_SHIPPED { return 1 }
250 return 0
251}