nx_retire_onto_lib.nx source
↩ module page · 787 lines · 40066 B
1// nx_retire_onto_lib.nx -- RETIRE A PRIVATE FUNCTION ONTO ITS SHARED OWNER, function side (global tooling,
2// 2026-08-24, born on procgen PG2).
3//
4// WHY THIS EXISTS: the library plane's first census (nx_libindex find isqrt) returned 106 of 5,517 libraries
5// carrying a private isqrt beside nx_vecmath's gate-proven vm_isqrt, and nx_nxa_fk carrying quaternion
6// primitives beside vm_q_*. nx_oo_extract moves BYTE-IDENTICAL bodies into one lib; these bodies are not
7// identical -- each is its own hand-rolled Newton loop -- so the move is "keep the private NAME, replace the
8// BODY with one call to the owner". That was done by hand for eight files earlier the same day. A hand edit
9// repeated 106 times is the class of work an organ exists for, and a hand edit is also the class of work
10// that silently half-lands (the estate's str.replace law).
11//
12// WHAT IT DOES: rewrites func <private>(<params>) -> <ret> { ... }
13// to func <private>(<params>) -> <ret> { return <owner>(<param names>) }
14// and inserts `import "<owner_lib basename>"` after the LAST import line when it is absent (before the first
15// top-level func/const when the file has no imports). Brace matching SKIPS string literals and line comments,
16// so a `}` inside a string or a comment cannot end the body early -- the gate plants exactly that.
17//
18// WHAT IT REFUSES, BY NAME: the function is absent or malformed; the owner lib is unreadable or lacks the
19// owner function; arity, any parameter TYPE, or the return type differ; the file IS the owner lib. A refusal
20// writes nothing. Idempotent: a body that already is the one-line delegation reports ALREADY and writes
21// nothing, so a sweep can be re-run after a partial apply and the partition still sums.
22//
23// WHAT IT DOES NOT DO: prove behaviour. The proof lane is the consumer's rebuild plus the consumer's own gates
24// on the roster. An exact floor replacing a capped Newton loop is a NAMED delta, never a silent one, and the
25// name of it is printed on the APPLIED line.
26//
27// NO SILENT CAPS: files are read whole through sys_read_file (sized from the file); the only bounded buffers
28// are a pattern scratch (RO_PAT_CAP, sized for "func <name>(" and `import "<basename>"`) and the parameter
29// table (RO_MAX_PARAMS -- a function with more parameters than that REFUSES by name rather than truncating).
30// license_tier: ORIGINAL
31
32import "nx_syscalls.nx"
33import "nx_store_seed_lib.nx"
34import "nx_gatekit_lib.nx"
35
36// ---- PROVE: the differential probe (added the same day, before the first real apply) ------------------------
37// A private isqrt may be a capped Newton loop, a rounded root, or a root over a pre-shifted scale. Replacing its
38// body on the strength of a matching SIGNATURE would change semantics silently -- the exact "I don't know what
39// this is" defect. So before an APPLY the organ GENERATES a probe program that imports the candidate and the
40// owner, compares <private>(v) against <owner>(v) over a declared input ladder, builds it with the estate's own
41// builder and runs it. Only exit 0 permits the rewrite. The ladder is exhaustive over 0..RO_PROBE_DENSE and a
42// structured sparse set above it (powers of two +-1 and squares on a 3/2 ladder up to the i64 root bound) --
43// declared here so nobody reads it as a sample of the whole domain. Unary i64 -> i64 only; anything else is
44// REFUSED-prove-unsupported by name.
45const RO_PROBE_DENSE: i64 = 1048576
46// RO_PROBE_MS is the slow roster's bound (nx_gate_roster_run GRR_MS_DEFAULT): a probe slower than the slow beat
47// is a hang, not a slow subject. RO_BUILD_MS is the same bound times the builder's cold-cache factor of 5.
48const RO_PROBE_MS: i64 = 60000
49const RO_BUILD_MS: i64 = 300000
50const RO_PROBE_OUTCAP: i64 = 65536
51const RO_PROBE_SRC_CAP: i64 = 4096
52// One corpus-root path plus a fixture or artifact name: PATH_MAX is 4096 on this host and no path here can exceed it.
53const RO_PROBE_PATH_CAP: i64 = 4096
54const RO_PROVE_PASS: i64 = 1
55const RO_PROVE_DIFFER: i64 = 0
56const RO_PROVE_UNBUILDABLE: i64 = 0 - 1
57const RO_PROVE_UNSUPPORTED: i64 = 0 - 2
58const RO_PROVE_NOROOT: i64 = 0 - 3
59// The builder REFUSED under admission (an I/O storm or CPU saturation on the box): that is a property of the
60// BOX, never of the candidate, and filing it as "unbuildable" would turn a busy hour into 95 false refusals.
61const RO_PROVE_ADMISSION: i64 = 0 - 4
62
63const RO_SYS_OPENAT: i64 = 257
64// getpid in the RV64 numbering __syscall TRANSLATES (172 -> x86-64 39). MEASURED 2026-08-24: pinning x86's 39
65// here reached x86 umount2, because 39 is a KNOWN RV64 key (umount2) and the translator maps known keys while
66// passing unknown numbers through raw -- which is also why 257/217 elsewhere in this tree only work by
67// passthrough luck. The pid makes every probe path unique per run: the gate's trial and a live sweep would
68// otherwise write and build the SAME probe file and hand each other verdicts about the other's candidate.
69const RO_SYS_GETPID: i64 = 172
70const RO_AT_FDCWD: i64 = 0 - 100
71const RO_O_WRONLY_CREAT_TRUNC: i64 = 0x241
72const RO_MODE_644: i64 = 420
73const RO_NL: i64 = 10
74const RO_CR: i64 = 13
75const RO_TAB: i64 = 9
76const RO_SP: i64 = 32
77const RO_LPAREN: i64 = 40
78const RO_RPAREN: i64 = 41
79const RO_LBRACE: i64 = 123
80const RO_RBRACE: i64 = 125
81const RO_COMMA: i64 = 44
82const RO_COLON: i64 = 58
83const RO_QUOTE: i64 = 34
84const RO_BSLASH: i64 = 92
85const RO_SLASH: i64 = 47
86const RO_MAX_PARAMS: i64 = 16
87const RO_P_STRIDE: i64 = 4
88// POSIX NAME_MAX is 255; a function name or a lib basename longer than that is an anomaly and refuses.
89const RO_PAT_CAP: i64 = 512
90const RO_PATH_CAP: i64 = 1024
91// Output slack over the input size: the new body is " return <owner>(<names>) " which is bounded by the
92// owner name plus the parameter names already present in the input, plus one import line.
93const RO_OUT_SLACK: i64 = 2 * RO_PAT_CAP
94
95// verdict codes -- every refusal class that a sweep must tally SEPARATELY gets its own code, because two
96// refusals with opposite remedies must never share a counter (a signature mismatch is "leave it", a build
97// failure is "this lib does not compile natively", a semantic difference is "this was never an isqrt").
98const RO_RETIRABLE: i64 = 0
99const RO_ALREADY: i64 = 1
100const RO_REFUSED: i64 = 2
101const RO_APPLIED: i64 = 3
102const RO_PROVEN: i64 = 4
103const RO_REFUSED_DIFFER: i64 = 5
104const RO_REFUSED_UNBUILDABLE: i64 = 6
105const RO_REFUSED_UNSUPPORTED: i64 = 7
106const RO_DEFERRED_ADMISSION: i64 = 8
107const RO_CODES: i64 = 9
108// modes for ro_one / ro_sweep
109const RO_MODE_DRY: i64 = 0
110const RO_MODE_PROVE: i64 = 1
111const RO_MODE_APPLY: i64 = 2
112
113// locate slots
114const RO_L_FSTART: i64 = 0
115const RO_L_PSTART: i64 = 1
116const RO_L_PEND: i64 = 2
117const RO_L_BOPEN: i64 = 3
118const RO_L_BCLOSE: i64 = 4
119const RO_L_RSTART: i64 = 5
120const RO_L_REND: i64 = 6
121const RO_L_N: i64 = 8
122
123// sweep tally slots: RO_CODES codes then candidates
124const RO_T_CAND: i64 = 9
125const RO_T_N: i64 = 11
126
127func ro_slen(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n }
128func ro_w(fd: i64, s: *u8) -> i64 { let n: i64 = ro_slen(s); if n > 0 { sys_write(fd, s, n) } return 0 }
129func ro_out(s: *u8) -> i64 { return ro_w(1, s) }
130func ro_num(v0: i64) -> i64 {
131 let b: *u8 = sys_mmap(32)
132 var v: i64 = v0
133 var neg: i64 = 0
134 if v < 0 { neg = 1; v = 0 - v }
135 var i: i64 = 31
136 b[i] = 0 as u8
137 if v == 0 { i = i - 1; b[i] = 48 as u8 }
138 while v > 0 { i = i - 1; b[i] = ((v % 10) + 48) as u8; v = v / 10 }
139 if neg == 1 { i = i - 1; b[i] = 45 as u8 }
140 var n: i64 = 0
141 while b[i+n] != (0 as u8) { n = n + 1 }
142 sys_write(1, b + i, n)
143 sys_munmap(b, 32)
144 return 0
145}
146func ro_is_ws(c: i64) -> i64 { if c == RO_SP { return 1 } if c == RO_TAB { return 1 } if c == RO_NL { return 1 } if c == RO_CR { return 1 } return 0 }
147func ro_streq(a: *u8, b: *u8) -> i64 {
148 var i: i64 = 0
149 while a[i] != (0 as u8) { if a[i] != b[i] { return 0 } i = i + 1 }
150 if b[i] != (0 as u8) { return 0 }
151 return 1
152}
153
154// find pat (C string) in buf[from..n); -1 when absent
155func ro_find(buf: *u8, n: i64, from: i64, pat: *u8) -> i64 {
156 let pl: i64 = ro_slen(pat)
157 if pl == 0 { return 0 - 1 }
158 var i: i64 = from
159 while i + pl <= n {
160 var k: i64 = 0
161 var same: i64 = 1
162 while k < pl { if buf[i + k] != pat[k] { same = 0; k = pl } k = k + 1 }
163 if same == 1 { return i }
164 i = i + 1
165 }
166 return 0 - 1
167}
168// find pat at the beginning of a line
169func ro_find_bol(buf: *u8, n: i64, pat: *u8) -> i64 {
170 var from: i64 = 0
171 var go: i64 = 1
172 while go == 1 {
173 let p: i64 = ro_find(buf, n, from, pat)
174 if p < 0 { go = 0 }
175 if go == 1 {
176 if p == 0 { return p }
177 if buf[p - 1] == (RO_NL as u8) { return p }
178 from = p + 1
179 }
180 }
181 return 0 - 1
182}
183func ro_count(buf: *u8, n: i64, pat: *u8) -> i64 {
184 var c: i64 = 0
185 var from: i64 = 0
186 var go: i64 = 1
187 while go == 1 {
188 let p: i64 = ro_find(buf, n, from, pat)
189 if p < 0 { go = 0 }
190 if go == 1 { c = c + 1; from = p + 1 }
191 }
192 return c
193}
194func ro_span_eq(a: *u8, ao: i64, al: i64, b: *u8, bo: i64, bl: i64) -> i64 {
195 if al != bl { return 0 }
196 var k: i64 = 0
197 while k < al { if a[ao + k] != b[bo + k] { return 0 } k = k + 1 }
198 return 1
199}
200func ro_ends_with(buf: *u8, s: i64, e: i64, suffix: *u8) -> i64 {
201 let sl: i64 = ro_slen(suffix)
202 if e - s < sl { return 0 }
203 return ro_span_eq(buf, e - sl, sl, suffix, 0, sl)
204}
205func ro_trim_start(buf: *u8, s: i64, e: i64) -> i64 {
206 var i: i64 = s
207 while i < e { if ro_is_ws(buf[i] as i64) == 1 { i = i + 1 } else { return i } }
208 return i
209}
210func ro_trim_end(buf: *u8, s: i64, e: i64) -> i64 {
211 var i: i64 = e
212 while i > s { if ro_is_ws(buf[i - 1] as i64) == 1 { i = i - 1 } else { return i } }
213 return i
214}
215func ro_basename(p: *u8) -> *u8 {
216 var i: i64 = 0
217 var last: i64 = 0
218 while p[i] != (0 as u8) { if p[i] == (RO_SLASH as u8) { last = i + 1 } i = i + 1 }
219 return p + last
220}
221
222// "func <name>(" into pat; returns its length; -1 when the name would overflow the pattern scratch
223func ro_mk_pat(pat: *u8, name: *u8) -> i64 {
224 if ro_slen(name) + 8 >= RO_PAT_CAP { return 0 - 1 }
225 var k: i64 = 0
226 let pre: *u8 = "func " as *u8
227 var i: i64 = 0
228 while pre[i] != (0 as u8) { pat[k] = pre[i]; k = k + 1; i = i + 1 }
229 i = 0
230 while name[i] != (0 as u8) { pat[k] = name[i]; k = k + 1; i = i + 1 }
231 pat[k] = RO_LPAREN as u8; k = k + 1
232 pat[k] = 0 as u8
233 return k
234}
235// `import "<lib>"` into pat; -1 on overflow
236func ro_mk_import(pat: *u8, lib: *u8) -> i64 {
237 if ro_slen(lib) + 12 >= RO_PAT_CAP { return 0 - 1 }
238 var k: i64 = 0
239 let pre: *u8 = "import \"" as *u8
240 var i: i64 = 0
241 while pre[i] != (0 as u8) { pat[k] = pre[i]; k = k + 1; i = i + 1 }
242 i = 0
243 while lib[i] != (0 as u8) { pat[k] = lib[i]; k = k + 1; i = i + 1 }
244 pat[k] = RO_QUOTE as u8; k = k + 1
245 pat[k] = 0 as u8
246 return k
247}
248
249// index just past the closing quote of the string literal opening at buf[i0]
250func ro_skip_str(buf: *u8, n: i64, i0: i64) -> i64 {
251 var i: i64 = i0 + 1
252 var go: i64 = 1
253 while go == 1 {
254 if i >= n { go = 0 }
255 if go == 1 {
256 let c: i64 = buf[i] as i64
257 if c == RO_BSLASH { i = i + 2 }
258 else { if c == RO_QUOTE { go = 0; i = i + 1 } else { i = i + 1 } }
259 }
260 }
261 return i
262}
263// index of the newline ending the line comment opening at buf[i0], or n
264func ro_skip_comment(buf: *u8, n: i64, i0: i64) -> i64 {
265 var i: i64 = i0
266 while i < n { if buf[i] == (RO_NL as u8) { return i } i = i + 1 }
267 return n
268}
269
270// locate `func <name>(` at BOL and its parameter span, return type span and body braces.
271// returns 1 found, 0 absent, -1 malformed, -2 name too long
272func ro_locate(buf: *u8, n: i64, name: *u8, loc: *i64) -> i64 {
273 let pat: *u8 = sys_mmap(RO_PAT_CAP)
274 let pl: i64 = ro_mk_pat(pat, name)
275 if pl < 0 { sys_munmap(pat, RO_PAT_CAP); return 0 - 2 }
276 let f: i64 = ro_find_bol(buf, n, pat)
277 sys_munmap(pat, RO_PAT_CAP)
278 if f < 0 { return 0 }
279 loc[RO_L_FSTART] = f
280 let ps: i64 = f + pl
281 loc[RO_L_PSTART] = ps
282 var i: i64 = ps
283 var depth: i64 = 1
284 var pe: i64 = 0 - 1
285 while i < n {
286 let c: i64 = buf[i] as i64
287 if c == RO_LPAREN { depth = depth + 1 }
288 if c == RO_RPAREN { depth = depth - 1; if depth == 0 { pe = i; i = n } }
289 i = i + 1
290 }
291 if pe < 0 { return 0 - 1 }
292 loc[RO_L_PEND] = pe
293 var bo: i64 = 0 - 1
294 i = pe + 1
295 while i < n { if buf[i] == (RO_LBRACE as u8) { bo = i; i = n } i = i + 1 }
296 if bo < 0 { return 0 - 1 }
297 loc[RO_L_BOPEN] = bo
298 loc[RO_L_RSTART] = 0 - 1
299 loc[RO_L_REND] = 0 - 1
300 let arrow: i64 = ro_find(buf, bo, pe, "->" as *u8)
301 if arrow >= 0 {
302 let rs: i64 = ro_trim_start(buf, arrow + 2, bo)
303 let re: i64 = ro_trim_end(buf, rs, bo)
304 loc[RO_L_RSTART] = rs
305 loc[RO_L_REND] = re
306 }
307 depth = 1
308 i = bo + 1
309 var bc: i64 = 0 - 1
310 while i < n {
311 let c2: i64 = buf[i] as i64
312 if c2 == RO_QUOTE { i = ro_skip_str(buf, n, i) }
313 else {
314 var handled: i64 = 0
315 if c2 == RO_SLASH { if i + 1 < n { if buf[i + 1] == (RO_SLASH as u8) { i = ro_skip_comment(buf, n, i); handled = 1 } } }
316 if handled == 0 {
317 if c2 == RO_LBRACE { depth = depth + 1 }
318 if c2 == RO_RBRACE { depth = depth - 1; if depth == 0 { bc = i; i = n } }
319 i = i + 1
320 }
321 }
322 }
323 if bc < 0 { return 0 - 1 }
324 loc[RO_L_BCLOSE] = bc
325 return 1
326}
327
328// parameters in buf[ps, pe): prm[4k] = name_off, name_len, type_off, type_len. returns count;
329// -1 when more than RO_MAX_PARAMS, -2 when a parameter carries no type.
330func ro_params(buf: *u8, ps: i64, pe: i64, prm: *i64) -> i64 {
331 var cnt: i64 = 0
332 var s: i64 = ps
333 var i: i64 = ps
334 var depth: i64 = 0
335 while i <= pe {
336 var c: i64 = RO_COMMA
337 if i < pe { c = buf[i] as i64 }
338 if c == RO_LPAREN { depth = depth + 1 }
339 if c == RO_RPAREN { depth = depth - 1 }
340 if c == RO_COMMA { if depth == 0 {
341 let ts: i64 = ro_trim_start(buf, s, i)
342 let te: i64 = ro_trim_end(buf, ts, i)
343 if te > ts {
344 if cnt >= RO_MAX_PARAMS { return 0 - 1 }
345 var col: i64 = 0 - 1
346 var k: i64 = ts
347 while k < te { if buf[k] == (RO_COLON as u8) { col = k; k = te } k = k + 1 }
348 if col < 0 { return 0 - 2 }
349 let ne: i64 = ro_trim_end(buf, ts, col)
350 let tys: i64 = ro_trim_start(buf, col + 1, te)
351 prm[cnt * RO_P_STRIDE + 0] = ts
352 prm[cnt * RO_P_STRIDE + 1] = ne - ts
353 prm[cnt * RO_P_STRIDE + 2] = tys
354 prm[cnt * RO_P_STRIDE + 3] = te - tys
355 cnt = cnt + 1
356 }
357 s = i + 1
358 } }
359 i = i + 1
360 }
361 return cnt
362}
363
364func ro_emit(out: *u8, o0: i64, s: *u8) -> i64 {
365 var o: i64 = o0
366 var i: i64 = 0
367 while s[i] != (0 as u8) { out[o] = s[i]; o = o + 1; i = i + 1 }
368 return o
369}
370
371// where an absent import line goes: after the last import line; else before the first BOL func/const; else 0
372func ro_import_slot(buf: *u8, n: i64) -> i64 {
373 var last: i64 = 0 - 1
374 var from: i64 = 0
375 var go: i64 = 1
376 while go == 1 {
377 let p: i64 = ro_find(buf, n, from, "import \"" as *u8)
378 if p < 0 { go = 0 }
379 if go == 1 {
380 if p == 0 { last = p } else { if buf[p - 1] == (RO_NL as u8) { last = p } }
381 from = p + 1
382 }
383 }
384 if last >= 0 {
385 var e: i64 = last
386 while e < n { if buf[e] == (RO_NL as u8) { return e + 1 } e = e + 1 }
387 return n
388 }
389 var f1: i64 = ro_find_bol(buf, n, "func " as *u8)
390 let c1: i64 = ro_find_bol(buf, n, "const " as *u8)
391 if c1 >= 0 { if f1 < 0 { f1 = c1 } else { if c1 < f1 { f1 = c1 } } }
392 if f1 < 0 { f1 = 0 }
393 return f1
394}
395
396// compose the retired file into out (cap >= n + RO_OUT_SLACK); returns its length.
397// import_added[0] = 1 when an import line was inserted.
398func ro_compose(buf: *u8, n: i64, loc: *i64, prm: *i64, np: i64, owner_fn: *u8, libname: *u8, out: *u8, import_added: *i64) -> i64 {
399 let ipat: *u8 = sys_mmap(RO_PAT_CAP)
400 ro_mk_import(ipat, libname)
401 var ins: i64 = 0 - 1
402 if ro_find(buf, n, 0, ipat) < 0 { ins = ro_import_slot(buf, n) }
403 import_added[0] = 0
404 let bo: i64 = loc[RO_L_BOPEN]
405 let bc: i64 = loc[RO_L_BCLOSE]
406 var o: i64 = 0
407 var i: i64 = 0
408 while i <= bo {
409 if i == ins { o = ro_emit(out, o, ipat); out[o] = RO_NL as u8; o = o + 1; import_added[0] = 1 }
410 out[o] = buf[i]; o = o + 1
411 i = i + 1
412 }
413 o = ro_emit(out, o, " return " as *u8)
414 o = ro_emit(out, o, owner_fn)
415 out[o] = RO_LPAREN as u8; o = o + 1
416 var p: i64 = 0
417 while p < np {
418 if p > 0 { o = ro_emit(out, o, ", " as *u8) }
419 var k: i64 = 0
420 while k < prm[p * RO_P_STRIDE + 1] { out[o] = buf[prm[p * RO_P_STRIDE + 0] + k]; o = o + 1; k = k + 1 }
421 p = p + 1
422 }
423 o = ro_emit(out, o, ") " as *u8)
424 i = bc
425 while i < n {
426 if i == ins { o = ro_emit(out, o, ipat); out[o] = RO_NL as u8; o = o + 1; import_added[0] = 1 }
427 out[o] = buf[i]; o = o + 1
428 i = i + 1
429 }
430 if ins == n { o = ro_emit(out, o, ipat); out[o] = RO_NL as u8; o = o + 1; import_added[0] = 1 }
431 sys_munmap(ipat, RO_PAT_CAP)
432 return o
433}
434
435func ro_report(path: *u8, fname: *u8, verdict: *u8, code: i64, quiet: i64) -> i64 {
436 if quiet == 0 {
437 ro_out("NX-RETIRE-ONTO file=" as *u8); ro_out(path)
438 ro_out(" fn=" as *u8); ro_out(fname)
439 ro_out(" verdict=" as *u8); ro_out(verdict)
440 ro_out("\n" as *u8)
441 }
442 return code
443}
444
445func ro_rt_eq(a: *u8, la: *i64, b: *u8, lb: *i64) -> i64 {
446 if la[RO_L_RSTART] < 0 { if lb[RO_L_RSTART] < 0 { return 1 } return 0 }
447 if lb[RO_L_RSTART] < 0 { return 0 }
448 return ro_span_eq(a, la[RO_L_RSTART], la[RO_L_REND] - la[RO_L_RSTART], b, lb[RO_L_RSTART], lb[RO_L_REND] - lb[RO_L_RSTART])
449}
450
451// the probe module's basename, unique per (function, process): _ro_probe_<fname>_<pid>
452func ro_probe_name(out: *u8, fname: *u8) -> i64 {
453 var o: i64 = ro_emit(out, 0, "_ro_probe_" as *u8)
454 o = ro_emit(out, o, fname)
455 out[o] = 95 as u8; o = o + 1
456 o = ro_emit_num(out, o, __syscall(RO_SYS_GETPID, 0, 0, 0, 0, 0, 0))
457 out[o] = 0 as u8
458 return o
459}
460
461// paths the probe needs, derived from the corpus root the gatekit already resolves (<X>/runtime/):
462// probe source <X>/runtime/<name>.nx, artifact <X>/_build/<name>.sov.elf, builder <X>/_offc/... with the
463// serving-root twin as the fallback. Returns 1, or 0 when no corpus root is reachable (REFUSED-no-root).
464func ro_probe_paths(name: *u8, src: *u8, elf: *u8, builder: *u8) -> i64 {
465 let root: *u8 = sys_mmap(RO_PROBE_PATH_CAP)
466 if gk_corpus_root(root) == 0 { return 0 }
467 let rl: i64 = ro_slen(root)
468 let x: i64 = rl - ro_slen("runtime/" as *u8)
469 if x < 0 { return 0 }
470 var i: i64 = 0
471 while i < rl { src[i] = root[i]; i = i + 1 }
472 var o: i64 = ro_emit(src, rl, name); o = ro_emit(src, o, ".nx" as *u8); src[o] = 0 as u8
473 i = 0
474 while i < x { elf[i] = root[i]; i = i + 1 }
475 o = ro_emit(elf, x, "_build/" as *u8); o = ro_emit(elf, o, name); o = ro_emit(elf, o, ".sov.elf" as *u8); elf[o] = 0 as u8
476 // the builder also leaves <name>.s and <name>.lock beside the artifact (measured in _build/ after the first
477 // gate runs); their paths share the elf prefix, so the caller derives them by suffix (ro_probe_side)
478 i = 0
479 while i < x { builder[i] = root[i]; i = i + 1 }
480 o = ro_emit(builder, x, "_offc/nx_sov_build_run.elf" as *u8); builder[o] = 0 as u8
481 if gk_exists(builder) == 1 { return 1 }
482 // serving-root twin: <X> is <root>/buildroot/ on the estate, and the tool lives one level up
483 let bl: i64 = ro_slen("buildroot/" as *u8)
484 if x >= bl {
485 i = 0
486 while i < x - bl { builder[i] = root[i]; i = i + 1 }
487 o = ro_emit(builder, x - bl, "nx_sov_build_run.elf" as *u8); builder[o] = 0 as u8
488 if gk_exists(builder) == 1 { return 1 }
489 }
490 return 0
491}
492
493// <elf path minus ".sov.elf"> + suffix -> out; used to name and remove the builder's side-files
494func ro_probe_side(elf: *u8, suffix: *u8, out: *u8) -> i64 {
495 let el: i64 = ro_slen(elf)
496 let sl: i64 = ro_slen(".sov.elf" as *u8)
497 if el <= sl { out[0] = 0 as u8; return 0 }
498 var i: i64 = 0
499 while i < el - sl { out[i] = elf[i]; i = i + 1 }
500 let o: i64 = ro_emit(out, el - sl, suffix)
501 out[o] = 0 as u8
502 return o
503}
504// remove every artifact a probe build leaves: the elf, the .s, the .lock
505func ro_probe_clean(elf: *u8) -> i64 {
506 let side: *u8 = sys_mmap(RO_PROBE_PATH_CAP)
507 gk_rm(elf)
508 ro_probe_side(elf, ".s" as *u8, side); gk_rm(side)
509 ro_probe_side(elf, ".lock" as *u8, side); gk_rm(side)
510 sys_munmap(side, RO_PROBE_PATH_CAP)
511 return 0
512}
513
514// emit the probe program: F = the private function, O = the owner, both unary i64 -> i64.
515func ro_probe_src(out: *u8, cand_base: *u8, owner_base: *u8, fname: *u8, owner_fn: *u8) -> i64 {
516 var o: i64 = 0
517 o = ro_emit(out, o, "// GENERATED by nx_retire_onto prove; transient, named per function and pid, removed after the run\n" as *u8)
518 o = ro_emit(out, o, "import \"" as *u8); o = ro_emit(out, o, cand_base); o = ro_emit(out, o, "\"\n" as *u8)
519 o = ro_emit(out, o, "import \"" as *u8); o = ro_emit(out, o, owner_base); o = ro_emit(out, o, "\"\n" as *u8)
520 o = ro_emit(out, o, "func main() -> i64 {\n var v: i64 = 0\n while v <= " as *u8)
521 o = ro_emit_num(out, o, RO_PROBE_DENSE)
522 o = ro_emit(out, o, " { if " as *u8); o = ro_emit(out, o, fname); o = ro_emit(out, o, "(v) != " as *u8); o = ro_emit(out, o, owner_fn)
523 o = ro_emit(out, o, "(v) { return 1 } v = v + 1 }\n var k: i64 = 20\n while k < 63 {\n let p: i64 = 1 << k\n" as *u8)
524 o = ro_emit(out, o, " if " as *u8); o = ro_emit(out, o, fname); o = ro_emit(out, o, "(p) != " as *u8); o = ro_emit(out, o, owner_fn); o = ro_emit(out, o, "(p) { return 1 }\n" as *u8)
525 o = ro_emit(out, o, " if " as *u8); o = ro_emit(out, o, fname); o = ro_emit(out, o, "(p - 1) != " as *u8); o = ro_emit(out, o, owner_fn); o = ro_emit(out, o, "(p - 1) { return 1 }\n" as *u8)
526 o = ro_emit(out, o, " if " as *u8); o = ro_emit(out, o, fname); o = ro_emit(out, o, "(p + 1) != " as *u8); o = ro_emit(out, o, owner_fn); o = ro_emit(out, o, "(p + 1) { return 1 }\n" as *u8)
527 // NEGATIVE inputs are outside an isqrt's domain, and that is exactly where two implementations may
528 // legitimately disagree (one returns 0, one loops, one returns the input). Behaviour-preserving means
529 // identical there too, so the owner must match the private body on -(2^k) as well; over-strict is the
530 // safe direction -- a DIFFER here is a named refusal, never a silent change.
531 o = ro_emit(out, o, " if " as *u8); o = ro_emit(out, o, fname); o = ro_emit(out, o, "(0 - p) != " as *u8); o = ro_emit(out, o, owner_fn); o = ro_emit(out, o, "(0 - p) { return 1 }\n k = k + 1\n }\n" as *u8)
532 o = ro_emit(out, o, " var m: i64 = 0 - 1\n while m > 0 - 1048577 { if " as *u8); o = ro_emit(out, o, fname); o = ro_emit(out, o, "(m) != " as *u8); o = ro_emit(out, o, owner_fn); o = ro_emit(out, o, "(m) { return 1 } m = m * 2 }\n" as *u8)
533 o = ro_emit(out, o, " var s: i64 = 1024\n while s < 3037000499 {\n let q: i64 = s * s\n" as *u8)
534 o = ro_emit(out, o, " if " as *u8); o = ro_emit(out, o, fname); o = ro_emit(out, o, "(q) != " as *u8); o = ro_emit(out, o, owner_fn); o = ro_emit(out, o, "(q) { return 1 }\n" as *u8)
535 o = ro_emit(out, o, " if " as *u8); o = ro_emit(out, o, fname); o = ro_emit(out, o, "(q - 1) != " as *u8); o = ro_emit(out, o, owner_fn); o = ro_emit(out, o, "(q - 1) { return 1 }\n s = s * 3 / 2 + 1\n }\n return 0\n}\n" as *u8)
536 out[o] = 0 as u8
537 return o
538}
539func ro_emit_num(out: *u8, o0: i64, v0: i64) -> i64 {
540 let b: *u8 = sys_mmap(32)
541 var v: i64 = v0
542 var neg: i64 = 0
543 if v < 0 { neg = 1; v = 0 - v }
544 var i: i64 = 31
545 b[i] = 0 as u8
546 if v == 0 { i = i - 1; b[i] = 48 as u8 }
547 while v > 0 { i = i - 1; b[i] = ((v % 10) + 48) as u8; v = v / 10 }
548 // a negative must never emit NOTHING: measured 2026-08-24, a wrong syscall number returned -EINVAL and the
549 // probe name silently lost its pid suffix while everything else read as if it had one
550 if neg == 1 { i = i - 1; b[i] = 45 as u8 }
551 let o: i64 = ro_emit(out, o0, b + i)
552 sys_munmap(b, 32)
553 return o
554}
555
556// classify a non-zero builder exit from the builder's OWN output: its admission governor prints VERDICT=QUEUE
557// when it declines to compile on a saturated box. A pure function of (output, rc) so the gate can plant both
558// shapes without needing a storm. Returns RO_PROVE_ADMISSION or RO_PROVE_UNBUILDABLE.
559func ro_build_rc_class(out: *u8, n: i64, rc: i64) -> i64 {
560 if rc == 0 { return RO_PROVE_PASS }
561 if ro_find(out, n, 0, "VERDICT=QUEUE" as *u8) >= 0 { return RO_PROVE_ADMISSION }
562 if ro_find(out, n, 0, "REFUSED-BUILD-ADMIT" as *u8) >= 0 { return RO_PROVE_ADMISSION }
563 return RO_PROVE_UNBUILDABLE
564}
565
566// the BINARY probe: F(a, b) vs O(a, b) over the cartesian square of a declared 49-value ladder
567// (0, +-1, +-2, +-3, +-7, +-2^4, +-2^7, ... +-2^61 in steps of three bits) = 2,401 pairs. The ladder is emitted
568// INTO the probe as a function so the probe carries its own declaration of what it examined.
569const RO_LADDER2_N: i64 = 49
570func ro_probe_src2(out: *u8, cand_base: *u8, owner_base: *u8, fname: *u8, owner_fn: *u8) -> i64 {
571 var o: i64 = 0
572 o = ro_emit(out, o, "// GENERATED by nx_retire_onto prove (binary); transient, named per function and pid, removed after the run\n" as *u8)
573 o = ro_emit(out, o, "import \"" as *u8); o = ro_emit(out, o, cand_base); o = ro_emit(out, o, "\"\n" as *u8)
574 o = ro_emit(out, o, "import \"" as *u8); o = ro_emit(out, o, owner_base); o = ro_emit(out, o, "\"\n" as *u8)
575 o = ro_emit(out, o, "func _ro_lad(k: i64) -> i64 {\n if k == 0 { return 0 }\n let s: i64 = k % 2\n let m: i64 = (k + 1) / 2\n var v: i64 = 0\n" as *u8)
576 o = ro_emit(out, o, " if m == 1 { v = 1 }\n if m == 2 { v = 2 }\n if m == 3 { v = 3 }\n if m == 4 { v = 7 }\n if m >= 5 { v = 1 << (4 + (m - 5) * 3) }\n if s == 1 { return 0 - v }\n return v\n}\n" as *u8)
577 o = ro_emit(out, o, "func main() -> i64 {\n var i: i64 = 0\n while i < " as *u8); o = ro_emit_num(out, o, RO_LADDER2_N)
578 o = ro_emit(out, o, " {\n var j: i64 = 0\n while j < " as *u8); o = ro_emit_num(out, o, RO_LADDER2_N)
579 o = ro_emit(out, o, " {\n let a: i64 = _ro_lad(i)\n let b: i64 = _ro_lad(j)\n if " as *u8)
580 o = ro_emit(out, o, fname); o = ro_emit(out, o, "(a, b) != " as *u8); o = ro_emit(out, o, owner_fn)
581 o = ro_emit(out, o, "(a, b) { return 1 }\n j = j + 1\n }\n i = i + 1\n }\n return 0\n}\n" as *u8)
582 out[o] = 0 as u8
583 return o
584}
585
586// prove <fname> in <path> is <owner_fn> on the declared ladder. Returns RO_PROVE_*.
587// Unary and binary i64 -> i64 are supported; every parameter must be i64 and the return type i64.
588func ro_prove(path: *u8, fname: *u8, lib: *u8, owner_fn: *u8, np: i64, buf: *u8, prm: *i64, loc: *i64) -> i64 {
589 if np < 1 { return RO_PROVE_UNSUPPORTED }
590 if np > 2 { return RO_PROVE_UNSUPPORTED }
591 var pi: i64 = 0
592 while pi < np {
593 if ro_span_eq(buf, prm[pi * RO_P_STRIDE + 2], prm[pi * RO_P_STRIDE + 3], "i64" as *u8, 0, 3) == 0 { return RO_PROVE_UNSUPPORTED }
594 pi = pi + 1
595 }
596 if loc[RO_L_RSTART] < 0 { return RO_PROVE_UNSUPPORTED }
597 if ro_span_eq(buf, loc[RO_L_RSTART], loc[RO_L_REND] - loc[RO_L_RSTART], "i64" as *u8, 0, 3) == 0 { return RO_PROVE_UNSUPPORTED }
598 let name: *u8 = sys_mmap(RO_PAT_CAP)
599 ro_probe_name(name, fname)
600 let src: *u8 = sys_mmap(RO_PROBE_PATH_CAP)
601 let elf: *u8 = sys_mmap(RO_PROBE_PATH_CAP)
602 let builder: *u8 = sys_mmap(RO_PROBE_PATH_CAP)
603 if ro_probe_paths(name, src, elf, builder) == 0 { return RO_PROVE_NOROOT }
604 let text: *u8 = sys_mmap(RO_PROBE_SRC_CAP)
605 if np == 2 { ro_probe_src2(text, ro_basename(path), ro_basename(lib), fname, owner_fn) }
606 else { ro_probe_src(text, ro_basename(path), ro_basename(lib), fname, owner_fn) }
607 if gk_write(src, text) < 0 { return RO_PROVE_NOROOT }
608 let out: *u8 = sys_mmap(RO_PROBE_OUTCAP)
609 let ol: *i64 = sys_mmap(16) as *i64
610 ro_probe_clean(elf)
611 let brc: i64 = gk_run_capture_ms(builder, name, "--build-only" as *u8, 0 as *u8, 0 as *u8, RO_BUILD_MS, out, RO_PROBE_OUTCAP, ol)
612 var verdict: i64 = ro_build_rc_class(out, ol[0], brc)
613 if verdict == RO_PROVE_PASS { verdict = RO_PROVE_UNBUILDABLE }
614 if brc == 0 { if gk_exists(elf) == 1 {
615 let rrc: i64 = gk_run_capture_ms(elf, 0 as *u8, 0 as *u8, 0 as *u8, 0 as *u8, RO_PROBE_MS, out, RO_PROBE_OUTCAP, ol)
616 if rrc == 0 { verdict = RO_PROVE_PASS } else { verdict = RO_PROVE_DIFFER }
617 } }
618 gk_rm(src)
619 ro_probe_clean(elf)
620 return verdict
621}
622
623// retire <fname> in <path> onto <owner_fn> declared in <lib>. Returns an RO_* code and prints one line.
624// mode: RO_MODE_DRY (signature check only) / RO_MODE_PROVE (plus the differential probe, no write) /
625// RO_MODE_APPLY (probe, then write only on PASS).
626func ro_one(path: *u8, fname: *u8, lib: *u8, owner_fn: *u8, mode: i64, quiet: i64) -> i64 {
627 if ro_streq(ro_basename(path), ro_basename(lib)) == 1 { return ro_report(path, fname, "REFUSED-owner-is-self" as *u8, RO_REFUSED, quiet) }
628 let lp: *i64 = sys_mmap(16) as *i64
629 let buf: *u8 = sys_read_file(path, lp)
630 if (buf as i64) == 0 { return ro_report(path, fname, "REFUSED-unreadable-file" as *u8, RO_REFUSED, quiet) }
631 let n: i64 = lp[0]
632 let loc: *i64 = sys_mmap(RO_L_N * 8) as *i64
633 let lf: i64 = ro_locate(buf, n, fname, loc)
634 if lf == 0 { return ro_report(path, fname, "REFUSED-no-such-function" as *u8, RO_REFUSED, quiet) }
635 if lf == 0 - 2 { return ro_report(path, fname, "REFUSED-name-too-long" as *u8, RO_REFUSED, quiet) }
636 if lf < 0 { return ro_report(path, fname, "REFUSED-malformed-function" as *u8, RO_REFUSED, quiet) }
637 let prm: *i64 = sys_mmap(RO_MAX_PARAMS * RO_P_STRIDE * 8) as *i64
638 let np: i64 = ro_params(buf, loc[RO_L_PSTART], loc[RO_L_PEND], prm)
639 if np < 0 { return ro_report(path, fname, "REFUSED-params-unparsable-or-over-cap" as *u8, RO_REFUSED, quiet) }
640 let lp2: *i64 = sys_mmap(16) as *i64
641 let ob: *u8 = sys_read_file(lib, lp2)
642 if (ob as i64) == 0 { return ro_report(path, fname, "REFUSED-owner-lib-unreadable" as *u8, RO_REFUSED, quiet) }
643 let on: i64 = lp2[0]
644 let oloc: *i64 = sys_mmap(RO_L_N * 8) as *i64
645 if ro_locate(ob, on, owner_fn, oloc) != 1 { return ro_report(path, fname, "REFUSED-owner-fn-absent" as *u8, RO_REFUSED, quiet) }
646 let oprm: *i64 = sys_mmap(RO_MAX_PARAMS * RO_P_STRIDE * 8) as *i64
647 let onp: i64 = ro_params(ob, oloc[RO_L_PSTART], oloc[RO_L_PEND], oprm)
648 if onp != np { return ro_report(path, fname, "REFUSED-arity-mismatch" as *u8, RO_REFUSED, quiet) }
649 var p: i64 = 0
650 while p < np {
651 if ro_span_eq(buf, prm[p * RO_P_STRIDE + 2], prm[p * RO_P_STRIDE + 3], ob, oprm[p * RO_P_STRIDE + 2], oprm[p * RO_P_STRIDE + 3]) == 0 {
652 return ro_report(path, fname, "REFUSED-param-type-mismatch" as *u8, RO_REFUSED, quiet)
653 }
654 p = p + 1
655 }
656 if ro_rt_eq(buf, loc, ob, oloc) == 0 { return ro_report(path, fname, "REFUSED-return-type-mismatch" as *u8, RO_REFUSED, quiet) }
657 let out: *u8 = sys_mmap(n + RO_OUT_SLACK)
658 let ia: *i64 = sys_mmap(8) as *i64
659 let no: i64 = ro_compose(buf, n, loc, prm, np, owner_fn, ro_basename(lib), out, ia)
660 if no == n { if ro_span_eq(out, 0, no, buf, 0, n) == 1 { return ro_report(path, fname, "ALREADY-retired" as *u8, RO_ALREADY, quiet) } }
661 if mode == RO_MODE_DRY {
662 if quiet == 0 {
663 ro_out("NX-RETIRE-ONTO file=" as *u8); ro_out(path); ro_out(" fn=" as *u8); ro_out(fname)
664 ro_out(" onto=" as *u8); ro_out(owner_fn); ro_out(" arity=" as *u8); ro_num(np)
665 ro_out(" body_bytes=" as *u8); ro_num(loc[RO_L_BCLOSE] - loc[RO_L_BOPEN] - 1)
666 ro_out(" import=" as *u8); if ia[0] == 1 { ro_out("would-add" as *u8) } else { ro_out("present" as *u8) }
667 ro_out(" verdict=RETIRABLE-dry\n" as *u8)
668 }
669 return RO_RETIRABLE
670 }
671 let pv: i64 = ro_prove(path, fname, lib, owner_fn, np, buf, prm, loc)
672 if pv == RO_PROVE_UNSUPPORTED { return ro_report(path, fname, "REFUSED-prove-unsupported (unary or binary i64 -> i64 only; a PROGRAM's private helper cannot be imported by a probe -- lift it into a lib first)" as *u8, RO_REFUSED_UNSUPPORTED, quiet) }
673 if pv == RO_PROVE_NOROOT { return ro_report(path, fname, "REFUSED-prove-no-corpus-root-or-builder" as *u8, RO_REFUSED_UNBUILDABLE, quiet) }
674 if pv == RO_PROVE_ADMISSION { return ro_report(path, fname, "DEFERRED-builder-admission-refused (the BOX is saturated; nothing is known about this candidate -- re-run when the storm clears)" as *u8, RO_DEFERRED_ADMISSION, quiet) }
675 if pv == RO_PROVE_UNBUILDABLE { return ro_report(path, fname, "REFUSED-probe-does-not-build (the lib does not compile natively beside the owner)" as *u8, RO_REFUSED_UNBUILDABLE, quiet) }
676 if pv == RO_PROVE_DIFFER { return ro_report(path, fname, "REFUSED-semantics-differ (the private body is NOT the owner on the declared ladder)" as *u8, RO_REFUSED_DIFFER, quiet) }
677 if mode == RO_MODE_PROVE {
678 if quiet == 0 {
679 ro_out("NX-RETIRE-ONTO file=" as *u8); ro_out(path); ro_out(" fn=" as *u8); ro_out(fname)
680 ro_out(" onto=" as *u8); ro_out(owner_fn); ro_out(" ladder=0.." as *u8); ro_num(RO_PROBE_DENSE)
681 ro_out("+pow2+-1+squares verdict=PROVEN-equal (no write)\n" as *u8)
682 }
683 return RO_PROVEN
684 }
685 let fd: i64 = __syscall(RO_SYS_OPENAT, RO_AT_FDCWD, path, RO_O_WRONLY_CREAT_TRUNC, RO_MODE_644, 0, 0)
686 if fd < 0 { return ro_report(path, fname, "REFUSED-cannot-write" as *u8, RO_REFUSED, quiet) }
687 sys_write(fd, out, no)
688 sys_close(fd)
689 if quiet == 0 {
690 ro_out("NX-RETIRE-ONTO file=" as *u8); ro_out(path); ro_out(" fn=" as *u8); ro_out(fname)
691 ro_out(" onto=" as *u8); ro_out(owner_fn); ro_out(" bytes=" as *u8); ro_num(n); ro_out("->" as *u8); ro_num(no)
692 ro_out(" import=" as *u8); if ia[0] == 1 { ro_out("added" as *u8) } else { ro_out("present" as *u8) }
693 ro_out(" verdict=APPLIED (PROVEN equal on the declared ladder before the write; the consumer rebuild and its gates remain the behavioural referee)\n" as *u8)
694 }
695 return RO_APPLIED
696}
697
698// sweep the library plane: every symbol ending in <suffix> (and not the owner function itself, and not in the
699// owner lib) is a candidate; each is retired (or dry-checked). tally[RO_*] per code, tally[RO_T_CAND] = candidates.
700// Returns 0 when the plane was read, -2 when the plane is absent/unreadable (REFUSED, nothing examined).
701func ro_sweep(prefix: *u8, suffix: *u8, lib: *u8, owner_fn: *u8, mode: i64, tally: *i64) -> i64 {
702 let lp: *i64 = sys_mmap(16) as *i64
703 let b: *u8 = sts_load_fit(prefix, lp)
704 if (b as i64) == 0 { ro_out("NX-RETIRE-ONTO sweep REFUSED no-plane -- run `nx_libindex build` first\n" as *u8); return 0 - 2 }
705 let n: i64 = lp[0]
706 // MEASURED by this organ's own gate on its first run: sts_load_fit hands back an EMPTY buffer, not a null,
707 // for an unseeded plane, so a sweep over nothing would print candidates=0 partition=0/0 RECONCILES -- a
708 // clean-looking answer about a plane that does not exist. Zero rows is a refusal, never a census.
709 if n <= 0 { ro_out("NX-RETIRE-ONTO sweep REFUSED empty-or-absent-plane -- run `nx_libindex build` first\n" as *u8); return 0 - 2 }
710 let pathbuf: *u8 = sys_mmap(RO_PATH_CAP)
711 let namebuf: *u8 = sys_mmap(RO_PAT_CAP)
712 var t: i64 = 0
713 while t < RO_T_N { tally[t] = 0; t = t + 1 }
714 var ls: i64 = 0
715 var i: i64 = 0
716 while i <= n {
717 var eol: i64 = 0
718 if i == n { eol = 1 }
719 if i < n { if b[i] == (RO_NL as u8) { eol = 1 } }
720 if eol == 1 {
721 if i > ls {
722 // columns: name TAB path TAB title TAB syms
723 var t1: i64 = 0 - 1
724 var t2: i64 = 0 - 1
725 var t3: i64 = 0 - 1
726 var k: i64 = ls
727 while k < i {
728 if b[k] == (RO_TAB as u8) {
729 if t1 < 0 { t1 = k } else { if t2 < 0 { t2 = k } else { if t3 < 0 { t3 = k } } }
730 }
731 k = k + 1
732 }
733 if t3 >= 0 {
734 let plen: i64 = t2 - t1 - 1
735 if plen > 0 { if plen < RO_PATH_CAP - 1 {
736 var q: i64 = 0
737 while q < plen { pathbuf[q] = b[t1 + 1 + q]; q = q + 1 }
738 pathbuf[plen] = 0 as u8
739 if ro_streq(ro_basename(pathbuf), ro_basename(lib)) == 0 {
740 var ss: i64 = t3 + 1
741 var m: i64 = t3 + 1
742 while m <= i {
743 var tokend: i64 = 0
744 if m == i { tokend = 1 }
745 if m < i { if b[m] == (RO_SP as u8) { tokend = 1 } }
746 if tokend == 1 {
747 if m > ss { if m - ss < RO_PAT_CAP - 1 {
748 if ro_ends_with(b, ss, m, suffix) == 1 {
749 var r: i64 = 0
750 while r < m - ss { namebuf[r] = b[ss + r]; r = r + 1 }
751 namebuf[m - ss] = 0 as u8
752 if ro_streq(namebuf, owner_fn) == 0 {
753 tally[RO_T_CAND] = tally[RO_T_CAND] + 1
754 let code: i64 = ro_one(pathbuf, namebuf, lib, owner_fn, mode, 0)
755 tally[code] = tally[code] + 1
756 }
757 }
758 } }
759 ss = m + 1
760 }
761 m = m + 1
762 }
763 }
764 } }
765 }
766 }
767 ls = i + 1
768 }
769 i = i + 1
770 }
771 let sum: i64 = tally[RO_RETIRABLE] + tally[RO_ALREADY] + tally[RO_REFUSED] + tally[RO_APPLIED] + tally[RO_PROVEN] + tally[RO_REFUSED_DIFFER] + tally[RO_REFUSED_UNBUILDABLE] + tally[RO_REFUSED_UNSUPPORTED] + tally[RO_DEFERRED_ADMISSION]
772 ro_out("NX-RETIRE-ONTO sweep suffix=" as *u8); ro_out(suffix); ro_out(" onto=" as *u8); ro_out(owner_fn)
773 ro_out(" mode=" as *u8); ro_num(mode)
774 ro_out(" candidates=" as *u8); ro_num(tally[RO_T_CAND])
775 ro_out(" retirable_dry=" as *u8); ro_num(tally[RO_RETIRABLE])
776 ro_out(" proven=" as *u8); ro_num(tally[RO_PROVEN])
777 ro_out(" already=" as *u8); ro_num(tally[RO_ALREADY])
778 ro_out(" applied=" as *u8); ro_num(tally[RO_APPLIED])
779 ro_out(" refused_signature=" as *u8); ro_num(tally[RO_REFUSED])
780 ro_out(" refused_semantics_differ=" as *u8); ro_num(tally[RO_REFUSED_DIFFER])
781 ro_out(" refused_unbuildable=" as *u8); ro_num(tally[RO_REFUSED_UNBUILDABLE])
782 ro_out(" refused_unsupported=" as *u8); ro_num(tally[RO_REFUSED_UNSUPPORTED])
783 ro_out(" deferred_admission=" as *u8); ro_num(tally[RO_DEFERRED_ADMISSION])
784 ro_out(" partition=" as *u8); ro_num(sum); ro_out("/" as *u8); ro_num(tally[RO_T_CAND])
785 if sum == tally[RO_T_CAND] { ro_out(" RECONCILES\n" as *u8) } else { ro_out(" LEAK\n" as *u8) }
786 return 0
787}