methodology
How OVM verifies releases, measures coding agents, and broadcasts verdicts
OVM installs and switches versions of Claude Code, Codex, and Pi — but its real job is judgment: deciding which upstream release is safe to run, measuring the ones that are, and publishing the verdict. This is the whole system. The regression testing that gates a release, the benchmark that rides the same pass, and the public feed that pushes the result are one methodology, not three tools.
- Verify
- Every upstream release is installed on real hardware before it is promoted, and a release that fails is withheld rather than offered. How far verification goes depends on the product: Claude Code and Codex are driven through real tool-use canaries on macOS and Linux; Pi is install-verified by unpacking completely and reporting its own version through the OVM launcher. Products states the tier for each one.
- Measure
- Claude Code and Codex are benchmarked in the same pass: launch latency, and — in the next dataset — cold vs warm, memory, and energy. Pi carries no performance numbers; an empty cell there means not measured, never measured and slow.
- Broadcast
- Release detections and the supported promotion or withholding events are published to a public Atom feed with WebSub push. The feed is an event surface; the registry remains authoritative for what can be installed.
01Installed is not works
The premise of the whole system: a release that installs cleanly can
still be dead on arrival. Codex 0.144.0 moved command execution into a
sidecar binary. codex --version worked,
login worked, and the first real tool call died — no
such file, every session, on a code path no smoke test exercised.
A version manager that reported "installed, success" would have shipped
it to every user. So OVM does not trust installation; it verifies
execution, then measures, then broadcasts.
02The regression gate
Every new release is held out of the registry until it proves it runs.
The gate is not a fixed check but a growing ledger — each row added in
response to a real failure, with the date it landed and the reason it
exists. ok on any platform admits a version; an
execution-probe fail is a veto that withholds or revokes it
even when it installed and launched cleanly.
| check | added | why it exists |
|---|---|---|
| install + launch | 2026-07-06 | The baseline: a version stays invisible to clients until it installs and launches on at least one platform (per-platform labels). |
| schema diff | 2026-07-06 | Diffs Codex's open-source state/migrations between the previous and new tags — flags added or breaking migrations (a DROP with no same-name recreate) before any data is touched. The one place source is diffed today. |
| tool-use probe | 2026-07-11 | A real command through the OVM launcher; with credentials, a session that must run echo <nonce> | rev and return the reversed nonce. A fail vetoes. Reason: Codex 0.144.0 installed and launched but could not execute a command. |
| strict sidecars | 2026-07-11 | Every helper binary the release ships must be present and spawnable (an asset-manifest baseline lists them). Reason: codex-code-mode-host shipped but wasn't spawnable, killing every session. |
| version swap | 2026-07-17 | Install the new and previous version, then assert ovm use flips the active version both ways. A swap failure vetoes like a probe failure. |
| behavioral downgrade | 2026-07-30 | A new stable Codex is classified compatible / degraded / broken / indeterminate by running the previous binary against state the new one has migrated. Only compatible admits; anything else — or a disagreement with the static migration diff — needs a recorded human adjudication, and real behavioral failures are never adjudicable. Reason: OVM exists to let you downgrade, so "the old binary still boots" is not evidence it still works. |
| cliproxyapi | 2026-07-17 | A new managed claudex proxy version installs (checksum-verified) and reports its own version. |
| signature drift | 2026-07-31 | Every supported macOS version is re-inspected daily with spctl/codesign — never launched — because Apple can revoke a certificate with no upstream release involved. The watched set comes from the registry and is kept resident on the runner; a missing version fails the scan instead of shrinking it. Reason: a revocation already moved the supported floor from rust-v0.120.0 to rust-v0.132.0. |
| source diff → review | proposed | Generalize the schema diff: diff the full source between the previous and new tags and have an agent review it for silent behavior or capability changes — across every product, not just Codex migrations. |
03The version manager's own suite
Before OVM can be trusted to verify anything, its own code has to be
correct — it moves symlinks, swaps control planes, and downloads
binaries. Over 700 unit and integration tests run
beside the source, isolated in throwaway temp directories, never the real
~/.ovm. The hardest paths get adversarial coverage: the
atomic self-update swap is fault-injected at every mutation
stage and must roll back to the exact prior selection; an install owner
killed mid-download is recovered by a second process into exactly one
complete install; checksum, archive-size, and SSRF-redirect attacks are
rejected across every download path; the claudex proxy withholds its key
from any listener whose identity it can't confirm. CI enforces the full
gate on both platforms:
| gate | checks |
|---|---|
| rust | fmt --check · clippy -D warnings · cargo test (macOS + Linux) |
| e2e matrix | installed control plane → shim → plugin → verified proxy → fake Claude |
| scripts | shellcheck · actionlint · bundle, npm, and registry contracts |
| supply chain | gitleaks (full history) · cargo-audit · cargo-deny |
| coverage | llvm-cov workspace line floor |
A macOS Gatekeeper sweeper closes the last gap: a binary
that installed cleanly can later be blocked if its Developer ID cert is
revoked, so the sweeper asks the live macOS policy engine
(spctl) every time rather than caching a verdict — a
benchmark never launches something the OS would refuse. It inspects with
spctl and codesign only, never by launching:
running a revoked binary raises a modal block dialog, which on an
unattended machine wedges the lane until someone dismisses it.
Revocation has no release attached — nothing upstream changes — so the sweep runs daily across every supported version, not just the newest. That set is derived from the registry and then made resident on the runner, because a signature can only be assessed against a binary that is actually on disk. The distinction matters: when coverage was instead read off whatever happened to be installed, routine pruning shrank the sweep from 24 versions to 5 while every report still read 0 blocked. A scan now fails when any expected version is missing, so an incomplete sweep can never be mistaken for a clean one.
This is the general shape of every check here: absence must never render as a verdict. A monitor that cannot see has to say so, otherwise silence is indistinguishable from success.
04Three states of evidence
Every probe the pipeline runs answers in one of three states, never two:
ok, fail, or indeterminate. The
third state exists because "the probe could not run" is neither a pass
nor a failure, and every attempt to squeeze it into a boolean lost
something. An indeterminate blocks a new
version's admission on that platform — a swap test that never happened
must not count as proof the swap worked — but it never
revokes a version that is already published, because
the deep lane reports indeterminate for infrastructure gaps, and one
broken runner must not pull healthy releases out from under users.
Evidence arrives from several independent lanes — the benchmark's launch verdicts, credential-less install probes, the deep execution probes — and the lanes combine with AND, never last-writer-wins: a platform passes only if every lane with an opinion passes, and a lane with no opinion abstains. This rule is the product of a real bug found twice: a passing install probe used to be able to overwrite a benchmark verdict that had watched the same release crash. A pass is admission evidence; it is never an answer to another lane's recorded failure.
The same honesty applies to what the registry says afterward. The
per-platform verified stamp on a version is rewritten from
the current run's evidence alone — a platform that stops passing loses
its label even when the version itself rightly stays published — and a
version nobody re-probed keeps its historical stamp untouched. Absence
of evidence neither wipes a past verification nor invents one.
For Codex, a fourth kind of evidence gates stable releases: behavioral downgrade classification. Upstream releases migrate the CLI's local state database; OVM's whole purpose is letting you move backwards, so each new stable is classified — compatible, degraded, broken, or indeterminate — by actually exercising an older binary against state the newer one has touched. Only compatible evidence admits a stable; degraded, broken, or indeterminate results veto it outright — behavioral evidence is held to a stricter standard than the execution probes, whose indeterminate merely withholds, because "we could not prove the downgrade works" is exactly the situation a version manager must not ship through. The one adjudicable case is a pure disagreement between compatible behavioral evidence and the static migration analysis, resolved by an explicitly recorded human entry; genuine behavioral failures are never adjudicable at all.
05The registry defends itself
The registry is the thing everything else trusts, so its refresh pipeline treats its own inputs as hostile. Upstream answers are validated for shape before anything is transformed: a version list must be a list of plausible version strings — an error object that parses as JSON, a bare string, or a list of garbage each used to transform "successfully" into nonsense. The verification gate applies the same discipline to its own baseline: a missing field, a padded or impossible version string, or an unreadable file refuses the run loudly before anything is written, because a damaged baseline that fails open would silently stop gating anything, and one that fails closed would mass-withhold the registry.
Some corruption cannot be detected by shape at all: an upstream API returning a truncated-but-valid page is indistinguishable from the truth. So the pipeline bounds the damage instead — a mass-retirement circuit breaker refuses any single refresh that would retire more than a small fraction of the previously published versions, and the override that permits a genuine mass removal must name the product it applies to. The one truncated listing the breaker was built against would have retired 471 of 472 published versions in one write.
Finally, nothing the registry advertises may dangle: every dist tag must name a version the file actually publishes, checked against what survives the gate — not just against what this run removed — so a tag left stale by an earlier run heals instead of persisting.
06Trusting bytes, not names
Every install is a transaction: a per-version lock, a quarantined
rebuild of the source tree, an .installing marker, and a
.complete marker written only after every check passes.
Downloads verify whatever the strongest available evidence is —
publisher checksums where upstream ships them, npm's subresource
integrity, declared byte lengths, and on macOS the publisher's code
signature — and a published checksum that cannot be fetched refuses the
install rather than quietly downgrading to weaker checks.
Importing a binary that is already on the machine (ovm
adopt) is held to the strongest checks an import can
have — it cannot reconstruct a publisher checksum or npm's integrity
metadata for bytes it did not download, so what remains is built on one
principle: the bytes verified must be the bytes
published. The source file is resolved once, opened without
following a final symlink, and proven — by file identity, not by path —
to be the file its name claimed; every later step reads that open
descriptor, so no rename, retarget, or link swap after the fact can
change what is copied. The staged copy is then verified (signature and
a re-run version check) before a same-directory rename publishes it.
Every file the transaction writes into its freshly created tree is
opened create-only, so a link planted at a destination fails the
install instead of truncating whatever it points at.
The limits are documented as deliberately as the guarantees: this defends the version label and the transaction's own tree, not a machine an attacker already controls — someone who owns the disk can hand OVM a matching binary and OVM will believe it. Honest edges, stated in the code, are part of the methodology.
07The benchmark next dataset
Benchmarking is not a separate activity — it is the measurement half of
the same per-release pass, run only on versions that cleared the canary.
Each version is exercised in the same modes: spawn
(--version), interactive (launch → the TUI
accepting input), and response (launch → first real
model answer, with the real MCP config, again with MCP disabled, and — for
products with a faster tier — a fast variant).
A requested model is also a compatibility probe. Model identifiers and protocol expectations can move ahead of an older CLI harness, so a current flagship is not assumed to run on every historical version. Explicit unsupported-model responses are published as incompatible, kept out of latency aggregates, and shown as gaps in the model timeline. Unknown execution errors remain failures; neither class is converted into a successful benchmark sample.
Observed example: Codex 0.138.0 rejects gpt-5.6-sol because
that model requires a newer Codex harness. OVM records the pair as
incompatible; it is not evidence that the model itself failed and it is
not plotted as a zero or slow response.
Sections 08–11, marked below, describe the next dataset — proposed changes to the benchmark, written for review before the ledgers are reset. Everything outside that band — the verification system above, the feed, and the pipeline below — runs today.
proposed · next dataset · not yet running
08Cold vs warm
The first launch of a freshly installed or re-indexed tool is a different measurement from its steady state; averaging them hides both. Each mode will run four times, with the first kept separate.
reduction
run #1 → cold (first-init) // recorded as *ColdMs
runs #2–4 → warm // *AvgMs (mean) + *StdDevMs
// today, for comparison — the cold run is smeared into the mean:
avg = mean(run#1, run#2, run#3)
This is not cosmetic. Our clean-room harness already showed why: Codex rebuilds a SQLite state index from its rollout files on the first launch after an import or migration — a one-time backfill of ~14 ms per session file, reaching ~25 s at 1,897 files / 6.8 GB. Claude has no separate index, so it is flat even cold. Warm time-to-ready is flat for both regardless of store size (Codex ~570 ms, Claude ~690 ms). Today that finding lives only in the research harness; this puts a cold and a warm number on every benchmarked coding-agent release, where a reindex regression would surface first.
09Resource & energy
Latency is half the story. A sampler walks the whole process tree — the tool plus the MCP servers it spawns — during the warm window.
| dimension | fields | how |
|---|---|---|
| memory | peakRssBytes, steadyRssBytes | Peak RSS during boot and idle footprint once ready, summed over the process tree. |
| cpu | cpuUserMs, cpuSysMs, threadCount, openFds | Work done (not wall-clock) plus cheap leak / fork-storm indicators. |
| energy | energyMilliJoules, avg{Cpu,Gpu,Ane}PowerMw | Real on-die power via powermetrics (Apple Silicon), attributed by differencing against an idle baseline. Long modes only. |
| environment | os, arch, hostCpuModel, hostCores, hostRamBytes, loadAvg1 | Makes cross-platform and cross-machine comparison valid; flags a busy runner. |
10The record
One append-only JSONL line per product / version / run. Every new field is optional, so older records stay valid, and the platform is read from the line rather than inferred from which folder it sits in.
HistoryRecord — new fields grouped
// timing — split cold vs warm, per mode
spawnColdMs · spawnAvgMs · spawnStdDevMs
interactiveColdMs · interactiveAvgMs · interactiveStdDevMs
responseColdMs · responseAvgMs · responseStdDevMs · responseNoMcp* · responseFast*
// resource + energy (macOS / Apple Silicon)
peakRssBytes · steadyRssBytes · cpuUserMs · cpuSysMs · threadCount · openFds
energyMilliJoules · avgCpuPowerMw · idlePackagePowerMw · powerAvailable
// environment — self-describing platform
os · arch · hostCpuModel · hostCores · hostRamBytes · loadAvg1
11Lanes
The macOS lane runs on the Mac mini against a real, growing session store on a subscription login — the numbers a heavy daily user feels, and the only honest place for the Codex reindex tax. The Linux lane runs in CI: reproducible and clean, strongest for spawn and startup. A combined lane unions both for range.
Because the real store keeps growing, a synthetic fixed fixture gives a frozen baseline that isolates a version's effect from session growth. It is built from open-source conversations — no personal data — and reproduces the shape that actually drives startup: the same file count, total bytes, and median and p90 file size as a real store (Codex ≈ 2,000 files / 7 GB, Claude ≈ 9,000 files / 6 GB). A CI runner with an empty home can then produce numbers comparable to the mini's, on demand.
12The public feed
Every verdict is broadcast, not just stored. OVM publishes a public Atom
feed at /versions.atom for
managed-product release verdicts. Its
entries are the verification detections themselves: a new release, a
version withheld from the registry because it hasn't verified on
any platform, a promotion once it clears. The feed carries a
WebSub hub link, and the pipeline pings the hub after
each deploy, so subscribers are pushed the moment a new
model clears the gate — no polling.
13One pass, two platforms
The scheduled and release-triggered lanes execute on the Mac mini (macOS) and in CI (Linux). The checks in a pass depend on the product's verification tier:
- Install the release through OVM exactly as a user would.
- Canary coding agents with the applicable tool-use, sidecar, version-swap, and schema checks.
- Gatekeeper-check applicable signed macOS binaries against the live policy engine.
- Benchmark Claude Code and Codex and append their ledger lines; Pi deliberately has no performance row.
- Promote & broadcast — only cleared versions enter the registry; the site re-renders and the feed pushes.
The night the canary went live, upstream shipped four releases overnight; the scheduled run installed, probed, and benchmarked all four on both platforms and refreshed the registry autonomously, before anyone was awake.
14Reproducible by design
Nothing here is a private green check. The test suite is public, the
canary's proof is a tagged pair, and every benchmark point in
bench-data/ carries the runner and run URL that produced it.
The benchmark measures how fast and how cheaply a CLI reaches a working
answer, not model quality; energy attribution leans on a quiet, serialized
machine and an idle baseline; cold numbers depend on their starting state,
so each run records the session-store size behind them. When the next
dataset ships, this page becomes the as-built record.