Opt-in third NLI inference backend (ARBORIST_NLI_BACKEND=tinygrad) in qa/nli/shadow.py, parallel to torch/onnx-int8, behind the #000049 cage: shadow-only, never an audit_mode input, never auto-preempts the proven path (guarded so it cannot regress torch/onnx). Loads the ONNX export through tinygrad's frontend wrapped to the existing model(**enc).logits contract so _nli_batch is byte-unchanged. bench/scripts/nli_backend_ab.py + make bench-nli-backends: deterministic A/B, gate is numerical agreement with the torch reference first, latency second (a divergent engine = a different shadow signal = a different nli_policy_hash). Instrument is honest — reports a requested backend as unavailable rather than relabelling a fallback's numbers. First CPU-smoke run already quantified that the deployed §7 #22 int8 export diverges Δmax≈0.42 from torch — the immunity property made measurable, not a defect. Real tinygrad numbers pending a producer-box run (tinygrad not an arborist dep; frontend op-coverage for the large MNLI checkpoints unverified by design). docs/onnx-vendor-capture-immunity.md: why the model-in-proof-path cage makes the inference engine an interchangeable sidecar, never a trust dependency — public-domain positioning capital. Indexed in CLAUDE.md. Full suite 2498 passed (identical to baseline); 24/24 NLI tests green.
6.3 KiB
ONNX vendor-capture immunity — why the engine is not a trust dependency
What this is: the rationale for why arborist is structurally immune to ONNX-format and ONNX-Runtime vendor capture — and why that immunity was a free side-effect of a discipline adopted for honesty, not for procurement reasons. Not a ticket; a positioning/architecture reference. Public-domain intellectual capital: the argument is reproducible and inheritable by any fork or downstream client that keeps the same cage. The headline: arborist puts zero neural inference in its proof path, so whichever vendor owns the inference engine owns none of arborist's trust boundary.
1. The capture vector, stated honestly
ONNX is an open model-exchange format; ONNX Runtime (ORT) is its dominant engine. Both are governed and overwhelmingly resourced by Microsoft. The systems-programming critique that motivated this note (ORT's ~2,500-line, many-flag, many-execution-provider build) is real, but it is the small version of the risk. The large version is the trust one:
Any system that places a neural model — its embedder, its NLI head, its reranker, its LLM — inside the chain of custody for its answers inherits that model's runtime, and therefore that runtime's vendor. The vendor's roadmap, deprecation policy, license drift, build complexity, and execution-provider politics all become load- bearing for your correctness guarantee.
This is the same defect class as a logged secret or a leaked context: a dependency that should have stayed at the edge has reached into the core. The fix is not "pick a better engine." The fix is not putting the engine in the core at all.
2. Where models are, and are not, in arborist
| layer | what runs there | model? | vendor-exposed? |
|---|---|---|---|
Merkle commit (merkle.py) |
SHA-256, fixed combine conventions | no | no |
Content store / cache key (store.py, qa/keys.py) |
canonical encodings, 8-dim key | no | no |
Verifier (qa/verify.py) |
byte-identical lexical matching (quote / span / entity / paraphrase) | no | no |
Audit chain (audit_events) |
sha256(prev ‖ canonical(body)) |
no | no |
NLI shadow (qa/nli/shadow.py) |
entailment contradiction veto | yes | yes — but sidecar |
Relevance shadow (qa/relevance/shadow.py) |
cross-encoder aboutness | yes | yes — but sidecar |
MT edges (qa/mt/translator.py) |
opus-mt query/display translation | yes | yes — but display-only |
Everything above the rule is the proof path: deterministic, hash-
anchored, model-free, reproducible from python + sqlite3 alone.
Everything below is a sidecar that is demote-only, never an
audit_mode input, never writes providence_cache / audit_events /
run_dag_root (the #000049 model-in-proof-path cage; the
verifier-stays-binary and "no soft signal in the hard chain" rules in
CLAUDE.md). A model in arborist can only ever lower confidence as an
advisory signal — it can never mint, promote, or sign a result.
3. The immunity, precisely
Because no model output is an input to any commitment, proof, cache key, or audit row:
- The inference engine is interchangeable. arborist already swaps
it silently:
qa/nli/shadow.pyprefers anoptimum.onnxruntimeint8 graph if one exists, picksCUDAExecutionProvider/CPUExecutionProvider, and falls through to the plaintransformers+torchpath on any failure — with no effect on any hash. ORT is an accelerator, not an authority. - A hostile vendor pivot is bounded and cheap. If Microsoft deprecated ORT, relicensed it, fragmented the ONNX opset, or its build complexity became untenable, the blast radius is: re-export the pinned checkpoint to whatever engine survives (torch always works; tinygrad's ONNX frontend is a candidate — #000049 §7). The checkpoint is already version-pinned in the NLI manifest; nothing in the proof path observes the swap. Cost is hours of producer-box work, not a correctness migration.
- Cache validity is engine-independent. A record's
falsification_stateandaudit_modewere decided by the deterministic verifier. Re-running tomorrow on a different engine cannot change a prior STRICT/HYBRID/UNGROUNDED verdict, because the engine never produced it. (Contrast: a system whose answer is graded by an LLM must re-grade — and silently re-trust — on every model or runtime change.)
The one place a model could ever touch authority is the deliberately-
unwired Phase-3 demotion hook in #000049. Even there the design
forces the exposure to be named: if NLI is ever allowed to demote
audit_mode, nli_policy_hash (model + k + agg + guard + θ) folds
into governance_policy_hash, so the model's identity becomes a
first-class, cache-partitioning, audited policy input — capture made
visible and versioned, never silent.
4. This was free — and that is the point
We did not design the cage to dodge Microsoft. We designed it because a model in the proof path is a honesty defect: a false-positive STRICT is corruption, and a model that can promote will eventually hallucinate a promotion. The deletion-first guardrails (delete the part: the model does not get to be in the hard chain) were adopted for truth.
Vendor-capture immunity fell out for free. That is the recurring shape of the right architectural call: a discipline taken for one good reason pays a second, unbid dividend. A system built to never lie about grounding turns out to also be a system no inference-engine vendor can hold hostage.
5. Why this is published intellectual capital
Per the Prime Mission, this argument is a gift to the ecosystem, not a moat. Any RAG / retrieval / agent system can adopt the same split: deterministic verifier in the proof path, models as demote-only sidecars on a producer box, engine identity versioned into a policy hash only if it is ever allowed to touch authority. A fork that keeps the cage inherits the immunity verbatim — no license, no dependency, no permission required. The cage is the gift.
See also: docs/lexical-first-rationale.md (the cost-asymmetry
sibling — why the cheap deterministic path is the default),
docs/soft-hash-channel-analysis.md (soft-vs-hard channel threat
model), and ticket #000049 §7 (the NLI cage, shadow path, and the
tinygrad/ORT engine-swap bench).