rightkit-ort 0.2.0

Product-neutral ONNX Runtime dynamic-library resolution, environment, execution-provider and session setup (single suite ort pin)
Documentation
# rightkit-ort

Internal, unpublished ONNX Runtime dynamic-library boundary for Right Suite.
Applications supply ordered absolute candidates; the crate validates the
platform filename, requires a regular file, canonicalizes the selected path,
records diagnostics, and refuses to replace a different configured runtime.

The crate owns no product environment variable, data root, bundled runtime,
model, provider policy, download, or UI behavior. Application adapters convert
legacy environment variables and canonical app-data locations into explicit
`RuntimeCandidate` values.

Also (0.2.0): `configure_runtime_with_options` adds forced `ORT_DYLIB_PATH`
replacement & missing-path binding with `RuntimeBindingStatus::Missing`.
Also (0.2.0): `CandidateSource::LegacyDefault` & `legacy_runtime_candidate`
add opt-in `<workspace>/tools/bin/<platform runtime filename>` candidates.
Also (0.2.0): `init_environment_with_options` adds deferred C environment
creation, ort-default telemetry, already-configured tolerance & verbatim loader errors.
Also (0.2.0): `clear_inherited_runtime_for_release` clears inherited
`ORT_DYLIB_PATH` in release builds & does nothing in debug builds.
Also (0.2.0): `developer_override_candidate(env_name)` reads a non-empty
app-named override as `RuntimeCandidate` with `CandidateSource::Explicit` in debug only.
Also (0.2.0): `configured_runtime` reports the last successfully bound path,
falling back to non-empty `ORT_DYLIB_PATH` for doctor readiness reporting.

## Binding & environment options

Existing `configure_runtime`, `init_environment`, `EnvironmentOptions` &
`EnvironmentReport` retain their signatures, fields & defaults. New option
types use strict binding, eager C environment creation, disabled telemetry,
external-configuration refusal & contextual loader errors by default.

```rust
use rightkit_ort::{
    configure_runtime_with_options, legacy_runtime_candidate, CandidateSource,
    RuntimeBindingOptions, RuntimeBindingStatus, RuntimeCandidate,
};

// App supplies absolute paths; no process cwd or implicit workspace discovery.
let binding = configure_runtime_with_options(
    [
        RuntimeCandidate::new(runtime_path, CandidateSource::Bundled),
        legacy_runtime_candidate(workspace_root)?,
    ],
    &RuntimeBindingOptions { force_replace: true, allow_missing: true },
)?;
if binding.status == RuntimeBindingStatus::Missing {
    // Membrane can report "memory writes refused" & skip initialization.
}
```

Candidates resolve in caller order. Missing mode prefers an available regular
file; only if none resolves does it bind & record the first absent candidate.
Missing paths retain their supplied absolute spelling; regular files are
canonicalized. Relative paths, wrong filenames, directories & System32 runtimes
remain invalid. Legacy candidates use `onnxruntime.dll`, `libonnxruntime.dylib`
or `libonnxruntime.so`; callers choose where to place them in candidate order.

With feature `session`, pass `EnvironmentInitOptions` to
`init_environment_with_options(&binding.selection, &options)`.
`defer_initialization: true` matches `ort::init_from(...).commit()`: dylib loading
still happens now, while C environment creation waits for first ORT use.
Deferred reports have status `Deferred`, empty `runtime_info` & no confirmed
active shared pool. `shared_pool_active()` includes a committed deferred pool
configuration so sessions can use it once ORT creates their environment.
`telemetry: None` preserves ort's default; `Some(false)` disables telemetry &
`Some(true)` enables it. `verbatim_loader_errors: true` preserves the loader's
original Display message, including newlines, without any added prefix.

`tolerate_already_initialized: true` accepts external configuration & reports
`AlreadyInitialized` on subsequent successful calls. Existing options stay in
place; ignored shared-pool requests never count as an active pool. First outcome
is cached, including failures; tolerance does not turn failures into success.
Binding & initialization belong before worker startup or any ORT use. Forced
environment-variable replacement cannot replace an already-loaded dylib.

Tests use temporary fixture files, an injected environment writer & a fake ORT
backend; these option tests require no real runtime binary. Existing macOS E2E
coverage remains separate.

## Version policy

The suite pins the Rust `ort` crate to `=2.0.0-rc.13` with `load-dynamic` and
API 24 enabled (`ort` declares `links = "onnxruntime"`, so every crate in one
build must agree). Do not enable `ort/default`: rc.13 raises its default API
floor to 27, which the approved runtime cannot serve. The approved macOS arm64 ONNX Runtime shared library is
`1.24.4`, recorded in `rightkit-media`'s native catalog. Runtime upgrades need
one catalog row, real native-host verification, and coordinated app migration;
this crate does not download or silently select a different runtime.

## Execution providers

ort rc.13 compiles each execution provider only behind its Cargo feature.
rightkit-ort turns on `coreml` for Apple targets and `directml` for Windows, so
no consumer feature is needed (the explicit `coreml` / `directml` features forward to
`ort/coreml` / `ort/directml` for consumers that want to name the provider).
Apps that run their own inference use the `rightkit_ort::ort` re-export
(`rightkit_ort::ort::{value::Tensor, session::Session, ...}`) instead of declaring
an `ort` dependency, so the release ownership scanner never sees one. Select at runtime with `ExecutionProvider`
(`Cpu`, `CoreMl`, `DirectMl`, or `ExecutionProvider::platform_accelerator()`).
An accelerator that is unsupported, fails registration, or fails model load is
an error unless `SessionOptions::with_cpu_fallback(true)` is set; then the
`*_reported` builders return `BuiltSession { provider, fallback }` naming the
CPU fallback and its reason.

`publish = false` remains mandatory until the macOS runtime/artifact catalog
gate passes.

Licensed under MIT OR Apache-2.0.

## Inherited `ORT_DYLIB_PATH`

`configure_runtime()` never trusts a different inherited value. If `ORT_DYLIB_PATH` is already set and does not canonicalise to the candidate `resolve_runtime` selects, it returns `RuntimeError::AlreadyConfigured` and ORT is not initialised. A planted path can therefore stop ORT from starting, but can never load a foreign library. Call `clear_inherited_runtime_for_release()` at process startup, before any thread spawns, runtime binding or ORT use: process environment mutation requires exclusive access. This release-only cleanup is consistent with "inherited ORT_DYLIB_PATH fails closed"; debug builds preserve the variable. Apps can put `developer_override_candidate("APP_ORT_RUNTIME")` first in their candidate list; unset or empty values return `None`, as do all release calls. `RuntimeSelection::source` reports which candidate won.

`configured_runtime()` is read-only & prefers the last successful crate binding
(including missing-mode paths) over later environment changes. Matching inherited
bindings are recorded too; failed bindings preserve the previous record. Without
a recorded binding it reports non-empty `ORT_DYLIB_PATH`, or `None`. Resolution
alone records nothing; this diagnostic does not validate or load a library.