code wiki / _hdl_build / nx_oo_extract.nx

nx_oo_extract.nx source

↩ module page · 653 lines · 37236 B

1// nx_oo_extract.nx -- BYTE-PROVEN OO DUP-FUNCTION EXTRACTOR (the real "object-oriented without losing 2// functionality" operation, unblocked by the 2026-07-21 byte-equiv proof). Moves functions that are 3// DUPLICATED byte-identically across N consumers into a shared base lib, repoints each consumer to 4// import it, and COMMITS only if EVERY consumer's rebuild is BYTE-IDENTICAL to before (else REVERTS all). 5// never-brick + rule-13 (originals backed up). Every refusal carries verdict+reason+fix (operator law). 6// argv: <funcname[,funcname...]> <baselib-srcpath> <buildonly-elf> <consumer-srcpath1> [consumer-srcpath2 ...] 7// [--proof=bytes|behave] [--workload=<path>] 8// exit: 0 EXTRACTED | 1 REFUSED(reverted) | 2 usage/precondition | 3 io/build error(reverted) 9// 10// v2 (2026-08-18, the /compare generator dedup): TWO capabilities the single-function v1 could not do. 11// (1) N FUNCTIONS IN ONE PASS. A comma-separated funcname list moves the whole shared set at once with ONE 12// import line and ONE proof cycle. v1 needed N runs and each run left the consumer importing a lib that 13// the NEXT run would rewrite -- and a base lib holding one function is not a base class, it is a shard. 14// (2) BEHAVIOURAL PROOF. `--proof=behave` proves the extraction by the consumer's OUTPUT, not its image: 15// each consumer is run BEFORE and AFTER over every argv line in --workload that names it, and the 16// captured stdout must be byte-identical. Needed because an added `import` line legitimately reorders 17// the compiled image (functions are laid out in source order), so `--proof=bytes` REFUSES a correct 18// extraction; the byte proof stays the default because it is the stronger claim when it holds. 19// Workload format: one line per run, `<consumer-target> <argv1> <argv2> ...`; a consumer with no 20// workload line has NO proof and the run REFUSES (a proof over an empty set is not a proof). 21// A function is extracted only if its body is byte-identical across EVERY consumer; a divergent body is 22// REFUSED by name -- resolve by rename or by making them equal first, never by picking one. 23// license_tier: ORIGINAL No hw writes (Rule 26). 24import "nx_seat_drive_lib.nx" 25import "nx_seg_store.nx" 26import "nx_deploy_lib.nx" 27import "nx_syscalls.nx" 28 29const OE_CAP: i64 = 2097152 30const OE_MAXC: i64 = 128 31const OE_MAXF: i64 = 64 // functions per extraction (argv[1] list); a REFUSED-by-count if exceeded 32const OE_NAME: i64 = 128 // one function-name slot 33const OE_MAXW: i64 = 256 // workload lines 34const OE_WARGV: i64 = 32 // argv tokens per workload line 35const OE_ABSPATH: i64 = 1024 // an absolute path buffer: start-cwd + /buildroot/_build/<target>.sov.elf 36 37func oe_read(path: *u8, buf: *u8, cap: i64) -> i64 { 38 let fd: i64 = sys_openat_rd(path) 39 if fd < 0 { return 0 - 1 } 40 var n: i64 = 0 41 var r: i64 = sys_read(fd, buf, cap - 1) 42 while r > 0 { n = n + r; if n >= cap - 1 { r = 0 } else { r = sys_read(fd, buf + n, cap - 1 - n) } } 43 sys_close(fd) 44 return n 45} 46func oe_isid(c: i64) -> i64 { 47 if c >= 97 { if c <= 122 { return 1 } } 48 if c >= 65 { if c <= 90 { return 1 } } 49 if c >= 48 { if c <= 57 { return 1 } } 50 if c == 95 { return 1 } 51 return 0 52} 53func oe_eq(a: *u8, an: i64, b: *u8, bn: i64) -> i64 { if an != bn { return 0 } var i: i64 = 0; while i < an { if a[i] != b[i] { return 0 } i = i + 1 } return 1 } 54func oe_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 } 55func oe_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 } 56// find func <fname>( at a line start; out[0]=body-start(the 'f'), out[1]=body-end(next func or n); ret 1/0 57func oe_find_func(buf: *u8, n: i64, fname: *u8, out: *i64) -> i64 { 58 var nl: i64 = 0 59 while fname[nl] != (0 as u8) { nl = nl + 1 } 60 var i: i64 = 0 61 var bol: i64 = 1 62 var fstart: i64 = 0 - 1 63 while i < n { 64 if bol == 1 { 65 var m: i64 = 1 66 if i + 5 + nl + 1 > n { m = 0 } 67 if m == 1 { if buf[i] != (102 as u8) { m = 0 } } 68 if m == 1 { if buf[i+1] != (117 as u8) { m = 0 } } 69 if m == 1 { if buf[i+2] != (110 as u8) { m = 0 } } 70 if m == 1 { if buf[i+3] != (99 as u8) { m = 0 } } 71 if m == 1 { if buf[i+4] != (32 as u8) { m = 0 } } 72 if m == 1 { 73 var k: i64 = 0 74 while k < nl { if buf[i+5+k] != fname[k] { m = 0; k = nl } else { k = k + 1 } } 75 } 76 if m == 1 { if buf[i+5+nl] != (40 as u8) { m = 0 } } 77 if m == 1 { 78 if fstart < 0 { 79 fstart = i 80 } else { 81 out[0] = fstart; out[1] = i; return 1 82 } 83 } else { 84 // any OTHER top-level declaration after we found ours ends the range: `func `, `const `, 85 // `struct `, `import ` (2026-08-18: a `const` between two functions was being swallowed 86 // into the earlier body, so two consumers differing only by a const's PLACEMENT read as 87 // divergent functions). 88 var isdecl: i64 = 0 89 if i + 5 <= n { if buf[i] == (102 as u8) { if buf[i+1] == (117 as u8) { if buf[i+2] == (110 as u8) { if buf[i+3] == (99 as u8) { if buf[i+4] == (32 as u8) { isdecl = 1 } } } } } } 90 if i + 6 <= n { if buf[i] == (99 as u8) { if buf[i+1] == (111 as u8) { if buf[i+2] == (110 as u8) { if buf[i+3] == (115 as u8) { if buf[i+4] == (116 as u8) { if buf[i+5] == (32 as u8) { isdecl = 1 } } } } } } } 91 if i + 7 <= n { if buf[i] == (115 as u8) { if buf[i+1] == (116 as u8) { if buf[i+2] == (114 as u8) { if buf[i+3] == (117 as u8) { if buf[i+4] == (99 as u8) { if buf[i+5] == (116 as u8) { if buf[i+6] == (32 as u8) { isdecl = 1 } } } } } } } } 92 if i + 7 <= n { if buf[i] == (105 as u8) { if buf[i+1] == (109 as u8) { if buf[i+2] == (112 as u8) { if buf[i+3] == (111 as u8) { if buf[i+4] == (114 as u8) { if buf[i+5] == (116 as u8) { if buf[i+6] == (32 as u8) { isdecl = 1 } } } } } } } } 93 if isdecl == 1 { if fstart >= 0 { out[0] = fstart; out[1] = i; return 1 } } 94 } 95 } 96 let c: i64 = buf[i] as i64 97 if c == 10 { bol = 1 } else { bol = 0 } 98 i = i + 1 99 } 100 if fstart >= 0 { out[0] = fstart; out[1] = n; return 1 } 101 return 0 102} 103// TRIM TRAILING BLANK LINES from a found body (2026-08-18): the extent above runs to the next `func` 104// line, so it swallows the blank lines BETWEEN functions -- and two consumers that differ only by 105// "one blank line after kv_n" read as DIVERGENT. Blank lines are not part of a function; the move 106// carries the body up to its last non-blank line and the byte-identity test judges the code. 107func oe_trim_body_end(buf: *u8, out: *i64) -> i64 { 108 // Walk back WHOLE LINES: a trailing line that is blank or begins with `//` (after indentation) is 109 // not the function's -- it is whitespace, or the header comment of the NEXT declaration (the estate 110 // documents a function in the lines ABOVE it). Stop at the first trailing line holding code. 111 var e: i64 = out[1] 112 let s: i64 = out[0] 113 var go: i64 = 1 114 while go == 1 { 115 if e <= s { go = 0 } else { 116 // find start of the last line ending at e (buf[e-1] is its last byte, or the '\n' before it) 117 var le: i64 = e 118 if le > s { if buf[le-1] == (10 as u8) { le = le - 1 } } 119 var ls: i64 = le 120 while ls > s { if buf[ls-1] == (10 as u8) { break } ls = ls - 1 } 121 // classify the line buf[ls..le) 122 var i: i64 = ls 123 while i < le { if buf[i] != (32 as u8) { if buf[i] != (9 as u8) { break } } i = i + 1 } 124 var drop: i64 = 0 125 if i >= le { drop = 1 } 126 if drop == 0 { if i + 1 < le { if buf[i] == (47 as u8) { if buf[i+1] == (47 as u8) { drop = 1 } } } } 127 if ls == s { drop = 0 } // never eat the function's own first line 128 if drop == 1 { e = ls } else { go = 0 } 129 } 130 } 131 out[1] = e 132 return e 133} 134func oe_find_func_trim(buf: *u8, n: i64, fname: *u8, out: *i64) -> i64 { 135 let r: i64 = oe_find_func(buf, n, fname, out) 136 if r == 1 { oe_trim_body_end(buf, out) } 137 return r 138} 139// build target (basename of srcpath minus .nx) via buildonly; snapshot buildroot/_build/<target>.sov.elf -> snappath 140func oe_build_snap(buildelf: *u8, target: *u8, snappath: *u8, buf: *u8) -> i64 { 141 let art: *u8 = sys_mmap(512) 142 // buildroot/_build/, NOT /tmp/: nx_sov_build_run has written _build/ (anchoring its own CWD to 143 // buildroot/) since 2026-07-30. Reading /tmp here meant the baseline artifact was NEVER found, so 144 // oe_build_snap returned 0 and every extraction ABORTED with no-baseline-artifact -- the byte-proof 145 // that makes this extractor safe has been inoperative, and it reported the fault as the CONSUMER's 146 // ("does-not-build-standalone") rather than its own. 147 var o: i64 = sd_cat(art, 0, "buildroot/_build/" as *u8) 148 o = sd_cat(art, o, target) 149 o = sd_cat(art, o, ".sov.elf" as *u8) 150 sys_unlinkat(art) 151 let av: *i64 = sys_mmap(16) as *i64 152 av[0] = target as i64 153 dep_run_capture(buildelf, av, 1, "/tmp/oe_build.log" as *u8) 154 let n: i64 = oe_read(art, buf, OE_CAP) 155 if n > 0 { 156 // the builder writes _build/<t>.sov.elf WITHOUT +x on this host, so a behavioural run's execve 157 // failed EACCES -> silent exit 127 -> an empty capture that read as "the consumer emits nothing" 158 // (the estate's inert-artifact landmine, measured 2026-08-19 on this very organ's first behave 159 // run). The extractor owns this baseline artifact's lifecycle, so it makes it runnable itself. 160 nx_chmod(art, MODE_0755) 161 if (snappath as i64) != 0 { ss_writefile(snappath, buf, n) } 162 } 163 return n 164} 165// basename of a path (after last '/') into out; returns len 166func oe_base(path: *u8, out: *u8) -> i64 { 167 var last: i64 = 0 - 1 168 var i: i64 = 0 169 while path[i] != (0 as u8) { if path[i] == (47 as u8) { last = i } i = i + 1 } 170 var o: i64 = 0 171 var j: i64 = last + 1 172 while path[j] != (0 as u8) { out[o] = path[j]; o = o + 1; j = j + 1 } 173 out[o] = 0 as u8 174 return o 175} 176// target = basename minus ".nx" 177func oe_target(path: *u8, out: *u8) -> i64 { 178 let bl: i64 = oe_base(path, out) 179 if bl >= 3 { if out[bl-3] == (46 as u8) { out[bl-3] = 0 as u8; return bl - 3 } } 180 return bl 181} 182// CONSUMER-CONST DEPENDENCY CHECK (2026-08-18, first real run): a moved body that reads a `const` the 183// CONSUMER declares compiles into a lib the parser reads BEFORE that const -- nx_parse: "module const 184// used before its declaration -- it would silently read 0". The extractor must see this in pass 1 and 185// refuse BY NAME, never discover it as a broken build in pass 5. Scans the consumer's `const NAME` 186// declarations and asks whether the body mentions NAME as a whole identifier. Returns 1 + prints the 187// name on the first hit, 0 when clean. 188func oe_body_uses_consumer_const(body: *u8, bn: i64, src: *u8, sn: i64, fname: *u8, cp: *u8) -> i64 { 189 var i: i64 = 0 190 var bol: i64 = 1 191 while i + 6 < sn { 192 if bol == 1 { if src[i] == (99 as u8) { if src[i+1] == (111 as u8) { if src[i+2] == (110 as u8) { if src[i+3] == (115 as u8) { if src[i+4] == (116 as u8) { if src[i+5] == (32 as u8) { 193 // const NAME ... -> NAME = identifier run after "const " 194 var ns: i64 = i + 6 195 var ne: i64 = ns 196 while ne < sn { if oe_isid(src[ne] as i64) == 0 { break } ne = ne + 1 } 197 let nl: i64 = ne - ns 198 if nl > 0 { 199 // whole-identifier search of NAME inside body 200 var j: i64 = 0 201 while j + nl <= bn { 202 var m: i64 = 1 203 var k: i64 = 0 204 while k < nl { if body[j+k] != src[ns+k] { m = 0; k = nl } else { k = k + 1 } } 205 if m == 1 { 206 var lb: i64 = 0 207 if j > 0 { lb = oe_isid(body[j-1] as i64) } 208 var rb: i64 = 0 209 if j + nl < bn { rb = oe_isid(body[j+nl] as i64) } 210 if lb == 0 { if rb == 0 { 211 sd_w("NX-OO-EXTRACT verdict=REFUSED reason=function-" as *u8); sd_w(fname); sd_w("-reads-consumer-const-" as *u8) 212 let nm: *u8 = sys_mmap(nl + 1); var q: i64 = 0; while q < nl { nm[q] = src[ns+q]; q = q + 1 } nm[nl] = 0 as u8 213 sd_w(nm); sd_w("-declared-in:" as *u8); sd_w(cp) 214 sd_w(" fix=a-lib-is-parsed-BEFORE-the-consumer,-so-that-const-would-read-0;-either-move-the-const-into-the-lib-too,-pass-it-as-a-parameter,-or-leave-this-function-out-of-the-list. no-changes-made\n" as *u8) 215 return 1 216 } } 217 } 218 j = j + 1 219 } 220 } 221 } } } } } } } 222 if src[i] == (10 as u8) { bol = 1 } else { bol = 0 } 223 i = i + 1 224 } 225 return 0 226} 227// LIB-IMPORT PLACEMENT (2026-08-18): the import goes AFTER the consumer's leading block of comments, 228// imports and consts -- never at byte 0. Placed first, the lib's bodies were parsed before the 229// consumer's own `import "nx_syscalls.nx"` and every MODE_*/K_MAGIC_* const they read "would silently 230// read 0" (measured). Returns the byte offset of the first line that is none of: blank, //, import, const. 231func oe_import_insert_at(src: *u8, sn: i64) -> i64 { 232 var p: i64 = 0 233 var last_ok: i64 = 0 234 var go: i64 = 1 235 while go == 1 { 236 if p >= sn { go = 0 } else { 237 var e: i64 = p 238 while e < sn { if src[e] == (10 as u8) { break } e = e + 1 } 239 var i: i64 = p 240 while i < e { if src[i] != (32 as u8) { break } i = i + 1 } 241 var ok: i64 = 0 242 if i >= e { ok = 1 } 243 if ok == 0 { if i + 1 < e { if src[i] == (47 as u8) { if src[i+1] == (47 as u8) { ok = 1 } } } } 244 if ok == 0 { if oe_starts(((src as i64) + i) as *u8, "import " as *u8) == 1 { ok = 1 } } 245 if ok == 0 { if oe_starts(((src as i64) + i) as *u8, "const " as *u8) == 1 { ok = 1 } } 246 if ok == 1 { last_ok = e + 1; p = e + 1 } else { go = 0 } 247 } 248 } 249 if last_ok > sn { last_ok = sn } 250 return last_ok 251} 252// split argv[1] "a,b,c" into the names table (OE_NAME stride, NUL-terminated); returns count (0 = empty/overflow) 253func oe_split_names(s: *u8, names: *u8) -> i64 { 254 var cnt: i64 = 0 255 var i: i64 = 0 256 var o: i64 = 0 257 var go: i64 = 1 258 while go == 1 { 259 let c: i64 = s[i] as i64 260 if c == 44 { names[cnt*OE_NAME + o] = 0 as u8; if o > 0 { cnt = cnt + 1 } o = 0; if cnt >= OE_MAXF { return 0 } } 261 else { if c == 0 { names[cnt*OE_NAME + o] = 0 as u8; if o > 0 { cnt = cnt + 1 } go = 0 } else { if o < OE_NAME - 1 { names[cnt*OE_NAME + o] = c as u8; o = o + 1 } } } 262 i = i + 1 263 } 264 return cnt 265} 266// BEHAVIOURAL RUN: execute buildroot/_build/<target>.sov.elf with the workload line's argv, stdout -> outfile. 267// Workload lines: "<target> <a1> <a2> ..." ; only lines whose first token equals target are run; returns runs done. 268// Every run's capture is a separate file (outprefix + index) so a mismatch names the exact argv line. 269// WORKLOAD CWD (2026-08-18, first real run): consumers that read relative data paths (the /compare 270// generators open knowledge/compare/<dom>.matrix from CWD=buildroot) captured EMPTY when forked from the 271// extractor's own CWD -- an empty proof the organ correctly refused. A workload line `@cwd <dir>` sets 272// the directory every FOLLOWING run's child chdirs into before exec; the elf path is made absolute from 273// the extractor's start directory first, so the chdir cannot break the exec. 274func oe_run_in(elf_abs: *u8, av: *i64, na: i64, outfile: *u8, cwd: *u8) -> i64 { 275 let pid: i64 = sys_fork() 276 if pid == 0 { 277 if (cwd as i64) != 0 { if cwd[0] != (0 as u8) { sys_chdir(cwd) } } 278 let fd: i64 = sys_openat_wr(outfile, MODE_0644) 279 if fd >= 0 { sys_dup3(fd, 1, 0); sys_dup3(fd, 2, 0) } 280 let argv: *i64 = sys_mmap(8 * (na + 2)) as *i64 281 let envp: *i64 = sys_mmap(16) as *i64; envp[0] = 0 282 argv[0] = elf_abs as i64 283 var i: i64 = 0 284 while i < na { argv[i+1] = av[i]; i = i + 1 } 285 argv[na+1] = 0 286 sys_execve_clean(elf_abs, argv, envp) 287 sys_exit(127) 288 } 289 let st: *i64 = sys_mmap(16) as *i64 290 sys_wait4(pid, st, 0) 291 return (st[0] >> 8) & 0xff 292} 293func oe_behave(target: *u8, wl: *u8, wn: i64, outprefix: *u8, tokbuf: *u8) -> i64 { 294 let elf: *u8 = sys_mmap(OE_ABSPATH) 295 let here: *u8 = sys_mmap(OE_ABSPATH) 296 sys_getcwd(here, OE_ABSPATH) 297 var eo: i64 = sd_cat(elf, 0, here); eo = sd_cat(elf, eo, "/buildroot/_build/" as *u8); eo = sd_cat(elf, eo, target); eo = sd_cat(elf, eo, ".sov.elf" as *u8) 298 let cwd: *u8 = sys_mmap(512) 299 cwd[0] = 0 as u8 300 let av: *i64 = sys_mmap(8 * OE_WARGV) as *i64 301 let outp: *u8 = sys_mmap(512) 302 var runs: i64 = 0 303 var p: i64 = 0 304 var line: i64 = 0 305 while p < wn { 306 var e: i64 = p 307 while e < wn { if wl[e] == (10 as u8) { break } e = e + 1 } 308 // tokenize wl[p..e) by spaces into tokbuf (NUL-separated), av[] points at each 309 var na: i64 = 0 310 var i: i64 = p 311 var to: i64 = 0 312 while i < e { 313 while i < e { if wl[i] != (32 as u8) { break } i = i + 1 } 314 if i < e { 315 if na < OE_WARGV { av[na] = ((tokbuf as i64) + to) as i64; na = na + 1 } 316 while i < e { if wl[i] == (32 as u8) { break } tokbuf[to] = wl[i]; to = to + 1; i = i + 1 } 317 tokbuf[to] = 0 as u8; to = to + 1 318 } 319 } 320 // `@cwd <dir>` directive: applies to every following run line 321 if na >= 2 { if oe_streq(av[0] as *u8, "@cwd" as *u8) == 1 { 322 var ci: i64 = 0 323 let cd: *u8 = av[1] as *u8 324 while cd[ci] != (0 as u8) { cwd[ci] = cd[ci]; ci = ci + 1 } 325 cwd[ci] = 0 as u8 326 na = 0 327 } } 328 if na >= 1 { if oe_streq(av[0] as *u8, target) == 1 { 329 var oo: i64 = sd_cat(outp, 0, outprefix); oo = sd_cat(outp, oo, "." as *u8); oo = sd_num(outp, oo, line); outp[oo] = 0 as u8 330 // pass argv[1..] to the elf (av[0] is the target name, the elf is argv[0] itself); the 331 // capture path is made absolute too, since the child may chdir before it opens it. 332 // UNBOUNDED BY CONTRACT, NOT BY OVERSIGHT: this tree's nx_deploy_lib twin carries no 333 // deadline runner (dep_run_capture_bounded lives only in runtime/, the two trees have 334 // diverged -- named here, not silently duplicated). A workload line must therefore be a 335 // TERMINATING CLI run (a generator emit, a census, a probe), never a daemon or a serve verb. 336 let rrc: i64 = oe_run_in(elf, ((av as i64) + 8) as *i64, na - 1, outp, cwd) 337 if rrc == 127 { 338 // exec itself failed (inert artifact / wrong path) -- say so, or the empty capture 339 // reads as "the consumer emits nothing" and the wrong subject gets investigated. 340 sd_w("OO-EXEC-FAIL elf=" as *u8); sd_w(elf); sd_w(" (rc=127: not-executable-or-absent; the capture for this line is meaningless)\n" as *u8) 341 } 342 runs = runs + 1 343 } } 344 line = line + 1 345 p = e + 1 346 } 347 return runs 348} 349// VOLATILE-FIELD MASK (2026-08-19, first run on the /compare generators): their json carries 350// `"generated_unix":<epoch>` -- two byte-equal captures taken seconds apart differ ONLY there, so a 351// perfect extraction read as OO-CHANGED. Which fields are volatile is a property of the CONSUMER, so it 352// is DATA: a workload line `@volatile <token>` masks every digit-run following `"<token>":` in BOTH 353// captures before the compare (digits -> '0'; nothing else touched, so any other drift still fails). 354func oe_mask_volatile(b: *u8, n: i64, tok: *u8) -> i64 { 355 var tl: i64 = 0 356 while tok[tl] != (0 as u8) { tl = tl + 1 } 357 if tl == 0 { return 0 } 358 var i: i64 = 0 359 while i + tl < n { 360 var m: i64 = 1 361 var k: i64 = 0 362 while k < tl { if b[i+k] != tok[k] { m = 0; k = tl } else { k = k + 1 } } 363 if m == 1 { 364 var j: i64 = i + tl 365 while j < n { let c: i64 = b[j] as i64; if c == 34 { j = j + 1 } else { if c == 58 { j = j + 1 } else { if c == 32 { j = j + 1 } else { break } } } } 366 while j < n { let d: i64 = b[j] as i64; if d >= 48 { if d <= 57 { b[j] = 48 as u8; j = j + 1 } else { break } } else { break } } 367 i = j 368 } else { i = i + 1 } 369 } 370 return 0 371} 372// compare every "<prefix>.<i>" capture pair (before vs after) for lines naming target; returns mismatches 373func oe_behave_cmp(target: *u8, wl: *u8, wn: i64, prefa: *u8, prefb: *u8, ba: *u8, bb: *u8) -> i64 { 374 let pa: *u8 = sys_mmap(512) 375 let pb: *u8 = sys_mmap(512) 376 var bad: i64 = 0 377 var p: i64 = 0 378 var line: i64 = 0 379 while p < wn { 380 var e: i64 = p 381 while e < wn { if wl[e] == (10 as u8) { break } e = e + 1 } 382 // first token 383 var i: i64 = p 384 while i < e { if wl[i] != (32 as u8) { break } i = i + 1 } 385 var j: i64 = i 386 while j < e { if wl[j] == (32 as u8) { break } j = j + 1 } 387 var same: i64 = 1 388 var k: i64 = 0 389 while i + k < j { if target[k] == (0 as u8) { same = 0; k = j } else { if wl[i+k] != target[k] { same = 0; k = j } else { k = k + 1 } } } 390 if same == 1 { if target[k] != (0 as u8) { same = 0 } } 391 if same == 1 { if j > i { 392 var oa: i64 = sd_cat(pa, 0, prefa); oa = sd_cat(pa, oa, "." as *u8); oa = sd_num(pa, oa, line); pa[oa] = 0 as u8 393 var ob: i64 = sd_cat(pb, 0, prefb); ob = sd_cat(pb, ob, "." as *u8); ob = sd_num(pb, ob, line); pb[ob] = 0 as u8 394 let na: i64 = oe_read(pa, ba, OE_CAP) 395 let nb: i64 = oe_read(pb, bb, OE_CAP) 396 // apply every @volatile mask declared in the workload to BOTH captures 397 var vp: i64 = 0 398 while vp < wn { 399 var ve: i64 = vp 400 while ve < wn { if wl[ve] == (10 as u8) { break } ve = ve + 1 } 401 if oe_starts(((wl as i64) + vp) as *u8, "@volatile " as *u8) == 1 { 402 let tk: *u8 = sys_mmap(128) 403 var to3: i64 = 0 404 var vs: i64 = vp + 10 405 while vs < ve { if wl[vs] == (32 as u8) { break } if to3 < 127 { tk[to3] = wl[vs]; to3 = to3 + 1 } vs = vs + 1 } 406 tk[to3] = 0 as u8 407 if na > 0 { oe_mask_volatile(ba, na, tk) } 408 if nb > 0 { oe_mask_volatile(bb, nb, tk) } 409 } 410 vp = ve + 1 411 } 412 if na <= 0 { bad = bad + 1; sd_w("OO-BEHAVE-EMPTY(before) " as *u8); sd_w(target); sd_w(" line=" as *u8); let t0: *u8 = sys_mmap(32); sd_num(t0, 0, line); sd_w(t0); sd_w("\n" as *u8) } 413 else { if oe_eq(ba, na, bb, nb) == 0 { bad = bad + 1; sd_w("OO-CHANGED(output) " as *u8); sd_w(target); sd_w(" line=" as *u8); let t1: *u8 = sys_mmap(32); sd_num(t1, 0, line); sd_w(t1); sd_w(" before=" as *u8); let t2: *u8 = sys_mmap(32); sd_num(t2, 0, na); sd_w(t2); sd_w("B after=" as *u8); let t3: *u8 = sys_mmap(32); sd_num(t3, 0, nb); sd_w(t3); sd_w("B\n" as *u8) } } 414 } } 415 line = line + 1 416 p = e + 1 417 } 418 return bad 419} 420 421func main(argc: i64, argv: *i64) -> i64 { 422 if argc < 5 { sd_w("usage: nx_oo_extract <funcname[,f2,...]> <baselib-srcpath> <buildonly-elf> <consumer-src...> [--proof=bytes|behave] [--workload=<path>]\n" as *u8); sys_exit(2); return 2 } 423 let basepath: *u8 = argv[2] as *u8 424 let buildelf: *u8 = argv[3] as *u8 425 // options are trailing "--" args; consumers are everything between argv[4] and the first option 426 var proof_behave: i64 = 0 427 var wlpath: *u8 = 0 as *u8 428 var nc: i64 = 0 429 var ai: i64 = 4 430 while ai < argc { 431 let a: *u8 = argv[ai] as *u8 432 if oe_starts(a, "--proof=" as *u8) == 1 { 433 if oe_streq(((a as i64) + 8) as *u8, "behave" as *u8) == 1 { proof_behave = 1 } 434 else { if oe_streq(((a as i64) + 8) as *u8, "bytes" as *u8) == 0 { sd_w("NX-OO-EXTRACT verdict=ABORTED reason=unknown-proof-mode fix=--proof=bytes|behave\n" as *u8); sys_exit(2); return 2 } } 435 } else { if oe_starts(a, "--workload=" as *u8) == 1 { wlpath = ((a as i64) + 11) as *u8 } 436 else { if oe_starts(a, "--" as *u8) == 1 { sd_w("NX-OO-EXTRACT verdict=ABORTED reason=unknown-option:" as *u8); sd_w(a); sd_w(" fix=see-usage\n" as *u8); sys_exit(2); return 2 } 437 else { nc = nc + 1 } } } 438 ai = ai + 1 439 } 440 if nc < 1 { sd_w("NX-OO-EXTRACT verdict=ABORTED reason=no-consumers fix=pass-at-least-one-consumer-src\n" as *u8); sys_exit(2); return 2 } 441 if nc > OE_MAXC { sd_w("NX-OO-EXTRACT verdict=ABORTED reason=too-many-consumers fix=split-the-run\n" as *u8); sys_exit(2); return 2 } 442 let names: *u8 = sys_mmap(OE_MAXF * OE_NAME) 443 let nf: i64 = oe_split_names(argv[1] as *u8, names) 444 if nf < 1 { sd_w("NX-OO-EXTRACT verdict=ABORTED reason=funcname-list-empty-or-over-limit fix=comma-separated,-at-most-64\n" as *u8); sys_exit(2); return 2 } 445 if proof_behave == 1 { if (wlpath as i64) == 0 { sd_w("NX-OO-EXTRACT verdict=ABORTED reason=proof=behave-needs---workload fix=pass---workload=<path>-with-one-'<target> <argv...>'-line-per-run\n" as *u8); sys_exit(2); return 2 } } 446 let basebn: *u8 = sys_mmap(256) 447 oe_base(basepath, basebn) 448 449 let cbuf: *u8 = sys_mmap(OE_CAP) 450 let rng: *i64 = sys_mmap(16) as *i64 451 // PASS 1: every function must exist in every consumer with a byte-identical body. bodies[] holds the 452 // reference copy of each (from consumer 0) for the lib; bl[] their lengths. 453 let bodies: *u8 = sys_mmap(OE_CAP) 454 let boff: *i64 = sys_mmap(8 * OE_MAXF) as *i64 455 let blen: *i64 = sys_mmap(8 * OE_MAXF) as *i64 456 var bused: i64 = 0 457 var fi: i64 = 0 458 while fi < nf { 459 let fname: *u8 = ((names as i64) + fi*OE_NAME) as *u8 460 var ci: i64 = 0 461 var first: i64 = 1 462 while ci < nc { 463 let cp: *u8 = argv[4 + ci] as *u8 464 let cn: i64 = oe_read(cp, cbuf, OE_CAP) 465 if cn <= 0 { sd_w("NX-OO-EXTRACT verdict=ABORTED reason=consumer-unreadable:" as *u8); sd_w(cp); sd_w(" fix=verify-the-consumer-source-path\n" as *u8); sys_exit(2); return 2 } 466 if oe_find_func_trim(cbuf, cn, fname, rng) != 1 { 467 sd_w("NX-OO-EXTRACT verdict=ABORTED reason=function-" as *u8); sd_w(fname); sd_w("-not-defined-in:" as *u8); sd_w(cp) 468 sd_w(" fix=only-pass-consumers-that-DEFINE-every-listed-function(check-funcmine-output)\n" as *u8); sys_exit(2); return 2 469 } 470 let bs: i64 = rng[0] 471 let be: i64 = rng[1] 472 if oe_body_uses_consumer_const(((cbuf as i64) + bs) as *u8, be - bs, cbuf, cn, fname, cp) == 1 { sys_exit(1); return 1 } 473 if first == 1 { 474 boff[fi] = bused; blen[fi] = be - bs 475 var t: i64 = 0 476 while t < be - bs { bodies[bused + t] = cbuf[bs + t]; t = t + 1 } 477 bused = bused + (be - bs) 478 first = 0 479 } else { 480 if oe_eq(((cbuf as i64) + bs) as *u8, be - bs, ((bodies as i64) + boff[fi]) as *u8, blen[fi]) == 0 { 481 sd_w("NX-OO-EXTRACT verdict=REFUSED reason=the-" as *u8); sd_w(fname); sd_w("-bodies-are-NOT-byte-identical-across-consumers(differs-in:" as *u8); sd_w(cp); sd_w(")" as *u8) 482 sd_w(" fix=only-byte-identical-duplicates-can-be-safely-extracted;-if-they-differ-they-are-DIVERGENT-resolve-by-rename-or-make-equal-first,-never-by-picking-one. no-changes-made\n" as *u8) 483 sys_exit(1); return 1 484 } 485 } 486 ci = ci + 1 487 } 488 fi = fi + 1 489 } 490 491 // PASS 2: baseline every consumer (build snapshot; behavioural captures if asked) + backup its source 492 let tgt: *u8 = sys_mmap(256) 493 let snap: *u8 = sys_mmap(512) 494 let bak: *u8 = sys_mmap(512) 495 let wl: *u8 = sys_mmap(OE_CAP) 496 var wn: i64 = 0 497 if proof_behave == 1 { 498 wn = oe_read(wlpath, wl, OE_CAP) 499 if wn <= 0 { sd_w("NX-OO-EXTRACT verdict=ABORTED reason=workload-unreadable-or-empty:" as *u8); sd_w(wlpath); sd_w(" fix=one-'<target> <argv...>'-line-per-run\n" as *u8); sys_exit(2); return 2 } 500 } 501 let tokbuf: *u8 = sys_mmap(OE_CAP) 502 let pref: *u8 = sys_mmap(512) 503 var ci: i64 = 0 504 while ci < nc { 505 let cp: *u8 = argv[4 + ci] as *u8 506 oe_target(cp, tgt) 507 var so: i64 = sd_cat(snap, 0, "/tmp/oo_" as *u8); so = sd_cat(snap, so, tgt); so = sd_cat(snap, so, ".before" as *u8) 508 let bn: i64 = oe_build_snap(buildelf, tgt, snap, cbuf) 509 if bn <= 0 { 510 // NAME THE RIGHT SUBJECT (2026-08-18, first real run): a missing baseline artifact was reported 511 // as "consumer does not build standalone" when the builder had REFUSED ADMISSION under an I/O 512 // storm (procs_blocked>=blocked_max) -- the box, not the consumer. Read the builder's own log 513 // for its admission verdict and say which it was. 514 let lg: *u8 = sys_mmap(OE_CAP) 515 let ln: i64 = oe_read("/tmp/oe_build.log" as *u8, lg, OE_CAP) 516 var admit_refused: i64 = 0 517 if ln > 0 { if dp_contains(lg, ln, "REFUSED-BUILD-ADMIT" as *u8) == 1 { admit_refused = 1 } } 518 if admit_refused == 1 { 519 sd_w("NX-OO-EXTRACT verdict=ABORTED reason=builder-REFUSED-ADMISSION-under-load(box-saturated,-not-the-consumer:" as *u8); sd_w(tgt); sd_w(")" as *u8) 520 sd_w(" fix=re-issue-when-/proc/loadavg-clears;-nothing-was-changed. no-changes-made\n" as *u8) 521 } else { 522 sd_w("NX-OO-EXTRACT verdict=ABORTED reason=consumer-" as *u8); sd_w(tgt); sd_w("-does-not-build-standalone(no-baseline-artifact)" as *u8) 523 sd_w(" fix=byte-proof-needs-a-buildable-holder;-see-/tmp/oe_build.log. no-changes-made\n" as *u8) 524 } 525 sys_exit(3); return 3 526 } 527 if proof_behave == 1 { 528 var po: i64 = sd_cat(pref, 0, "/tmp/oo_" as *u8); po = sd_cat(pref, po, tgt); po = sd_cat(pref, po, ".before" as *u8); pref[po] = 0 as u8 529 let runs: i64 = oe_behave(tgt, wl, wn, pref, tokbuf) 530 if runs == 0 { 531 sd_w("NX-OO-EXTRACT verdict=ABORTED reason=consumer-" as *u8); sd_w(tgt); sd_w("-has-NO-workload-line(a-proof-over-the-empty-set-is-not-a-proof)" as *u8) 532 sd_w(" fix=add-'<target> <argv...>'-lines-to-the-workload-for-every-consumer. no-changes-made\n" as *u8) 533 sys_exit(2); return 2 534 } 535 sd_w("OO-BASELINE " as *u8); sd_w(tgt); sd_w(" runs=" as *u8); let rb: *u8 = sys_mmap(32); sd_num(rb, 0, runs); sd_w(rb); sd_w("\n" as *u8) 536 } 537 let cn: i64 = oe_read(cp, cbuf, OE_CAP) 538 var bo: i64 = sd_cat(bak, 0, cp); bo = sd_cat(bak, bo, ".oobak" as *u8) 539 ss_writefile(bak, cbuf, cn) 540 ci = ci + 1 541 } 542 543 // PASS 3: write the base lib (header + every extracted body, in list order) 544 let lib: *u8 = sys_mmap(OE_CAP) 545 var lo: i64 = sd_cat(lib, 0, "// AUTO-EXTRACTED shared base (nx_oo_extract). license_tier: ORIGINAL No hw writes (Rule 26).\n" as *u8) 546 lo = sd_cat(lib, lo, "// functions: " as *u8); lo = sd_cat(lib, lo, argv[1] as *u8); lo = sd_cat(lib, lo, "\n" as *u8) 547 // the lib declares its own foundation import so it reads standalone; the flattener dedups repeats 548 lo = sd_cat(lib, lo, "import \"nx_syscalls.nx\"\n" as *u8) 549 fi = 0 550 while fi < nf { 551 var t2: i64 = 0 552 while t2 < blen[fi] { lib[lo] = bodies[boff[fi] + t2]; lo = lo + 1; t2 = t2 + 1 } 553 if lo > 0 { if lib[lo-1] != (10 as u8) { lib[lo] = 10 as u8; lo = lo + 1 } } 554 fi = fi + 1 555 } 556 ss_writefile(basepath, lib, lo) 557 558 // PASS 4: edit each consumer (prepend ONE import, remove EVERY listed func def) 559 let nfb: *u8 = sys_mmap(OE_CAP) 560 ci = 0 561 while ci < nc { 562 let cp: *u8 = argv[4 + ci] as *u8 563 var cn: i64 = oe_read(cp, cbuf, OE_CAP) 564 fi = 0 565 while fi < nf { 566 let fname: *u8 = ((names as i64) + fi*OE_NAME) as *u8 567 oe_find_func_trim(cbuf, cn, fname, rng) 568 let bs: i64 = rng[0] 569 let be: i64 = rng[1] 570 var no: i64 = 0 571 var t3: i64 = 0 572 while t3 < bs { nfb[no] = cbuf[t3]; no = no + 1; t3 = t3 + 1 } 573 t3 = be 574 while t3 < cn { nfb[no] = cbuf[t3]; no = no + 1; t3 = t3 + 1 } 575 // swap: cbuf <- nfb 576 var t4: i64 = 0 577 while t4 < no { cbuf[t4] = nfb[t4]; t4 = t4 + 1 } 578 cn = no 579 fi = fi + 1 580 } 581 // insert the ONE lib import after the consumer's leading comment/import/const block (see oe_import_insert_at) 582 let at: i64 = oe_import_insert_at(cbuf, cn) 583 var no2: i64 = 0 584 var t5: i64 = 0 585 while t5 < at { nfb[no2] = cbuf[t5]; no2 = no2 + 1; t5 = t5 + 1 } 586 no2 = sd_cat(nfb, no2, "import \"" as *u8); no2 = sd_cat(nfb, no2, basebn); no2 = sd_cat(nfb, no2, "\"\n" as *u8) 587 while t5 < cn { nfb[no2] = cbuf[t5]; no2 = no2 + 1; t5 = t5 + 1 } 588 ss_writefile(cp, nfb, no2) 589 ci = ci + 1 590 } 591 592 // PASS 5: rebuild each consumer and prove (bytes, or behaviour over the workload) 593 var changed: i64 = 0 594 let bufb: *u8 = sys_mmap(OE_CAP) 595 let prefb: *u8 = sys_mmap(512) 596 ci = 0 597 while ci < nc { 598 let cp: *u8 = argv[4 + ci] as *u8 599 oe_target(cp, tgt) 600 var so: i64 = sd_cat(snap, 0, "/tmp/oo_" as *u8); so = sd_cat(snap, so, tgt); so = sd_cat(snap, so, ".before" as *u8) 601 let an: i64 = oe_build_snap(buildelf, tgt, 0 as *u8, cbuf) 602 if an <= 0 { 603 changed = changed + 1 604 // same attribution as the pass-2 abort (a fix in one path and not its sibling is half a fix): 605 // an admission-refused rebuild is the BOX, not the change -- it still counts as unverifiable 606 // (so the revert below is correct), but the message must not indict the extraction. 607 let lg2: *u8 = sys_mmap(OE_CAP) 608 let ln2: i64 = oe_read("/tmp/oe_build.log" as *u8, lg2, OE_CAP) 609 var adm2: i64 = 0 610 if ln2 > 0 { if dp_contains(lg2, ln2, "REFUSED-BUILD-ADMIT" as *u8) == 1 { adm2 = 1 } } 611 if adm2 == 1 { sd_w("OO-BUILD-ADMIT-REFUSED(box-saturated,-unverifiable-this-run) " as *u8); sd_w(tgt); sd_w(" fix=re-issue-when-load-clears\n" as *u8) } 612 else { sd_w("OO-CHANGED(build-broke) " as *u8); sd_w(tgt); sd_w(" see=/tmp/oe_build.log\n" as *u8) } 613 } else { 614 if proof_behave == 0 { 615 let sn: i64 = oe_read(snap, bufb, OE_CAP) 616 if oe_eq(cbuf, an, bufb, sn) == 0 { changed = changed + 1; sd_w("OO-CHANGED(bytes) " as *u8); sd_w(tgt); sd_w("\n" as *u8) } 617 } else { 618 var po: i64 = sd_cat(pref, 0, "/tmp/oo_" as *u8); po = sd_cat(pref, po, tgt); po = sd_cat(pref, po, ".before" as *u8); pref[po] = 0 as u8 619 var pb: i64 = sd_cat(prefb, 0, "/tmp/oo_" as *u8); pb = sd_cat(prefb, pb, tgt); pb = sd_cat(prefb, pb, ".after" as *u8); prefb[pb] = 0 as u8 620 oe_behave(tgt, wl, wn, prefb, tokbuf) 621 let bad: i64 = oe_behave_cmp(tgt, wl, wn, pref, prefb, cbuf, bufb) 622 if bad > 0 { changed = changed + 1 } 623 } 624 } 625 ci = ci + 1 626 } 627 628 if changed == 0 { 629 sd_w("NX-OO-EXTRACT verdict=EXTRACTED reason=" as *u8); sd_w(argv[1] as *u8) 630 sd_w("-moved-to-" as *u8); sd_w(basebn) 631 sd_w("-and-all-" as *u8) 632 let ob: *u8 = sys_mmap(32); sd_num(ob, 0, nc); sd_w(ob) 633 if proof_behave == 0 { sd_w("-consumers-rebuilt-BYTE-IDENTICAL(behaviour-preserved)" as *u8) } 634 else { sd_w("-consumers-rebuilt-and-every-workload-run-OUTPUT-IDENTICAL(behaviour-preserved-over-the-declared-workload)" as *u8) } 635 sd_w(" fix=none-committed;-remove-the-.oobak-backups-when-satisfied\n" as *u8) 636 sys_exit(0); return 0 637 } 638 // any consumer changed -> REVERT everything 639 ci = 0 640 while ci < nc { 641 let cp: *u8 = argv[4 + ci] as *u8 642 var bo: i64 = sd_cat(bak, 0, cp); bo = sd_cat(bak, bo, ".oobak" as *u8) 643 let cn: i64 = oe_read(bak, cbuf, OE_CAP) 644 if cn > 0 { ss_writefile(cp, cbuf, cn) } 645 ci = ci + 1 646 } 647 sys_unlinkat(basepath) 648 sd_w("NX-OO-EXTRACT verdict=REFUSED reason=" as *u8) 649 let ob2: *u8 = sys_mmap(32); sd_num(ob2, 0, changed); sd_w(ob2) 650 sd_w("-consumer(s)-changed-after-extraction(behaviour-NOT-preserved) fix=extraction-not-safe-here-see-OO-CHANGED-lines;-all-consumers-RESTORED-from-.oobak-and-the-base-lib-removed(safe)\n" as *u8) 651 sys_exit(1) 652 return 1 653}