Line references are pinned to main at 992e7d1d.
Where
src-tauri/src/commands/runtime_bootstrap.rs L610-611, inside ensure_runtime_ready_or_install_blocking.
What goes wrong
When separation needs a runtime and nothing is installed, the install path resolves its catalog directly from the embedded snapshot:
// L610-611
let catalog = catalog::embedded_catalog();
ensure_runtime_ready_or_install_with_catalog(app_data_dir, status, catalog, emit)
The app already maintains a fresher verified catalog in AppState.shell.catalog_cache: the background update worker (app_runtime.rs L337-339) populates it ~15s after startup, and check_runtime_updates populates it on every settings-driven check. The explicit download_runtime command consumes that cache through download_runtime_source (L350-362), which prefers the cached catalog when its generation is newer than the embedded one. The separation-triggered install path never consults it.
Effect
A user whose embedded snapshot is older than the published stable catalog (e.g. an app binary embedding generation 12 while generation 13 is live) installs the stale embedded runtime even though the process has already fetched and verified the newer catalog. Concretely, with generation 13 shipping the static-CRT Windows runtimes (#284, #363): a first-run user on an older binary who triggers separation gets the gen-12 onnxruntime.dll that needs the VC++ redistributable, and then immediately sees an update prompt for the runtime they just downloaded.
Suggested resolution
Route the separation-triggered install through the same refreshed-catalog selection as download_runtime (download_runtime_source): use the cached verified catalog when its generation is newer, falling back to the embedded snapshot otherwise.