nx_accept_lib.nx source
↩ module page · 1032 lines · 45494 B
1// nx_accept_lib.nx -- THE THREE-PARTY ACCEPTANCE LEDGER: the decision core behind every ACCEPTANCE cell on
2// /compare (2026-08-30). Operator standing order, verbatim: "doing it poorly isn't a complete and needs to be
3// shown as that on /compare and your work; it's not complete till you and I and the nishi team agree."
4//
5// A subject is ACCEPTED iff ALL THREE signatures hold, each read from its own sovereign plane:
6// 1. OPERATOR -- knowledge/store/accept- : the LATEST row whose actor is `operator` and whose targets field
7// carries the token ga_accept_<subject> says ACCEPT (REJECT, UNJUDGED, absent do not).
8// 2. REFEREE -- knowledge/store/referee- : the LATEST row for <subject> says composite GOOD AND its percept is
9// at or above floor_percept_<tier> READ FROM knowledge/cjc_panel.conf (never a literal here), its
10// tier is in the panel receipt's tiers_admitted list, and that receipt says admitted=1. The row's
11// own word GOOD is necessary and NOT sufficient: the floor is re-derived so a row cannot lie.
12// 3. SEAT -- knowledge/store/attest- : a row for <subject> naming the shipping seat and its stamp.
13// Anything less is INCOMPLETE, and INCOMPLETE names WHICH signature is missing and WHY.
14//
15// HOW THE BOARD FLIPS. `nx_accept emit` regenerates buildroot/runtime/nx_accept_decl.nx from the planes: one
16// top-level declaration ga_accept_<subject> per ACCEPTED subject and NOTHING for any other. The /compare regen
17// measures that file exactly as it measures every organ (nx_symdecl_lib: a column-0 declaration), so an
18// ACCEPTANCE watch row lands only when the three-party rule holds. A hand-written declaration is a lie: the next
19// emit erases it and nx_accept_gate convicts it (re-derivation must equal the bytes on disk).
20//
21// JOIN RULE, stated once: a plane row GOVERNS subject X iff its targets field carries the token ga_accept_X, bare
22// or domain-qualified (gameengine:ga_accept_X). The subject key IS the suffix of the acceptance symbol, so the
23// board and the ledger cannot name the same thing two ways. Rows with no such token are counted UNMAPPED and
24// printed, never silently dropped.
25//
26// LIB+PROGRAM SPLIT ON PURPOSE: every rule is a function of caller-supplied plane prefixes, conf path and buffers,
27// so nx_accept_gate drives the SAME code over fixture planes under /tmp and never the production planes.
28// COMPOSES, NEVER RE-IMPLEMENTS: nx_seg_store's sequential cursor (plane iteration; ss_get point lookups are the
29// documented quadratic read), nx_comparewatch_lib (tab-field parsing + strict q:<n> keys), nx_lineconf_lib
30// (line-anchored key=value), nx_estate_path (CWD-independent artifact paths).
31// HONEST LIMIT: the actor column is caller-supplied. This ledger buys ATTRIBUTION and TAMPER-EVIDENCE through the
32// plane's own hist- provenance, not cryptographic proof of who the operator is; the signed-row rung (nx_evattest,
33// role=human key) is the named next step, not a claim made here.
34// license_tier: ORIGINAL No hw writes (Rule 26).
35import "nx_syscalls.nx"
36import "nx_seg_store.nx"
37import "nx_comparewatch_lib.nx"
38import "nx_lineconf_lib.nx"
39import "nx_estate_path.nx"
40import "nx_store_seed_lib.nx" // sts_load_fit: the newest-version-per-key row reader (2026-08-31, see al_rows_open)
41
42// ---- the DEFAULTS a program passes; the gate passes fixtures ---------------------------------------------
43const AL_PFX_ACCEPT: *u8 = "knowledge/store/accept-"
44const AL_PFX_REFEREE: *u8 = "knowledge/store/referee-"
45const AL_PFX_ATTEST: *u8 = "knowledge/store/attest-"
46const AL_PANEL_CONF: *u8 = "knowledge/cjc_panel.conf"
47const AL_DECL_PATH: *u8 = "buildroot/runtime/nx_accept_decl.nx"
48const AL_DECL_SIBLING: *u8 = "buildroot/runtime/nx_accept_lib.nx"
49const AL_DECL_BASENAME: *u8 = "nx_accept_decl.nx"
50const AL_DECL_ROW: *u8 = "runtime/nx_accept_decl.nx"
51const AL_BOARDS_DIR: *u8 = "buildroot/knowledge/compare"
52const AL_BOARDS_DIR_FROM_BUILDROOT: *u8 = "knowledge/compare"
53const AL_SYM_PFX: *u8 = "ga_accept_"
54const AL_WATCH_PFX: *u8 = "_ABSENT_:"
55const AL_MATRIX_SFX: *u8 = ".matrix"
56const AL_ACTOR_OPERATOR: *u8 = "operator"
57const AL_KEY_RECEIPT: *u8 = "receipt"
58const AL_KEY_ADMITTED: *u8 = "admitted"
59const AL_KEY_TIERS_ADMITTED: *u8 = "tiers_admitted"
60const AL_KEY_TIERS: *u8 = "tiers"
61const AL_KEY_FLOOR_PFX: *u8 = "floor_percept_"
62const AL_TMP_SFX: *u8 = ".tmp"
63
64// ---- byte constants (named, never bare) --------------------------------------------------------------------
65const AL_TAB: i64 = 9
66const AL_NL: i64 = 10
67const AL_CR: i64 = 13
68const AL_SPACE: i64 = 32
69const AL_BANG: i64 = 33
70const AL_HASH: i64 = 35
71const AL_COMMA: i64 = 44
72const AL_MINUS: i64 = 45
73const AL_DOT: i64 = 46
74const AL_SLASH: i64 = 47
75const AL_D0: i64 = 48
76const AL_D9: i64 = 57
77const AL_COLON: i64 = 58
78const AL_AT: i64 = 64
79const AL_LOWA: i64 = 97
80const AL_LOWZ: i64 = 122
81const AL_USCORE: i64 = 95
82const AL_PIPE: i64 = 124
83const AL_BASE10: i64 = 10
84const AL_KIND_TOMB: i64 = 2 // seg-store record kind 2 = tombstone (nx_seg_store contract)
85
86// ---- capacities: each announces when exceeded, none is silent -----------------------------------------
87const AL_MAX_SUBJ: i64 = 64
88const AL_MAX_TOK: i64 = 16
89const AL_MAX_WATCH: i64 = 64
90const AL_NAMEW: i64 = 64
91const AL_ORGW: i64 = 128
92const AL_REC: i64 = 512
93const AL_NUMCAP: i64 = 32
94const AL_PATHCAP: i64 = 1024
95const AL_LISTCAP: i64 = 256
96const AL_KEYCAP: i64 = 128
97const AL_DENTCAP: i64 = 65536
98const AL_DECL_CAP: i64 = 65536
99const AL_LINE_MAX: i64 = 1024
100const AL_DATECAP: i64 = 16
101const AL_SC_WORDS: i64 = 8
102
103// ---- string field offsets/widths inside one subject record (AL_REC bytes) --------------------------------
104const AL_F_NAME: i64 = 0
105const AL_W_NAME: i64 = 64
106const AL_F_OPID: i64 = 64
107const AL_W_OPID: i64 = 96
108const AL_F_OPDATE: i64 = 160
109const AL_W_DATE: i64 = 16
110const AL_F_OPACTOR: i64 = 176
111const AL_W_ACTOR: i64 = 32
112const AL_F_RTIER: i64 = 208
113const AL_W_TIER: i64 = 16
114const AL_F_RSHA: i64 = 224
115const AL_W_SHA: i64 = 72
116const AL_F_RSEAT: i64 = 296
117const AL_W_SEAT: i64 = 32
118const AL_F_RDATE: i64 = 328
119const AL_F_ASEAT: i64 = 344
120const AL_F_ASTAMP: i64 = 376
121const AL_W_STAMP: i64 = 64
122const AL_F_ADATE: i64 = 440
123
124// ---- integer slots per subject -------------------------------------------------------------------------------
125const AL_IW: i64 = 16
126const AL_I_OPV: i64 = 0 // operator verdict code (actor == operator rows only)
127const AL_I_ANYV: i64 = 1 // latest verdict of ANY actor (informational)
128const AL_I_RCOMP: i64 = 2 // referee composite code
129const AL_I_RPERCEPT: i64 = 3
130const AL_I_ATT: i64 = 4 // 1 = a usable attestation row exists
131const AL_I_OPSEEN: i64 = 5
132const AL_I_RSEEN: i64 = 6
133const AL_I_ASEEN: i64 = 7
134
135// ---- book header words ---------------------------------------------------------------------------------------
136const AL_BK_WORDS: i64 = 32
137const AL_B_N: i64 = 0
138const AL_B_INTS: i64 = 1
139const AL_B_STRS: i64 = 2
140const AL_B_OVERFLOW: i64 = 3
141const AL_B_ACC_ROWS: i64 = 4
142const AL_B_REF_ROWS: i64 = 5
143const AL_B_ATT_ROWS: i64 = 6
144const AL_B_UNMAPPED: i64 = 7
145const AL_B_MALFORMED: i64 = 8
146const AL_B_ACC_PLANE: i64 = 9
147const AL_B_REF_PLANE: i64 = 10
148const AL_B_ATT_PLANE: i64 = 11
149const AL_B_TOMB: i64 = 12
150const AL_B_FOREIGN: i64 = 13
151const AL_B_BADNAME: i64 = 14
152const AL_B_ACC_PATH: i64 = 16
153const AL_B_REF_PATH: i64 = 17
154const AL_B_ATT_PATH: i64 = 18
155
156// ---- accept- row fields: id | subject-or-description | verdict | date | actor | words | targets --------------
157const AL_AF_ID: i64 = 0
158const AL_AF_VERDICT: i64 = 2
159const AL_AF_DATE: i64 = 3
160const AL_AF_ACTOR: i64 = 4
161const AL_AF_TARGETS: i64 = 6
162// ---- referee- row fields: id | subject | frame_sha256 | composite | percept | tier | date | seat -----------
163const AL_RF_SUBJECT: i64 = 1
164const AL_RF_SHA: i64 = 2
165const AL_RF_COMP: i64 = 3
166const AL_RF_PERCEPT: i64 = 4
167const AL_RF_TIER: i64 = 5
168const AL_RF_DATE: i64 = 6
169const AL_RF_SEAT: i64 = 7
170// ---- attest- row fields: id | subject | seat | stamp | words | date --------------------------------------------
171const AL_TF_SUBJECT: i64 = 1
172const AL_TF_SEAT: i64 = 2
173const AL_TF_STAMP: i64 = 3
174const AL_TF_DATE: i64 = 5
175
176// ---- codes ----------------------------------------------------------------------------------------------------
177const AL_V_NONE: i64 = 0
178const AL_V_ACCEPT: i64 = 1
179const AL_V_REJECT: i64 = 2
180const AL_V_UNJUDGED: i64 = 3
181const AL_V_INVALID: i64 = 4
182const AL_R_NONE: i64 = 0
183const AL_R_GOOD: i64 = 1
184const AL_R_BAD: i64 = 2
185const AL_R_INVALID: i64 = 3
186const AL_RC_OK: i64 = 0
187const AL_RC_MISSING: i64 = 1
188const AL_RC_BAD: i64 = 2
189const AL_RC_INVALID: i64 = 3
190const AL_RC_TIER_UNADMITTED: i64 = 4
191const AL_RC_NO_FLOOR: i64 = 5
192const AL_RC_BELOW_FLOOR: i64 = 6
193const AL_RC_PANEL_UNADMITTED: i64 = 7
194const AL_ST_UNKNOWN: i64 = 0
195const AL_ST_ACCEPTED: i64 = 1
196const AL_ST_INCOMPLETE: i64 = 2
197const AL_DV_IDENTICAL: i64 = 0
198const AL_DV_DIFFERS: i64 = 1
199const AL_DV_ABSENT: i64 = 2
200const AL_DV_CAP: i64 = 3
201// why[] slots handed back by al_state
202const AL_WHY_OP: i64 = 0
203const AL_WHY_REF: i64 = 1
204const AL_WHY_ATT: i64 = 2
205const AL_WHY_FLOOR: i64 = 3
206const AL_WHY_WORDS: i64 = 4
207
208// ---- conf struct words --------------------------------------------------------------------------------------
209const AL_CF_WORDS: i64 = 16
210const AL_C_BUF: i64 = 0
211const AL_C_LEN: i64 = 1
212const AL_C_ADMITTED: i64 = 2
213const AL_C_TADM: i64 = 3
214const AL_C_TIERS: i64 = 4
215const AL_C_CONF_OK: i64 = 5
216const AL_C_RCPT_OK: i64 = 6
217const AL_C_PATH: i64 = 7
218const AL_C_RPATH: i64 = 8
219
220// ---- civil date from epoch seconds (Howard Hinnant's days-to-civil; every constant named) ------------------
221const AL_SEC_PER_DAY: i64 = 86400
222const AL_EPOCH_SHIFT_DAYS: i64 = 719468
223const AL_DAYS_PER_ERA: i64 = 146097
224const AL_YEARS_PER_ERA: i64 = 400
225const AL_DAYS_4Y: i64 = 1460
226const AL_DAYS_100Y: i64 = 36524
227const AL_DAYS_400Y_LESS1: i64 = 146096
228const AL_DAYS_YEAR: i64 = 365
229const AL_LEAP_4: i64 = 4
230const AL_LEAP_100: i64 = 100
231const AL_MP_MUL: i64 = 5
232const AL_MP_ADD: i64 = 2
233const AL_MP_DIV: i64 = 153
234const AL_MONTH_WRAP: i64 = 10
235const AL_MONTH_ADD: i64 = 3
236const AL_MONTH_SUB: i64 = 9
237const AL_FEB: i64 = 2
238const AL_TWO_DIGITS: i64 = 10
239
240// ---- tiny string kit --------------------------------------------------------------------------------------------
241func al_slen(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n }
242func 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 }
243func al_catsl(d: *u8, o: i64, s: *u8, so: i64, n: i64) -> i64 { var i: i64 = 0; var p: i64 = o; while i < n { d[p] = s[so + i]; p = p + 1; i = i + 1 } return p }
244func al_catn(d: *u8, o: i64, v: i64) -> i64 {
245 var m: i64 = v
246 var p: i64 = o
247 if m < 0 { d[p] = AL_MINUS as u8; p = p + 1; m = 0 - m }
248 let t: *u8 = sys_mmap(AL_NUMCAP)
249 var k: i64 = 0
250 if m == 0 { t[0] = AL_D0 as u8; k = 1 }
251 while m > 0 { t[k] = (AL_D0 + (m % AL_BASE10)) as u8; m = m / AL_BASE10; k = k + 1 }
252 var i: i64 = 0
253 while i < k { d[p + i] = t[k - 1 - i]; i = i + 1 }
254 return p + k
255}
256func 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 }
257func al_strcmp(a: *u8, b: *u8) -> i64 { var i: i64 = 0; while a[i] != (0 as u8) { if a[i] != b[i] { return (a[i] as i64) - (b[i] as i64) } i = i + 1 } return 0 - (b[i] as i64) }
258func al_starts(s: *u8, p: *u8) -> i64 { var i: i64 = 0; while p[i] != (0 as u8) { if s[i] != p[i] { return 0 } i = i + 1 } return 1 }
259func al_ends(s: *u8, sfx: *u8) -> i64 {
260 let n: i64 = al_slen(s)
261 let m: i64 = al_slen(sfx)
262 if n < m { return 0 }
263 var k: i64 = 0
264 while k < m { if s[n - m + k] != sfx[k] { return 0 } k = k + 1 }
265 return 1
266}
267// subject identifiers are lowercase [a-z0-9_]+, first byte not a digit -- they become part of a func name
268func al_ident_char(c: i64) -> i64 {
269 if c >= AL_LOWA { if c <= AL_LOWZ { return 1 } }
270 if c >= AL_D0 { if c <= AL_D9 { return 1 } }
271 if c == AL_USCORE { return 1 }
272 return 0
273}
274func al_ident_ok(s: *u8, so: i64, n: i64) -> i64 {
275 if n <= 0 { return 0 }
276 if n >= AL_W_NAME { return 0 }
277 let c0: i64 = s[so] as i64
278 if c0 >= AL_D0 { if c0 <= AL_D9 { return 0 } }
279 var i: i64 = 0
280 while i < n { if al_ident_char(s[so + i] as i64) == 0 { return 0 } i = i + 1 }
281 return 1
282}
283// copy a slice into a fixed-width record field, truncated to width-1 and NUL-terminated
284func al_setf(rec: *u8, off: i64, w: i64, src: *u8, so: i64, n: i64) -> i64 {
285 var m: i64 = n
286 if m > w - 1 { m = w - 1 }
287 var i: i64 = 0
288 while i < m { rec[off + i] = src[so + i]; i = i + 1 }
289 rec[off + m] = 0 as u8
290 return m
291}
292// strict decimal with optional leading minus over a slice; ok[0]=1 when parsed
293func al_parse_int(v: *u8, o: i64, l: i64, ok: *i64) -> i64 {
294 ok[0] = 0
295 if l <= 0 { return 0 }
296 var i: i64 = 0
297 var neg: i64 = 0
298 if (v[o] as i64) == AL_MINUS { neg = 1; i = 1 }
299 var val: i64 = 0
300 var digits: i64 = 0
301 while i < l {
302 let c: i64 = v[o + i] as i64
303 if c < AL_D0 { return 0 }
304 if c > AL_D9 { return 0 }
305 val = val * AL_BASE10 + (c - AL_D0)
306 digits = digits + 1
307 i = i + 1
308 }
309 if digits == 0 { return 0 }
310 ok[0] = 1
311 if neg == 1 { return 0 - val }
312 return val
313}
314// exact token membership in a comma-separated list
315func al_list_has(list: *u8, tok: *u8) -> i64 {
316 if (list as i64) == 0 { return 0 }
317 let tl: i64 = al_slen(tok)
318 if tl == 0 { return 0 }
319 var s: i64 = 0
320 var i: i64 = 0
321 var going: i64 = 1
322 while going == 1 {
323 var atend: i64 = 0
324 if list[i] == (0 as u8) { atend = 1 } else { if (list[i] as i64) == AL_COMMA { atend = 1 } }
325 if atend == 1 {
326 if i - s == tl {
327 var same: i64 = 1
328 var k: i64 = 0
329 while k < tl { if list[s + k] != tok[k] { same = 0; k = tl } else { k = k + 1 } }
330 if same == 1 { return 1 }
331 }
332 if list[i] == (0 as u8) { going = 0 }
333 s = i + 1
334 }
335 i = i + 1
336 }
337 return 0
338}
339// YYYY-MM-DD from epoch seconds (UTC), written NUL-terminated; returns the length
340func al_civil_date(epoch_s: i64, out: *u8) -> i64 {
341 var days: i64 = epoch_s / AL_SEC_PER_DAY
342 let z: i64 = days + AL_EPOCH_SHIFT_DAYS
343 var zz: i64 = z
344 if z < 0 { zz = z - AL_DAYS_400Y_LESS1 }
345 let era: i64 = zz / AL_DAYS_PER_ERA
346 let doe: i64 = z - era * AL_DAYS_PER_ERA
347 let yoe: i64 = (doe - doe / AL_DAYS_4Y + doe / AL_DAYS_100Y - doe / AL_DAYS_400Y_LESS1) / AL_DAYS_YEAR
348 var y: i64 = yoe + era * AL_YEARS_PER_ERA
349 let doy: i64 = doe - (AL_DAYS_YEAR * yoe + yoe / AL_LEAP_4 - yoe / AL_LEAP_100)
350 let mp: i64 = (AL_MP_MUL * doy + AL_MP_ADD) / AL_MP_DIV
351 let d: i64 = doy - (AL_MP_DIV * mp + AL_MP_ADD) / AL_MP_MUL + 1
352 var m: i64 = mp + AL_MONTH_ADD
353 if mp >= AL_MONTH_WRAP { m = mp - AL_MONTH_SUB }
354 if m <= AL_FEB { y = y + 1 }
355 var o: i64 = al_catn(out, 0, y)
356 out[o] = AL_MINUS as u8; o = o + 1
357 if m < AL_TWO_DIGITS { out[o] = AL_D0 as u8; o = o + 1 }
358 o = al_catn(out, o, m)
359 out[o] = AL_MINUS as u8; o = o + 1
360 if d < AL_TWO_DIGITS { out[o] = AL_D0 as u8; o = o + 1 }
361 o = al_catn(out, o, d)
362 out[o] = 0 as u8
363 return o
364}
365
366// ---- the BOOK: every subject the three planes mention, with its three signatures -------------------------
367func al_bk_new() -> *i64 {
368 let bk: *i64 = sys_mmap(8 * AL_BK_WORDS) as *i64
369 var i: i64 = 0
370 while i < AL_BK_WORDS { bk[i] = 0; i = i + 1 }
371 bk[AL_B_INTS] = sys_mmap(8 * AL_IW * AL_MAX_SUBJ) as i64
372 bk[AL_B_STRS] = sys_mmap(AL_REC * AL_MAX_SUBJ) as i64
373 bk[AL_B_ACC_PATH] = sys_mmap(AL_PATHCAP) as i64
374 bk[AL_B_REF_PATH] = sys_mmap(AL_PATHCAP) as i64
375 bk[AL_B_ATT_PATH] = sys_mmap(AL_PATHCAP) as i64
376 return bk
377}
378func al_bk_rec(bk: *i64, i: i64) -> *u8 { return (bk[AL_B_STRS] + i * AL_REC) as *u8 }
379func al_bk_ints(bk: *i64, i: i64) -> *i64 { return (bk[AL_B_INTS] + i * AL_IW * 8) as *i64 }
380func al_bk_name(bk: *i64, i: i64) -> *u8 { return (bk[AL_B_STRS] + i * AL_REC + AL_F_NAME) as *u8 }
381func al_bk_find(bk: *i64, name: *u8, so: i64, n: i64) -> i64 {
382 var i: i64 = 0
383 while i < bk[AL_B_N] {
384 let nm: *u8 = al_bk_name(bk, i)
385 if cw_field_eq(name, so, n, nm) == 1 { return i }
386 i = i + 1
387 }
388 return 0 - 1
389}
390func al_bk_find_z(bk: *i64, z: *u8) -> i64 { return al_bk_find(bk, z, 0, al_slen(z)) }
391// find-or-add; -1 when the book is full (counted in AL_B_OVERFLOW, announced by every reader)
392func al_bk_get(bk: *i64, name: *u8, so: i64, n: i64) -> i64 {
393 let f: i64 = al_bk_find(bk, name, so, n)
394 if f >= 0 { return f }
395 if bk[AL_B_N] >= AL_MAX_SUBJ { bk[AL_B_OVERFLOW] = bk[AL_B_OVERFLOW] + 1; return 0 - 1 }
396 let i: i64 = bk[AL_B_N]
397 let it: *i64 = al_bk_ints(bk, i)
398 var k: i64 = 0
399 while k < AL_IW { it[k] = 0; k = k + 1 }
400 let rec: *u8 = al_bk_rec(bk, i)
401 var z: i64 = 0
402 while z < AL_REC { rec[z] = 0 as u8; z = z + 1 }
403 al_setf(rec, AL_F_NAME, AL_W_NAME, name, so, n)
404 bk[AL_B_N] = i + 1
405 return i
406}
407
408// every ga_accept_<ident> token inside a targets slice -> subject indices (find-or-add). A token counts only at a
409// boundary (slice start, ',', ':' or ' '), so a longer identifier sharing the prefix is not a match.
410func al_targets_subjects(bk: *i64, v: *u8, o: i64, l: i64, idx: *i64, cap: i64) -> i64 {
411 let pf: *u8 = AL_SYM_PFX
412 let pl: i64 = al_slen(pf)
413 var found: i64 = 0
414 var i: i64 = o
415 let e: i64 = o + l
416 while i + pl <= e {
417 var m: i64 = 1
418 var j: i64 = 0
419 while j < pl { if v[i + j] != pf[j] { m = 0; j = pl } else { j = j + 1 } }
420 var advanced: i64 = 0
421 if m == 1 {
422 var bd: i64 = 0
423 if i == o { bd = 1 } else {
424 let pc: i64 = v[i - 1] as i64
425 if pc == AL_COMMA { bd = 1 }
426 if pc == AL_COLON { bd = 1 }
427 if pc == AL_SPACE { bd = 1 }
428 }
429 if bd == 1 {
430 var k: i64 = i + pl
431 var run: i64 = 1
432 while run == 1 { if k < e { if al_ident_char(v[k] as i64) == 1 { k = k + 1 } else { run = 0 } } else { run = 0 } }
433 let nl: i64 = k - (i + pl)
434 if al_ident_ok(v, i + pl, nl) == 1 {
435 let si: i64 = al_bk_get(bk, v, i + pl, nl)
436 if si >= 0 { if found < cap { idx[found] = si; found = found + 1 } }
437 } else { bk[AL_B_BADNAME] = bk[AL_B_BADNAME] + 1 }
438 i = k
439 advanced = 1
440 }
441 }
442 if advanced == 0 { i = i + 1 }
443 }
444 return found
445}
446// does a NUL-terminated targets string already carry ga_accept_<subject> as a whole token?
447func al_has_token(targets: *u8, subject: *u8) -> i64 {
448 let bk: *i64 = al_bk_new()
449 let idx: *i64 = sys_mmap(8 * AL_MAX_TOK) as *i64
450 al_targets_subjects(bk, targets, 0, al_slen(targets), idx, AL_MAX_TOK)
451 if al_bk_find_z(bk, subject) >= 0 { return 1 }
452 return 0
453}
454
455// ---- plane resolution: a relative prefix from the caller's CWD first, then the estate root ------------------
456// (the banked planepeek/census trap: a bare or mis-rooted prefix reads a populated plane as EMPTY). The
457// resolved prefix is copied into out either way; the return says whether ANY segment resolved there.
458func al_plane_resolve(rel: *u8, out: *u8) -> i64 {
459 let st: *i64 = ss_cur_open(rel)
460 var o: i64 = al_cat(out, 0, rel)
461 out[o] = 0 as u8
462 if st[1] > 0 { return 1 }
463 if (rel[0] as i64) != AL_SLASH {
464 o = al_cat(out, 0, EP_ROOT)
465 o = al_cat(out, o, rel)
466 out[o] = 0 as u8
467 let st2: *i64 = ss_cur_open(out)
468 if st2[1] > 0 { return 1 }
469 o = al_cat(out, 0, rel)
470 out[o] = 0 as u8
471 }
472 return 0
473}
474// advance the cursor to the next LIVE data record. q:n and foreign keys and tombstones are counted, never folded
475// into the rows. sc[0..3] = key ptr, key len, value ptr, value len.
476func al_next(bk: *i64, pfx: *u8, cur: *i64, sc: *i64) -> i64 {
477 var going: i64 = 1
478 while going == 1 {
479 let r: i64 = ss_cur_next(pfx, cur, sc, ((sc as i64) + 8) as *i64, ((sc as i64) + 16) as *i64, ((sc as i64) + 24) as *i64)
480 if r == 0 { return 0 }
481 let kidx: i64 = cw_key_idx(sc[0] as *u8, sc[1])
482 if kidx == CW_KEY_FOREIGN { bk[AL_B_FOREIGN] = bk[AL_B_FOREIGN] + 1 } else {
483 if kidx != CW_KEY_COUNT {
484 if cur[6] == AL_KIND_TOMB { bk[AL_B_TOMB] = bk[AL_B_TOMB] + 1 } else { return 1 }
485 }
486 }
487 }
488 return 0
489}
490
491// ---- NEWEST-WINS ROW ITERATION (2026-08-31) ---------------------------------------------------------------
492// The raw cursor (al_next) visits EVERY RECORD IN EVERY SEGMENT, and a plane written by nx_store_put -- which
493// re-seeds the whole plane on every put -- carries one full copy of itself per write. MEASURED on the live
494// accept- plane the first time `nx_accept emit` ran: 5 operator rows read as 15 records (1+2+3+4+5), every
495// counter tripled and every UNMAPPED row printed once per surviving version. The verdicts were right only
496// because the newest copy happened to be visited last -- a correct answer standing on segment order, not on
497// a rule. sts_load_fit is the estate's canonical row reader (q:0..q:n-1, newest version per key, tombstoned
498// keys dropped): the same path nx_store_put itself takes on every write, so the counts below are counts of
499// ROWS, never of versions. al_next is kept for readers that need the raw record stream (foreign keys,
500// tombstones); the three walks and the verb-side helpers read rows through this pair.
501// ROW ORDER IS WRITE ORDER: nx_store_put removes a replaced id and appends the new row at the end, so the
502// last row seen for a subject is the latest write -- the date column is printed, never trusted for ordering.
503const AL_RS_WORDS: i64 = 4
504const AL_RS_BUF: i64 = 0
505const AL_RS_LEN: i64 = 1
506const AL_RS_POS: i64 = 2
507func al_rows_open(pfx: *u8) -> *i64 {
508 let rs: *i64 = sys_mmap(8 * AL_RS_WORDS) as *i64
509 let lp: *i64 = sys_mmap(16) as *i64
510 lp[0] = 0
511 let b: *u8 = sts_load_fit(pfx, lp)
512 rs[AL_RS_BUF] = b as i64
513 rs[AL_RS_LEN] = lp[0]
514 rs[AL_RS_POS] = 0
515 if (b as i64) == 0 { rs[AL_RS_LEN] = 0 }
516 return rs
517}
518// next non-empty row: sc[2] = value ptr, sc[3] = value len (the same slots the cursor walk filled)
519func al_rows_next(rs: *i64, sc: *i64) -> i64 {
520 let b: *u8 = rs[AL_RS_BUF] as *u8
521 let n: i64 = rs[AL_RS_LEN]
522 var p: i64 = rs[AL_RS_POS]
523 while p < n {
524 var e: i64 = p
525 while e < n { if (b[e] as i64) == AL_NL { break } e = e + 1 }
526 var el: i64 = e
527 if el > p { if (b[el - 1] as i64) == AL_CR { el = el - 1 } }
528 rs[AL_RS_POS] = e + 1
529 if el > p {
530 sc[2] = (b as i64) + p
531 sc[3] = el - p
532 return 1
533 }
534 p = e + 1
535 }
536 rs[AL_RS_POS] = n
537 return 0
538}
539
540func al_walk_accept(bk: *i64, pfx: *u8) -> i64 {
541 let cur: *i64 = al_rows_open(pfx)
542 if cur[AL_RS_LEN] <= 0 { return 0 }
543 bk[AL_B_ACC_PLANE] = 1
544 let sc: *i64 = sys_mmap(8 * AL_SC_WORDS) as *i64
545 let f: *i64 = sys_mmap(16) as *i64
546 let idx: *i64 = sys_mmap(8 * AL_MAX_TOK) as *i64
547 while al_rows_next(cur, sc) == 1 {
548 let v: *u8 = sc[2] as *u8
549 let vl: i64 = sc[3]
550 bk[AL_B_ACC_ROWS] = bk[AL_B_ACC_ROWS] + 1
551 if cw_field(v, vl, AL_AF_TARGETS, f) == 0 { bk[AL_B_MALFORMED] = bk[AL_B_MALFORMED] + 1 } else {
552 let nt: i64 = al_targets_subjects(bk, v, f[0], f[1], idx, AL_MAX_TOK)
553 if nt == 0 { bk[AL_B_UNMAPPED] = bk[AL_B_UNMAPPED] + 1 } else {
554 var vc: i64 = AL_V_INVALID
555 if cw_field(v, vl, AL_AF_VERDICT, f) == 1 {
556 if cw_field_eq(v, f[0], f[1], "ACCEPT" as *u8) == 1 { vc = AL_V_ACCEPT }
557 if cw_field_eq(v, f[0], f[1], "REJECT" as *u8) == 1 { vc = AL_V_REJECT }
558 if cw_field_eq(v, f[0], f[1], "UNJUDGED" as *u8) == 1 { vc = AL_V_UNJUDGED }
559 }
560 var isop: i64 = 0
561 if cw_field(v, vl, AL_AF_ACTOR, f) == 1 { if cw_field_eq(v, f[0], f[1], AL_ACTOR_OPERATOR) == 1 { isop = 1 } }
562 var t: i64 = 0
563 while t < nt {
564 let si: i64 = idx[t]
565 let it: *i64 = al_bk_ints(bk, si)
566 let rec: *u8 = al_bk_rec(bk, si)
567 it[AL_I_ANYV] = vc
568 if isop == 1 {
569 it[AL_I_OPV] = vc
570 it[AL_I_OPSEEN] = it[AL_I_OPSEEN] + 1
571 if cw_field(v, vl, AL_AF_ID, f) == 1 { al_setf(rec, AL_F_OPID, AL_W_OPID, v, f[0], f[1]) }
572 if cw_field(v, vl, AL_AF_DATE, f) == 1 { al_setf(rec, AL_F_OPDATE, AL_W_DATE, v, f[0], f[1]) }
573 if cw_field(v, vl, AL_AF_ACTOR, f) == 1 { al_setf(rec, AL_F_OPACTOR, AL_W_ACTOR, v, f[0], f[1]) }
574 }
575 t = t + 1
576 }
577 }
578 }
579 }
580 return 1
581}
582func al_walk_referee(bk: *i64, pfx: *u8) -> i64 {
583 let cur: *i64 = al_rows_open(pfx)
584 if cur[AL_RS_LEN] <= 0 { return 0 }
585 bk[AL_B_REF_PLANE] = 1
586 let sc: *i64 = sys_mmap(8 * AL_SC_WORDS) as *i64
587 let f: *i64 = sys_mmap(16) as *i64
588 let ok: *i64 = sys_mmap(16) as *i64
589 while al_rows_next(cur, sc) == 1 {
590 let v: *u8 = sc[2] as *u8
591 let vl: i64 = sc[3]
592 bk[AL_B_REF_ROWS] = bk[AL_B_REF_ROWS] + 1
593 if cw_field(v, vl, AL_RF_SEAT, f) == 0 { bk[AL_B_MALFORMED] = bk[AL_B_MALFORMED] + 1 } else {
594 cw_field(v, vl, AL_RF_SUBJECT, f)
595 if al_ident_ok(v, f[0], f[1]) == 0 { bk[AL_B_BADNAME] = bk[AL_B_BADNAME] + 1 } else {
596 let si: i64 = al_bk_get(bk, v, f[0], f[1])
597 if si >= 0 {
598 let it: *i64 = al_bk_ints(bk, si)
599 let rec: *u8 = al_bk_rec(bk, si)
600 it[AL_I_RSEEN] = it[AL_I_RSEEN] + 1
601 var comp: i64 = AL_R_INVALID
602 if cw_field(v, vl, AL_RF_COMP, f) == 1 {
603 if cw_field_eq(v, f[0], f[1], "GOOD" as *u8) == 1 { comp = AL_R_GOOD }
604 if cw_field_eq(v, f[0], f[1], "BAD" as *u8) == 1 { comp = AL_R_BAD }
605 }
606 var p: i64 = 0
607 if cw_field(v, vl, AL_RF_PERCEPT, f) == 1 { p = al_parse_int(v, f[0], f[1], ok); if ok[0] == 0 { comp = AL_R_INVALID } }
608 it[AL_I_RCOMP] = comp
609 it[AL_I_RPERCEPT] = p
610 if cw_field(v, vl, AL_RF_TIER, f) == 1 { al_setf(rec, AL_F_RTIER, AL_W_TIER, v, f[0], f[1]) }
611 if cw_field(v, vl, AL_RF_SHA, f) == 1 { al_setf(rec, AL_F_RSHA, AL_W_SHA, v, f[0], f[1]) }
612 if cw_field(v, vl, AL_RF_SEAT, f) == 1 { al_setf(rec, AL_F_RSEAT, AL_W_SEAT, v, f[0], f[1]) }
613 if cw_field(v, vl, AL_RF_DATE, f) == 1 { al_setf(rec, AL_F_RDATE, AL_W_DATE, v, f[0], f[1]) }
614 }
615 }
616 }
617 }
618 return 1
619}
620func al_walk_attest(bk: *i64, pfx: *u8) -> i64 {
621 let cur: *i64 = al_rows_open(pfx)
622 if cur[AL_RS_LEN] <= 0 { return 0 }
623 bk[AL_B_ATT_PLANE] = 1
624 let sc: *i64 = sys_mmap(8 * AL_SC_WORDS) as *i64
625 let f: *i64 = sys_mmap(16) as *i64
626 while al_rows_next(cur, sc) == 1 {
627 let v: *u8 = sc[2] as *u8
628 let vl: i64 = sc[3]
629 bk[AL_B_ATT_ROWS] = bk[AL_B_ATT_ROWS] + 1
630 if cw_field(v, vl, AL_TF_DATE, f) == 0 { bk[AL_B_MALFORMED] = bk[AL_B_MALFORMED] + 1 } else {
631 cw_field(v, vl, AL_TF_SUBJECT, f)
632 if al_ident_ok(v, f[0], f[1]) == 0 { bk[AL_B_BADNAME] = bk[AL_B_BADNAME] + 1 } else {
633 let si: i64 = al_bk_get(bk, v, f[0], f[1])
634 if si >= 0 {
635 let it: *i64 = al_bk_ints(bk, si)
636 let rec: *u8 = al_bk_rec(bk, si)
637 it[AL_I_ASEEN] = it[AL_I_ASEEN] + 1
638 var usable: i64 = 1
639 if cw_field(v, vl, AL_TF_SEAT, f) == 1 { if f[1] <= 0 { usable = 0 } al_setf(rec, AL_F_ASEAT, AL_W_SEAT, v, f[0], f[1]) } else { usable = 0 }
640 if cw_field(v, vl, AL_TF_STAMP, f) == 1 { if f[1] <= 0 { usable = 0 } al_setf(rec, AL_F_ASTAMP, AL_W_STAMP, v, f[0], f[1]) } else { usable = 0 }
641 if cw_field(v, vl, AL_TF_DATE, f) == 1 { al_setf(rec, AL_F_ADATE, AL_W_DATE, v, f[0], f[1]) }
642 it[AL_I_ATT] = usable
643 }
644 }
645 }
646 }
647 return 1
648}
649// load all three planes (each resolved CWD-first, then estate root). Returns the number of planes that resolved.
650func al_load(bk: *i64, pfx_acc: *u8, pfx_ref: *u8, pfx_att: *u8) -> i64 {
651 var n: i64 = 0
652 n = n + al_plane_resolve(pfx_acc, bk[AL_B_ACC_PATH] as *u8)
653 n = n + al_plane_resolve(pfx_ref, bk[AL_B_REF_PATH] as *u8)
654 n = n + al_plane_resolve(pfx_att, bk[AL_B_ATT_PATH] as *u8)
655 al_walk_accept(bk, bk[AL_B_ACC_PATH] as *u8)
656 al_walk_referee(bk, bk[AL_B_REF_PATH] as *u8)
657 al_walk_attest(bk, bk[AL_B_ATT_PATH] as *u8)
658 return n
659}
660
661// ---- the panel conf + its admission receipt: the ONLY source of the GOOD floor -----------------------------
662func al_conf_load(conf_rel: *u8) -> *i64 {
663 let cf: *i64 = sys_mmap(8 * AL_CF_WORDS) as *i64
664 var i: i64 = 0
665 while i < AL_CF_WORDS { cf[i] = 0; i = i + 1 }
666 let path: *u8 = sys_mmap(AL_PATHCAP)
667 path[0] = 0 as u8
668 cf[AL_C_PATH] = path as i64
669 let rpath: *u8 = sys_mmap(AL_PATHCAP)
670 rpath[0] = 0 as u8
671 cf[AL_C_RPATH] = rpath as i64
672 let ta: *u8 = sys_mmap(AL_LISTCAP)
673 ta[0] = 0 as u8
674 cf[AL_C_TADM] = ta as i64
675 let tl: *u8 = sys_mmap(AL_LISTCAP)
676 tl[0] = 0 as u8
677 cf[AL_C_TIERS] = tl as i64
678 if ep_artifact_path(path, conf_rel) == 0 { return cf }
679 let ln: *i64 = sys_mmap(16) as *i64
680 let b: *u8 = sys_read_file(path, ln)
681 if (b as i64) == 0 { return cf }
682 cf[AL_C_BUF] = b as i64
683 cf[AL_C_LEN] = ln[0]
684 cf[AL_C_CONF_OK] = 1
685 let rrel: *u8 = sys_mmap(AL_PATHCAP)
686 if lcf_str(b, ln[0], AL_KEY_RECEIPT, rrel, AL_PATHCAP) <= 0 { return cf }
687 if ep_artifact_path(rpath, rrel) == 0 { return cf }
688 let rl: *i64 = sys_mmap(16) as *i64
689 let rb: *u8 = sys_read_file(rpath, rl)
690 if (rb as i64) == 0 { return cf }
691 cf[AL_C_RCPT_OK] = 1
692 let adm: i64 = lcf_int(rb, rl[0], AL_KEY_ADMITTED)
693 if adm == LCF_MISS { cf[AL_C_ADMITTED] = 0 } else { cf[AL_C_ADMITTED] = adm }
694 lcf_str(rb, rl[0], AL_KEY_TIERS_ADMITTED, ta, AL_LISTCAP)
695 lcf_str(rb, rl[0], AL_KEY_TIERS, tl, AL_LISTCAP)
696 return cf
697}
698// floor_percept_<tier> from the conf; LCF_MISS when the conf is unreadable or the tier has no admitted floor
699func al_floor_for_tier(cf: *i64, tier: *u8) -> i64 {
700 if cf[AL_C_CONF_OK] == 0 { return LCF_MISS }
701 if al_slen(tier) == 0 { return LCF_MISS }
702 let key: *u8 = sys_mmap(AL_KEYCAP)
703 var o: i64 = al_cat(key, 0, AL_KEY_FLOOR_PFX)
704 o = al_cat(key, o, tier)
705 key[o] = 0 as u8
706 return lcf_int(cf[AL_C_BUF] as *u8, cf[AL_C_LEN], key)
707}
708// the referee signature for subject si: AL_RC_OK or the FIRST reason it does not hold (floor_out = the bar used)
709func al_ref_check(bk: *i64, cf: *i64, si: i64, floor_out: *i64) -> i64 {
710 floor_out[0] = LCF_MISS
711 let it: *i64 = al_bk_ints(bk, si)
712 let rec: *u8 = al_bk_rec(bk, si)
713 if it[AL_I_RSEEN] == 0 { return AL_RC_MISSING }
714 if it[AL_I_RCOMP] == AL_R_INVALID { return AL_RC_INVALID }
715 if it[AL_I_RCOMP] == AL_R_NONE { return AL_RC_INVALID }
716 if it[AL_I_RCOMP] == AL_R_BAD { return AL_RC_BAD }
717 if cf[AL_C_ADMITTED] != 1 { return AL_RC_PANEL_UNADMITTED }
718 let tier: *u8 = ((rec as i64) + AL_F_RTIER) as *u8
719 if al_list_has(cf[AL_C_TADM] as *u8, tier) == 0 { return AL_RC_TIER_UNADMITTED }
720 let fl: i64 = al_floor_for_tier(cf, tier)
721 if fl == LCF_MISS { return AL_RC_NO_FLOOR }
722 floor_out[0] = fl
723 if it[AL_I_RPERCEPT] < fl { return AL_RC_BELOW_FLOOR }
724 return AL_RC_OK
725}
726// the derived state; why[] carries the three verdict codes and the floor so a caller can NAME what is missing
727func al_state(bk: *i64, cf: *i64, si: i64, why: *i64) -> i64 {
728 let it: *i64 = al_bk_ints(bk, si)
729 let fo: *i64 = sys_mmap(16) as *i64
730 why[AL_WHY_OP] = it[AL_I_OPV]
731 why[AL_WHY_REF] = al_ref_check(bk, cf, si, fo)
732 why[AL_WHY_ATT] = it[AL_I_ATT]
733 why[AL_WHY_FLOOR] = fo[0]
734 if why[AL_WHY_OP] == AL_V_ACCEPT { if why[AL_WHY_REF] == AL_RC_OK { if why[AL_WHY_ATT] == 1 { return AL_ST_ACCEPTED } } }
735 return AL_ST_INCOMPLETE
736}
737func al_vname(c: i64) -> *u8 {
738 if c == AL_V_ACCEPT { return "ACCEPT" as *u8 }
739 if c == AL_V_REJECT { return "REJECT" as *u8 }
740 if c == AL_V_UNJUDGED { return "UNJUDGED" as *u8 }
741 if c == AL_V_INVALID { return "INVALID" as *u8 }
742 return "NONE" as *u8
743}
744func al_rname(c: i64) -> *u8 {
745 if c == AL_R_GOOD { return "GOOD" as *u8 }
746 if c == AL_R_BAD { return "BAD" as *u8 }
747 if c == AL_R_INVALID { return "INVALID" as *u8 }
748 return "NONE" as *u8
749}
750func al_rcname(c: i64) -> *u8 {
751 if c == AL_RC_OK { return "OK" as *u8 }
752 if c == AL_RC_MISSING { return "REF-MISSING" as *u8 }
753 if c == AL_RC_BAD { return "REF-BAD" as *u8 }
754 if c == AL_RC_INVALID { return "REF-INVALID-ROW" as *u8 }
755 if c == AL_RC_TIER_UNADMITTED { return "REF-TIER-UNADMITTED" as *u8 }
756 if c == AL_RC_NO_FLOOR { return "REF-NO-FLOOR-FOR-TIER" as *u8 }
757 if c == AL_RC_BELOW_FLOOR { return "REF-PERCEPT-BELOW-FLOOR" as *u8 }
758 return "REF-PANEL-UNADMITTED" as *u8
759}
760func al_stname(c: i64) -> *u8 {
761 if c == AL_ST_ACCEPTED { return "ACCEPTED" as *u8 }
762 if c == AL_ST_INCOMPLETE { return "INCOMPLETE" as *u8 }
763 return "UNKNOWN" as *u8
764}
765
766// ---- the generated declaration file, DERIVED and DETERMINISTIC ---------------------------------------------
767// Deliberately no timestamp: two emits over the same planes must be byte-identical, which is what lets the gate
768// convict a hand edit by re-derivation. Accepted subjects are emitted in NAME order, not plane order, so a plane
769// rewrite that reorders rows cannot move the bytes either.
770func al_emit_buf(bk: *i64, cf: *i64, out: *u8, cap: i64) -> i64 {
771 var o: i64 = 0
772 o = al_cat(out, o, "// nx_accept_decl.nx -- GENERATED ACCEPTANCE DECLARATIONS. <" as *u8)
773 out[o] = AL_BANG as u8
774 o = o + 1
775 o = al_cat(out, o, "-- NX-DERIVED: regenerated artefact, not authored memory -->\n" as *u8)
776 o = al_cat(out, o, "// WRITTEN ONLY BY `nx_accept emit` from knowledge/store/accept- + referee- + attest- and the panel floors in\n" as *u8)
777 o = al_cat(out, o, "// knowledge/cjc_panel.conf (per-tier floor_percept_<tier>; receipt admitted + tiers_admitted). One top-level\n" as *u8)
778 o = al_cat(out, o, "// declaration ga_accept_<subject> exists here iff the THREE-PARTY RULE holds for <subject>: latest operator row\n" as *u8)
779 o = al_cat(out, o, "// ACCEPT AND latest referee row GOOD at or above the admitted per-tier floor AND a seat attestation row. Nothing\n" as *u8)
780 o = al_cat(out, o, "// else is declared. The /compare regen measures this file like any organ (column-0 declaration), so an ACCEPTANCE\n" as *u8)
781 o = al_cat(out, o, "// watch row flips ONLY on agreement. A hand-written declaration is convicted by nx_accept_gate (re-derivation must\n" as *u8)
782 o = al_cat(out, o, "// equal these bytes) and erased by the next emit. Do not edit; run `nx_accept emit`.\n" as *u8)
783 let ord: *i64 = sys_mmap(8 * AL_MAX_SUBJ) as *i64
784 let why: *i64 = sys_mmap(8 * 8) as *i64
785 var na: i64 = 0
786 var i: i64 = 0
787 while i < bk[AL_B_N] {
788 if al_state(bk, cf, i, why) == AL_ST_ACCEPTED { ord[na] = i; na = na + 1 }
789 i = i + 1
790 }
791 // selection sort by subject name
792 var a: i64 = 0
793 while a < na {
794 var best: i64 = a
795 var b2: i64 = a + 1
796 while b2 < na {
797 if al_strcmp(al_bk_name(bk, ord[b2]), al_bk_name(bk, ord[best])) < 0 { best = b2 }
798 b2 = b2 + 1
799 }
800 if best != a { let t: i64 = ord[a]; ord[a] = ord[best]; ord[best] = t }
801 a = a + 1
802 }
803 if na == 0 { o = al_cat(out, o, "// (no subject currently satisfies the three-party rule -- no declarations emitted)\n" as *u8) }
804 var k: i64 = 0
805 while k < na {
806 if o + AL_LINE_MAX >= cap { return 0 - 1 }
807 let si: i64 = ord[k]
808 let rec: *u8 = al_bk_rec(bk, si)
809 let it: *i64 = al_bk_ints(bk, si)
810 al_state(bk, cf, si, why)
811 o = al_cat(out, o, "// ACCEPTED " as *u8)
812 o = al_cat(out, o, al_bk_name(bk, si))
813 o = al_cat(out, o, ": operator=" as *u8)
814 o = al_cat(out, o, ((rec as i64) + AL_F_OPID) as *u8)
815 o = al_cat(out, o, " (" as *u8)
816 o = al_cat(out, o, ((rec as i64) + AL_F_OPDATE) as *u8)
817 o = al_cat(out, o, ") referee=frame:" as *u8)
818 o = al_cat(out, o, ((rec as i64) + AL_F_RSHA) as *u8)
819 o = al_cat(out, o, " percept=" as *u8)
820 o = al_catn(out, o, it[AL_I_RPERCEPT])
821 o = al_cat(out, o, " floor=" as *u8)
822 o = al_catn(out, o, why[AL_WHY_FLOOR])
823 o = al_cat(out, o, " tier=" as *u8)
824 o = al_cat(out, o, ((rec as i64) + AL_F_RTIER) as *u8)
825 o = al_cat(out, o, " by=" as *u8)
826 o = al_cat(out, o, ((rec as i64) + AL_F_RSEAT) as *u8)
827 o = al_cat(out, o, " (" as *u8)
828 o = al_cat(out, o, ((rec as i64) + AL_F_RDATE) as *u8)
829 o = al_cat(out, o, ") attest=" as *u8)
830 o = al_cat(out, o, ((rec as i64) + AL_F_ASEAT) as *u8)
831 o = al_cat(out, o, " stamp=" as *u8)
832 o = al_cat(out, o, ((rec as i64) + AL_F_ASTAMP) as *u8)
833 o = al_cat(out, o, " (" as *u8)
834 o = al_cat(out, o, ((rec as i64) + AL_F_ADATE) as *u8)
835 o = al_cat(out, o, ")\n" as *u8)
836 o = al_cat(out, o, "func " as *u8)
837 o = al_cat(out, o, AL_SYM_PFX)
838 o = al_cat(out, o, al_bk_name(bk, si))
839 o = al_cat(out, o, "() -> i64 { return 1 }\n" as *u8)
840 k = k + 1
841 }
842 out[o] = 0 as u8
843 return o
844}
845// how many ACCEPTED subjects the book holds under this conf
846func al_count_accepted(bk: *i64, cf: *i64) -> i64 {
847 let why: *i64 = sys_mmap(8 * 8) as *i64
848 var n: i64 = 0
849 var i: i64 = 0
850 while i < bk[AL_B_N] { if al_state(bk, cf, i, why) == AL_ST_ACCEPTED { n = n + 1 } i = i + 1 }
851 return n
852}
853// compare the on-disk declaration file with a fresh derivation: IDENTICAL / DIFFERS / ABSENT / CAP
854func al_decl_verify(bk: *i64, cf: *i64, path: *u8) -> i64 {
855 let want: *u8 = sys_mmap(AL_DECL_CAP)
856 let wn: i64 = al_emit_buf(bk, cf, want, AL_DECL_CAP)
857 if wn < 0 { return AL_DV_CAP }
858 let ln: *i64 = sys_mmap(16) as *i64
859 let b: *u8 = sys_read_file(path, ln)
860 if (b as i64) == 0 { return AL_DV_ABSENT }
861 if ln[0] != wn { return AL_DV_DIFFERS }
862 var i: i64 = 0
863 while i < wn { if b[i] != want[i] { return AL_DV_DIFFERS } i = i + 1 }
864 return AL_DV_IDENTICAL
865}
866func al_dvname(c: i64) -> *u8 {
867 if c == AL_DV_IDENTICAL { return "IDENTICAL" as *u8 }
868 if c == AL_DV_DIFFERS { return "DIFFERS" as *u8 }
869 if c == AL_DV_ABSENT { return "ABSENT" as *u8 }
870 return "CAP-EXCEEDED" as *u8
871}
872// tmp + fsync + rename: the file is either the old bytes or the new bytes, never a prefix
873func al_write_atomic(path: *u8, buf: *u8, n: i64) -> i64 {
874 let tmp: *u8 = sys_mmap(AL_PATHCAP)
875 var o: i64 = al_cat(tmp, 0, path)
876 o = al_cat(tmp, o, AL_TMP_SFX)
877 tmp[o] = 0 as u8
878 let fd: i64 = sys_openat_wr(tmp, MODE_0644)
879 if fd < 0 { return 0 - 1 }
880 var off: i64 = 0
881 while off < n {
882 let r: i64 = sys_write(fd, ((buf as i64) + off) as *u8, n - off)
883 if r <= 0 { sys_close(fd); return 0 - 2 }
884 off = off + r
885 }
886 sys_fsync(fd)
887 sys_close(fd)
888 if sys_renameat(tmp, path) != 0 { return 0 - 3 }
889 return 0
890}
891// count column-0 `func ga_accept_` declarations in a buffer -- the regen's own rule, used as a denominator
892func al_count_decls(b: *u8, n: i64) -> i64 {
893 let pf: *u8 = sys_mmap(AL_KEYCAP)
894 var o: i64 = al_cat(pf, 0, "func " as *u8)
895 o = al_cat(pf, o, AL_SYM_PFX)
896 pf[o] = 0 as u8
897 let pl: i64 = o
898 var cnt: i64 = 0
899 var i: i64 = 0
900 while i + pl <= n {
901 var bol: i64 = 0
902 if i == 0 { bol = 1 } else { if (b[i - 1] as i64) == AL_NL { bol = 1 } }
903 if bol == 1 {
904 var m: i64 = 1
905 var j: i64 = 0
906 while j < pl { if b[i + j] != pf[j] { m = 0; j = pl } else { j = j + 1 } }
907 if m == 1 { cnt = cnt + 1 }
908 }
909 i = i + 1
910 }
911 return cnt
912}
913// where the declaration file lives: beside this lib, resolved CWD-independently through the sibling that MUST
914// exist (a probe for the decl file itself would fail before the first emit)
915func al_decl_path(out: *u8) -> i64 {
916 if ep_artifact_path(out, AL_DECL_SIBLING) == 0 { out[0] = 0 as u8; return 0 }
917 var n: i64 = al_slen(out)
918 let sib: i64 = al_slen("nx_accept_lib.nx" as *u8)
919 n = n - sib
920 let o: i64 = al_cat(out, n, AL_DECL_BASENAME)
921 out[o] = 0 as u8
922 return 1
923}
924// the boards directory, CWD-first then the buildroot tree
925func al_boards_dir(out: *u8) -> i64 {
926 var fd: i64 = sys_openat_rd(AL_BOARDS_DIR)
927 if fd >= 0 { sys_close(fd); al_cat(out, 0, AL_BOARDS_DIR); out[al_slen(AL_BOARDS_DIR)] = 0 as u8; return 1 }
928 var o: i64 = al_cat(out, 0, EP_BUILDROOT)
929 o = al_cat(out, o, AL_BOARDS_DIR_FROM_BUILDROOT)
930 out[o] = 0 as u8
931 fd = sys_openat_rd(out)
932 if fd >= 0 { sys_close(fd); return 1 }
933 out[0] = 0 as u8
934 return 0
935}
936// one board: every row whose symbol (watch or landed form) is ga_accept_<ident> -> (subject, domain, organ)
937func al_scan_one_board(dir: *u8, nm: *u8, subj: *u8, doms: *u8, orgs: *u8, cap: i64, count0: i64, over: *i64) -> i64 {
938 var count: i64 = count0
939 let path: *u8 = sys_mmap(AL_PATHCAP)
940 var o: i64 = al_cat(path, 0, dir)
941 path[o] = AL_SLASH as u8
942 o = o + 1
943 o = al_cat(path, o, nm)
944 path[o] = 0 as u8
945 let ln: *i64 = sys_mmap(16) as *i64
946 let b: *u8 = sys_read_file(path, ln)
947 if (b as i64) == 0 { return count }
948 let n: i64 = ln[0]
949 let pf: *u8 = AL_SYM_PFX
950 let pl: i64 = al_slen(pf)
951 let wl: i64 = al_slen(AL_WATCH_PFX)
952 let doml: i64 = al_slen(nm) - al_slen(AL_MATRIX_SFX)
953 var p: i64 = 0
954 while p < n {
955 var e: i64 = p
956 while e < n { if (b[e] as i64) == AL_NL { break } e = e + 1 }
957 var skip: i64 = 0
958 if e == p { skip = 1 } else {
959 let c0: i64 = b[p] as i64
960 if c0 == AL_HASH { skip = 1 }
961 if c0 == AL_AT { skip = 1 }
962 }
963 if skip == 0 {
964 // pipes 1..3 bound organ (field 1) and symbol (field 2)
965 var p1: i64 = 0 - 1
966 var p2: i64 = 0 - 1
967 var p3: i64 = e
968 var q: i64 = p
969 var np: i64 = 0
970 while q < e {
971 if (b[q] as i64) == AL_PIPE {
972 np = np + 1
973 if np == 1 { p1 = q }
974 if np == 2 { p2 = q }
975 if np == 3 { p3 = q; q = e }
976 }
977 q = q + 1
978 }
979 if p2 >= 0 {
980 var ss: i64 = p2 + 1
981 var se: i64 = p3
982 if se - ss > wl {
983 var isw: i64 = 1
984 var w: i64 = 0
985 while w < wl { if b[ss + w] != AL_WATCH_PFX[w] { isw = 0; w = wl } else { w = w + 1 } }
986 if isw == 1 { ss = ss + wl }
987 }
988 if se - ss > pl {
989 var m: i64 = 1
990 var j: i64 = 0
991 while j < pl { if b[ss + j] != pf[j] { m = 0; j = pl } else { j = j + 1 } }
992 if m == 1 {
993 if al_ident_ok(b, ss + pl, se - ss - pl) == 1 {
994 if count < cap {
995 al_setf(subj, count * AL_NAMEW, AL_NAMEW, b, ss + pl, se - ss - pl)
996 al_setf(doms, count * AL_NAMEW, AL_NAMEW, nm, 0, doml)
997 al_setf(orgs, count * AL_ORGW, AL_ORGW, b, p1 + 1, p2 - p1 - 1)
998 count = count + 1
999 } else { over[0] = over[0] + 1 }
1000 }
1001 }
1002 }
1003 }
1004 }
1005 p = e + 1
1006 }
1007 return count
1008}
1009// every ACCEPTANCE watch/landed row across all *.matrix boards in dir. -1 when dir is unreadable.
1010func al_scan_boards(dir: *u8, subj: *u8, doms: *u8, orgs: *u8, cap: i64, over: *i64) -> i64 {
1011 over[0] = 0
1012 let fd: i64 = sys_openat_rd(dir)
1013 if fd < 0 { return 0 - 1 }
1014 let db: *u8 = sys_mmap(AL_DENTCAP)
1015 var count: i64 = 0
1016 var more: i64 = 1
1017 while more == 1 {
1018 let n: i64 = sys_getdents64(fd, db, AL_DENTCAP)
1019 if n <= 0 { more = 0 } else {
1020 var off: i64 = 0
1021 while off < n {
1022 let rec: *u8 = ((db as i64) + off) as *u8
1023 let rl: i64 = dirent_reclen(rec)
1024 let nm: *u8 = dirent_name(rec)
1025 if al_ends(nm, AL_MATRIX_SFX) == 1 { count = al_scan_one_board(dir, nm, subj, doms, orgs, cap, count, over) }
1026 if rl <= 0 { off = n } else { off = off + rl }
1027 }
1028 }
1029 }
1030 sys_close(fd)
1031 return count
1032}