code wiki / _hdl_build / nx_capsweep_lib.nx
nx_capsweep_lib.nx source
↩ module page · 221 lines · 9819 B
1// nx_capsweep_lib.nx -- CR1 of /compare/capregistry: THE WHOLE-REGISTRY LIFECYCLE JOIN.
2//
3// THE DEFECT THIS CLOSES, MEASURED 2026-08-28 in a single session: three censuses of the SAME estate
4// returned three different denominators -- nx_wirecensus 2048 promoted artifacts, nx_execsurface 2418
5// organs, nx_artifactdrift 1295 registry rows. Every one of those partitions RECONCILES INTERNALLY and
6// every one is correct about its own subject, so NOTHING LOOKS WRONG -- and yet no reader can state how
7// many distinct units the estate has, because nothing joins them PER UNIT.
8//
9// WHAT THIS IS NOT: a fourth census. It collects nothing and it walks no directory. It JOINS artifacts the
10// existing censuses have already written, so it cannot disagree with them about anything except the join.
11// If it ever grows a collector, that is the moment it becomes a rival ruler and stops being trustworthy.
12//
13// COMPOSED, NEVER RE-IMPLEMENTED: wc_read, wc_read_tail, wc_parse_registered, wc_parse_authorised,
14// wc_parse_invoked, wc_has and wc_elflen all come from nx_wirecensus_lib. There is exactly ONE parser for
15// the allowlist, the consent ledger and the actlog in this estate, and it is not this file.
16
17import "nx_syscalls.nx"
18import "nx_wirecensus_lib.nx"
19
20// The unit table. execsurface.tsv enumerated 2418 organs when this was written; 8192 is 3.4x headroom and
21// overflow is ANNOUNCED through trunc rather than absorbed. A cap that fills in silence is the defect this
22// whole board exists to find, so this one may not have it.
23const CS_MAXU: i64 = 8192
24const CS_TAB: i64 = 9
25const CS_NL: i64 = 10
26const CS_HASH: i64 = 35
27const CS_DASH: i64 = 45
28const CS_SURF_FIELD: i64 = 7 // column index of first_surface in execsurface.tsv, read from its emitter
29
30// Surface codes, derived from column 7 of execsurface.tsv.
31const CS_S_NONE: i64 = 0
32const CS_S_CLOCK: i64 = 1
33const CS_S_CRON: i64 = 2
34const CS_S_DAEMON: i64 = 3
35const CS_S_ROSTER: i64 = 4
36const CS_S_ACTLOG: i64 = 5
37const CS_S_FORK: i64 = 6
38const CS_S_REF: i64 = 7
39const CS_S_UNKNOWN: i64 = 8
40
41// Lifecycle stage bits, so one row carries the whole chain rather than four booleans a reader must recombine.
42const CS_B_SURFACE: i64 = 1
43const CS_B_REGISTERED: i64 = 2
44const CS_B_AUTHORISED: i64 = 4
45const CS_B_INVOKED: i64 = 8
46
47// Add-if-absent into a CALLER-SIZED table.
48// THIS DELIBERATELY DOES NOT COMPOSE wc_add, and the reason is the point of the organ: wc_add is hard-capped
49// at WC_MAXT = 2048 while the surface census enumerates 2418 organs, so composing it would have silently
50// dropped 370 units -- the exact silent-cap defect this board was written to expose. Here the cap is a
51// PARAMETER and every rejected row increments trunc, which the caller must print.
52func cs_add(names: *u8, lens: *i64, cnt: i64, cap: i64, p: *u8, l: i64, trunc: *i64) -> i64 {
53 if l <= 0 { return cnt }
54 if l >= WC_NAMEMAX { return cnt }
55 if wc_has(names, lens, cnt, p, l) == 1 { return cnt }
56 if cnt >= cap { trunc[0] = trunc[0] + 1; return cnt }
57 let base: i64 = cnt * WC_NAMEMAX
58 var k: i64 = 0
59 while k < l { names[base + k] = p[k]; k = k + 1 }
60 names[base + l] = 0 as u8
61 lens[cnt] = l
62 return cnt + 1
63}
64
65// Field-boundary scan with a SEPARATE cursor and a clean return, never a clobbered index. A loop that exits
66// by overwriting the cursor it is meant to report destroys its own answer; this estate wrote that eol-scan
67// defect four times in one day, so it is not written a fifth time here.
68func cs_field_end(buf: *u8, s: i64, lim: i64) -> i64 {
69 var j: i64 = s
70 while j < lim {
71 if buf[j] == (CS_TAB as u8) { return j }
72 j = j + 1
73 }
74 return lim
75}
76
77// Start offset of field <want> on the line [ls, lim).
78func cs_field_start(buf: *u8, ls: i64, lim: i64, want: i64) -> i64 {
79 var fs: i64 = ls
80 var f: i64 = 0
81 while f < want {
82 let fe: i64 = cs_field_end(buf, fs, lim)
83 if fe < lim { fs = fe + 1 } else { fs = lim }
84 f = f + 1
85 }
86 return fs
87}
88
89// first_surface token -> code. Two bytes are required because clock and cron share their first.
90func cs_surf_code(buf: *u8, s: i64, e: i64) -> i64 {
91 if e <= s { return CS_S_NONE }
92 if buf[s] == (CS_DASH as u8) { return CS_S_NONE }
93 if e - s < 2 { return CS_S_UNKNOWN }
94 let c0: i64 = buf[s] as i64
95 let c1: i64 = buf[s + 1] as i64
96 if c0 == 100 { return CS_S_DAEMON }
97 if c0 == 97 { return CS_S_ACTLOG }
98 if c0 == 102 { return CS_S_FORK }
99 if c0 == 99 {
100 if c1 == 108 { return CS_S_CLOCK }
101 if c1 == 114 { return CS_S_CRON }
102 return CS_S_UNKNOWN
103 }
104 if c0 == 114 {
105 if c1 == 111 { return CS_S_ROSTER }
106 if c1 == 101 { return CS_S_REF }
107 return CS_S_UNKNOWN
108 }
109 return CS_S_UNKNOWN
110}
111
112// Column 0 (name) and column 7 (first_surface) of every non-comment line of execsurface.tsv.
113// The trailing footer line begins with the comment byte and is SKIPPED here: it carries the census's own
114// organs= total, and it is read SEPARATELY by cs_footer_num so the two numbers can be COMPARED instead of
115// one silently standing in for the other.
116func cs_parse_surface(buf: *u8, n: i64, names: *u8, lens: *i64, surf: *i64, cap: i64, trunc: *i64) -> i64 {
117 var cnt: i64 = 0
118 var ls: i64 = 0
119 var i: i64 = 0
120 while i <= n {
121 var eol: i64 = 0
122 if i == n { eol = 1 }
123 else { if buf[i] == (CS_NL as u8) { eol = 1 } }
124 if eol == 1 {
125 if i > ls {
126 if buf[ls] != (CS_HASH as u8) {
127 let e0: i64 = cs_field_end(buf, ls, i)
128 let raw: *u8 = ((buf as i64) + ls) as *u8
129 let l0: i64 = wc_elflen(raw, e0 - ls)
130 let before: i64 = cnt
131 cnt = cs_add(names, lens, cnt, cap, raw, l0, trunc)
132 if cnt > before {
133 let fs: i64 = cs_field_start(buf, ls, i, CS_SURF_FIELD)
134 surf[cnt - 1] = cs_surf_code(buf, fs, i)
135 }
136 }
137 }
138 ls = i + 1
139 }
140 i = i + 1
141 }
142 return cnt
143}
144
145// Read the integer that follows <key> on the footer line, or -1 when it is absent.
146// -1 IS A THIRD STATE ON PURPOSE: a missing footer must read UNKNOWN, never zero, because a zero here would
147// make the reconciliation appear to balance against a total nobody published.
148func cs_footer_num(buf: *u8, n: i64, key: *u8) -> i64 {
149 var klen: i64 = 0
150 while key[klen] != (0 as u8) { klen = klen + 1 }
151 var i: i64 = 0
152 while i + klen <= n {
153 var k: i64 = 0
154 var same: i64 = 1
155 while k < klen {
156 if buf[i + k] != key[k] { same = 0; k = klen } else { k = k + 1 }
157 }
158 if same == 1 {
159 var j: i64 = i + klen
160 var v: i64 = 0
161 var got: i64 = 0
162 while j < n {
163 let c: i64 = buf[j] as i64
164 if c >= 48 {
165 if c <= 57 { v = v * 10 + (c - 48); got = 1; j = j + 1 }
166 else { j = n }
167 } else { j = n }
168 }
169 if got == 1 { return v }
170 return 0 - 1
171 }
172 i = i + 1
173 }
174 return 0 - 1
175}
176
177// The lifecycle bitmask for one unit.
178func cs_stage_bits(has_surface: i64, reg: i64, auth: i64, inv: i64) -> i64 {
179 var b: i64 = 0
180 if has_surface == 1 { b = b + CS_B_SURFACE }
181 if reg == 1 { b = b + CS_B_REGISTERED }
182 if auth == 1 { b = b + CS_B_AUTHORISED }
183 if inv == 1 { b = b + CS_B_INVOKED }
184 return b
185}
186
187// WHY A RESIDUAL NEEDS A REASON, MEASURED 2026-08-28 THE HOUR THE WORKLIST FIRST EXISTED: the 126 names the
188// join could not match are NOT one class. Reading them found four causes with FOUR DIFFERENT REMEDIES --
189// tools registered under an MCP name that is not an elf basename at all (not a defect), names whose artifact
190// is a STAGED .elf.new that was never promoted (registered and uncallable, worse than dark), names promoted
191// AFTER the spine snapshot was taken (the spine is behind, not the estate -- nx_capsweep appeared in its OWN
192// residual this way), and genuinely dark rows. ★NAME WHICH REASON: TWO CAUSES WITH OPPOSITE REMEDIES MUST
193// NOT SHARE ONE COUNTER, or the count sends its reader at the wrong work.
194//
195// PURE BY CONSTRUCTION: the two filesystem probes stay in the CALLER and this takes their results as
196// booleans, so the classifier is gate-testable without touching a filesystem and a mutation reaches it.
197const CS_R_STALE_SPINE: i64 = 1
198const CS_R_SCAFFOLD: i64 = 2
199const CS_R_NO_ARTIFACT: i64 = 3
200
201func cs_residual_reason(elf_exists: i64, new_exists: i64) -> i64 {
202 // ORDER IS LOAD-BEARING: a promoted artifact can also still have a stale .elf.new beside it, and that is
203 // a SPINE-FRESHNESS fact, not a scaffold. Testing scaffold first would misfile every such row.
204 if elf_exists == 1 { return CS_R_STALE_SPINE }
205 if new_exists == 1 { return CS_R_SCAFFOLD }
206 // DELIBERATELY NOT SPLIT INTO ALIAS-vs-DARK. Separating those needs the allowlist's elf column, which
207 // this organ does not parse, so the honest label is the one that names what was actually established:
208 // no artifact of that NAME exists. Guessing which of the two it is would be the confident-wrong answer.
209 return CS_R_NO_ARTIFACT
210}
211
212// THE PARTITION PREDICATE. The join publishes a unit count ONLY when every input population is accounted
213// for: units seen = units carried, and every registered name is either joined or counted as a residual.
214// A count whose parts do not sum is a leak, and this organ refuses to print one.
215func cs_partition_ok(units: i64, joined: i64, residual: i64) -> i64 {
216 if units < 0 { return 0 }
217 if joined < 0 { return 0 }
218 if residual < 0 { return 0 }
219 if joined + residual == units { return 1 }
220 return 0
221}