nx_contentdiff_display_20260907.nx source
↩ module page · 316 lines · 14875 B
1// nx_contentdiff.nx -- THE PROMOTE RULER. Answers one question: does the candidate binary still contain
2// everything the LIVE binary contains?
3//
4// WHY (debts 1785452162, 1785526315, 1785526809): the ecosystem has ~703 deployed organs awaiting a
5// rebuild, and the gate guarding that queue was BYTE SIZE. Size is uninformative IN BOTH DIRECTIONS,
6// proven twice by measurement:
7// SHRINK is not regression -- 16 live organs had LARGER .prev files, yet the smaller live binaries
8// were string SUPERSETS (lost_from_live=0). Restoring the bigger ones would have BEEN the regression.
9// GROWTH is not improvement -- nx_law_warden rebuilt GREW 161951 -> 186696 bytes while losing three
10// whole detectors (laws_measured 11 -> 8, enforced_permil 1000 -> 727).
11// A gate keyed on bytes is therefore wrong about half the time and cannot tell you which half.
12//
13// THE RULER: printable content. Every printable run of >= CD_MINLEN bytes in the LIVE binary must still
14// be findable somewhere in the candidate. Anything missing is capability the rebuild would DESTROY.
15// Searching the candidate's RAW BYTES (not a re-extracted string set) is deliberate and stricter: a
16// string that survived but got tokenized differently still counts as present, so a MISS is a real miss.
17//
18// ★2026-08-06 -- THE RULER MOVED OUT, THE ORACLE STAYED. This organ had NO DEPLOYED BINARY and no
19// registry row, so the check it specifies had never actually run anywhere: debt 1785531571 asked for it
20// to be wired into /api/promote and nothing could be, because the measure lived inside this main() with
21// nothing importable to wire. It now lives in nx_contentdiff_lib (cdl_lost) and is called BOTH here and
22// by the staging guard inside md_promote_staged. This file keeps its exact output contract; it simply
23// no longer owns a private copy of the arithmetic.
24//
25// FAIL-CLOSED: unreadable input is RED, never "clean". Verdict GREEN iff lost_from_live == 0.
26// NOT DEDUPED, and it says so in the output: runs are counted as encountered, so the counts are
27// occurrence counts and lost>0 is the signal -- declaring that beats a silent, prettier number.
28// THE ORACLE SPENDS THE FULL BUDGET (every run, whole run) -- it runs to completion and can afford it.
29//
30// nx_contentdiff <live-elf> <candidate-elf> [all|positive-display-limit]
31// Optional display depth changes evidence visibility only; counts and verdict remain shared.
32//
33// license_tier: ORIGINAL No hw writes (Rule 26). expect_exit: 0
34import "nx_syscalls.nx"
35import "nx_gate_verdict.nx"
36import "_hdl_build/nx_contentdiff_lib.nx"
37
38const CD_CAP: i64 = 4194304
39const CD_MINLEN: i64 = 6
40const CD_SHOW: i64 = 8
41const CD_SHOW_ALL: i64 = 0 - 1
42const CD_SHOW_BAD: i64 = 0 - 2
43const CD_DECIMAL_BASE: i64 = 10
44const CD_I64_MAX: i64 = 9223372036854775807
45const CD_DIGIT_ZERO: i64 = 48
46const CD_DIGIT_NINE: i64 = 57
47
48// Zero is refused: hiding every detail would make existing "no runs" messages misleading.
49func cd_display_arg(p: *u8) -> i64 {
50 if p[0] == (97 as u8) { if p[1] == (108 as u8) { if p[2] == (108 as u8) { if p[3] == (0 as u8) { return CD_SHOW_ALL } } } }
51 var i: i64 = 0; var value: i64 = 0
52 while p[i] != (0 as u8) {
53 let c: i64 = p[i] as i64
54 if c < CD_DIGIT_ZERO { return CD_SHOW_BAD }
55 if c > CD_DIGIT_NINE { return CD_SHOW_BAD }
56 let digit: i64 = c - CD_DIGIT_ZERO
57 if value > (CD_I64_MAX - digit) / CD_DECIMAL_BASE { return CD_SHOW_BAD }
58 value = value * CD_DECIMAL_BASE + digit
59 i = i + 1
60 }
61 if value <= 0 { return CD_SHOW_BAD }
62 return value
63}
64
65func cd_slurp(path: *u8, buf: *u8, cap: i64) -> i64 {
66 let fd: i64 = sys_openat_rd(path)
67 if fd < 0 { return 0 - 1 }
68 var tot: i64 = 0
69 var go: i64 = 1
70 while go == 1 {
71 let r: i64 = sys_read(fd, ((buf as i64) + tot) as *u8, cap - tot)
72 if r <= 0 { go = 0 } else { tot = tot + r }
73 if tot >= cap { go = 0 }
74 }
75 sys_close(fd)
76 return tot
77}
78
79// DISPLAY ONLY -- names the first CD_SHOW lost runs so a reader sees WHAT would be destroyed, not just
80// how many. Uses the SAME shared primitives as the count, so the two can never disagree about what
81// "lost" means; the authoritative numbers still come from cdl_lost.
82// THE ACTIONABLE CLASS, LISTED SEPARATELY (2026-09-03). cd_show_lost prints the first CD_SHOW runs of
83// ALL losses, and on any cross-toolchain comparison those are dominated by build-flavour metadata: a real
84// front-door comparison printed 8 source paths while the 4 losses that needed adjudication were past the
85// cap and UNREACHABLE. ★A LIST THAT NAMES EIGHT LOSSES THAT DO NOT MATTER WHILE UNABLE TO NAME THE FOUR
86// THAT DO IS THE ONE THING THIS ORACLE EXISTS TO PREVENT -- it is the count-without-a-worklist defect
87// wearing a worklist. The partition already computes the class; the list simply never used it.
88// Prints ONLY runs that are neither a source path nor a symbol name, i.e. the class the flavour axis
89// cannot explain away and a human must therefore read. Additive: the all-losses list above is untouched.
90func cd_show_other(a: *u8, an: i64, b: *u8, bn: i64) -> i64 {
91 return cd_show_other_limit(a, an, b, bn, CD_SHOW)
92}
93func cd_show_other_limit(a: *u8, an: i64, b: *u8, bn: i64, limit: i64) -> i64 {
94 var shown: i64 = 0
95 var i: i64 = 0
96 while i < an {
97 let rl: i64 = cdl_runlen(a, an, i)
98 if rl >= CD_MINLEN {
99 if shown < limit {
100 if cdl_contains(b, bn, a, i, rl) == 0 {
101 if cdl_is_srcpath(a, i, rl) == 0 {
102 if cdl_is_ident(a, i, rl) == 0 { if cdl_is_sectname(a, i, rl) == 0 {
103 shown = shown + 1
104 gv_puts(" LOST-OTHER: " as *u8)
105 sys_write(1, ((a as i64) + i) as *u8, rl)
106 gv_puts("\n" as *u8)
107 } }
108 }
109 }
110 }
111 }
112 if rl > 0 { i = i + rl }
113 if rl == 0 { i = i + 1 }
114 }
115 return shown
116}
117
118// AND THE OTHER HALF OF THE SYMMETRIC PASS: NAME WHAT THE CANDIDATE ADDS, not just how many.
119// `gained_by_candidate` shipped as a bare COUNT, which is the estate's own count-without-a-worklist
120// defect -- and it is the field that answers PROVENANCE ("is this binary really built from my source?"),
121// so a reader who needs it most had to re-run the whole ruler with the arguments swapped to see a list.
122// ★A COUNTER IS THE DEFAULT AND A LIST IS AN AFTERTHOUGHT; ADD THE ARRAY IN THE SAME EDIT AS THE COUNTER.
123func cd_show_gained(a: *u8, an: i64, b: *u8, bn: i64) -> i64 {
124 return cd_show_gained_limit(a, an, b, bn, CD_SHOW)
125}
126func cd_show_gained_limit(a: *u8, an: i64, b: *u8, bn: i64, limit: i64) -> i64 {
127 var shown: i64 = 0
128 var i: i64 = 0
129 while i < bn {
130 let rl: i64 = cdl_runlen(b, bn, i)
131 if rl >= CD_MINLEN {
132 if shown < limit {
133 if cdl_contains(a, an, b, i, rl) == 0 {
134 if cdl_is_srcpath(b, i, rl) == 0 {
135 if cdl_is_ident(b, i, rl) == 0 { if cdl_is_sectname(b, i, rl) == 0 {
136 shown = shown + 1
137 gv_puts(" GAINED: " as *u8)
138 sys_write(1, ((b as i64) + i) as *u8, rl)
139 gv_puts("\n" as *u8)
140 } }
141 }
142 }
143 }
144 }
145 if rl > 0 { i = i + rl }
146 if rl == 0 { i = i + 1 }
147 }
148 return shown
149}
150
151func cd_show_lost(a: *u8, an: i64, b: *u8, bn: i64) -> i64 {
152 return cd_show_lost_limit(a, an, b, bn, CD_SHOW)
153}
154func cd_show_lost_limit(a: *u8, an: i64, b: *u8, bn: i64, limit: i64) -> i64 {
155 var shown: i64 = 0
156 var i: i64 = 0
157 while i < an {
158 let rl: i64 = cdl_runlen(a, an, i)
159 if rl >= CD_MINLEN {
160 if shown < limit {
161 if cdl_contains(b, bn, a, i, rl) == 0 {
162 shown = shown + 1
163 gv_puts(" LOST: " as *u8)
164 sys_write(1, ((a as i64) + i) as *u8, rl)
165 gv_puts("\n" as *u8)
166 }
167 }
168 }
169 if rl > 0 { i = i + rl }
170 if rl == 0 { i = i + 1 }
171 }
172 return shown
173}
174
175func main(argc: i64, argv: *i64) -> i64 {
176 if argc < 3 {
177 gv_puts("usage: nx_contentdiff <live-elf> <candidate-elf> [all|positive-display-limit]\n" as *u8)
178 sys_exit(2)
179 return 2
180 }
181 var display: i64 = CD_SHOW
182 if argc > 3 {
183 display = cd_display_arg(argv[3] as *u8)
184 if argc > 4 { display = CD_SHOW_BAD }
185 if display == CD_SHOW_BAD {
186 gv_puts("error=invalid-display-limit expected=all-or-positive-decimal\n" as *u8)
187 sys_exit(2)
188 return 2
189 }
190 }
191 let livep: *u8 = argv[1] as *u8
192 let candp: *u8 = argv[2] as *u8
193
194 let a: *u8 = sys_mmap(CD_CAP)
195 let b: *u8 = sys_mmap(CD_CAP)
196 let an: i64 = cd_slurp(livep, a, CD_CAP)
197 let bn: i64 = cd_slurp(candp, b, CD_CAP)
198
199 gv_puts("=== NX-CONTENTDIFF live=" as *u8)
200 gv_puts(livep)
201 gv_puts(" candidate=" as *u8)
202 gv_puts(candp)
203 gv_puts(" ===\n" as *u8)
204
205 if an <= 0 {
206 gv_puts("verdict=RED rule=live-unreadable\n" as *u8)
207 sys_exit(1)
208 return 1
209 }
210 if bn <= 0 {
211 gv_puts("verdict=RED rule=candidate-unreadable\n" as *u8)
212 sys_exit(1)
213 return 1
214 }
215
216 // FULL BUDGET: every qualifying run, whole run, no sampling.
217 let prm: *i64 = sys_mmap(8 * CDL_P_SLOTS) as *i64
218 prm[CDL_P_MINLEN] = CD_MINLEN
219 prm[CDL_P_MAXSAMPLES] = 0
220 prm[CDL_P_MAXTOKLEN] = 0
221 let st: *i64 = sys_mmap(8 * CDL_O_SLOTS) as *i64
222 let permil: i64 = cdl_lost(a, an, b, bn, prm, st)
223
224 var forward_limit: i64 = display
225 if display == CD_SHOW_ALL { forward_limit = st[CDL_O_RUNS] }
226 if argc > 3 {
227 gv_puts("display_limit=" as *u8)
228 gv_puts(argv[3] as *u8)
229 gv_puts("\n" as *u8)
230 }
231 cd_show_lost_limit(a, an, b, bn, forward_limit)
232
233 gv_puts("\nlive_bytes=" as *u8)
234 gv_num(an)
235 gv_puts(" candidate_bytes=" as *u8)
236 gv_num(bn)
237 gv_puts("\nruns_scanned=" as *u8)
238 gv_num(st[CDL_O_RUNS])
239 gv_puts(" lost_from_live=" as *u8)
240 gv_num(st[CDL_O_LOST])
241 gv_puts(" lost_permil=" as *u8)
242 gv_num(permil)
243 gv_puts(" minlen=" as *u8)
244 gv_num(CD_MINLEN)
245 gv_puts("\ndeduped=0 (occurrence counts, declared not hidden)\n" as *u8)
246
247 // ---- THE REVERSE DIRECTION, AND WHY IT IS PRINTED HERE (2026-09-03) --------------------------
248 // nx_staging_guard has taken this measurement since 2026-08-06 -- the SAME cdl_lost with its
249 // arguments swapped, no second ruler -- and its comment carries the reason: A LOSS DETECTOR THAT
250 // COUNTS ONLY WHAT VANISHED CANNOT TELL A RENAME FROM A REMOVAL. It was never surfaced HERE, in the
251 // oracle a seat runs by hand, so the measurement had to be rediscovered from scratch: on 2026-09-03
252 // a forward-only RED of 332/1803 read as "the live binary cannot be rebuilt", and the reverse pass
253 // (8/1474) is what showed the loss was one-way rather than a re-encode. That cost an hour and a
254 // wrong sev-7 filing. ★A FIX WIRED INTO ONE CONSUMER AND NOT ITS SIBLING IS HALF A FIX, AND THE HALF
255 // LEFT UNDONE WAS THE VERB WHOSE PURPOSE IS TO TELL YOU WHAT TO FIX.
256 let sr: *i64 = sys_mmap(8 * CDL_O_SLOTS) as *i64
257 let rpermil: i64 = cdl_lost(b, bn, a, an, prm, sr)
258 gv_puts("candidate_runs=" as *u8)
259 gv_num(sr[CDL_O_RUNS])
260 gv_puts(" gained_by_candidate=" as *u8)
261 gv_num(sr[CDL_O_LOST])
262 gv_puts(" gained_permil=" as *u8)
263 gv_num(rpermil)
264 let sym: i64 = cdl_symclass(st[CDL_O_LOST], sr[CDL_O_LOST])
265 gv_puts("\nsymmetry=" as *u8)
266 gv_puts(cdl_symname(sym))
267 gv_puts("\n" as *u8)
268
269 // ---- THE FLAVOUR AXIS: partition the loss, never fold it into the verdict -------------------
270 let flav: i64 = cdl_lost_srcpath(a, an, b, bn, CD_MINLEN, st)
271 let srcp: i64 = st[CDL_O_SRCPATH]
272 let idnt: i64 = st[CDL_O_IDENT]
273 let sect: i64 = st[CDL_O_SECT]
274 let other: i64 = st[CDL_O_LOST] - flav
275 gv_puts("lost_srcpath=" as *u8)
276 gv_num(srcp)
277 gv_puts(" lost_symbolname=" as *u8)
278 gv_num(idnt)
279 gv_puts(" lost_sectname=" as *u8)
280 gv_num(sect)
281 gv_puts(" lost_other=" as *u8)
282 gv_num(other)
283 gv_puts(" (partition of lost_from_live; sums to " as *u8)
284 gv_num(srcp + idnt + sect + other)
285 gv_puts(")\n" as *u8)
286 // NAME the class the flavour axis cannot explain -- and say so when it is EMPTY, because an empty
287 // actionable class is the strongest possible read of a RED that is purely build flavour.
288 let shown_other: i64 = cd_show_other_limit(a, an, b, bn, forward_limit)
289 if shown_other == 0 { gv_puts(" (no LOST-OTHER runs: every loss is build metadata -- a source path, a symbol name or an ELF/DWARF section name)\n" as *u8) }
290 var reverse_limit: i64 = display
291 if display == CD_SHOW_ALL { reverse_limit = sr[CDL_O_RUNS] }
292 let shown_gain: i64 = cd_show_gained_limit(a, an, b, bn, reverse_limit)
293 if shown_gain == 0 { gv_puts(" (no GAINED runs outside build metadata: the candidate adds no new printable content -- read this as a PROVENANCE signal)\n" as *u8) }
294 if flav > 0 {
295 if flav >= other {
296 gv_puts("FLAVOUR MISMATCH SUSPECTED: most of the loss is compiler-embedded SOURCE PATHS and SYMBOL\n" as *u8)
297 gv_puts(" NAMES, which is what -g adds (one path per unit, one symbol per subprogram -- the build line\n" as *u8)
298 gv_puts(" prints `debug-info subprograms=N`, and N should be close to lost_symbolname above).\n" as *u8)
299 gv_puts(" A --debug build and a release build of the SAME source differ by ~184 permil,\n" as *u8)
300 gv_puts(" roughly 4x the regression band, so this RED may be a build-flavour artifact and not a loss.\n" as *u8)
301 gv_puts(" MEASURE, DO NOT ASSUME: rebuild the candidate with `nx_sov_build_run <t> --build-only --debug`\n" as *u8)
302 gv_puts(" and re-run. On nx_hostctl that took lost_from_live 332 -> 2, and the 2 were deliberate.\n" as *u8)
303 gv_puts(" THE VERDICT BELOW IS DELIBERATELY UNCHANGED: a source path can still be load-bearing, so this\n" as *u8)
304 gv_puts(" is a separate ANNOUNCED axis, never a widened conjunct. Enumerate lost_other before accepting.\n" as *u8)
305 }
306 }
307 gv_puts("\n" as *u8)
308
309 let ctr: *i64 = gv_ctr()
310 gv_check("C1 live binary readable" as *u8, an > 0, ctr)
311 gv_check("C2 candidate binary readable" as *u8, bn > 0, ctr)
312 gv_check("C3 no printable content lost from live" as *u8, st[CDL_O_LOST] == 0, ctr)
313 let rc: i64 = gv_verdict("CONTENTDIFF" as *u8, ctr, "candidate retains every printable run the live binary has" as *u8)
314 sys_exit(rc)
315 return rc
316}