# mvirt 0.9.0

migrations: yes
wire: unchanged
rev: 1aa758e8cf7aef89968477589bfa801c0719cc75

v0.9.0 — the HA control plane, working on an upgraded store

0.8.0 shipped the highly-available control plane and could not run it on any
store that predates it. This release fixes that, and two errors in the growth
reconciler that the fleet surfaced on the way.

**Upgrade directly from 0.7.0 to 0.9.0.** If you already deployed 0.8.0, upgrade
now: on an upgraded store its `host_node` table stops accepting writes, which
stalls node heartbeats and makes the control-plane growth reconciler retry the
same host forever. Nothing is lost and nothing crashes — the writes are rejected,
not corrupted — and 0.9.0's migration repairs the catalog on first boot.

What was wrong

* Appending optional columns to an entity is free when *reading* an old row, and
  not free when writing one: the stored catalog decides what a row may contain,
  so on a database created before the columns existed every write to that table
  is rejected. m0126 brings the two affected catalogs up to date.

* The bootstrap voter's raft id is the configured `1`, not the id derived from
  its host record. The reconciler derived it unconditionally, which left that
  voter outside its own desired member set — so the adoption-first rail refused
  to grow — and would have described a second member for a host that already had
  one. A host that is already a member now keeps the id it has.

* The member-address rewrite now refuses to record an address this replica is not
  listening on, which also orders the underlay bind change correctly: a member
  writes its raft credential for its next start, so the bind follows one restart
  behind the material.

Everything 0.8.0 announced still holds: raft mTLS with member-identity peer
authorization, the control-plane group growing the raft, adoption over the node
tunnel, and edge leader affinity. Growing to three voters is documented in
docs/runbooks/control-plane-ha.md.


## 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.
