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.
Features
Section titled “Features”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.
Pagination stops reverting to page 1
Section titled “Pagination stops reverting to page 1”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).
The static /models page no longer crashes
Section titled “The static /models page no longer crashes”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.
Deployment
Section titled “Deployment”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.