ONNX Runtime has one source: the chain#
Owner rule, 2026-09-23. Every component that compiles against, links or loads ONNX Runtime uses the ORT this repository builds from source. Nothing downloads, restores or installs a second one: no NuGet package, no PyPI wheel, no release zip, no apt package, no copy bundled inside another project, no pyke build. There are no exceptions, and a plugin EP counts as ORT.
This page owns the mechanism: which consumers exist, how each one reaches the
chain ORT, which guard proves it, and what each guard cannot see. The rule
itself, as an agent must keep it, is
windows-build-invariants.md § ONNX Runtime has exactly one source
for Windows and AGENTS.md § Linux Build Rules for Linux.
What “the chain ORT” is#
Windows |
Linux |
|
|---|---|---|
Built by |
|
|
Installed at |
|
|
Python wheel |
|
|
Source root compiled into it |
|
|
The last row is the fingerprint every guard uses. ORT compiles its source paths
into its binaries through __FILE__, so the chain’s DLL carries
C:\temp\onnx-src\onnxruntime\core\... and its .so carries
/opt/onnxruntime/onnxruntime/core/.... Measured on 2026-09-23: Windows ML’s
C:\Windows\System32\onnxruntime.dll (1.17) carries C:\__w\1\s\onnxruntime\...,
and the PyPI GPU wheel carries N:\_work\1\s. Two consequences:
Moving either source directory, or adding
-ffile-prefix-map/-fmacro-prefix-mapto the ORT build, breaks every guard and every consumer repo at once. They fail closed, but they all fail.A version is not provenance. PyPI publishes onnxruntime 1.31.0 for cp314 too, without DirectML, so a name-and-version check cannot tell it from the chain wheel. The guards compare bytes.
The census (G1, G6) reads a whole source-file path, not the directory
(since 2026-09-24). A fingerprint is onnxruntime/core/ or
onnxruntime/contrib_ops/, then a path ending in .cc, .cpp, .cxx, .c,
.h, .hpp, .inc, .cu or .cuh, then a NUL byte. That is the shape
__FILE__ leaves in a binary. Before, the directory alone counted, and that
failed OmniAccelerANT’s Linux lane (run 35928030957, x64 and arm64):
OxidANT’s loader (
ort_runtime.rs) keeps/opt/onnxruntime/onnxruntime/core/as a string, because it looks for that fingerprint in the ORT file it loads. The Windows build keepsC:\temp\onnx-src\onnxruntime\core\.rustc stores string literals back to back, with no NUL between them. The census read the text before the directory,
...invalid Once state, as a relative build root and calledliboxidant.soan ORT build without a fingerprint:UNPROVEN. On Windows the same string would have madeoxidant.dllSTALE.Now such a file is an importer. G6 checks that its
ld.solookup lands on the chain ORT, a check it used to skip for it.G1 had the same fault. FFmpeg compiles its configure line into every library and tool, and the chain’s line holds
-I/usr/local/lib/onnxruntime-cpu/include/onnxruntime/core/session, so every FFmpeg ELF counted as an ORT build with no fingerprint. Nowlibavfilteris theffmpegconsumer in the contract, and the rest are not ORT.
Nothing real was lost. Measured on 2026-09-24, old rule against new:
in a local
:latest-cross(e8eb8a42, ORT 1.29.0), the chainlibonnxruntime.sokeeps all 592 of its fingerprints,libonnxruntime_providers_dnnl.so23 of 23, the Android build 545 of 545;on a Windows host, a chain
onnxruntime.dll(a consumer’s runner copy, rootC:\temp\onnx-src) keeps 608 of 608, and Windows ML’s in-box 1.17 in System32 518 of 518.
The PyPI and DirectML wheels and the WebGPU EP were not measured.
The rule for a consumer: it may name the chain directory, but it must never
embed a whole ORT source-file path. A file that does is counted as an ORT build
and fails the census as STALE or FOREIGN, so the mistake fails closed.
The same shape binds a consumer’s test fixtures. A fake ORT written as
"$chainSrc OrtGetApiBase" (a space after the .cc) has no fingerprint under
this rule. A chain fixture then no longer ties to the chain root, and a stale
one reads UNPROVEN where the test expects STALE. End the fake path with a
NUL, "$chainSrc`0OrtGetApiBase": that passes the census before and after
the change, so it can land ahead of the pin bump. Three Windows ORT suites
needed it: OmniAccelerANT’s OrtRunner.Tests.ps1 (2 of 6 failed at the fix),
OxidANT’s OrtPayload.Tests.ps1 and AccelerANTgine’s OrtBundle.Tests.ps1
(one case each).
An ORT under another name#
A fingerprint and a name are not the only way to recognise an ORT. Every ORT
build defines its entry point, OrtGetApiBase, and a consumer only imports it,
or looks it up with dlsym. So since 2026-09-24 the census also counts a file
that defines it as an ORT instance, whatever the file is called:
Linux (
ort_census_probe.py,elf_defines): the ELF’s dynamic symbol table holdsOrtGetApiBasewith a section index (notSHN_UNDEF). The probe finds the symbol throughDT_GNU_HASH, orDT_HASHwhen there is no GNU table, the same lookupld.somakes. Its BIN line ends indef.Windows (
WindowsOrtProvenance.Common, throughGet-PeExportNamesinWindowsTargetArch.Common): the PE’s export table namesOrtGetApiBase, and not as a forwarder. A forwarder (onnxruntime.OrtGetApiBase) runsonnxruntime.dll’s code, so it stays an importer and G6 resolves it.
Such a file is then graded by its bytes like any other ORT instance. With no
fingerprint and no chain match it is UNPROVEN (“an ORT under another name”).
Before, it was an importer, and an $ORIGIN RUNPATH next to the chain ORT was
enough for G6 to pass it. OmniAccelerANT’s packer gives exactly that RUNPATH to
every ELF that holds OrtGetApiBase. The narrower fingerprint of 2026-09-24
had widened the hole a little: an ORT whose paths lost their NUL passed too.
Measured on 2026-09-24 in a local :latest-cross (e8eb8a42). The image’s chain
ORT was renamed to libhelper.so, given an $ORIGIN RUNPATH and put beside the
chain ORT, in two forms. In the first, every ORT directory string is overwritten.
In the second, the directories are kept and the NUL after each path is broken.
Both have one byte flipped. The fix branch before this change passed both
(ORT census PASS), and now both are UNPROVEN.
Nothing real moved. In a whole-image census of that image, no file changed its verdict, apart from the scratch copies above. On real files:
the chain
libonnxruntime.sodefines the symbol, found through both hash tables;libAccelerANTgine.soandliboxidant.sodo not;the 2026-09-17 OmniAccelerANT release bundle still passes.
On Windows, the chain onnxruntime.dll and Windows ML’s copy both export it,
and oxidant.dll and the 80-odd GStreamer and runtime DLLs of a runner do not.
Not covered: an ORT that is renamed, stripped of its fingerprints and
rebuilt so it no longer exports OrtGetApiBase. That is deliberate evasion,
not an accident this gate exists for. Archive members are still found by name
and by fingerprint only, because nothing loads them from inside the archive.
What was wrong before 2026-09-23#
Windows OpenCV downloaded
onnxruntime-win-x64-1.25.1.zipat configure time (-win-arm64-on the cross lane), with no pin and no SHA256, and linked dnn and G-API against it. The shipped image still looked clean: dnn’s install glob readsbin\, and the zip keeps its DLLs inlib\.Windows GenAI compiled and linked against
Microsoft.ML.OnnxRuntime.DirectML1.24.4, whichortlib.cmakerestores from the aiinfra ORT-Nightly feed with no hash wheneverORT_HOMEis unset.The rocm venv carried PyPI’s
onnxruntime-ep-webgpu0.4.0.The app venv reconcile uninstalled fixed name lists and missed
-webgpu,-rocm,-qnn,-openvino,-trainingand-winml. On Linux a missing chain wheel fell back to the app lock’s PyPI 1.27.0 without a word.The hub’s Windows consumer API (
WindowsOnnx.Common) installed NuGet ORT, andWindowsMediaRuntime.Commonstaged only NuGetruntimes\<rid>\nativelayouts.Linux held the rule by accident: OpenCV built without ORT when the chain was missing; dnn’s install copy in
/opt/opencv5/libwon theld.solookup; an apt soname repair could pulllibonnxruntime1.x(it did, on 2026-08-27); FFmpeg fell back to any vendorlibonnxruntime.pc.Consumer CI venvs synced inside our images tested PyPI ORT.
Consumer repos: OxidANT statically linked pyke’s ORT 1.28.0; AccelerANTgine’s CMake searched
C:/onnxruntime, Program Files, vcpkg,/usrand pkg-config; OmniAccelerANT could load System32’s Windows ML copy.
Every consumer, and how it reaches the chain ORT#
Consumer |
Lane |
How it gets the chain ORT |
Its own gate, then G2 |
|---|---|---|---|
OpenCV dnn + G-API |
Windows, every lane incl. the arm64 cross |
§ OpenCV on Windows below |
|
OpenCV |
Linux, both passes |
|
|
GenAI |
Windows |
an |
|
GenAI |
Linux |
|
|
FFmpeg |
Windows |
the chain headers in |
G2 reads |
FFmpeg |
Linux |
the chain’s |
|
GStreamer |
Windows (merge stage) |
the merged |
G2 reads |
GStreamer |
Linux |
the chain |
|
AMD GPU plugin EP ( |
Windows rocm spike |
built against the image’s ORT |
G2 in phase 5 |
WebGPU EP |
Windows rocm spike |
built in-tree into the chain |
configure and wheel gates in |
App venv (OrchestrANT) |
both |
purge every ORT distribution the census names, force-install the chain wheels, then the census check |
|
Consumer CI venvs |
both, inside our images |
|
census check plus an import proof ( |
Rust |
both |
G3: the image ENV names the chain ORT |
Test-Container § 19, contract row |
|
Windows |
|
|
apt and |
Linux |
the soname deny is in code; |
|
FFmpeg on Linux stops; it never builds without ORT. ffmpeg_probe_libonnxruntime
exits when the chain is missing or its synthesized-.pc probe cannot compile and
link it; before 2026-09-23 it skipped the backend. The probe runs after
_ffmpeg_cross_args, with the compiler and cross search directories FFmpeg’s
configure gets, and the ORT stage leaves what it reads on every arch by the same
code: the flat include/onnxruntime_c_api.h (copy_onnx_headers_to_output) and
the lib/libonnxruntime.so link (ensure_onnxruntime_symlink). So it fails only
where FFmpeg’s own require libonnxruntime would. The skip would stop the build
anyway, one step later: ffmpeg_ort_link_findings requires
CONFIG_LIBONNXRUNTIME=yes.
OpenCV on Windows: the shim, the hook and the gate#
OpenCV 5.0.0 had two defects on every Windows lane:
modules/dnn/CMakeLists.txt:141testsHAVE_ONNXRUNTIME, whichFindONNXnever sets. dnn then downloaded its own ORT, FORCE-rewroteONNXRT_ROOT_DIR(:279) and re-ran FindONNX (:287). Evidence:out/build-logs/rebuild-push-amd64-20260922-034439.loglines 307666, 308144 and 308502.G-API’s
dml_ep.cppcompiled to a stub that throws.FindONNX.cmake:93looks forinclude/onnxruntime/core/providers/dml/, but ORT (1.30 and 1.31 alike) installsdml_provider_factory.hflat intoinclude/onnxruntime/.
Build-OpencvFromSource.ps1 fixes both without a source patch:
The shim.
New-OpencvOrtNestedIncluderebuilds ORT’s source-tree header layout atC:\temp\opencv-src\ort-nested. It throws when the chain lacksonnxruntime_cxx_api.hordml_provider_factory.h.The arguments, the same on every lane (
Get-OpencvOrtCmakeArgs): the shim asONNXRT_ROOT_DIR, the chain’slibasCMAKE_LIBRARY_PATH,-DHAVE_ONNXRUNTIME=ON, the chain version, andCMAKE_DISABLE_FIND_PACKAGE_onnxruntime/_ONNXRuntime. The config packages stay off because the chain’sonnxruntimeConfig.cmakenames the DLL as its link library.The hook.
windows/scripts/patches/opencv/cmake-hooks/POST_CREATE_MODULE_LIBRARY_opencv_gapi.cmakeis loaded by OpenCV itself throughOPENCV_CMAKE_HOOKS_DIR. It givesopencv_gapi/DELAYLOADfordxcore.dll,d3d12.dll,dxgi.dllandDirectML.dll, the set ORT delay-loads. Without itcv2would fail to load whereverdxcore.dllis missing (Windows Server 2019). Only hook files may live in that directory: OpenCV registers every*.cmakein it.The gate.
Get-OpencvOrtConfigureFindingreads the configure log,CMakeCache.txtandbuild.ninja. It stops the stage on a download line, a summary other thanONNX Runtime: YES (ver <chain>), a cache entry naming3rdparty/onnxruntime, adml_ep.cppcompile withoutHAVE_ONNX_DML, anyHAVE_ONNX_COREMLdefine, or a gapi link without the four/DELAYLOADs.
What changes in the shipped bytes on every lane: opencv_dnn500.dll and
opencv_gapi500.dll compile against the chain’s headers (1.31 since 2026-10-13) and need an
onnxruntime.dll of that version or later. dml_ep.cpp is compiled with
HAVE_ONNX_DML instead of the stub that throws; no DirectML session has run
yet. On the arm64 cross lane opencv_gapi500.dll is the first
PE that imports dxcore.dll. servercore:ltsc2025 carries it (measured
2026-09-23 at the image’s own OS build), so the merge stage’s import walk
resolves it. A future base without it fails that walk; the fix is a measured
-ClientOsPattern entry, never dropping the delay-load.
The guards#
The six guards come in two orthogonal halves plus reach. G1 judges the shipped bytes and G2 judges the build inputs. Neither is enough alone: G1 would pass the pre-2026-09-23 Windows OpenCV image, and G2 cannot see a consumer nobody registered. The STAMP verdict joins them: every consumer G1 finds in an image must carry a stamp G2 wrote against this image’s chain ORT.
Guard |
What it proves |
Where |
What it does NOT cover |
|---|---|---|---|
G1 ORT census |
every ORT binary in the image is the chain’s, byte for byte, and every importer resolves to it |
Windows: |
header-only provenance; files the image user cannot read; which file a |
G2 build gate + stamp |
no foreign ORT in a consumer’s tree, fetch caches, build records or logs; a pass writes the stamp |
Windows: |
an ORT under a non-ORT file name; what loads at run time; pip’s pre-23.3 HTTP cache; on Linux the bytes in uv’s cache, which is graded by where uv fetched a wheel (§ The fetch caches G2 grades) |
G3 fetch-proof crate env |
an |
|
Rust builds outside our images; a consumer that overrides the env |
G4 static denylist |
no script, Dockerfile or workflow re-arms a download, a NuGet/PyPI/apt ORT, a |
|
an upstream bump that fetches by itself (G2/G1 catch it); names built at run time; a verb and an ORT token on different lines; |
G5 documented invariant |
the next agent knows the rule |
|
nothing mechanical, except that fix11 greps the invariant heading |
G6 consumer bundle census |
a shipped app carries the chain ORT of the image it was built in, and every importer finds it |
|
which copy a bare host really loads beyond the modelled loader order |
G2 runs at the end of every consumer build, after the consumer’s own gate and before its tree is removed:
Lane |
Call sites |
Stamp |
|---|---|---|
Windows |
|
|
Linux |
|
|
A stamp names the sha256 of the chain core library it was gated against. A failing rerun deletes the old stamp first. G1 arms its STAMP verdict once the G2 code is present, and an image built before G2 therefore fails STAMP until its consumer stages are rebuilt.
The chain wheel manifest follows the wheel (Linux). The runtime image never
holds the chain wheel, so 03-media/runtime/collect-artifacts.sh hashes its
native members into <prefix>/ort-provenance.sha256 for G1. The same RUN then
runs repair-wheels.sh, which on a cross build strips and repacks every wheel
(and natively may let auditwheel rewrite one), and the venvs install those
bytes. So repair-wheels.sh proves every manifest row against /opt/wheels
before it rewrites anything (ort_manifest_rows check) and re-points each row
at the rewritten wheel of the same name, platform tag aside, afterwards
(follow). A wheel under the chain wheel’s name with other bytes, or a second
wheel of that name, platform tag aside, before or after the rewrite, stops the
media stage: the retag would rename such a twin onto the chain wheel. A wheel
the manifest never listed never enters it. The cp3XYt twins have their own manifest,
<prefix>/ort-provenance-free-threaded.sha256, which repair-wheels.sh --free-threaded proves and
follows against /opt/wheels-free-threaded the same way. G1 reads both, and accepts a chain member
of an ORT twin in that store.
Placement is a cache rule. Both G2 files import or source nothing, and each
is mounted per file into exactly its consumer RUNs: C:\bkmnt\ortmods\ on
Windows, /opt/scripts/03-media/ort-provenance.sh on Linux. They stay out of
the census module, out of buildmods, migraphxmods, WindowsSourceBuild.Common
and Build-MediaCoreAll.ps1, and out of 03-media/core/ and 03-media/runtime/,
which whole images copy. Otherwise one edit would re-key five compile RUNs.
fix11 enforces the mounts.
How G4 runs: one judging pass#
fix11 reads its scan set once into a corpus (<path>:<line>:<text>, comment lines
dropped). The fix11_ort_* checks do not grep it; they QUEUE rules, and
_f11_judge answers every rule in one awk pass, a verdict per rule in queue order:
Helper |
Rule |
FAIL names |
|---|---|---|
|
no live line matches |
the first five lines |
|
|
the count |
|
every file with a line matching |
the files |
|
no verdict: the count lands in |
— |
Until 2026-09-24 each rule was its own awk run over the corpus, about 50 per gate
run. test-critical-fixes.sh runs fix11 once per knocked-out row, so the suite went
from 4.4 s to 45-59 s on the CI runner, and the 68 mutation entries that re-run it
pushed the preflight job past its 45-minute timeout.
Why one pass is written the way it is. gawk (the runner’s awk) caches a
dynamic regex per call site and recompiles it whenever the site sees a different
one. So the judge loops rules outside and lines inside: each rule’s regexes are
compiled once. _f11_env_writes had one match() site shared by seven regexes,
recompiled seven times per line: 22 s of the runner’s 32 s real-tree run. Each
form now has its own site, and lines naming no ort-sys variable are skipped first.
Measured 2026-09-24 in the CI-parity container, real tree: gawk 10.1 s → 0.7 s,
mawk 1.4 s → 0.4 s.
A pass that dies is a FAIL. If the judge returns fewer verdicts than rules,
fix11 fails (the judging pass broke); otherwise a broken awk would pass every
rule it was handed.
The fetch caches G2 grades#
Every G2 call also grades the fetch caches of the machine it runs on:
Get-OrtGateDefaultCache on Windows, ort_gate_default_caches on Linux. Each
root is read at its tool’s override variable, else at the tool’s default.
Cache |
Windows |
Linux |
What fails |
|---|---|---|---|
pyke’s ORT download ( |
under |
under |
any file |
pip ( |
yes |
yes |
an HTTP body that is a wheel with a top-level |
uv ( |
yes |
yes |
Windows: an ORT file whose bytes are not the chain’s. Linux: an ORT wheel uv fetched over HTTP |
NuGet ( |
yes |
yes |
an ORT-named file or archive, a |
cargo’s registry and git ( |
no |
yes |
the same |
FFmpeg’s SDK cache ( |
no |
yes |
the same |
Linux grades uv by source, not by bytes. There uv and pip are BuildKit
cache mounts that outlive every build, so uv’s cache holds the unpacked chain
wheels of earlier builds, whose bytes are not this build’s. uv records a local
wheel (/opt/wheels, a --find-links directory) with a .rev entry and one it
downloaded with .http, under wheels-v*/<bucket>/<package>/; only the .http
kind can be foreign. A PyPI ORT that any earlier build downloaded into one of
these mounts fails every later G2 call until a RUN with the same mount removes it
(uv cache clean onnxruntime, or the pip body the finding names). That is
fail-closed on purpose.
Not graded: ccache and sccache (object files, no ORT names) and apt’s archive,
which the apt-plan and dpkg gates own. test-ort-provenance-build.sh fails when
any other cache mount of a Linux G2 RUN is missing from the default list. GenAI’s
G2 runs in its own RUN after the build RUN, so that RUN mounts the build RUN’s uv
and pip caches under the same ids; the same test fails when one is missing.
The venv census. linux/scripts/03-media/runtime/ort-venv-census.py is the
one classifier for Python environments, on both lanes. It treats as ORT every
distribution named onnxruntime or onnxruntime-* and every owner of the
onnxruntime, onnxruntime_genai or onnxruntime_extensions package, never a
fixed list. --check --store DIR requires each of them to match the store wheel
of the same name and version file by file, onnxruntime to have exactly one
owner, and the import to resolve to it. Build-TorchApp.ps1 embeds a verbatim
copy, pinned by TorchApp.OrtCensus.Tests.ps1.
The app uv sync installs no ORT. On Windows every onnxruntime or
onnxruntime-* name in uv.lock goes to --no-install-package, and a locked
runtime or GenAI flavour with no chain wheel of its family stops the stage.
Linux skips onnxruntime and onnxruntime-genai when a chain wheel covers them.
The in-box ONNX Runtime (Windows ML)#
Windows 11 ships an ORT with the OS. This client host carries Windows ML’s
C:\Windows\System32\onnxruntime.dll 1.17, a SysWOW64 twin, and copies under
Edge WebView and the Windows App Runtime. The images carry none. A one-RUN
probe over bk-windows-base on 2026-09-23 (servercore:ltsc2025 at the
WINDOWS_BASE_DIGEST pin, OS build 26100.33438) found no onnxruntime*,
Windows.AI.MachineLearning*.dll, Microsoft.AI.MachineLearning*.dll or
DirectML*.dll anywhere on C:\, the VS Build Tools included. The only name
hits were vcpkg’s port records C:\vcpkg\versions\o-\onnxruntime*.json, which
are not binaries.
Smoke § 25 asserts this on every amd64 lane, because the standard LoadLibrary
search puts System32 ahead of PATH: an in-box copy would take every importer
that reaches the chain ORT through PATH. The INBOX verdict fails on any ORT
instance under the Windows directory, and on Windows ML’s API DLL, which carries
the ORT ABI under another name. No $ortCensusExemption entry can waive an
in-box path. The cross lane skips the assertion: the image’s Windows directory
is not the device’s, and G6 already assumes a client System32 copy.
If a base bump brings one, keep the previous WINDOWS_BASE_DIGEST in
versions.env. Do not exempt it, and never delete or patch files under
C:\Windows in a layer; fix11 refuses a script line doing so to an ORT or
Windows ML file. Staging the chain DLL beside each exe does not clear the
census today. Image mode searches
only an importer’s own directory before System32, so a plugin still resolves to
the in-box copy (UNRESOLVED). A chain copy outside the prefix and the wheel
store is ELSEWHERE. The in-box file keeps its bytes verdict (FOREIGN for a
Windows ML build), which no exemption can waive. Admitting such a base is a
deliberate census change on three fronts: exe-directory chain copies as a
byte-checked allowed home, image mode modelling the host exes’ directories, and
a decision on the in-box bytes verdict.
Adding a new ORT consumer#
Build it against the chain. Headers and import library come from
ONNX_ROOTor the chain prefix. Close every fetch branch its build system has: a pre-set cache variable, anORT_HOME, aFETCHCONTENT_SOURCE_DIR_*pointed at an empty directory, disabled CMake package lookups.Give it its own gate when its build system has a known fetch branch, as OpenCV and GenAI do. Throw on any finding.
Call G2 once, after the build and before the tree is removed. Pass at least one log and every build record; a call without a log is a finding.
Mount the G2 file per file into that one RUN. Never widen a shared closure for it.
Register it in
Get-OrtConsumerContract(Windows) orort_census_contract(Linux), with its stamp path. Anything carrying the ORT ABI outside the contract is UNREGISTERED.Add its row to
F11_GATE_CALLSinverify-critical-fixes.sh. Renaming a gate function later means editing that table in the same change.Python: its wheel goes into the chain store, and the census must pass. Never a PyPI ORT, never a prebuilt plugin-EP wheel.
Run-time loading: resolve the chain file by absolute path. A bare-name load on Windows reaches System32’s Windows ML copy first. Windows packaging: stage the chain files beside the exe with
Copy-ChainOrtBesideand prove what ships withNew-OrtProvenPayloadorAssert-ChainOrtTree(the shared glue), never by copying ORT by hand.Licences: a
docs/deps/deps.jsonrow for anything it ships beside the chain ORT.Mutation-test it: a suite that goes red when its check is removed, and a
docs/scripts/mutations.jsonentry on Linux.
The consumer repositories#
These changes sit in the consumers’ working trees. Their gitlinks move only
after each repo commits and pushes, and each repo’s own AGENTS.md and
CHANGELOG.md carry the detail.
OxidANT. Every
onnxruntime*feature isort/load-dynamic+api-24, declared on the workspace dependency, anddownload-binariesis gone.kataglyphis_inference::ort_runtime::ensure_ort_loaded()loads an absolute path only, fromORT_DYLIB_PATH, the exe directory,ONNX_ROOT\bin/ORT_LIB_LOCATIONor the image prefix, and refuses a file without the chain source-root fingerprint.scripts/linux/check-ort-chain-only.shgatesCargo.lockand the resolved feature graph in its Linux lane. The Windows zip, MSIX and MSI ship the chainonnxruntime.dll,onnxruntime_providers_shared.dllandDirectML.dll, staged fromONNX_ROOT\bin; each package’s payload passes G6 first, and counts as loading ORT when its exe or any DLL it ships does.AccelerANTgine.
cmake/SystemLibDependencies.cmakeREQUIREs ORT from one prefix withNO_DEFAULT_PATH, and stops with FATAL_ERROR unless the runtime library carries the chain fingerprint. Its own Windows lane stages through the hub’sCopy-MediaRuntimeBundle, which is chain-only once its hub pin moves, and runs G6 over each stagedbin\and over the release install tree its NSIS/WiX/ZIP installers pack, into which the CMake file installs the provenonnxruntime.dll; its Python package ships the chain layout only, G6-proved.OmniAccelerANT.
Build-Windows.ps1stages the chain ORT beside the runner exe on every build, after theC:\runtime\binglob, which no longer copies ORT, and stamps the runner’s G6 pass.Start-Windows.ps1re-runs G6 on the host against that stamped copy, refuses an unstamped, foreign or stray runner and anORT_DYLIB_PATHof other bytes, and no longer putsC:\onnxruntime\libon PATH. The runner’s own chain copy therefore always wins over System32’s.runner\Release, the MSIX copy, is rebuilt from a proven preset on every build and re-proved beforemsix:create. The Linux bundle takeslibonnxruntime*from a fingerprinted chain directory only, andcheck-bundle-closure.shruns G6 over it whenever a file is ORT-named or names the ORT ABI. The cat-stream pi-bundle is G6-proved in the image run that assembles it.OrchestrANT drops its Python 3.13 test legs (owner decision 2026-09-23): the chain wheels are cp314 and the images carry CPython 3.14 only. The hub’s python-ci defaults (
PY_VERSIONS,COVERAGE_VERSION) moved to 3.14 with it.
Two couplings to keep in mind:
The consumers’ packaging proof is this repo’s G6, so it follows a move of
C:\temp\onnx-srcor/opt/onnxruntime(Get-OrtChainSourceRoot,ort_census_chain_roots). Literal copies of the fingerprint remain in their source pickers: AccelerANTgine’s CMake, OmniAccelerANT’srust_builder/linux/CMakeLists.txtandbundle-runtime.sh, and OxidANT’sort_runtime.rs.Both images bake
ORT_DYLIB_PATH(G3). Inside an image, OxidANT treats it as the only candidate, so an app’s own staged copy is not the one loaded there, and a GPU consumer must point it atonnxruntime-gpu.
Not proven by a build yet#
One lane has reached part of it: on 2026-09-25 the Windows rocm lane’s AMDGPU
EP stage ran G2 and hit the third red below, on the EP’s own intermediate .tar
(fixed the same day, windows-rocm.md). For every other lane
the first run is still the real test. The likeliest first reds, all fail-closed:
GenAI and OpenCV’s G-API DirectML EP compiling against the 1.31 headers under clang-cl for the first time.
A distro package in the Linux media closure that depends on
libonnxruntime1.x(Ubuntu’sgstreamer1.0-plugins-baddoes).A G2 false positive on a real record path; the finding names the record and the path.
A PyPI ORT that an earlier build left in a Linux uv or pip cache mount, now that G2 grades those mounts.
Failure messages#
You see |
Where |
Meaning |
|---|---|---|
|
Windows, end of a consumer build |
G2; each |
|
Linux, end of a consumer build |
G2, same rules |
|
Linux, G2 |
a PyPI ORT in a cache mount, left by this build or an earlier one: § The fetch caches G2 grades |
|
Linux media runtime RUN, |
a wheel under the chain wheel’s name replaced it after |
|
the same |
a second wheel of the chain wheel’s name, version and ABI is in |
|
the same |
after the strip and retag two wheels share the chain wheel’s name, or its member is gone |
|
either lane, G2 |
the consumer built without ORT at all |
|
smoke |
the consumer’s layer predates G2, or ran against another ORT build: rebuild that stage |
|
smoke § 25 / SHIPPED-TRUTH E |
G1 verdicts, defined in |
|
smoke § 25, |
the base image now ships an ORT in its Windows directory: § The in-box ONNX Runtime |
|
torch stage |
|
|
Windows torch stage, before |
the store lacks that flavour’s chain wheel: a media-stage problem |
|
a consumer’s |
|
|
preflight |
G4 found a re-armed download or a lost wiring row |
|
|
the NuGet facility is chain-only |