# Native model portability and runtime hardening

Portability execution reviewed **23 October 2026**; the current catalog summary below was refreshed **25 October 2026**. The portability pass checked the automatic model-installation route against publisher wheel inventories and exercised actual inference on the available Linux CPU host. Its original measurements and regression results remain dated to that pass. It does not equate platform selection tests, published wheels, or source review with native Windows/macOS execution.

## Corrected portability failures

### Intel Mac runtime selection

The previous managed-runtime requirements selected ONNX Runtime 1.31.0 on every OS. Its release has Apple Silicon macOS wheels but no Intel macOS wheel. Faster Whisper now selects **ONNX Runtime 1.23.2 on Intel macOS**, retaining 1.31.0 elsewhere. The conditional requirement is part of the installer input and recorded installation provenance. Faster Whisper's primary runtime, CTranslate2 and tokenizer versions remain pinned.

The Intel route requires standard CPython 3.11–3.13 and macOS 13 or newer. ONNX Runtime 1.23.2 has no CPython 3.14 Intel Mac wheel. The CLI and browser can still run under another Python; a model-specific blocker is returned before model downloads. Exact Whisper GGUF models use a separate runtime and do not require ONNX Runtime.

We also tested the proposed older runtime against the real portable Fluid Mini weights. **It failed correctly during graph initialization:** the model uses 6-bit `MatMulNBits`, while ONNX Runtime 1.23.2 only supports 4-bit and 8-bit forms. Consequently Mini ONNX remains pinned to 1.31.0 and reports an explicit Intel Mac blocker. Olenji does not download unusable weights, quietly change the selected model, or claim that merely resolving an older package proves model compatibility.

Real Faster Whisper Tiny inference with ONNX Runtime 1.23.2 succeeded on Linux: the 11-second JFK fixture produced the expected text and 22 model word timestamps. This confirms that the selected older runtime can execute Faster Whisper's model/VAD path; native Intel Mac execution remains a release gate.

Primary evidence: [ORT 1.31.0 files](https://pypi.org/project/onnxruntime/1.31.0/#files), [ORT 1.23.2 files](https://pypi.org/project/onnxruntime/1.23.2/#files), `validation/native-wheel-inventory.json`, and `validation/onnx-intel-compat-inference.json`.

### Machine-readable runtime requirements

`models get`, model list/plan items, and doctor backend records now expose `runtime_support`. This includes the process architecture, Python version, installation route, exact requirement strings, relevant OS/libc minimums and a human-readable blocker. Native execution is explicitly not implied by this metadata.

The reviewed automatic-install baseline is standard **CPython 3.11–3.14 on a supported 64-bit desktop OS**. PyPy, free-threaded Python, unknown CPU architectures, and glibc older than 2.28 are rejected for managed inference rather than falling into accidental source builds. The glibc baseline follows the intersection of the pinned binary dependencies; Alpine/musl requires a different runtime distribution and is outside this automatic installer.

On Windows, architecture selection follows the **Python interpreter's wheel target**. An x64 interpreter under Windows ARM emulation follows the x64 wheel lane even when the machine reports ARM hardware.

| Runtime | Windows x64 | Windows ARM64 Python | Linux x64/ARM64, glibc 2.28+ | macOS Intel | macOS Apple Silicon |
| --- | --- | --- | --- | --- | --- |
| Faster Whisper | Published wheel route | No CTranslate2 ARM64 wheel; x64 Python or another model is required | Published wheel route | ORT 1.23.2; Python 3.11–3.13; macOS 13+ | ORT 1.31.0; macOS 14+ |
| Exact GGUF / transcribe.cpp | Published wheel route | Pinned source build requires Git, CMake and MSVC ARM64 C++ tools; native validation pending | Published wheel route | Published wheel route; macOS 11+ | Published wheel route; macOS 11+ |
| Fluid Mini ONNX | Published wheel route | Published wheel route; native inference pending | Published wheel route | Blocked: required ORT operators lack an Intel binary | ORT 1.31.0; macOS 14+ |
| WeSpeaker / sherpa-onnx | Published wheel route | Published wheel route; native inference pending | Published wheel route | Published wheel route; macOS 11+ | Published wheel route; macOS 11+ |
| Exact Core ML models | Unavailable | Unavailable | Unavailable | Unavailable | Model-specific macOS 14/15+, Swift 6.2 build prerequisites |
| Apple Legacy / SpeechAnalyzer | Unavailable | Unavailable | Unavailable | Legacy only; model/toolchain prerequisites apply | Legacy; Analyzer requires macOS 26 and supported OS assets |

A wheel route is installer evidence, **not** a claim that every model or GPU combination was executed. CTranslate2 also requires the Microsoft Visual C++ runtime on Windows. Its [installation documentation](https://opennmt.net/CTranslate2/installation.html) describes supported CPU architectures and prerequisites. The [transcribe.cpp Windows build guide](https://github.com/handy-computer/transcribe.cpp/blob/4d7c1ccefd39e5a9ea36cca5f8fefc6dcc14b99b/docs/build-windows.md) describes the source-build toolchain.

The managed transcribe.cpp native distribution is now explicitly pinned to `transcribe-cpp-native==0.4.1`; the wrapper's broad `0.4.1.*` transitive requirement no longer chooses a different native patch without review. Normal managed installs require wheels; the existing transcribe.cpp fallback is a separate source build pinned to the reviewed source commit. Transitive packages still follow their declared resolver constraints; this change does not claim a complete per-platform dependency hash lock.

### Default application dependency resolution on six targets

The final checked-in application dependency lock resolved successfully with **binary packages only** for all six CPython 3.12 targets. Each resolver input used the default dependencies from `pyproject.toml`, constrained to the frozen non-development export of `uv.lock`. Optional inference environments are separate from this application dependency check.

| Target | Explicit target baseline | Resolved packages | Result |
| --- | --- | ---: | --- |
| Windows x64 | `x86_64-pc-windows-msvc` | 45 | Binary resolution passed |
| Windows ARM64 | `aarch64-pc-windows-msvc` | 45 | Binary resolution passed |
| Linux x64 | `x86_64-manylinux_2_28` | 43 | Binary resolution passed |
| Linux ARM64 | `aarch64-manylinux_2_28` | 43 | Binary resolution passed |
| macOS Intel | `MACOSX_DEPLOYMENT_TARGET=13.0` | 43 | Binary resolution passed |
| macOS Apple Silicon | `MACOSX_DEPLOYMENT_TARGET=14.0` | 43 | Binary resolution passed |

This verifies that the reviewed lock has suitable published artifacts without falling back to source builds. It does not execute those wheels on their native OS or prove native libraries, permissions, device drivers or hardware capture. The complete command, selected requirement lists, deployment targets and SHA-256 identities are recorded in `validation/default-platform-resolution.json`. The reviewed `uv.lock` SHA-256 is `656d22dd07ac8a7ef8bc318c91368d29c0c083b883a7f0f4d9469a1c8483703e`.

The default microphone dependency now requires `sounddevice>=0.5.6`. The actual Windows ARM64 wheel contains `libportaudioarm64.dll` with the correct ARM64 PE machine identifier (`0xAA64`); the reviewed loader selects it from the interpreter's wheel platform. The wheel also bundles other CPU variants, so checking that *every* bundled DLL is ARM64 would give a false failure. This is binary/header and loader-source inspection, not a recording test.

Windows system audio now includes `SoundCard>=0.4.6` in the default application install. The reviewed 0.4.6 capture source uses `numpy.frombuffer(...).copy()`, avoiding the removed binary `numpy.fromstring` path, and loads the OS's `ole32` through CFFI without bundling a fixed x86/x64 DLL. Windows ARM64 resolution also selects an ARM64 CFFI wheel. Physical WASAPI capture remains a native hardware release gate. Wheel identities and the scope of this review are recorded in `validation/windows-arm-audio-wheel.json`; the upstream releases are [sounddevice 0.5.6](https://pypi.org/project/sounddevice/0.5.6/) and [SoundCard 0.4.6](https://pypi.org/project/SoundCard/0.4.6/).

### Unicode in worker protocols and model files

A UTF-8 parent pipe can otherwise be decoded using a Windows ANSI code page by the child interpreter. This can corrupt Turkish/Japanese text and Unicode file paths. Managed environments now set `PYTHONIOENCODING=utf-8` and `PYTHONUTF8=1`; the standalone worker explicitly configures its stdin/stdout/stderr to UTF-8 before processing input. Model manifests, installer metadata, tokenizer vocabularies and Mini configuration files are also read explicitly as UTF-8.

A real subprocess regression starts with **ASCII stdio and UTF-8 mode disabled**, sends a Turkish/Japanese path, and verifies an exact UTF-8 JSONL round-trip. Another subprocess reads a non-ASCII installation manifest under an ASCII locale. These execute on Linux and specifically reproduce locale/protocol hazards; they are not labeled as Windows native tests. [Python's encoding environment documentation](https://docs.python.org/3.12/using/cmdline.html#envvar-PYTHONIOENCODING) explains the underlying pipe behavior.

### Cancellation owns the whole installer process tree

`olenji.processes.terminate_process` operates on a known, currently live `Popen` child, never on a PID read from a stale service file. Tree cancellation uses an isolated POSIX session/process group and Windows `taskkill /PID … /T /F`, followed by bounded wait/kill cleanup. A pip/CMake child can no longer continue changing an installation after the installer reports cancellation just because only its parent was stopped. Audio capture adopts the same helper.

A real subprocess test starts a parent with a child that ignores SIGTERM, verifies the child's heartbeat, cancels the private tree and confirms the heartbeat stops and parent is reaped. Windows command selection has a separate simulated regression, including `CREATE_NO_WINDOW` so a background service's cleanup does not open a console window. [Microsoft documents `/T` as including child processes](https://learn.microsoft.com/en-us/windows-server/administration/windows-commands/taskkill).

### Apple helper identity and PCM contract

Managed Apple helpers now record and compare the interpreter target architecture as well as source identity and binary size. A runtime copied from a different architecture is not reported ready solely because its source revision matches.

ScreenCaptureKit output validates 16 kHz Float32 before writing bytes and handles interleaved as well as planar float channels when downmixing. Unsupported sample formats produce a clear failure instead of feeding wrongly interpreted audio into the transcript clock. Apple [explicitly documents 16 kHz capture support](https://developer.apple.com/documentation/screencapturekit/scstreamconfiguration/samplerate). The native Swift compiler and physical system-audio path were not available on this Linux host; the checked-in native macOS job must compile and exercise them.

## Recorded inference measurements — 23 October 2026

The same public 11-second JFK recording was transcribed twice with five real installed model implementations, using CPU and four requested threads. First calls include worker/model initialization; warm calls reuse the loaded model. These measurements characterize this host and fixture. They are not a quality benchmark, a throughput guarantee, or a before/after speedup claim.

| Model | First call | Warm call | Output timing |
| --- | ---: | ---: | --- |
| Faster Whisper Tiny | 1.274 s | 0.661 s | Actual model segment and 22 word timestamps |
| Exact Whisper Tiny Q8 GGUF | 0.882 s | 0.428 s | Actual model segment timestamps |
| Moonshine Streaming Tiny Q8 | 0.432 s | 0.238 s | Clip coverage |
| Fluid Speech Mini ONNX | 2.343 s | 1.718 s | Clip coverage |
| Qwen3 ASR 0.6B Q8 | 3.128 s | 2.007 s | Clip coverage |

Every model recognized the expected phrase. The small Mini ONNX sessions now also disable idle thread spinning. Evidence is in `validation/deep-native-inference.json`.

The native Core ML helper still starts a process and loads a model for each bounded window/utterance. It bounds input memory but does not promise a persistent native decoder or low live latency for large Core ML models. A persistent Swift worker should be implemented and benchmarked on a compatible Mac; it was deliberately not introduced without a compiler/native validation path in this pass.

## Regression evidence and remaining gates

The focused model/native suite passes **102 tests**, including **33 new regressions** in `tests/test_native_portability.py`. It covers Python/OS/architecture support boundaries, wrong-architecture Apple helper reuse, conditional dependency selection, Unicode pipes/manifests, early blockers, owned process-tree shutdown, existing model-integrity checks and bounded audio clocks.

Native Windows x64/ARM64 inference, macOS Intel/Apple Silicon inference, Swift compilation/runtime, native hardware capture and GPU drivers remain distinct release gates.

As of the **25 October source and publisher review**, the catalog contains **all 17 current exact FluidVoice identities and 13 additional identities**, including one speaker model. The added parity member is the already-catalogued Qwen3 ASR 1.7B Q8_0 GGUF; its pinned artifact and existing portable runtime route are unchanged. Seven exact choices have transcribe.cpp routes and ten retain Apple-specific requirements. This refresh adds no native execution claim to the measurements above. See [current model coverage](/docs/1.2.0/models.md), [the dated audit](/docs/1.2.0/source/#source-038d198f2b03a663291f) and [competitive acceptance gaps](/docs/1.2.0/source/#source-73f3aaed78d4eb242e0a).
