code wiki / _hdl_build / nx_capcliff.nx
nx_capcliff.nx source
↩ module page · 619 lines · 39953 B
1// nx_capcliff.nx -- READER-CAP CLIFF DETECTOR for append-only ledgers, WITH THE REMEDY CENSUS (DI13).
2//
3// WHY THIS EXISTS (measured 2026-08-06). Several estate readers capture a ledger into a BOUNDED
4// buffer -- 4 MiB is the recurring number (nx_debt_view declares capture_cap=4194304; nx_catalog
5// reports actlog 4194304B exactly). When the ledger grows PAST that cap the reader keeps working and
6// silently returns a TRUNCATED PREFIX. Two were already over on the day this was written:
7// knowledge/status/actlog.jrnl -- read at offset 4194304 returns bytes and 'more remains', while
8// nx_catalog reports exactly 4194304B. The boundary row is epoch 1785966081 (~21h before), so
9// EVERY INVOCATION SINCE THEN IS INVISIBLE and nx_catalog calls freshly-run organs
10// REGISTERED-DARK (S4) 'callable, authorised, NEVER RUN'. The estate's headline ADOPTION signal
11// was being manufactured by a truncated buffer.
12// knowledge/store/debt- -- nx_plane_check says rows=3326 GREEN bytes=4217666, while nx_debt page
13// reports total=3311 and nx_debt show cannot find the ~15 newest rows.
14//
15// ***BECAUSE THESE LEDGERS ARE APPEND-ONLY, A PREFIX CAP ALWAYS EATS THE NEWEST ROWS FIRST.*** The
16// instrument therefore degrades exactly as new work arrives, and every downstream metric drifts
17// toward 'nothing happened lately'. That is the worst possible failure direction for an adoption or
18// debt gauge, and nothing announced it.
19//
20// This organ makes the cliff PREDICTABLE instead of discovered: it measures each rostered ledger
21// against the cap and reports headroom, so a crossing is forecast rather than found by accident.
22//
23// THE REMEDY CENSUS (DI13, 2026-09-06). An OVER row is a SIZE fact, not a proven reader defect: a
24// TAIL-anchored or whole-file reader loses nothing, a HEAD-anchored one loses the newest rows. So every
25// OVER ledger is now judged against knowledge/capcliff_remedy.conf, rows `ledger|kind|target|note`:
26// reader target = <file:line> of the consumer's READ SITE. The organ READS THAT LINE and classifies
27// it -- WHOLE (sys_read_file), TAIL (SEEK_END or a *_tail( helper), HEAD (a bare sys_read),
28// UNVERIFIED (none of those: a declaration that did not point at a read). The conf declares
29// WHERE to look; the classification is measured, never copied from the row.
30// writer target = <file:line> of the appender (verified: the line must append).
31// guard target = sizeguard:<byte-cliff>:<line-cliff>; nx_sizeguard is FORKED on the ledger with that
32// budget and its exit code is the guard's verdict (0 GREEN 1 AMBER 2 RED 3 UNMEASURED).
33// mention target = a file that names the ledger without reading it (comment, fixture); declared, not judged.
34// Remedy states describe the DECLARED ROSTER, not a complete semantic census of all source consumers.
35// GOVERNED: declared readers are WHOLE/TAIL or guarded GREEN/AMBER; BREACHED: a declared guard reads RED;
36// UNGOVERNED: a declared HEAD/UNVERIFIED reader has no working guard. UNREGISTERED: a readable conf has
37// no matching ledger rows. UNMEASURED: conf unreadable or zero declared readers, including writer-only rows.
38// Zero declared readers cannot prove no actual readers. The legacy NO-READER state code/name is retained
39// for compatibility but no current evidence contract establishes it. Output carries the roster truth scope
40// and semantic_coverage=UNMEASURED. Unknown coverage abstains with exit 3 in remedy and OVER-ledger scan;
41// known UNGOVERNED/BREACHED evidence retains exit 6 precedence. No journal rotation is performed.
42//
43// nx_capcliff scan [roster.conf] [cap_bytes] [remedy.conf]
44// nx_capcliff remedy <ledger> [remedy.conf] one ledger's remedy census, on demand
45// nx_capcliff selftest
46// verdicts: OVER (past the cap) | NEAR (>= NEAR_PERMIL of cap) | OK | MISSING (rostered but absent -- reported,
47// NEVER counted as OK).
48// exit: 0 all OK or every OVER ledger governed | 4 NEAR present | 6 an OVER ledger UNGOVERNED or BREACHED |
49// 3 remedy coverage UNREGISTERED/UNMEASURED | 2 usage | 5 empty roster | selftest: 0 GREEN / 1 RED
50// license_tier: ORIGINAL expect_exit: 0
51import "nx_syscalls.nx"
52import "nx_tool_run.nx"
53import "nx_gate_verdict.nx"
54const CC_MAGIC_4096: i64 = 4096
55
56const CC_CAP_DEFAULT: i64 = 4194304
57const CC_NEAR_PERMIL: i64 = 900
58const CC_MAXROWS: i64 = 256
59const CC_CONFCAP: i64 = 65536
60const CC_EXIT_NEAR: i64 = 4
61const CC_EXIT_OVER: i64 = 6
62const CC_EXIT_EMPTY: i64 = 5
63const CC_EXIT_UNMEASURED: i64 = 3
64const CC_SEEK_END: i64 = 2
65const CC_REMEDY_CONF: *u8 = "knowledge/capcliff_remedy.conf" as *u8
66const CC_SIZEGUARD: *u8 = "./nx_sizeguard.elf" as *u8
67const CC_SIZEGUARD_BUILT: *u8 = "_build/nx_sizeguard.sov.elf" as *u8
68const CC_GUARD_OUT: i64 = 4096
69const CC_LINE_CAP: i64 = 4096
70const CC_MODE_644: i64 = 420
71const CC_MODE_755: i64 = 493
72const CC_FIX_DIR: *u8 = "/tmp/nx_capcliff_recovery_20260912" as *u8
73// anchoring classes (a partition of every declared reader)
74const CC_ANCH_UNVERIFIED: i64 = 0
75const CC_ANCH_WHOLE: i64 = 1
76const CC_ANCH_TAIL: i64 = 2
77const CC_ANCH_HEAD: i64 = 3
78// remedy states
79const CC_ST_UNGOVERNED: i64 = 0
80const CC_ST_GOVERNED: i64 = 1
81const CC_ST_BREACHED: i64 = 2
82const CC_ST_NOREADER: i64 = 3
83const CC_ST_UNREGISTERED: i64 = 4
84const CC_ST_UNMEASURED: i64 = 5
85// guard verdicts mirror nx_sizeguard's exit codes; -1 = no guard declared; -2 = guard binary absent
86const CC_GUARD_NONE: i64 = 0 - 1
87const CC_GUARD_NOELF: i64 = 0 - 2
88const CC_SG_GREEN: i64 = 0
89const CC_SG_AMBER: i64 = 1
90const CC_SG_RED: i64 = 2
91// counts[] slots filled by cc_remedy
92const CC_K_READERS: i64 = 0
93const CC_K_WHOLE: i64 = 1
94const CC_K_TAIL: i64 = 2
95const CC_K_HEAD: i64 = 3
96const CC_K_UNVER: i64 = 4
97const CC_K_WRITERS: i64 = 5
98const CC_K_WUNVER: i64 = 6
99const CC_K_GUARD: i64 = 7
100const CC_K_MENTIONS: i64 = 8
101const CC_K_N: i64 = 9
102
103func cw(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 }
104func cwe(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(2,s,n); return 0 }
105func cwn(v: i64) -> i64 { var m: i64=v; if m<0{cw("-" as *u8);m=0-m} let t:*u8=sys_mmap(28); var k:i64=0; if m==0{t[0]=48 as u8;k=1} while m>0{t[k]=(48+(m%10)) as u8;m=m/10;k=k+1} var i:i64=0; let o:*u8=sys_mmap(28); while i<k{o[i]=t[k-1-i];i=i+1} sys_write(1,o,k); sys_munmap(t,28); sys_munmap(o,28); return 0 }
106func cwb(b: *u8, s: i64, e: i64) -> i64 { if e>s { sys_write(1, (b as i64 + s) as *u8, e-s) } return 0 }
107
108func cc_streq(a: *u8, b: *u8) -> i64 {
109 var i: i64 = 0
110 var r: i64 = 2
111 while r == 2 { if a[i] != b[i] { r = 0 } else { if a[i] == (0 as u8) { r = 1 } else { i = i + 1 } } }
112 return r
113}
114func cc_slen(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n }
115func cc_cat(d: *u8, o: i64, s: *u8) -> i64 { var i: i64 = 0; var oo: i64 = o; while s[i] != (0 as u8) { d[oo] = s[i]; oo = oo + 1; i = i + 1 } d[oo] = 0 as u8; return oo }
116func cc_catn(d: *u8, o: i64, v: i64) -> i64 {
117 var m: i64 = v
118 var oo: i64 = o
119 if m < 0 { d[oo] = 45 as u8; oo = oo + 1; m = 0 - m }
120 let t: *u8 = sys_mmap(32)
121 var k: i64 = 0
122 if m == 0 { t[0] = 48 as u8; k = 1 }
123 while m > 0 { t[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 }
124 while k > 0 { k = k - 1; d[oo] = t[k]; oo = oo + 1 }
125 d[oo] = 0 as u8
126 return oo
127}
128// substring within buf[s,e)
129func cc_span_has(buf: *u8, s: i64, e: i64, lit: *u8) -> i64 {
130 let m: i64 = cc_slen(lit)
131 if m == 0 { return 0 }
132 var i: i64 = s
133 while i + m <= e {
134 var j: i64 = 0
135 var same: i64 = 1
136 while j < m { if buf[i + j] != lit[j] { same = 0; j = m } else { j = j + 1 } }
137 if same == 1 { return 1 }
138 i = i + 1
139 }
140 return 0
141}
142func cc_has(s: *u8, lit: *u8) -> i64 { return cc_span_has(s, 0, cc_slen(s), lit) }
143func cc_span_eq(buf: *u8, s: i64, e: i64, lit: *u8) -> i64 { let ll: i64 = cc_slen(lit); if e - s != ll { return 0 } var i: i64 = 0; while i < ll { if buf[s + i] != lit[i] { return 0 } i = i + 1 } return 1 }
144
145func cc_atoi(s: *u8) -> i64 {
146 var v: i64 = 0
147 var i: i64 = 0
148 while s[i] != (0 as u8) { let c: i64 = s[i]; if c >= 48 { if c <= 57 { v = v*10 + (c - 48) } } i = i + 1 }
149 return v
150}
151// the decimal at buf[s,e), digits only, or -1
152func cc_span_int(buf: *u8, s: i64, e: i64) -> i64 {
153 var v: i64 = 0
154 var nd: i64 = 0
155 var i: i64 = s
156 while i < e { let c: i64 = buf[i] as i64; if c >= 48 { if c <= 57 { v = v * 10 + (c - 48); nd = nd + 1 } } i = i + 1 }
157 if nd == 0 { return 0 - 1 }
158 return v
159}
160
161// SIZE BY lseek(SEEK_END). Returns -1 when the path cannot be opened -- a MISSING ledger must never
162// read as a small one, because 'small' would score OK and hide a roster that points at nothing.
163func cc_size(path: *u8) -> i64 {
164 let fd: i64 = sys_openat_rd(path)
165 if fd < 0 { return 0 - 1 }
166 let sz: i64 = sys_lseek(fd, 0, CC_SEEK_END)
167 sys_close(fd)
168 if sz < 0 { return 0 - 1 }
169 return sz
170}
171
172// copy a NUL-terminated path out of the conf buffer span [s,e) into dst
173func cc_copy(buf: *u8, s: i64, e: i64, dst: *u8) -> i64 {
174 var i: i64 = s
175 var o: i64 = 0
176 while i < e { dst[o] = buf[i]; o = o + 1; i = i + 1 }
177 dst[o] = 0 as u8
178 return o
179}
180// the idx-th '|'-separated field of buf[rs,re): sp[0]=start sp[1]=end; 1 when present
181func cc_field(buf: *u8, rs: i64, re: i64, idx: i64, sp: *i64) -> i64 {
182 var f: i64 = 0
183 var s: i64 = rs
184 var i: i64 = rs
185 while i <= re {
186 var cut: i64 = 0
187 if i == re { cut = 1 } else { if buf[i] == (124 as u8) { cut = 1 } }
188 if cut == 1 {
189 if f == idx { sp[0] = s; sp[1] = i; return 1 }
190 f = f + 1
191 s = i + 1
192 }
193 i = i + 1
194 }
195 return 0
196}
197// index of the newline ending the line that contains p, or n
198func cc_line_end(buf: *u8, n: i64, p: i64) -> i64 { var i: i64 = p; var go: i64 = 1; while go == 1 { if i >= n { go = 0 } else { if buf[i] == (10 as u8) { go = 0 } else { i = i + 1 } } } return i }
199
200// ---- the remedy census (DI13) ------------------------------------------------------------------------------------
201// line ln (1-based) of the file at path, copied to dst (cut at CC_LINE_CAP); -1 when the file or the line is absent
202func cc_read_line(path: *u8, ln: i64, dst: *u8) -> i64 {
203 dst[0] = 0 as u8
204 let l: *i64 = sys_mmap(16) as *i64
205 let b: *u8 = sys_read_file(path, l)
206 if (b as i64) == 0 { return 0 - 1 }
207 let n: i64 = l[0]
208 var cur: i64 = 1
209 var i: i64 = 0
210 while cur < ln { if i >= n { return 0 - 1 } if b[i] == (10 as u8) { cur = cur + 1 } i = i + 1 }
211 if i >= n { return 0 - 1 }
212 let e: i64 = cc_line_end(b, n, i)
213 var o: i64 = 0
214 var k: i64 = i
215 while k < e { if o + 1 < CC_LINE_CAP { dst[o] = b[k]; o = o + 1 } k = k + 1 }
216 dst[o] = 0 as u8
217 return o
218}
219// the anchoring class of ONE read-site line. Order matters: a whole-file read names sys_read_file; a tail read
220// names SEEK_END or a *_tail( helper; a bare sys_read( is head-anchored; anything else did not point at a read.
221func cc_anchor_class(line: *u8) -> i64 {
222 if cc_has(line, "sys_read_file(" as *u8) == 1 { return CC_ANCH_WHOLE }
223 if cc_has(line, "SEEK_END" as *u8) == 1 { return CC_ANCH_TAIL }
224 // the same constant in two spellings is two constants to every scanner: `sys_lseek(fd, 0, 2)` IS SEEK_END
225 if cc_has(line, "sys_lseek(" as *u8) == 1 { if cc_has(line, ", 2)" as *u8) == 1 { return CC_ANCH_TAIL } }
226 if cc_has(line, "_tail(" as *u8) == 1 { return CC_ANCH_TAIL }
227 if cc_has(line, "sys_read(" as *u8) == 1 { return CC_ANCH_HEAD }
228 return CC_ANCH_UNVERIFIED
229}
230func cc_anchor_name(c: i64) -> *u8 {
231 if c == CC_ANCH_WHOLE { return "WHOLE" as *u8 }
232 if c == CC_ANCH_TAIL { return "TAIL" as *u8 }
233 if c == CC_ANCH_HEAD { return "HEAD" as *u8 }
234 return "UNVERIFIED" as *u8
235}
236// split "<file>:<line>" (the LAST colon) into path (NUL-terminated) and the line number; -1 when malformed
237func cc_split_site(spec: *u8, s: i64, e: i64, path: *u8) -> i64 {
238 var c: i64 = e
239 var seek: i64 = 1
240 while seek == 1 { if c <= s { seek = 0 } else { if spec[c - 1] == (58 as u8) { seek = 0 } else { c = c - 1 } } }
241 if c <= s { return 0 - 1 }
242 cc_copy(spec, s, c - 1, path)
243 return cc_span_int(spec, c, e)
244}
245// the anchoring of a declared reader "<file>:<line>": reads that line and classifies it
246func cc_anchoring(spec: *u8, s: i64, e: i64, path: *u8, line: *u8) -> i64 {
247 let ln: i64 = cc_split_site(spec, s, e, path)
248 if ln < 0 { return CC_ANCH_UNVERIFIED }
249 if cc_read_line(path, ln, line) < 0 { return CC_ANCH_UNVERIFIED }
250 return cc_anchor_class(line)
251}
252func cc_exists(path: *u8) -> i64 { let fd: i64 = sys_openat_rd(path); if fd < 0 { return 0 } sys_close(fd); return 1 }
253// FORK nx_sizeguard on the ledger with the declared budget "sizeguard:<bytes>:<lines>"; its exit code is the verdict
254func cc_guard(ledger: *u8, spec: *u8, s: i64, e: i64, out: *u8, olen: *i64) -> i64 {
255 olen[0] = 0
256 if cc_span_has(spec, s, e, "sizeguard:" as *u8) == 0 { return CC_GUARD_NONE }
257 // fields after the verb, ':'-separated: the first ':' ends the verb, the second separates the two budgets
258 var c1: i64 = 0 - 1
259 var c2: i64 = 0 - 1
260 var q: i64 = s
261 while q < e { if spec[q] == (58 as u8) { if c1 < 0 { c1 = q } else { if c2 < 0 { c2 = q } } } q = q + 1 }
262 if c1 < 0 { return CC_GUARD_NONE }
263 if c2 < 0 { return CC_GUARD_NONE }
264 let bytes: i64 = cc_span_int(spec, c1 + 1, c2)
265 let lines: i64 = cc_span_int(spec, c2 + 1, e)
266 if bytes <= 0 { return CC_GUARD_NONE }
267 if lines <= 0 { return CC_GUARD_NONE }
268 var elf: *u8 = CC_SIZEGUARD
269 if cc_exists(elf) == 0 { elf = CC_SIZEGUARD_BUILT }
270 if cc_exists(elf) == 0 { return CC_GUARD_NOELF }
271 let bs: *u8 = sys_mmap(32)
272 let ls: *u8 = sys_mmap(32)
273 cc_catn(bs, 0, bytes)
274 cc_catn(ls, 0, lines)
275 let av: *i64 = sys_mmap(48) as *i64
276 av[0] = elf as i64
277 av[1] = ledger as i64
278 av[2] = bs as i64
279 av[3] = ls as i64
280 av[4] = 0
281 return tr_run_capture(elf, av, out, CC_GUARD_OUT - 8, olen)
282}
283func cc_state_name(st: i64) -> *u8 {
284 if st == CC_ST_GOVERNED { return "GOVERNED" as *u8 }
285 if st == CC_ST_BREACHED { return "BREACHED" as *u8 }
286 if st == CC_ST_NOREADER { return "NO-READER" as *u8 }
287 if st == CC_ST_UNREGISTERED { return "UNREGISTERED" as *u8 }
288 if st == CC_ST_UNMEASURED { return "UNMEASURED" as *u8 }
289 return "UNGOVERNED" as *u8
290}
291// THE REMEDY CENSUS for one ledger: walks the conf, verifies every declared reader/writer/guard, prints one line
292// per declaration and one REMEDY line, fills counts[], returns the state.
293func cc_remedy(ledger: *u8, conf: *u8, counts: *i64, quiet: i64) -> i64 {
294 var i: i64 = 0
295 while i < CC_K_N { counts[i] = 0; i = i + 1 }
296 counts[CC_K_GUARD] = CC_GUARD_NONE
297 let l: *i64 = sys_mmap(16) as *i64
298 let b: *u8 = sys_read_file(conf, l)
299 var have: i64 = 0
300 var n: i64 = 0
301 if (b as i64) != 0 { have = 1; n = l[0] }
302 let sp: *i64 = sys_mmap(16) as *i64
303 let path: *u8 = sys_mmap(CC_MAGIC_4096)
304 let line: *u8 = sys_mmap(CC_LINE_CAP)
305 let gout: *u8 = sys_mmap(CC_GUARD_OUT)
306 let gl: *i64 = sys_mmap(16) as *i64
307 var registered: i64 = 0
308 var rs: i64 = 0
309 var scanning: i64 = have
310 while scanning == 1 {
311 if rs >= n { scanning = 0 } else {
312 let re: i64 = cc_line_end(b, n, rs)
313 if re > rs { if b[rs] != (35 as u8) {
314 if cc_field(b, rs, re, 0, sp) == 1 { if cc_span_eq(b, sp[0], sp[1], ledger) == 1 {
315 registered = registered + 1
316 let ks: *i64 = sys_mmap(16) as *i64
317 let ts: *i64 = sys_mmap(16) as *i64
318 if cc_field(b, rs, re, 1, ks) == 1 { if cc_field(b, rs, re, 2, ts) == 1 {
319 if cc_span_eq(b, ks[0], ks[1], "reader" as *u8) == 1 {
320 let ac: i64 = cc_anchoring(b, ts[0], ts[1], path, line)
321 counts[CC_K_READERS] = counts[CC_K_READERS] + 1
322 if ac == CC_ANCH_WHOLE { counts[CC_K_WHOLE] = counts[CC_K_WHOLE] + 1 }
323 if ac == CC_ANCH_TAIL { counts[CC_K_TAIL] = counts[CC_K_TAIL] + 1 }
324 if ac == CC_ANCH_HEAD { counts[CC_K_HEAD] = counts[CC_K_HEAD] + 1 }
325 if ac == CC_ANCH_UNVERIFIED { counts[CC_K_UNVER] = counts[CC_K_UNVER] + 1 }
326 if quiet == 0 { cw(" reader " as *u8); cwb(b, ts[0], ts[1]); cw(" anchoring=" as *u8); cw(cc_anchor_name(ac)); cw("\n" as *u8) }
327 }
328 if cc_span_eq(b, ks[0], ks[1], "writer" as *u8) == 1 {
329 counts[CC_K_WRITERS] = counts[CC_K_WRITERS] + 1
330 let ln: i64 = cc_split_site(b, ts[0], ts[1], path)
331 var ok: i64 = 0
332 if ln >= 0 { if cc_read_line(path, ln, line) >= 0 { if cc_has(line, "append" as *u8) == 1 { ok = 1 } } }
333 if ok == 0 { counts[CC_K_WUNVER] = counts[CC_K_WUNVER] + 1 }
334 if quiet == 0 { cw(" writer " as *u8); cwb(b, ts[0], ts[1]); if ok == 1 { cw(" appends=VERIFIED\n" as *u8) } else { cw(" appends=UNVERIFIED\n" as *u8) } }
335 }
336 if cc_span_eq(b, ks[0], ks[1], "guard" as *u8) == 1 {
337 let gv: i64 = cc_guard(ledger, b, ts[0], ts[1], gout, gl)
338 counts[CC_K_GUARD] = gv
339 if quiet == 0 {
340 cw(" guard " as *u8); cwb(b, ts[0], ts[1]); cw(" verdict=" as *u8)
341 if gv == CC_SG_GREEN { cw("GREEN" as *u8) }
342 if gv == CC_SG_AMBER { cw("AMBER" as *u8) }
343 if gv == CC_SG_RED { cw("RED" as *u8) }
344 if gv == CC_GUARD_NOELF { cw("NO-GUARD-BINARY" as *u8) }
345 if gv == CC_GUARD_NONE { cw("MALFORMED" as *u8) }
346 if gv > CC_SG_RED { cw("UNMEASURED" as *u8) }
347 cw("\n" as *u8)
348 }
349 }
350 if cc_span_eq(b, ks[0], ks[1], "mention" as *u8) == 1 {
351 counts[CC_K_MENTIONS] = counts[CC_K_MENTIONS] + 1
352 if quiet == 0 { cw(" mention " as *u8); cwb(b, ts[0], ts[1]); cw(" (declared, not judged)\n" as *u8) }
353 }
354 } }
355 } }
356 } }
357 rs = re + 1
358 }
359 }
360 // the state
361 var st: i64 = CC_ST_UNGOVERNED
362 let blind: i64 = counts[CC_K_HEAD] + counts[CC_K_UNVER]
363 // A configured writer or mention is not a complete census of consumers. No existing
364 // contract proves zero readers, so preserve that state code but abstain on this input.
365 if counts[CC_K_READERS] == 0 { st = CC_ST_UNMEASURED } else {
366 if blind == 0 { st = CC_ST_GOVERNED } else {
367 let gv: i64 = counts[CC_K_GUARD]
368 if gv == CC_SG_GREEN { st = CC_ST_GOVERNED }
369 if gv == CC_SG_AMBER { st = CC_ST_GOVERNED }
370 if gv == CC_SG_RED { st = CC_ST_BREACHED }
371 }
372 }
373 if have == 0 { st = CC_ST_UNMEASURED } else { if registered == 0 { st = CC_ST_UNREGISTERED } }
374 if quiet == 0 {
375 cw(" REMEDY " as *u8); cw(ledger)
376 cw(" readers=" as *u8); cwn(counts[CC_K_READERS]); cw(" whole=" as *u8); cwn(counts[CC_K_WHOLE]); cw(" tail=" as *u8); cwn(counts[CC_K_TAIL])
377 cw(" head=" as *u8); cwn(counts[CC_K_HEAD]); cw(" unverified=" as *u8); cwn(counts[CC_K_UNVER])
378 cw(" writers=" as *u8); cwn(counts[CC_K_WRITERS]); cw(" writers_unverified=" as *u8); cwn(counts[CC_K_WUNVER])
379 cw(" guard=" as *u8); cwn(counts[CC_K_GUARD]); cw(" mentions=" as *u8); cwn(counts[CC_K_MENTIONS])
380 cw(" conf=" as *u8); if have == 1 { cw("PRESENT" as *u8) } else { cw("ABSENT" as *u8) }
381 cw(" registered_rows=" as *u8); cwn(registered)
382 cw(" coverage=DECLARED-ROSTER semantic_coverage=UNMEASURED" as *u8)
383 cw(" => " as *u8); cw(cc_state_name(st)); cw("\n" as *u8)
384 if st == CC_ST_UNREGISTERED { cw(" next=register-evidence-backed-consumer-sites; no matching declaration is not proof of no readers\n" as *u8) }
385 if st == CC_ST_UNMEASURED { cw(" next=verify-remedy-config-and-consumer-coverage; zero declared readers is not a complete absence proof\n" as *u8) }
386 }
387 return st
388}
389
390func cc_scan(conf: *u8, cap: i64, remedy: *u8) -> i64 {
391 if cap <= 0 {
392 cwe("NX-CAPCLIFF REFUSED: cap must be > 0 -- a zero cap marks every ledger OVER and the alarm becomes noise\n" as *u8)
393 return 2
394 }
395 let fd: i64 = sys_openat_rd(conf)
396 if fd < 0 {
397 cwe("NX-CAPCLIFF REFUSED: cannot read roster " as *u8); cwe(conf); cwe(" -- refusing to report GREEN over a roster it never read\n" as *u8)
398 return CC_EXIT_EMPTY
399 }
400 // CAP REMOVED 2026-08-23 (nx_capcensus lane): ONE sys_read of CC_CONFCAP silently dropped any
401 // roster tail past 65,536 bytes -- the same shape as nx_cron_reconcile's single 16,383-byte read
402 // of a 24,356-byte registry, which left 11 production jobs inert while printing declared=55 as
403 // if that were the population. sys_read_file sizes its buffer from the file itself (lseek END)
404 // and cannot short-read, so the roster is read WHOLE at any size. The fd check above is kept so
405 // the unreadable-roster refusal is byte-for-byte the behaviour it always had.
406 sys_close(fd)
407 let lenp: *i64 = sys_mmap(8) as *i64
408 *lenp = 0
409 let buf: *u8 = sys_read_file(conf, lenp)
410 let n: i64 = *lenp
411 let pbuf: *u8 = sys_mmap(CC_MAGIC_4096)
412 let counts: *i64 = sys_mmap(8 * CC_K_N) as *i64
413
414 cw("=== nx_capcliff -- append-only ledgers vs the reader capture cap ===\ncap=" as *u8); cwn(cap)
415 cw(" near_at_permil=" as *u8); cwn(CC_NEAR_PERMIL); cw(" roster=" as *u8); cw(conf); cw(" remedy=" as *u8); cw(remedy); cw("\n" as *u8)
416
417 var rows: i64 = 0
418 var over: i64 = 0
419 var near: i64 = 0
420 var missing: i64 = 0
421 var governed: i64 = 0
422 var ungoverned: i64 = 0
423 var breached: i64 = 0
424 var noreader: i64 = 0
425 var unmeasured: i64 = 0
426 var i: i64 = 0
427 while i < n {
428 // Find the line span [i,nl). A break that OVERWRITES THE CURSOR destroys the newline position:
429 // the first draft exited by setting i = n+1, so e collapsed to n and the WHOLE FILE parsed as
430 // one line whose first byte was '#'. Every row vanished and the organ answered
431 // RED-EMPTY-nothing-checked -- which is the ONLY reason the bug was visible at all. A scanner
432 // that had defaulted to GREEN over zero rows would have shipped silently.
433 var nl: i64 = i
434 var brk: i64 = 0
435 while brk == 0 {
436 if nl >= n { brk = 1 } else { if buf[nl] == (10 as u8) { brk = 1 } else { nl = nl + 1 } }
437 }
438 let s: i64 = i
439 var e: i64 = nl
440 // trim trailing CR so a CRLF roster parses identically
441 if e > s { if buf[e-1] == (13 as u8) { e = e - 1 } }
442 if e > s { if buf[s] != (35 as u8) {
443 // CAP REMOVED 2026-08-23 (nx_capcensus lane): `rows` is a COUNTER -- nothing is indexed
444 // by it -- so `rows < CC_MAXROWS` was a PURE SILENT SKIP: ledger 257 and beyond was
445 // never examined and never counted, while the verdict still printed rows=256 as if that
446 // were the population. That is the nx_cron_reconcile declared=55 defect exactly. A cap
447 // is not a number to tune, so it is REMOVED rather than raised. Provably neutral for any
448 // roster of <=256 rows (byte-identical output); strictly more correct above that.
449 if rows >= 0 {
450 cc_copy(buf, s, e, pbuf)
451 let sz: i64 = cc_size(pbuf)
452 rows = rows + 1
453 cw(" " as *u8)
454 if sz < 0 {
455 missing = missing + 1
456 cw("MISSING " as *u8); cwb(buf, s, e); cw(" (rostered but unreadable -- NOT counted OK)\n" as *u8)
457 } else {
458 let permil: i64 = sz * 1000 / cap
459 if sz >= cap {
460 over = over + 1
461 cw("OVER " as *u8); cwb(buf, s, e); cw(" bytes=" as *u8); cwn(sz)
462 cw(" = " as *u8); cwn(permil); cw(" permil of the NOMINAL reader window -- a SIZE fact; the remedy census below says whether any reader is blind\n" as *u8)
463 let st: i64 = cc_remedy(pbuf, remedy, counts, 0)
464 if st == CC_ST_GOVERNED { governed = governed + 1 }
465 if st == CC_ST_UNGOVERNED { ungoverned = ungoverned + 1 }
466 if st == CC_ST_BREACHED { breached = breached + 1 }
467 if st == CC_ST_NOREADER { noreader = noreader + 1 }
468 if st == CC_ST_UNREGISTERED { unmeasured = unmeasured + 1 }
469 if st == CC_ST_UNMEASURED { unmeasured = unmeasured + 1 }
470 } else { if permil >= CC_NEAR_PERMIL {
471 near = near + 1
472 cw("NEAR " as *u8); cwb(buf, s, e); cw(" bytes=" as *u8); cwn(sz)
473 cw(" = " as *u8); cwn(permil); cw(" permil, headroom=" as *u8); cwn(cap - sz); cw(" bytes\n" as *u8)
474 } else {
475 cw("OK " as *u8); cwb(buf, s, e); cw(" bytes=" as *u8); cwn(sz)
476 cw(" = " as *u8); cwn(permil); cw(" permil, headroom=" as *u8); cwn(cap - sz); cw(" bytes\n" as *u8)
477 } }
478 }
479 }
480 } }
481 i = e + 1
482 }
483
484 if rows == 0 {
485 cw("NX-CAPCLIFF verdict=RED-EMPTY-nothing-checked-this-is-not-a-pass (roster had no usable rows)\n" as *u8)
486 return CC_EXIT_EMPTY
487 }
488 cw("NX-CAPCLIFF rows=" as *u8); cwn(rows); cw(" over=" as *u8); cwn(over); cw(" near=" as *u8); cwn(near); cw(" missing=" as *u8); cwn(missing)
489 cw(" over_governed=" as *u8); cwn(governed); cw(" over_noreader=" as *u8); cwn(noreader); cw(" over_ungoverned=" as *u8); cwn(ungoverned); cw(" over_breached=" as *u8); cwn(breached)
490 cw(" over_unmeasured=" as *u8); cwn(unmeasured)
491 if governed + noreader + ungoverned + breached + unmeasured == over { cw(" remedy_partition=RECONCILES" as *u8) } else { cw(" remedy_partition=LEAK" as *u8) }
492 if ungoverned + breached > 0 { cw(" verdict=RED (an OVER ledger has a HEAD-anchored or unverified reader with no working guard, or its guard has already fired: the newest rows are being lost to a reader that cannot see them, or a refusal nobody acted on. Fix the reader's anchoring or declare and arm a guard in " as *u8); cw(remedy); cw(")\n" as *u8); return CC_EXIT_OVER }
493 if unmeasured > 0 { cw(" verdict=UNMEASURED (OVER ledger consumer coverage is unregistered or unmeasured; inspect the remedy declarations)\n" as *u8); return CC_EXIT_UNMEASURED }
494 if near > 0 { cw(" verdict=AMBER (a ledger is approaching the cap -- act before it crosses, because the crossing is SILENT)\n" as *u8); return CC_EXIT_NEAR }
495 if over > 0 { cw(" verdict=GREEN (every OVER ledger is governed: its readers are whole-file or tail-anchored, or a loud guard stands before its cliff; the cap is a declared horizon, not an alarm)\n" as *u8); return 0 }
496 cw(" verdict=GREEN (every rostered ledger fits its readers' capture)\n" as *u8)
497 return 0
498}
499
500// ---- selftest on the base class ------------------------------------------------------------------------------
501func cc_wfile(path: *u8, s: *u8) -> i64 {
502 let fd: i64 = sys_openat_wr(path, CC_MODE_644)
503 if fd < 0 { return 0 - 1 }
504 let n: i64 = cc_slen(s)
505 sys_write(fd, s, n)
506 sys_close(fd)
507 return n
508}
509func cc_selftest() -> i64 {
510 // The private build runner starts in buildroot; live ledger fixtures belong to the serving root.
511 if cc_exists("knowledge/capcliff_ledgers.conf" as *u8) == 0 {
512 if cc_exists("../knowledge/capcliff_ledgers.conf" as *u8) == 1 { sys_chdir(".." as *u8) }
513 }
514 let ctr: *i64 = gv_ctr()
515 gv_head("nx_capcliff selftest -- each tooth carries its opposite; the remedy census on planted consumers" as *u8)
516 // T1 a file that EXISTS must measure > 0; T2 OPPOSITE: a MISSING file must be -1, NEVER 0
517 let s_ok: i64 = cc_size("knowledge/capcliff_ledgers.conf" as *u8)
518 gv_check("T1 an existing file measures more than zero bytes" as *u8, (s_ok > 0) as i64, ctr)
519 gv_kv("t1_bytes" as *u8, s_ok)
520 gv_check_eq("neg-control-T2 a missing file returns -1, never 0 (0 would score OK and hide a dead roster row)" as *u8, cc_size("knowledge/zzq_no_such_ledger_91827.jrnl" as *u8), 0 - 1, ctr)
521 // T3 the live cliff: actlog must ALREADY be over 4 MiB (this is why the organ exists); T4 OPPOSITE: a ledger under
522 let s_act: i64 = cc_size("knowledge/status/actlog.jrnl" as *u8)
523 gv_check("T3 actlog.jrnl is at or past the nominal window (the measured cliff that motivated this organ)" as *u8, (s_act >= CC_CAP_DEFAULT) as i64, ctr)
524 gv_kv("t3_actlog_bytes" as *u8, s_act)
525 let s_ws: i64 = cc_size("knowledge/status/ws_sync.jrnl" as *u8)
526 var t4: i64 = 0
527 if s_ws > 0 { if s_ws < CC_CAP_DEFAULT { t4 = 1 } }
528 gv_check("T4 ws_sync.jrnl is under the window (the OPPOSITE of T3, so the compare is real)" as *u8, t4, ctr)
529 gv_kv("t4_ws_sync_bytes" as *u8, s_ws)
530 gv_check("neg-control-T5 an unreadable roster does not open (scan REFUSES with exit 5, never GREEN over a roster it never read)" as *u8, (sys_openat_rd("knowledge/zzq_no_such_roster_91827.conf" as *u8) < 0) as i64, ctr)
531 // fixtures under /tmp/nx_capcliff (created at setup; nothing is shared with a production beat)
532 sys_mkdir(CC_FIX_DIR, CC_MODE_755)
533 let csrc: *u8 = "/tmp/nx_capcliff_recovery_20260912/c.nx" as *u8
534 cc_wfile(csrc, " let b: *u8 = sys_read_file(p, l)\n let t: *u8 = cl_slurp_tail(p, l)\n let n: i64 = sys_read(fd, b, 4096)\n let x: i64 = 1\n let sz: i64 = sys_lseek(fd, 0, SEEK_END)\n" as *u8)
535 let wsrc: *u8 = "/tmp/nx_capcliff_recovery_20260912/w.nx" as *u8
536 cc_wfile(wsrc, " let fd: i64 = sys_openat_append(p, 420)\n" as *u8)
537 let line: *u8 = sys_mmap(CC_LINE_CAP)
538 let path: *u8 = sys_mmap(CC_MAGIC_4096)
539 let spec1: *u8 = "/tmp/nx_capcliff_recovery_20260912/c.nx:1" as *u8
540 let spec2: *u8 = "/tmp/nx_capcliff_recovery_20260912/c.nx:2" as *u8
541 let spec3: *u8 = "/tmp/nx_capcliff_recovery_20260912/c.nx:3" as *u8
542 let spec4: *u8 = "/tmp/nx_capcliff_recovery_20260912/c.nx:4" as *u8
543 let spec5: *u8 = "/tmp/nx_capcliff_recovery_20260912/c.nx:5" as *u8
544 let spec9: *u8 = "/tmp/nx_capcliff_recovery_20260912/c.nx:99" as *u8
545 gv_check_eq("T6 a sys_read_file line is WHOLE" as *u8, cc_anchoring(spec1, 0, cc_slen(spec1), path, line), CC_ANCH_WHOLE, ctr)
546 gv_check_eq("T6b a *_tail( helper line is TAIL" as *u8, cc_anchoring(spec2, 0, cc_slen(spec2), path, line), CC_ANCH_TAIL, ctr)
547 gv_check_eq("T6c a bare sys_read( line is HEAD" as *u8, cc_anchoring(spec3, 0, cc_slen(spec3), path, line), CC_ANCH_HEAD, ctr)
548 gv_check_eq("neg-control-T6d a line that reads nothing is UNVERIFIED (a declaration that did not point at a read)" as *u8, cc_anchoring(spec4, 0, cc_slen(spec4), path, line), CC_ANCH_UNVERIFIED, ctr)
549 gv_check_eq("T6e a SEEK_END line is TAIL" as *u8, cc_anchoring(spec5, 0, cc_slen(spec5), path, line), CC_ANCH_TAIL, ctr)
550 gv_check_eq("neg-control-T6f a line past the end of the file is UNVERIFIED, never acquitted" as *u8, cc_anchoring(spec9, 0, cc_slen(spec9), path, line), CC_ANCH_UNVERIFIED, ctr)
551 // five fixture ledgers of 200 bytes and a remedy conf that governs them differently
552 let body: *u8 = "0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789\n0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789\n" as *u8
553 cc_wfile("/tmp/nx_capcliff_recovery_20260912/led_a.log" as *u8, body)
554 cc_wfile("/tmp/nx_capcliff_recovery_20260912/led_b.log" as *u8, body)
555 cc_wfile("/tmp/nx_capcliff_recovery_20260912/led_c.log" as *u8, body)
556 cc_wfile("/tmp/nx_capcliff_recovery_20260912/led_d.log" as *u8, body)
557 cc_wfile("/tmp/nx_capcliff_recovery_20260912/led_e.log" as *u8, body)
558 let rconf: *u8 = "/tmp/nx_capcliff_recovery_20260912/remedy.conf" as *u8
559 cc_wfile(rconf, "# fixture remedy conf\n/tmp/nx_capcliff_recovery_20260912/led_a.log|reader|/tmp/nx_capcliff_recovery_20260912/c.nx:1|whole\n/tmp/nx_capcliff_recovery_20260912/led_a.log|reader|/tmp/nx_capcliff_recovery_20260912/c.nx:2|tail\n/tmp/nx_capcliff_recovery_20260912/led_a.log|writer|/tmp/nx_capcliff_recovery_20260912/w.nx:1|append\n/tmp/nx_capcliff_recovery_20260912/led_a.log|mention|/tmp/nx_capcliff_recovery_20260912/c.nx|comment\n/tmp/nx_capcliff_recovery_20260912/led_b.log|reader|/tmp/nx_capcliff_recovery_20260912/c.nx:3|head, no guard\n/tmp/nx_capcliff_recovery_20260912/led_c.log|reader|/tmp/nx_capcliff_recovery_20260912/c.nx:3|head\n/tmp/nx_capcliff_recovery_20260912/led_c.log|guard|sizeguard:1000000:100000|budget far above 200 B\n/tmp/nx_capcliff_recovery_20260912/led_d.log|reader|/tmp/nx_capcliff_recovery_20260912/c.nx:3|head\n/tmp/nx_capcliff_recovery_20260912/led_d.log|guard|sizeguard:10:1|budget below 200 B: the guard has fired\n" as *u8)
560 let counts: *i64 = sys_mmap(8 * CC_K_N) as *i64
561 gv_check_eq("T7 a ledger whose readers are all WHOLE or TAIL is GOVERNED" as *u8, cc_remedy("/tmp/nx_capcliff_recovery_20260912/led_a.log" as *u8, rconf, counts, 1), CC_ST_GOVERNED, ctr)
562 gv_check_eq("T7b its readers partition (readers = whole + tail + head + unverified)" as *u8, counts[CC_K_READERS], counts[CC_K_WHOLE] + counts[CC_K_TAIL] + counts[CC_K_HEAD] + counts[CC_K_UNVER], ctr)
563 gv_check_eq("T7c the writer's append is verified and the mention counted" as *u8, counts[CC_K_WRITERS] * 100 + counts[CC_K_WUNVER] * 10 + counts[CC_K_MENTIONS], 101, ctr)
564 gv_check_eq("neg-control-T8 a HEAD reader with no guard is UNGOVERNED" as *u8, cc_remedy("/tmp/nx_capcliff_recovery_20260912/led_b.log" as *u8, rconf, counts, 1), CC_ST_UNGOVERNED, ctr)
565 gv_check_eq("T9 a HEAD reader behind a sizeguard reading GREEN is GOVERNED (the guard is FORKED, not trusted)" as *u8, cc_remedy("/tmp/nx_capcliff_recovery_20260912/led_c.log" as *u8, rconf, counts, 1), CC_ST_GOVERNED, ctr)
566 gv_check_eq("T9b the forked guard's verdict was GREEN" as *u8, counts[CC_K_GUARD], CC_SG_GREEN, ctr)
567 gv_check_eq("neg-control-T10 a HEAD reader behind a sizeguard reading RED is BREACHED (the refusal fired and nobody acted)" as *u8, cc_remedy("/tmp/nx_capcliff_recovery_20260912/led_d.log" as *u8, rconf, counts, 1), CC_ST_BREACHED, ctr)
568 gv_check_eq("T11 uncovered ledger is UNREGISTERED, never NO-READER" as *u8, cc_remedy("/tmp/nx_capcliff_recovery_20260912/led_e.log" as *u8, rconf, counts, 1), CC_ST_UNREGISTERED, ctr)
569 gv_check_eq("T11b missing config is UNMEASURED" as *u8, cc_remedy("/tmp/nx_capcliff_recovery_20260912/led_a.log" as *u8, "/tmp/nx_capcliff_recovery_20260912/missing-private.conf" as *u8, counts, 1), CC_ST_UNMEASURED, ctr)
570 let zconf: *u8 = "/tmp/nx_capcliff_recovery_20260912/writer-only.conf" as *u8
571 cc_wfile(zconf, "/tmp/nx_capcliff_recovery_20260912/led_e.log|writer|/tmp/nx_capcliff_recovery_20260912/w.nx:1|verified writer, reader census not proven\n" as *u8)
572 gv_check_eq("T11c verified writer alone cannot prove no readers" as *u8, cc_remedy("/tmp/nx_capcliff_recovery_20260912/led_e.log" as *u8, zconf, counts, 1), CC_ST_UNMEASURED, ctr)
573 // T12 the scan's verdict over a fixture roster at a 100-byte cap: b and d make it RED; without them it is GREEN
574 cc_wfile("/tmp/nx_capcliff_recovery_20260912/roster_red.conf" as *u8, "/tmp/nx_capcliff_recovery_20260912/led_a.log\n/tmp/nx_capcliff_recovery_20260912/led_b.log\n/tmp/nx_capcliff_recovery_20260912/led_c.log\n/tmp/nx_capcliff_recovery_20260912/led_d.log\n/tmp/nx_capcliff_recovery_20260912/led_e.log\n" as *u8)
575 cc_wfile("/tmp/nx_capcliff_recovery_20260912/roster_green.conf" as *u8, "/tmp/nx_capcliff_recovery_20260912/led_a.log\n/tmp/nx_capcliff_recovery_20260912/led_c.log\n" as *u8)
576 cc_wfile("/tmp/nx_capcliff_recovery_20260912/roster_unknown.conf" as *u8, "/tmp/nx_capcliff_recovery_20260912/led_e.log\n" as *u8)
577 gv_check_eq("T12c scan uncovered OVER ledger abstains with exit 3" as *u8, cc_scan("/tmp/nx_capcliff_recovery_20260912/roster_unknown.conf" as *u8, 100, rconf), CC_EXIT_UNMEASURED, ctr)
578 gv_check_eq("T12 scan: an ungoverned or breached OVER ledger makes the verdict RED (exit 6)" as *u8, cc_scan("/tmp/nx_capcliff_recovery_20260912/roster_red.conf" as *u8, 100, rconf), CC_EXIT_OVER, ctr)
579 gv_check_eq("T12b scan: registered governed readers preserve GREEN (exit 0)" as *u8, cc_scan("/tmp/nx_capcliff_recovery_20260912/roster_green.conf" as *u8, 100, rconf), 0, ctr)
580 gv_check_eq("neg-control-T13 scan refuses an empty roster with exit 5" as *u8, cc_scan("/tmp/nx_capcliff_recovery_20260912/zzq_absent_roster.conf" as *u8, 100, rconf), CC_EXIT_EMPTY, ctr)
581 return gv_verdict("nx_capcliff" as *u8, ctr, "the size ruler and its opposites, the anchoring classifier on planted read sites, the forked guard in both directions, and the scan verdict that carries RED only for an ungoverned or breached cliff" as *u8)
582}
583
584func main(argc: i64, argv: *i64) -> i64 {
585 // ARGLESS NOW DEFAULTS TO `scan` (2026-08-07). The tickless clock forks scheduled organs ARGLESSLY,
586 // so an organ that REQUIRES a verb can never be put on the clock -- it would print usage and exit 2
587 // every tick, which reads as a running job that never finds anything. That is exactly why THIS
588 // detector was never scheduled while the very cliff it exists to catch was crossed for the THIRD
589 // time: nx_debt's DB_CAP went 4MiB -> 32MiB on 2026-08-06 after the plane silently returned a
590 // truncated prefix and the reader lost its NEWEST rows. `scan` is the only non-selftest verb, so
591 // defaulting to it loses no capability and makes the organ schedulable.
592 // LAW: A TOOL THAT CANNOT RUN ARGLESS CANNOT BE SCHEDULED, AND A DETECTOR THAT CANNOT BE SCHEDULED
593 // ONLY EVER RUNS WHEN SOMEONE ALREADY SUSPECTS THE PROBLEM.
594 var verb: *u8 = "scan" as *u8
595 if argc >= 2 { verb = argv[1] as *u8 }
596 if cc_streq(verb, "selftest" as *u8) == 1 { let rc: i64 = cc_selftest(); sys_exit(rc); return rc }
597 if cc_streq(verb, "remedy" as *u8) == 1 {
598 if argc < 3 { cwe("usage: nx_capcliff remedy <ledger> [remedy.conf]\n" as *u8); sys_exit(2); return 2 }
599 var rconf: *u8 = CC_REMEDY_CONF
600 if argc >= 4 { rconf = argv[3] as *u8 }
601 let counts: *i64 = sys_mmap(8 * CC_K_N) as *i64
602 let st: i64 = cc_remedy(argv[2] as *u8, rconf, counts, 0)
603 if st == CC_ST_UNREGISTERED { sys_exit(CC_EXIT_UNMEASURED); return CC_EXIT_UNMEASURED }
604 if st == CC_ST_UNMEASURED { sys_exit(CC_EXIT_UNMEASURED); return CC_EXIT_UNMEASURED }
605 if st == CC_ST_UNGOVERNED { sys_exit(CC_EXIT_OVER); return CC_EXIT_OVER }
606 if st == CC_ST_BREACHED { sys_exit(CC_EXIT_OVER); return CC_EXIT_OVER }
607 return 0
608 }
609 if cc_streq(verb, "scan" as *u8) == 0 { cwe("usage: nx_capcliff scan [roster.conf] [cap_bytes] [remedy.conf] | remedy <ledger> [remedy.conf] | selftest\n" as *u8); sys_exit(2); return 2 }
610 var conf: *u8 = "knowledge/capcliff_ledgers.conf" as *u8
611 var cap: i64 = CC_CAP_DEFAULT
612 var remedy: *u8 = CC_REMEDY_CONF
613 if argc >= 3 { conf = argv[2] as *u8 }
614 if argc >= 4 { cap = cc_atoi(argv[3] as *u8) }
615 if argc >= 5 { remedy = argv[4] as *u8 }
616 let rc: i64 = cc_scan(conf, cap, remedy)
617 if rc != 0 { sys_exit(rc) }
618 return rc
619}