diff --git a/03-DESIGN/01-to-be/28-building-the-bus.md b/03-DESIGN/01-to-be/28-building-the-bus.md index 6b7b4e3..f3c692f 100644 --- a/03-DESIGN/01-to-be/28-building-the-bus.md +++ b/03-DESIGN/01-to-be/28-building-the-bus.md @@ -683,12 +683,43 @@ healthy while reacting to nothing. > crash-looped for two hours and nothing could be deployed until it was repaired by hand. > An earlier version of this note said the old broker stays as an ordinary provider of > `amqp` ([ADR 0127](../../02-DECISIONS/0127-amqp-is-a-provision-not-the-bus.md)); that is withdrawn by [ADR 0131](../../02-DECISIONS/0131-everything-on-the-mesh-speaks-to-the-broker-seat.md) — see 5.4. -- [ ] 5.3 **the seat changes hands as one act.** A command takes a seat and the assignment taking it + + **What the first live attempt found, 2026-09-27.** With the seat handed over on record and the + new bus's module registered and assigned beside the old one, `push` refused the control node: + *not one user has a credential for the new bus*. The check is right — a bus whose user list is + empty refuses every connection in the mesh — and it exposed the half of this task nobody had + built. A credential is minted at three moments only: a machine's at enrolment, a module's at + `module issue`, a person's at `operator`. **Nothing mints one for a machine already enrolled, or + for the control plane itself.** And on the host, the membership — bus address, fingerprint, + password, transport — is written once, at enrolment, and nothing ever rewrites it. So "move + each machine and confirm it reports" had no mechanism under it on either side. + + The mechanism, to build before anything moves: + - **the control plane mints what is missing** — every user the records derive with no hash — + and delivers each plaintext where its owner reads it: a machine's inside its declaration, as a + sealed *membership* for the new bus (address, fingerprint, password, transport); a module's as + its broker secret, the path `module issue` already uses; the control plane's own as its module + secret, so it reads it the way any module does; + - **the host saves a delivered membership and re-dials on it** — the same file enrolment wrote, + the same reconnect path a lost connection takes, so a machine moved this way is a machine + that came back, and nothing new has to be right for it to work; + - **the switch is then two acts in one push**: `MESH_BUS_NATS` on the control plane, and + `seat mesh-broker --to /` — the seat never empty, every machine + already holding a credential that works on the other side. + + Until the first bullet exists the check keeps refusing, and it should: a machine moved without + a credential cannot come back, and afterwards there is no bus to tell it anything over. +- [x] 5.3 **the seat changes hands as one act.** A command takes a seat and the assignment taking it over, and the seat is never empty in between — the emptiness is the outage of 2026-09-27, when the control plane, which finds its own bus through this seat, lost the address and looped. - Today only `seat rename` exists. This is what 5.2 uses to move `mesh-broker` from the old - broker's assignment to the new one's, and it is built first ([ADR 0131](../../02-DECISIONS/0131-everything-on-the-mesh-speaks-to-the-broker-seat.md)). -- [ ] 5.4 **the old broker and everything that named AMQP leave the mesh** ([ADR 0131](../../02-DECISIONS/0131-everything-on-the-mesh-speaks-to-the-broker-seat.md), + **Built 2026-09-27** (mesh-controller `seat_holding`, migration 0039; design 26 says how it is + checked). Its first live use recorded the standing holder — which the row moving under it had + made unable to satisfy what the seat delivers, so the first handover on a mesh that predates the + record writes down who holds without re-judging them. This is what 5.2 uses to move + `mesh-broker` from the old broker's assignment to the new one's ([ADR 0131](../../02-DECISIONS/0131-everything-on-the-mesh-speaks-to-the-broker-seat.md)). +- [~] 5.4 **the old broker and everything that named AMQP leave the mesh** — the catalogue half done + 2026-09-27 (three modules removed; registration refuses the word; the seat's row delivers + `mesh-bus`, migration 0040); the live half — unassigning the old broker — waits on 5.2 ([ADR 0131](../../02-DECISIONS/0131-everything-on-the-mesh-speaks-to-the-broker-seat.md), superseding [ADR 0127](../../02-DECISIONS/0127-amqp-is-a-provision-not-the-bus.md)): the two modules that required `amqp` are removed, the broker's module is unassigned and removed, registration refuses a manifest that provides or requires `amqp`, and a whole-catalogue check asserts none does. Not