feat(fleet): B4.3 — per-mission rootfs selection (missions.backend)

`vm_create` takes a backend name and boots `rootfs-<backend>.ext4`; NULL
or "default" boots the golden image. Makes the per-CLI images from B4.1
actually reachable (one image per CLI, per A6).

A missing image is an ERROR naming the file and how to build it, never a
quiet fall back to the default. That fallback is the tempting version and
the wrong one: it would run a claude mission in a kimi VM, or in a rootfs
with no CLI at all, and report success for whatever came out. Verified on
real hardware, not just in a unit test — the selftest asks for an image
that does not exist and FAILS if it boots.

`create` now reports the rootfs that actually booted, not the one that was
requested, so a mission artifact can show the wrong VM ran.

The migration adds no CHECK constraint listing the CLIs. Which images
exist is a property of the NODES, not the schema; a constraint would need
migrating for every new image while still not guaranteeing the image
exists anywhere. The node validates and names what is missing. Backend
names are `[A-Za-z0-9_-]` and rejected rather than sanitised, since they
become filenames.

Verified on tank: default backend 8/8; `CLAWMATES_FC_BACKEND=agent-terminal`
9/9 including the absent-image check, create in 910ms on a rootfs built
from a real Docker image. 435 tests green, no leaked processes or VM dirs.

Co-Authored-By: Claude Opus 5 <[email protected]>
This commit is contained in:
Omar Sobh
2026-08-05 10:38:45 -07:00
co-authored by Claude Opus 5
parent fcf5d7b16c
commit 6687f8b808
5 changed files with 151 additions and 7 deletions
+3
View File
@@ -27,5 +27,8 @@ rustls = { version = "0.23", default-features = false, features = ["ring"] }
webrtc = "0.17.1"
bytes = "1.12.0"
[dev-dependencies]
tempfile = "3"
[lints]
workspace = true