nx_contentdiff_cli_candidate_t295.nx source
↩ module page · 274 lines · 14268 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 "nx_contentdiff_iterator_candidate_t295.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 cd_display_summary(label: *u8, shown: i64, total: i64) -> i64 {
176 gv_puts("display_class=" as *u8); gv_puts(label)
177 gv_puts(" shown=" as *u8); gv_num(shown)
178 gv_puts(" total=" as *u8); gv_num(total)
179 gv_puts(" omitted=" as *u8); gv_num(total - shown)
180 gv_puts("\n" as *u8)
181 return 0
182}
183
184
185struct NxCdDisplay {total:i64,shown:i64,source:i64,ident:i64,section:i64,other:i64}
186const CD_STRUCT_ALL:i64=0
187const CD_STRUCT_OTHER:i64=1
188const CD_STRUCT_SOURCE:i64=2
189func cd_structured_names(a:*NxCdStructured,b:*NxCdStructured,label:*u8,mode:i64,limit:i64,out:*NxCdDisplay)->i64{
190 out.total=0;out.shown=0;out.source=0;out.ident=0;out.section=0;out.other=0
191 var pos:i64=0;var span:NxCdSpan
192 while cds_next_span(a,&pos,&span)==1{
193 var missing:i64=0
194 if mode==CD_STRUCT_SOURCE{missing=cds_source_missing(a,b,&span)}else{
195 if span.length>=CD_MINLEN{missing=cds_span_missing(a,b,&span,0)}
196 }
197 if missing==1{
198 let klass:i64=cds_span_class(a,&span)
199 if mode!=CD_STRUCT_OTHER||klass==CDS_CLASS_OTHER{
200 out.total=out.total+1
201 if klass==CDS_CLASS_SOURCE{out.source=out.source+1}else{
202 if klass==CDS_CLASS_IDENT{out.ident=out.ident+1}else{if klass==CDS_CLASS_SECTION{out.section=out.section+1}else{out.other=out.other+1}}
203 }
204 if out.shown<limit{
205 gv_puts(" ");gv_puts(label);gv_puts(": ");sys_write(1,(a.buf as i64+span.offset) as *u8,span.length);gv_puts("\n")
206 out.shown=out.shown+1
207 }
208 }
209 }
210 };return out.shown
211}
212func cd_structured_error(state:i64,reason:*u8)->i64{
213 gv_puts("comparison_kind=elf-structured-v1 structured_state=");gv_num(state)
214 gv_puts(" verdict=RED rule=");gv_puts(reason);gv_puts(" lost_from_live=-1 source_removed=-1 evidence=unqualified\n");return 1
215}
216// Complete read-only file mappings; this path never compares a fixed-size prefix.
217func cd_structured_paths(livep:*u8,candp:*u8,display:i64)->i64{
218 var an:i64=0;var bn:i64=0
219 let a:*u8=sys_map_file(livep,&an)
220 if (a as i64)<=0{return cd_structured_error(CDS_INVALID,"live-unreadable")}
221 let b:*u8=sys_map_file(candp,&bn)
222 if (b as i64)<=0{sys_munmap_direct(a,an);return cd_structured_error(CDS_INVALID,"candidate-unreadable")}
223 gv_puts("=== NX-CONTENTDIFF live=");gv_puts(livep);gv_puts(" candidate=");gv_puts(candp);gv_puts(" ===\n")
224 var x:NxCdStructured;var y:NxCdStructured
225 let xi:i64=cds_init(&x,a,an);let yi:i64=cds_init(&y,b,bn)
226 let prm:*i64=sys_mmap_try(CDL_P_SLOTS*__size_of(i64)) as *i64
227 var rc:i64=xi;if rc==0{rc=yi};if (prm as i64)<=0{rc=CDS_RESOURCE}
228 var forward:NxCdResult;var reverse:NxCdResult
229 if rc==0{
230 prm[CDL_P_MINLEN]=CD_MINLEN;prm[CDL_P_MAXSAMPLES]=0;prm[CDL_P_MAXTOKLEN]=0
231 rc=cds_measure(&x,&y,prm,&forward)
232 if rc==0{rc=forward.state}
233 if rc==0{rc=cds_measure(&y,&x,prm,&reverse);if rc==0{rc=reverse.state}}
234 }
235 var result:i64=1
236 if rc!=0{cd_structured_error(rc,"structured-comparison-refused")}else{
237 var limit:i64=display;if display==CD_SHOW_ALL{limit=CD_I64_MAX}
238 var loss:NxCdDisplay;var other:NxCdDisplay;var gain:NxCdDisplay;var sources:NxCdDisplay;var added:NxCdDisplay
239 cd_structured_names(&x,&y,"LOST",CD_STRUCT_ALL,limit,&loss)
240 cd_structured_names(&x,&y,"LOST-OTHER",CD_STRUCT_OTHER,limit,&other)
241 cd_structured_names(&y,&x,"GAINED",CD_STRUCT_OTHER,limit,&gain)
242 cd_structured_names(&x,&y,"SOURCE-REMOVED",CD_STRUCT_SOURCE,limit,&sources)
243 cd_structured_names(&y,&x,"SOURCE-ADDED",CD_STRUCT_SOURCE,limit,&added)
244 var consistent:i64=1
245 if loss.total!=forward.lost||sources.total!=forward.source_removed||added.total!=forward.source_added{consistent=0}
246 if other.total!=loss.other||loss.source+loss.ident+loss.section+loss.other!=loss.total{consistent=0}
247 if consistent==0{cd_structured_error(CDS_INVALID,"count-enumeration-disagreement")}else{
248 gv_puts("\ncomparison_kind=elf-structured-v1 structured_state=0\nlive_bytes=");gv_num(an);gv_puts(" candidate_bytes=");gv_num(bn)
249 gv_puts("\nruns_scanned=");gv_num(forward.runs);gv_puts(" lost_from_live=");gv_num(forward.lost);gv_puts(" lost_permil=");gv_num(cds_permil(forward.lost,forward.checked));gv_puts(" minlen=");gv_num(CD_MINLEN)
250 gv_puts("\ndeduped=0 (occurrence counts, declared not hidden)\ncandidate_runs=");gv_num(reverse.runs);gv_puts(" gained_by_candidate=");gv_num(reverse.lost);gv_puts(" gained_permil=");gv_num(cds_permil(reverse.lost,reverse.checked))
251 gv_puts("\nsymmetry=");gv_puts(cdl_symname(cdl_symclass(forward.lost,reverse.lost)))
252 gv_puts("\nlost_srcpath=");gv_num(loss.source);gv_puts(" lost_symbolname=");gv_num(loss.ident);gv_puts(" lost_sectname=");gv_num(loss.section);gv_puts(" lost_other=");gv_num(loss.other)
253 gv_puts("\nsource_removed=");gv_num(forward.source_removed);gv_puts(" source_added=");gv_num(forward.source_added);gv_puts("\n")
254 cd_display_summary("LOST",loss.shown,loss.total);cd_display_summary("LOST-OTHER",other.shown,other.total);cd_display_summary("GAINED",gain.shown,gain.total)
255 cd_display_summary("SOURCE-REMOVED",sources.shown,sources.total);cd_display_summary("SOURCE-ADDED",added.shown,added.total)
256 if forward.lost==0&&forward.source_removed==0{
257 gv_puts("NX-CONTENTDIFF verdict=GREEN (qualified structured content and source paths retained; behavior unmeasured)\n");result=0
258 }else{gv_puts("NX-CONTENTDIFF verdict=RED (content or source-path loss requires review; counts do not prove behavior)\n")}
259 }
260 }
261 cds_close(&x);cds_close(&y)
262 if (prm as i64)>0{sys_munmap_direct(prm as *u8,CDL_P_SLOTS*__size_of(i64))}
263 sys_munmap_direct(a,an);sys_munmap_direct(b,bn);return result
264}
265func main(argc:i64,argv:*i64)->i64{
266 if argc<3{gv_puts("usage: nx_contentdiff <live-elf> <candidate-elf> [all|positive-display-limit]\n");return 2}
267 var display:i64=CD_SHOW
268 if argc>3{
269 display=cd_display_arg(argv[3] as *u8);if argc>4{display=CD_SHOW_BAD}
270 if display==CD_SHOW_BAD{gv_puts("error=invalid-display-limit expected=all-or-positive-decimal\n");return 2}
271 gv_puts("display_limit=");gv_puts(argv[3] as *u8);gv_puts("\n")
272 }
273 return cd_structured_paths(argv[1] as *u8,argv[2] as *u8,display)
274}