AxIR Verification Instruments
June 13, 2026 · View on GitHub
The IR+compiler story is enforced by three independent instruments, each
catching a failure mode the others cannot see. All three run against the
same 364 fixtures under ir/conformance/ across the five generated targets
(python, go, rust, java, cpp).
1. Provenance — are the functions defined from the IR?
npm run axir -- audit provenance ir/axcore/root.axir
Proves every core-function registry entry is defined exactly once inside the
generated BEGIN/END AXIR CORE EMITTED FUNCTIONS markers, with no shadow
definitions elsewhere in the package. Enforced for all targets at compile
time and in CI (test:axir phase); per-package metrics land in
packages/<target>/axir-provenance.json.
Catches: hand-written reimplementations masquerading as generated code, dropped emissions, duplicate definitions.
Cannot catch: an emitted function nobody calls — wrappers can pass every fixture while running hand orchestration beside the generated code.
2. Coverage — are the functions executed by conformance?
npm run axir:audit:coverage # all five targets + asymmetry diff
npm run axir -- audit --targets rust coverage ir/axcore/root.axir
Every emitted function marks itself on first entry when
AXIR_COVERAGE_FILE is set (a single env-gated branch otherwise). The audit
compiles each target, runs its full conformance suite with tracing, and
diffs the traced names against the registry — reporting unexercised
functions per module and cross-target asymmetries (a function exercised
under python but not under go is a wiring or runner gap in go).
Catches: wrappers that bypass emitted orchestration, fixture runners that exercise hand parallels, suites that never reach a module.
Cannot catch: a runner that executes the right code but asserts nothing.
3. Perturbation — do the runners actually check the results?
npm run axir:perturb:check # all targets; or: ... go rust
Mutates one expected_* value in the alphabetically first fixture of every
suite and requires every target to fail that fixture (after a pristine
self-test pass). A target that accepts a perturbed expectation has a runner
that is not comparing behavior — the failure mode that lets shams survive
both provenance and coverage.
Catches: missing assertions, allowlist-gated comparisons, error paths that fabricate the expected error from the fixture's own text.
Working the gaps
The coverage asymmetry section is the work queue: drive every target to the
python reference set, then shrink the global unexercised list (functions
no target exercises) by adding fixtures. When changing any runner, rerun all
three instruments — each fix historically moves more than one needle, and
the instruments check each other (the python self-containment tripwire in
tools/axir/internal/axir/axir_test.go is the static fourth man).