Step 2: adoption recreates the bus once, on purpose

2.3 was already true and is now proved — the seat refusal is generic, and
three tests pin what matters: a second bus is refused by name, a different
bus implementation is refused too (which is what makes the bus replaceable),
and the AMQP broker no longer contends so both run on one mesh.

2.1/2.2 turned out not to be a no-op. The host keeps a container only when
its spec matches exactly; genesis raises the upstream image and the module
declares the mesh-built one carrying the entrypoint, so assigning it
recreates the container. That is ADR 0067's pivot and it is safe only
because the bus carries nothing yet — which is why step 2 comes before
anything speaks NATS. After it, never again: the config is a directory
mount, so accounts change without touching the container's spec.
This commit is contained in:
2026-09-26 21:40:02 +02:00
parent 86a084b7ff
commit 39c802cbd4
+29 -5
View File
@@ -180,11 +180,35 @@ and it is what makes steps 3 and 4 safe to develop against a live mesh. A runnin
a foundation module by being raised again; it adopts one in place a foundation module by being raised again; it adopts one in place
([ADR 0100](../../02-DECISIONS/0100-a-node-in-use-is-adopted-before-it-is-converged.md)). ([ADR 0100](../../02-DECISIONS/0100-a-node-in-use-is-adopted-before-it-is-converged.md)).
- [ ] 2.1 the server raised beside the existing broker on its own ports, carrying nothing - [ ] 2.1 the server raised beside the existing broker on its own ports, carrying nothing —
- [ ] 2.2 the `nats` module adopted onto it in place, holding the data and configuration it was installer-side, from the upstream image
raised with - [ ] 2.2 the `nats` module assigned, which **recreates the container once, deliberately** (see
- [ ] 2.3 the seat claim, and the resolver's refusal of a second holder mesh-wide below), keeping its JetStream directory
- [ ] 2.4 the adoption bed - [x] 2.3 the seat claim, and the resolver's refusal of a second holder mesh-wide — **already
true and now proved**: the refusal is generic to any mesh-scoped seat, and three tests pin
what matters for this one — a second bus anywhere is refused naming the seat, a *different*
bus implementation is refused for the same reason (which is what lets the bus be replaced
at all), and the AMQP broker no longer contends for it, so both run on one mesh
- [ ] 2.4 the adoption bed — deferred with the other beds
> **Adoption here is not a no-op, and pretending it would be is the trap.** The host keeps an
> existing container only when its spec matches the declaration exactly
> ([`apply.go`](https://git.novox.be/novox/mesh-host): *existed && before.Spec == want && running*
> → unchanged; anything else is `rm -f` and recreate). Genesis raises the server from the
> **upstream** image, because nothing has been built yet; the module declares the **mesh-built**
> artifact, which carries the entrypoint that reloads configuration in place. Those two specs
> differ, so assigning the module recreates the container.
>
> That is correct, and it is [ADR 0067](../../02-DECISIONS/0067-genesis-is-a-pivot.md)'s pivot
> exactly: raise a temporary thing, then reinstall it as an ordinary module. It is safe **only
> because it happens while the bus carries nothing** — which is what 2.1 means by "carrying
> nothing", and why step 2 comes before anything speaks NATS rather than after. One recreate, at
> the one moment it costs nothing.
>
> **After that, never again.** The configuration is a directory mount rather than a file, so
> rewriting accounts does not change the container's spec and the entrypoint reloads the server in
> place. That is the whole point of task 1.2, and this is the moment it pays: every later account,
> permission or person's access change touches a running bus with connections on it.
**Done when.** A mesh already running has the server adopted, holding `mesh-broker`; a second **Done when.** A mesh already running has the server adopted, holding `mesh-broker`; a second
assignment anywhere is refused at resolution — *one per mesh*; and every node is still on the old assignment anywhere is refused at resolution — *one per mesh*; and every node is still on the old