# mvirt 0.6.0

migrations: yes
wire: unchanged
rev: 25ee3472e36943965ba3743b9f373cc819075a26

mvirt 0.6.0


The cluster can be upgraded from its own console (ADR-0072). Until now day-2
upgrades ran entirely outside the product: an operator workstation holding the
instance flake bumped one URL and drove colmena over root SSH — the widest
credential we have, kept alive only because upgrades had no other path.

What changed:

- The control plane knows what is published. It polls two pointer documents,
  `latest/` (announced) and the new `candidate/` (published but not yet
  announced), because the registry's package listing API needs credentials
  while the artifacts do not — a cluster can fetch a release it can name but
  cannot discover names, so the pipeline publishes them. `GET /v1/releases`
  reports the running version and both channels, including the two facts that
  change an upgrade's shape: whether it migrates the store, and whether the
  storage wire moved. "We have not looked" and "you are current" are different
  answers and are shown as such.

- The fleet declaration lives in the store. The operator's own deployment flake
  is adopted verbatim; the platform applies exactly one transformation to it,
  ever — pointing the `mvirt` input at the release being staged — and refuses
  rather than guesses when it cannot tell which pin that is.

- Nodes stage their own next system. The control plane pins the artifact hash
  when the desired version is set; the node fetches, verifies against that hash,
  and builds its own closure in a separate oneshot, because the operation
  replaces the agent binary and takes minutes. Nothing is activated: staging is
  safe to run on every host at once.

- Activation and rollback are explicit, per host, from the console. There is no
  rollout automation on purpose: orchestrating this owes its users draining and
  live migration, which do not exist yet, so automating the sequence would only
  automate guest downtime. The confirm dialog shows what the host is about to
  take down; two cases are refused outright — activating a generation the host
  no longer has staged, and rolling the store-owning control-plane host back
  across a migration.

Also in this release: a template's image lives in the object store and nowhere
else, retiring the placed chunk-set arm of template materialization.

Upgrade: control-plane host first, then nodes one at a time. This release
MIGRATES the store, so the control-plane host cannot be rolled back by booting
the previous generation — only by restoring a backup. The control plane writes
one immediately before applying the migrations.

Known limits: a host actually rebooting into a staged system has not been
proven on hardware yet — the dev cluster's nodes are source-built VMs whose only
correct system is their own. This release is where that proof gets made.

## Upgrading

Point your flake's `mvirt` input at this release and redeploy the control-plane
host first, then each node in turn:

```
nix run .#colmena -- apply boot --reboot --on <control-plane host>
nix run .#colmena -- apply boot --reboot --on <node>   # one at a time
```

**This release migrates the store.** Once the control plane has started, the
previous version will refuse to run against it — migrations are forward-only, so
rolling the control-plane host back means restoring a backup, with data loss back
to the backup point. The control plane writes a backup immediately before it
applies migrations; nodes roll back freely by booting the previous generation.
