Taken during the outage of 2026-09-27, when the protocol leaked into the seat's contract: to hold mesh-broker a module had to provide amqp, so the module that will carry the bus could not hold the seat that names the bus, while the module being retired could. Supersedes 0127. Modules depend on the seat and reach the bus through the sdk; no manifest provides or requires amqp; the old broker's module and the two modules that required it leave the catalogue; the AMQP transport is deleted once every node reports on the new bus. Design 28 step 5 rewritten under it: the seat handover becomes its own task and is built first, because the seat the control plane dereferences cannot be empty in between — that emptiness was the outage. The cost note now carries what was measured rather than what was assumed. 0128 and 0130 extended 0127; each now rests on 0131 with a dated note and changes nothing it decided. Every other citation of 0127 names its replacement. records.py still fails on 0120/0112, which predates this branch.
5.8 KiB
topic, status, superseded-by, date, deciders, reconstructed, supersedes
| topic | status | superseded-by | date | deciders | reconstructed | supersedes |
|---|---|---|---|---|---|---|
| the mesh | superseded | 0131-everything-on-the-mesh-speaks-to-the-broker-seat.md | 2026-09-26 | jochen | false | 02-DECISIONS/0125-the-bus-is-the-only-broker.md |
127. AMQP is a provision, not the bus
Context
ADR 0125 decided that the bus is the only broker, and went
one step further than it had grounds for: it also decided that the amqp interface — a module
requiring a message broker of its own — "is not carried forward" and "retires with the
compatibility broker rather than gaining a successor", with the two modules declaring it converted
to the bus in step 4.
The operator's correction: AMQP is deprecated as the mesh's transport, not abolished as a
service. The broker module keeps running and keeps answering amqp requirements. It is no
longer a core part of the mesh — "it's just a module like mssql now."
What 0117 conflated is two different reasons a module might ask for a broker, which look identical in a manifest:
- To talk to other modules. Wrong under one bus, and the thing 0117 was right to refuse: a private broker used as inter-module transport is a second bus, with every guarantee crossing a seam and no scoping the mesh can see.
- Because it genuinely needs an AMQP broker, the way something needs a database — a queue for its own internals, or interop with software that speaks AMQP and nothing else. That is a backing service, and the mesh has a word for backing services already.
0117 saw the first and legislated against both. The second is ordinary, and forbidding it would make the mesh unable to run a large class of perfectly normal software while claiming that as architecture.
Considered Options
- Keep 0117 as written — retire the interface, convert the two modules. Rejected by the operator, and wrongly reasoned besides: it treats "needs an AMQP broker" as always a mistake.
- Keep the broker as the predecessor's compatibility module, as ADR 0106 framed it, with a retirement condition. Rejected: it is not single-purpose and its clients are not only the predecessor's, so the retirement condition describes a day that will not come.
- The broker is an ordinary provider module of an ordinary provision. Adopted.
Decision
The mesh's bus is NATS and only NATS. Everything 0117 decided about the bus stands: one bus,
a module's messaging is subjects on it scoped by what it declares, no module is handed a bus of
its own, and the mesh-broker seat is the NATS server's.
amqp remains a provision a module may require, answered by the broker module the way
postgres-database is answered by the store module or a database is answered by mssql. It is not
deprecated as an interface; the software behind it is simply no longer the mesh's nervous system.
The broker module stops being foundation. It claims no seat — mesh-broker is the NATS
server's — it is not raised at genesis, nothing in the mesh requires it, and a mesh that never
installs it is a complete mesh. It is installed when something wants it, like any other provider.
The rule that survives, stated so it can be applied: inter-module communication goes over the bus. A module may hold a broker, a database or a cache as a backing service; it may not use one as a channel to another module. The line is not which software is involved, it is whether a second module is on the other end.
Neither amqp-ping nor amqp-email-forwarder needs converting. 0117 put that work in step 4;
it is removed. They require a backing service and a provider answers.
Consequences
- The "compatibility broker" framing is wrong and goes. There is no
lavinmq-compat, no single purpose and no retirement condition. Design 25 §5 is corrected. - ADR 0106's progressive insight was itself wrong and is corrected by a second one there. It said 0117 would make 0106's "one purpose — the predecessor's clients" sentence true by moving the mesh's modules off. Nothing moves off; the sentence is simply not what the broker is.
- The seat change stands, for a better reason than 0117 gave: not because a broker cannot be
provisioned, but because this broker is not the mesh's bus. The broker module drops its
mesh-brokerclaim and thenatsmodule takes it. - Step 4 loses two conversions; step 1 and the WBS are otherwise unaffected.
- What got harder: the rule is now a judgement rather than a prohibition. "Is this a backing service or a channel to another module?" has to be asked in review, where 0117 could have answered it with a parser. That is the honest cost of allowing the legitimate case.
How it is checked
- A module's own messaging needs no
requires. The check from 0117, unchanged: a module declaring onlyemitsandconsumesreaches its subjects and is refused every other. - The broker holds no seat. A manifest test: the broker module claims nothing, and a mesh raised without it is complete — genesis names it nowhere.
amqpresolves like any provision. A resolution test: a module requiring it is answered by the provider, refused when none is assigned, and neither case touches the bus.- What cannot be checked mechanically, and is said rather than implied: that a module holding a broker is not using it to reach another module. Review, not a parser.