code wiki / (root) / nx_contentdiff_display_20260907.nx

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}