nx_cc_equiv_gate.nx
buildroot/runtime/nx_cc_equiv_gate.nx
about
nx_cc_equiv_gate.nx -- COMPILER DIFFERENTIAL-BEHAVIOR ORACLE: miscompile-detection for the sovereign toolchain (EMI-style baseline-vs-challenger build + stdout byte-equal + self-host stage).
Team organ (Engineer-owned) born from the dom/licm dormant-paths
discovery (ledger T#opt-dom-licm-dormant-paths, 2026-06-10): the
deref-cast precedence bug had silently disabled 4 optimizer reads
since they were written, and AWAKENING them broke the self-host at
generation 3 -- a class of defect no single-binary test catches.
This gate judges ANY compiler mutation by BEHAVIOR, not by asm:
For each corpus row (deterministic, network-free modules):
build with BASELINE cc -> run -> raw wait4 status + stdout bytes
build with CHALLENGER cc -> run -> same
row PASS iff both build, statuses EQUAL, stdout BYTE-EQUAL.
(Different codegen/hoisting is fine; different BEHAVIOR is not.)
SELF-HOST stage (the gen3-class catch):
challenger compiles runtime/nx_compile_x86.nx -> gen2 binary;
gen2 must then compile a probe module whose binary runs exit 0.
This is exactly where the awakened-LICM breakage surfaced
(gen3: "unknown type name 'nx_size'").
Usage: nx_cc_equiv_gate <challenger_elf> [feature_source.nx]
challenger: REQUIRED (a stale default once produced ten confident FAIL rows about a leftover).
baseline: _offc/nx_cc_sovereign.elf (the LIVE toolchain) unless knowledge/cc_equiv_baseline.conf
names another compiler on its first line. A node names the HUB's promoted compiler there
(pulled through nx_content_get, digest-verified) so a candidate that ADDS a language
feature can still be judged DIFFERENTIALLY against a baseline that builds the whole
corpus (2026-09-15: __size_of on struct types left 5 of 10 rows unbuildable by the live
laptop compiler, and "both sides must build" could never pass any capability-adding
release -- loosening the rule was the only other exit, and it is the wrong one).
â PATHS ARE RESOLVED AFTER THE BUILDROOT ANCHOR: from nxc2/ a relative `_build/x.elf` means
buildroot/_build/x.elf. Measured 2026-09-15: a relative challenger path silently named a Sep-4
fossil in buildroot/_build instead of the candidate in nxc2/_build, and the gate printed the
caller's path as if it were that binary. Pass an ABSOLUTE path; the gate prints the byte size of
every compiler it will exec so the identity is checkable, and refuses a challenger byte-identical
to the baseline (a self-comparison measures nothing).
Run with CWD=nxc2/ or nishihost/ (it anchors into buildroot/). Exit 0 iff all rows + self-host PASS.
Verdicts stream to stdout AND append to the durable log
knowledge/status/cc_equiv_gate.log (Archivist rule).
dependencies 2 imports · 0 importers
imports: nx_syscalls.nxnx_gate_verdict.nx
imported by: nobody (leaf or entry point)
call flow from main pre-order; caps 40 nodes / depth 6 declared; ↻ = already shown
structs
| none |
consts
| 49 | const EQ_ROWS: i64 = 10 |
| 51 | const EQ_CONF_CAP: i64 = 4096 |
functions
| 54 | func eq_first_line(buf: *u8, n: i64) -> i64 called by 1: main |
| 65 | func eq_puts2(logfd: i64, s: *u8) -> i64 |
| 73 | func eq_putn2(logfd: i64, v: i64) -> i64 |
| 91 | func eq_cat(dst: *u8, off: i64, s: *u8) -> i64 |
| 98 | func eq_catn(dst: *u8, off: i64, v: i64) -> i64 |
| 117 | func eq_uniq(pre: *u8, nonce: i64, suf: *u8) -> *u8 |
| 128 | func eq_nonce() -> i64 |
| 144 | func eq_run(path: *u8, argv: *i64, envp: *i64, redir_out: i64, redir_err: i64) -> i64 |
| 160 | func eq_fsize(path: *u8) -> i64 |
| 177 | func eq_build(cc_path: *u8, src_path: *u8, s_tmp: *u8, o_tmp: *u8, |
| 214 | func eq_run_capture(elf: *u8, out_path: *u8, envp: *i64, devnull: i64) -> i64 |
| 224 | func eq_files_equal(pa: *u8, pb: *u8) -> i64 |
| 257 | func eq_probe(logfd: i64, tag: *u8, path: *u8) -> i64 |
| 266 | func eq_anchor_root() -> i64 |
| 273 | func main(argc: i64, argv: *i64) -> i64 |