code wiki / _hdl_build / nx_autofix_ensemble.nx
nx_autofix_ensemble.nx source
↩ module page · 138 lines · 5964 B
1// nx_autofix_ensemble.nx -- THE LIVE ENSEMBLE (autonomous-builder lane, 2026-07-20). One command
2// for the measured neuro-symbolic climb: run maker#1 over the whole manifest, auto-run each later
3// maker ONLY on the previous stage's misses, then union the property-verified greens (nx_autofix_cascade).
4// SOUND because the judge (nx_symjudge, autofix stage 5b) property-verifies every green, so unioning
5// diverse makers can never admit a wrong fix. Forks the proven _offc/nx_autofix_auto.elf (per model)
6// + _offc/nx_autofix_cascade.elf (union) -- pure orchestration, miss-extraction in nx_autofix_ens_lib.
7//
8// N-MAKER (2026-07-23, F960 consume half): argv[2..] is a MODEL LIST, not a fixed pair, so the
9// hardware router feeds it directly -- `nx_autofix_ensemble <manifest> $(nx_hw_envelope makers)` runs
10// whatever maker set this host's hwtier- row declares (phone->supercomputer, code unchanged). The
11// measured 3-maker 92% union is now ONE command instead of three runs plus a manual cascade.
12// BACK-COMPAT (rule 19, additive): with exactly two models the staging, prompts, ledger paths and
13// cascade inputs are IDENTICAL to the 2-maker organ -- the old invocation is byte-for-byte the old run.
14// PER-MAKER PROMPT LAW (NB11): maker#1 = the tuned primary -> `clean`; every later maker = general
15// fallback -> `strict`. Bounded by construction: at most AE_MAXMK makers, and the cap is DECLARED in
16// the output (a silently-truncated maker list would read as a complete ensemble).
17// argv: <manifest> <model1> [model2 ...] (manifest rows: name|path)
18// exit: 0. Prints per-stage summaries + the final NX-AUTOFIX-CASCADE ensemble line.
19// license_tier: ORIGINAL No hw writes (Rule 26).
20import "nx_autofix_ens_lib.nx"
21import "nx_seg_store.nx"
22import "nx_deploy_lib.nx"
23import "nx_syscalls.nx"
24
25const AE_CAP: i64 = 1048576
26const AE_MAXMK: i64 = 8
27const AE_PATH: i64 = 64
28const AE_ARGV: i64 = 128
29const AE_ZERO: i64 = 48
30
31func ae_w(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } sys_write(1, s, n); return 0 }
32func ae_wn(v: i64) -> i64 {
33 var m: i64 = v
34 if m < 0 { ae_w("-" as *u8); m = 0 - m }
35 let t: *u8 = sys_mmap(24)
36 var k: i64 = 0
37 if m == 0 { t[0] = AE_ZERO as u8; k = 1 }
38 while m > 0 { t[k] = (AE_ZERO + (m % 10)) as u8; m = m / 10; k = k + 1 }
39 let o: *u8 = sys_mmap(24)
40 var i: i64 = 0
41 while i < k { o[i] = t[k - 1 - i]; i = i + 1 }
42 sys_write(1, o, k)
43 return 0
44}
45func ae_readfile(path: *u8, box: *i64) -> *u8 {
46 let lb: *i64 = sys_mmap(8) as *i64
47 let b: *u8 = sys_read_file(path, lb)
48 if (b as i64) == 0 { box[0] = 0; return 0 as *u8 }
49 box[0] = lb[0]
50 return b
51}
52func ae_dump(path: *u8) -> i64 {
53 let box: *i64 = sys_mmap(8) as *i64
54 let b: *u8 = ae_readfile(path, box)
55 if (b as i64) != 0 { sys_write(1, b, box[0]) }
56 return 0
57}
58
59// per-stage scratch path; the BUILDER lives in nx_autofix_ens_lib so the gate proves it (a stage-path
60// collision would let maker#3 clobber maker#2's ledger and the union would silently lose a maker).
61func ae_path(pre: *u8, k: i64, suf: *u8) -> *u8 {
62 let dst: *u8 = sys_mmap(AE_PATH)
63 ael_stage_path(dst, pre, k, suf)
64 return dst
65}
66
67func main(argc: i64, argv: *i64) -> i64 {
68 if argc < 3 { ae_w("usage: nx_autofix_ensemble <manifest> <model1> [model2 ...]\n" as *u8); sys_exit(2); return 2 }
69 let manp: *u8 = argv[1] as *u8
70 let loopelf: *u8 = "_offc/nx_autofix_auto.elf" as *u8
71 let casc: *u8 = "_offc/nx_autofix_cascade.elf" as *u8
72
73 var nmk: i64 = argc - 2
74 var capped: i64 = 0
75 if nmk > AE_MAXMK { capped = nmk - AE_MAXMK; nmk = AE_MAXMK }
76 ae_w("=== NX-AUTOFIX-ENSEMBLE makers=" as *u8)
77 ae_wn(nmk)
78 if capped > 0 { ae_w(" CAPPED-DROPPED=" as *u8); ae_wn(capped) }
79 ae_w(" (maker#1 clean prompt, later makers strict)\n" as *u8)
80
81 let av: *i64 = sys_mmap(AE_ARGV) as *i64
82 let lps: *i64 = sys_mmap(AE_MAXMK * 8) as *i64
83 var work: *u8 = manp
84 var stages: i64 = 0
85 var k: i64 = 0
86 while k < nmk {
87 let lp: *u8 = ae_path("/tmp/ens_l" as *u8, k + 1, ".ledger" as *u8)
88 let op: *u8 = ae_path("/tmp/ens_s" as *u8, k + 1, ".out" as *u8)
89 ae_w("=== stage " as *u8)
90 ae_wn(k + 1)
91 ae_w(": maker#" as *u8)
92 ae_wn(k + 1)
93 ae_w("\n" as *u8)
94 av[0] = argv[2 + k]
95 av[1] = work as i64
96 av[2] = lp as i64
97 if k == 0 { av[3] = "clean" as *u8 as i64 } else { av[3] = "strict" as *u8 as i64 }
98 dep_run_capture(loopelf, av, 4, op)
99 lps[stages] = lp as i64
100 stages = stages + 1
101
102 // hand the NEXT maker only what this stage missed (chains: misses-of-misses)
103 let lbox: *i64 = sys_mmap(8) as *i64
104 let lg: *u8 = ae_readfile(lp, lbox)
105 let wbox: *i64 = sys_mmap(8) as *i64
106 let wm: *u8 = ae_readfile(work, wbox)
107 var nmiss: i64 = 0
108 let miss: *u8 = sys_mmap(AE_CAP)
109 let missbox: *i64 = sys_mmap(8) as *i64
110 missbox[0] = 0
111 if (lg as i64) != 0 { if (wm as i64) != 0 { nmiss = ael_extract_misses(lg, lbox[0], wm, wbox[0], miss, missbox) } }
112 ae_w("stage " as *u8)
113 ae_wn(k + 1)
114 ae_w(" misses handed on: " as *u8)
115 ae_wn(nmiss)
116 ae_w("\n" as *u8)
117 if nmiss > 0 {
118 let mp: *u8 = ae_path("/tmp/ens_miss" as *u8, k + 1, ".txt" as *u8)
119 ss_writefile(mp, miss, missbox[0])
120 work = mp
121 } else {
122 if k + 1 < nmk { ae_w("all instances resolved -- remaining makers SKIPPED (not run, not counted)\n" as *u8) }
123 k = nmk
124 }
125 k = k + 1
126 }
127
128 ae_w("=== NX-AUTOFIX-ENSEMBLE union over " as *u8)
129 ae_wn(stages)
130 ae_w(" ledger(s) ===\n" as *u8)
131 av[0] = manp as i64
132 var j: i64 = 0
133 while j < stages { av[1 + j] = lps[j]; j = j + 1 }
134 dep_run_capture(casc, av, 1 + stages, "/tmp/ens_cascade.out" as *u8)
135 ae_dump("/tmp/ens_cascade.out" as *u8)
136 sys_exit(0)
137 return 0
138}