Skip to content

v0.5.1 (2026-07-13)

v0.5.1 is a durability-and-polish follow-up to v0.5.0. Its one substantial change makes a published run’s media survive the loss of the volumes it was read from — the lesson of a cluster recreate that wiped both the backend’s ephemeral store and the artifact service’s PVC. The rest is a batch of console fixes and the deployment that rolls v0.5.0 into production.

Run media is exported once, under content-stable keys

Section titled “Run media is exported once, under content-stable keys”

A published run’s media — its proof-of-implementation images and videos, and an asset-generation run’s produced files — now lives under a snapshot-independent media/runs/<id>/ prefix keyed by the run id, outside any single snapshot’s prefix. It is written once and referenced by every later snapshot, instead of being re-read and re-uploaded — and, for video, re-transcoded — on each publish.

On each publish the snapshot builder lists what is already present under media/runs/ and, for anything already there, references it in the per-run document without reading the source bytes or re-uploading. So a publish stays cheap as asset-generation runs accumulate, and — because the public snapshot bucket has no GC — a run’s media persists even after the volumes the bytes were read from are gone. A per-run document still names its media by the served-filename basename the site keys on, so the contract is preserved. If the existing-media listing fails, the publish degrades to re-exporting everything rather than aborting the refresh. See snapshot.

Recovering run media from a prior snapshot

Section titled “Recovering run media from a prior snapshot”

A new scripts/recover-run-media-from-snapshot.{sh,mjs} restores run media after the recreate case where both the backend store and the artifact service PVC were wiped: it copies each published run’s proof/asset media from a prior public snapshot prefix (the surviving copy in R2) back into the backend store and triggers a single refresh. It’s the counterpart to backfill-run-media.sh, which sources from the artifact service and so can’t help when that volume is gone. scripts/lib/env.sh gains a per-environment TCAB_SNAPSHOT_URL (the public snapshot read base), and the backups doc adds the missing run-media row and a Recreating a cluster runbook.

The seeded model picker shows the full catalog again

Section titled “The seeded model picker shows the full catalog again”

The New Run form seeds each combination row’s model with a concrete slug, so the ModelCombobox’s value is a committed selection rather than a query. The dropdown substring-matched its options against that value, collapsing the whole catalog down to the one selected model. It now narrows the list only while the user is actively typing; a committed/seeded value (or focus) shows every model again. The Coverage config picker, which reuses the component, is covered too.

The active list reflects a run’s real phase

Section titled “The active list reflects a run’s real phase”

A launched run was tracked optimistically as running, and the active-list reconcile only ever added new runs or pruned finished ones — it never refreshed the phase of an already-tracked run. So a run held back at its harness’s parallelism cap (pending) or spinning up its driver and container (starting) sat as running the whole time. A just-enqueued run is now tracked as queued (its true backend state), and reconcileActiveRuns emits phase updates for tracked runs whose reported state has advanced. Phase updates don’t require a complete worker picture and never resurrect a run locally marked failed.

useResetPageOnChange listed setPage in its effect dependencies, but react-router v7 rebuilds the search-params setter on every location.search change. Clicking to page 2 changed setPage’s identity, re-firing the reset effect and snapping the list back to page 1 — the URL updated for a split second, then reverted. The hook now reacts only to its resetKey (holding the latest setPage in a ref and tracking the previous key, so genuine sort/scope changes still reset while page navigation is left alone).

useModelConfig() called useBackend(), which asserts a <BackendProvider> is mounted. The static gallery mounts none, so /models threw and rendered nothing. A new useOptionalBackend() (mirroring useOptionalWorkers) reads the client, so a missing provider now reads as an unconfigured backend — the model-config affordance hides on the static site instead of crashing the page.

The pricing chart stops warning on a short history

Section titled “The pricing chart stops warning on a short history”

The price-over-time line left its z channel implicit, so Plot inferred it from stroke: "series" and warned about high implicit-z cardinality whenever the series count exceeded half the point count — which a short history (a single observation: one Input and one Output point) always trips. Naming z: "series" explicitly — the per-series grouping we already want — silences it.

Staging and prod roll to v0.5.0, in lockstep

Section titled “Staging and prod roll to v0.5.0, in lockstep”

Both azure overlays now pin the v0.5.0 release build a74d1414: staging moves its service images from 9bb4858e and its TCAB_CONTAINER_TAG from 8b5953a3; prod moves its service images from v0.4.1 (b3c2b322) and its TCAB_CONTAINER_TAG from v0.4.0 (ba19bd69). Unlike v0.4.1, the v0.5.0 work touched the asset-generation and foray crates that build-containers watches, so the run images were republished at the same sha — service and run images are back in lockstep on one git sha. Both clusters applied and rolled out green, all workloads Running against managed Postgres.

Reference implementations published to prod

Section titled “Reference implementations published to prod”

The non-experimental cases’ reference implementations are now published to prod as well as staging; test-cases/reference-builds.lock.json gains the prod entries the backend ingests during catalog reconciliation. See reference implementations.