code wiki / _hdl_build / nx_consol_apply_mc.nx
nx_consol_apply_mc.nx source
↩ module page · 170 lines · 8246 B
1// nx_consol_apply_mc.nx -- MULTI-CONSUMER consolidation applier (extends nx_consol_apply past the
2// zero-importer soundness limit). To retire a shadow of a LIB that N organs import, rebuild EVERY
3// importer + byte-compare each artifact before/after: CONSOLIDATED only if ALL importers are byte-
4// identical (the retired copy was dead for all of them), else REFUSE + restore (never-brick). This is
5// the COMPLETE behaviour-preservation proof for a multi-consumer shadow -- no consumer can silently
6// change. Importers come from the atlas/funcmine importer histogram (a file, one target per line).
7// argv: <shadow> <retire> <buildonly-elf> <importers-file>
8// Artifact convention: buildonly writes /tmp/<importer>.sov.elf (BEFORE saved to /tmp/<importer>.mcbefore).
9// exit: 0 CONSOLIDATED | 1 REFUSED (restored) | 2 usage/shadow-absent | 3 no buildable importer / move err
10// license_tier: ORIGINAL No hw writes (Rule 26).
11import "nx_seat_drive_lib.nx"
12import "nx_seg_store.nx"
13import "nx_deploy_lib.nx"
14import "nx_syscalls.nx"
15const MC_MAGIC_1048576: i64 = 1048576
16
17const MC_CAP: i64 = 4194304
18const MC_MAXI: i64 = 512
19
20func mc_exists(path: *u8) -> i64 { let fd: i64 = sys_openat_rd(path); if fd >= 0 { sys_close(fd); return 1 } return 0 }
21func mc_read(path: *u8, buf: *u8, cap: i64) -> i64 {
22 let fd: i64 = sys_openat_rd(path)
23 if fd < 0 { return 0 - 1 }
24 var n: i64 = 0
25 var r: i64 = sys_read(fd, buf, cap - 1)
26 while r > 0 { n = n + r; if n >= cap - 1 { r = 0 } else { r = sys_read(fd, buf + n, cap - 1 - n) } }
27 sys_close(fd)
28 return n
29}
30func mc_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 }
31// build importer T (target name span), snapshot /tmp/T.sov.elf -> outpath; returns artifact bytes or -1
32func mc_build_snap(buildelf: *u8, tname: *u8, artpath: *u8, snappath: *u8, buf: *u8) -> i64 {
33 // SOUNDNESS: unlink the artifact FIRST so a FAILED build leaves no stale artifact (which would
34 // otherwise read as a false "identical"). Its presence after == the build genuinely produced it.
35 sys_unlinkat(artpath)
36 let av: *i64 = sys_mmap(16) as *i64
37 av[0] = tname as i64
38 dep_run_capture(buildelf, av, 1, "/tmp/mc_build.log" as *u8)
39 let n: i64 = mc_read(artpath, buf, MC_CAP)
40 if n > 0 { if (snappath as i64) != 0 { ss_writefile(snappath, buf, n) } }
41 return n
42}
43
44func main(argc: i64, argv: *i64) -> i64 {
45 if argc < 5 { sd_w("usage: nx_consol_apply_mc <shadow> <retire> <buildonly-elf> <importers-file>\n" as *u8); sys_exit(2); return 2 }
46 let shadow: *u8 = argv[1] as *u8
47 let retire: *u8 = argv[2] as *u8
48 let buildelf: *u8 = argv[3] as *u8
49 let impfile: *u8 = argv[4] as *u8
50 if mc_exists(shadow) == 0 {
51 sd_w("NX-CONSOL-APPLY-MC verdict=ABORTED reason=shadow-file-not-found:" as *u8); sd_w(shadow)
52 sd_w(" fix=verify-the-path;-it-may-already-be-consolidated-(check-runtime/_retired_shadow/)\n" as *u8)
53 sys_exit(2); return 2
54 }
55
56 // read importers list (one basename per line)
57 let ib: *u8 = sys_mmap(MC_MAGIC_1048576)
58 let in2: i64 = mc_read(impfile, ib, MC_MAGIC_1048576)
59 if in2 <= 0 {
60 sd_w("NX-CONSOL-APPLY-MC verdict=ABORTED reason=no-importers-listed(empty-file)" as *u8)
61 sd_w(" fix=if-this-is-a-ZERO-importer-organ-use-single-target-nx_consol_apply-instead;-else-regenerate-the-importer-list\n" as *u8)
62 sys_exit(2); return 2
63 }
64 // store per-importer name spans + built flag
65 let noff: *i64 = sys_mmap(8 * MC_MAXI) as *i64
66 let nlen: *i64 = sys_mmap(8 * MC_MAXI) as *i64
67 let built: *i64 = sys_mmap(8 * MC_MAXI) as *i64
68 var ni: i64 = 0
69 var i: i64 = 0
70 while i < in2 {
71 var le: i64 = i
72 var s: i64 = 1
73 while s == 1 { if le >= in2 { s = 0 } else { if ib[le] == (10 as u8) { s = 0 } else { le = le + 1 } } }
74 if le > i { if ni < MC_MAXI { noff[ni] = i; nlen[ni] = le - i; ib[le] = 0 as u8; ni = ni + 1 } }
75 i = le + 1
76 }
77
78 let buf: *u8 = sys_mmap(MC_CAP)
79 let bufb: *u8 = sys_mmap(MC_CAP)
80 let art: *u8 = sys_mmap(512)
81 let snap: *u8 = sys_mmap(512)
82 var nbuilt: i64 = 0
83
84 // BEFORE: build each importer, snapshot
85 var k: i64 = 0
86 while k < ni {
87 let tn: *u8 = ((ib as i64) + noff[k]) as *u8
88 // art = /tmp/<tn>.sov.elf ; snap = /tmp/<tn>.mcbefore
89 var ao: i64 = sd_cat(art, 0, "/tmp/" as *u8)
90 ao = sd_cat(art, ao, tn)
91 ao = sd_cat(art, ao, ".sov.elf" as *u8)
92 var so: i64 = sd_cat(snap, 0, "/tmp/" as *u8)
93 so = sd_cat(snap, so, tn)
94 so = sd_cat(snap, so, ".mcbefore" as *u8)
95 let bn: i64 = mc_build_snap(buildelf, tn, art, snap, buf)
96 if bn > 0 { built[k] = 1; nbuilt = nbuilt + 1 } else { built[k] = 0 }
97 k = k + 1
98 }
99 if nbuilt == 0 {
100 sd_w("NX-CONSOL-APPLY-MC verdict=ABORTED reason=no-importer-could-be-built(no-baseline-to-compare)" as *u8)
101 sd_w(" fix=importer-names-may-be-non-buildable-by-bare-name-or-in-unscanned-dirs-resolve-them-to-real-build-targets;-or-the-importers-are-genuinely-broken(separate-debt)-fix-them-first. shadow-UNTOUCHED\n" as *u8)
102 sys_exit(3); return 3
103 }
104
105 // RETIRE the shadow
106 if sys_renameat(shadow, retire) != 0 {
107 sd_w("NX-CONSOL-APPLY-MC verdict=ABORTED reason=retire-move-failed(filesystem-error)" as *u8)
108 sd_w(" fix=ensure-the-retire-directory-exists-and-is-writable(mkdir-p-its-parent). shadow-UNTOUCHED\n" as *u8)
109 sys_exit(3); return 3
110 }
111
112 // AFTER: rebuild EVERY importer (built AND unbuilt) and require its outcome UNCHANGED. SOUND
113 // coverage: built-before -> must be byte-identical now; unbuilt-before -> must STILL not build
114 // (a before-broken importer that now builds is a CHANGE too -> refuse). No importer is a blind spot.
115 var changed: i64 = 0
116 k = 0
117 while k < ni {
118 let tn: *u8 = ((ib as i64) + noff[k]) as *u8
119 var ao: i64 = sd_cat(art, 0, "/tmp/" as *u8)
120 ao = sd_cat(art, ao, tn)
121 ao = sd_cat(art, ao, ".sov.elf" as *u8)
122 var so: i64 = sd_cat(snap, 0, "/tmp/" as *u8)
123 so = sd_cat(snap, so, tn)
124 so = sd_cat(snap, so, ".mcbefore" as *u8)
125 let an: i64 = mc_build_snap(buildelf, tn, art, 0 as *u8, buf)
126 if built[k] == 1 {
127 let sn: i64 = mc_read(snap, bufb, MC_CAP)
128 if an <= 0 { changed = changed + 1; sd_w("MC-CHANGED(build-broke) " as *u8); sd_w(tn); sd_w("\n" as *u8) } else {
129 if mc_eq(buf, an, bufb, sn) == 0 { changed = changed + 1; sd_w("MC-CHANGED " as *u8); sd_w(tn); sd_w("\n" as *u8) }
130 }
131 } else {
132 if an > 0 { changed = changed + 1; sd_w("MC-CHANGED(now-builds) " as *u8); sd_w(tn); sd_w("\n" as *u8) }
133 }
134 k = k + 1
135 }
136
137 if changed == 0 {
138 sd_w("NX-CONSOL-APPLY-MC verdict=CONSOLIDATED (all " as *u8)
139 let ob: *u8 = sys_mmap(32)
140 sd_num(ob, 0, ni)
141 sd_w(ob)
142 sd_w(" importers unchanged, " as *u8)
143 sd_num(ob, 0, nbuilt)
144 sd_w(ob)
145 sd_w(" built; shadow was dead) retired=" as *u8)
146 sd_w(retire)
147 sd_w("\n" as *u8)
148 sys_exit(0)
149 return 0
150 }
151 // some importer changed -> the shadow was LIVE for it -> RESTORE + REFUSE
152 if sys_renameat(retire, shadow) != 0 {
153 sd_w("NX-CONSOL-APPLY-MC verdict=REFUSED-AND-RESTORE-FAILED reason=an-importer-changed-AND-the-restore-move-failed shadow=" as *u8)
154 sd_w(shadow)
155 sd_w(" fix=MANUAL-RESTORE-NEEDED-move-" as *u8)
156 sd_w(retire)
157 sd_w("-back-to-" as *u8)
158 sd_w(shadow)
159 sd_w("-immediately\n" as *u8)
160 sys_exit(3)
161 return 3
162 }
163 sd_w("NX-CONSOL-APPLY-MC verdict=REFUSED reason=" as *u8)
164 let ob2: *u8 = sys_mmap(32)
165 sd_num(ob2, 0, changed)
166 sd_w(ob2)
167 sd_w("-importer(s)-changed-when-the-shadow-was-retired-so-the-shadow-is-LIVE(genuinely-used,-not-dead) fix=this-is-a-DIVERGENT-lib-not-a-dead-shadow:-resolve-by-RENAME+REPOINT(three-party-SHARP1)-not-retirement;-the-MC-CHANGED-line(s)-above-name-the-consumer(s)-that-resolve-the-retired-copy. shadow-RESTORED(safe)\n" as *u8)
168 sys_exit(1)
169 return 1
170}