Vox Binary Freshness & Single-Source-of-Truth (2026)
Vox Binary Freshness & Single-Source-of-Truth (2026)
Section titled “Vox Binary Freshness & Single-Source-of-Truth (2026)”1. The incident
Section titled “1. The incident”While landing a PR, running vox ci ssot-drift directly produced guard
failures (nomenclature flags on already-grandfathered crates; turso flags on
already-sanctioned crates) that did not reflect the current source. Root
cause: the installed vox.exe was 0.5.0+build.601 while the workspace
source was 0.6.0 — an old binary running outdated guard logic and
allowlists. Acting on its output produced a wrong edit (see the
Turso handoff §6).
Important scoping fact: the git pre-push hook is already safe — it runs
cargo run -q -p vox-cli -- ci pre-push (.git/hooks/pre-push, generated by
vox ci install-hooks), i.e. always builds from source. The staleness only bites
direct vox … invocations by humans and agents who run the installed
binary instead of cargo run. Those direct runs are exactly where people
diagnose problems, so a stale binary produces confidently-wrong conclusions.
2. Two underlying problems
Section titled “2. Two underlying problems”- No freshness signal on direct invocations. Nothing tells a developer that
their installed
voxis older than the working tree. Versioning is sound —VOX_VERSION = CARGO_PKG_VERSION + "+build." + VOX_BUILD_NUMBER + " (" + VOX_GIT_HASH + ")"(crates/vox-cli/src/lib.rs), whereVOX_BUILD_NUMBER = git rev-list --count HEADandVOX_GIT_HASH = git rev-parse --short HEADat build time (crates/vox-build-meta/src/lib.rs). The data to detect staleness exists; nothing compares it to the workspace. - No canonical binary location (SSOT). Two binaries exist —
~/.cargo/bin/vox.exe(fromcargo install) and~/.vox/bin/vox.exe(voxup-managed). They can drift to different versions, and which one “wins” depends onPATHorder. There is no declared canonical.
There is prior art for staleness detection: command-compliance’s
check_command_registry_embed_matches_disk fails when the binary’s
include_str!-embedded command registry differs from disk — i.e. it already
catches one flavor of stale binary. We should generalize that idea to version.
3. Design — automatic staleness prevention
Section titled “3. Design — automatic staleness prevention”3.1 Build-number freshness self-check (primary)
Section titled “3.1 Build-number freshness self-check (primary)”When vox runs inside a Vox workspace, compare its embedded build number
against the working tree’s:
- Embedded:
env!("VOX_BUILD_NUMBER")(thegit rev-list --count HEADat build time). - Live:
git rev-list --count HEADin the repo root at run time. - If
embedded < live(binary built at an older commit) → the binary is stale.
Behavior:
- Warn on any direct invocation:
vox is stale (built at commit N; workspace is at M). Run \cargo install —path crates/vox-cli —force` (or your install command).` - Hard-fail for
vox ci *subcommands specifically — these are guard/SSOT commands whose whole purpose is an accurate verdict; a stale verdict is worse than no verdict. Provide an escape hatch env var (e.g.VOX_SKIP_FRESHNESS_CHECK=1) for the rare intentional case.
Build number (not semver) is the right signal: it catches same-version
staleness (0.6.0+build.601 vs 0.6.0+build.1917), which semver comparison
misses. Insertion point: the CLI dispatcher (run_vox_cli_from_parsed in
crates/vox-cli/src/lib.rs) so it covers every direct invocation; or, more
narrowly, at the top of run_ssot_drift / vox ci dispatch.
3.2 Canonical binary SSOT
Section titled “3.2 Canonical binary SSOT”- Declare
~/.cargo/bin/vox.exethe canonical install target (standard Rust toolchain path; whatcargo install -p vox-cliproduces). - Have voxup (or a
vox self-install) install/refresh that path, or make~/.vox/bina forwarder to it — one real binary, not two that can diverge. - Add a
vox doctorcheck that asserts everyvoxonPATHreports the same build number, and that it matches the workspace when inside one.
3.3 Tie the refresh to the version bump
Section titled “3.3 Tie the refresh to the version bump”The motivating ask: prevent staleness automatically when we go up to the next version. Make the bump self-correcting:
- Extend the existing
vox ci gui-version-syncpattern (which already reads the workspace[workspace.package] versionand syncs GUI/runtimepackage.json) with a binary-freshness assertion in the samessot-driftstep. - Add a documented post-bump step (version-bump runbook): after editing
[workspace.package] version, run the install command so~/.cargo/bin/voxmatches. The freshness self-check (§3.1) then announces any miss instead of silently misleading.
4. Recommended first slice
Section titled “4. Recommended first slice”The smallest high-value change: §3.1 build-number self-check, hard-failing
vox ci * with a VOX_SKIP_FRESHNESS_CHECK override, reusing the workspace-version
reader already in gui_version_sync.rs. That alone would have turned this
incident’s silent misdirection into a one-line, actionable error.
5. Cross-refs
Section titled “5. Cross-refs”- Versioning:
crates/vox-cli/src/lib.rs(VOX_VERSION),crates/vox-build-meta/src/lib.rs. - Hook generation:
crates/vox-cli/src/commands/ci/install_hooks.rs;.git/hooks/pre-push. - Existing version parity:
crates/vox-cli/src/commands/ci/gui_version_sync.rs. - Existing stale-binary detection precedent:
command_compliance/validators.rs::check_command_registry_embed_matches_disk. - Companion: Turso ownership migration handoff.