The glossary's authority page still named the controller's seat the-controller in two entries, contradicting its own seat section after ADR 0079; issue 058's heading kept the pre-renumber 059; 055's fixed-by named branches that stop existing after merge (now merge commits/PRs) and its located-in listed file paths where the convention wants repos; 056's located-in named mesh-host, which received no fix, instead of mesh-catalog; and the design layer never said the one-store/one-broker property is enforced — 07-the-foundation and the installation table now state the seats. https://claude.ai/code/session_01D6qtiYU3P9jk3pnAXyAFyx
57 lines
3.2 KiB
Markdown
57 lines
3.2 KiB
Markdown
---
|
|
status: resolved
|
|
opened: 2026-09-17
|
|
located-in: [mesh-controller, mesh-catalog]
|
|
fixed-by: mesh-catalog + mesh-controller (the foundation modules claim mesh-scoped seats)
|
|
amended-design: 02-DECISIONS/0079-the-foundation-seats-are-named-after-their-servers.md
|
|
---
|
|
|
|
# 056 — An adopted module assigned to a second node raises a second server
|
|
|
|
## Symptom
|
|
|
|
The store and broker are adopted in place ([ADR 0078](../../02-DECISIONS/0078-the-store-and-broker-are-modules.md),
|
|
issue 051): genesis raises `mesh-store`/`mesh-broker` on the control-node, and assigning the
|
|
`postgres`/`lavinmq` module there makes the module reconcile the already-running container instead
|
|
of raising a new one. Adoption works *because the container is already running on that node*.
|
|
|
|
Nothing stops the same module being assigned to a **second** node. On a node where no
|
|
`mesh-store` is running, the applier finds no container by that name and raises one — a second
|
|
postgres, a second broker. The whole point of Phase 3 — "one postgres, one lavinmq" — holds only
|
|
by the convention that genesis assigns these modules to the control-node alone; it is not enforced.
|
|
|
|
## Why it matters
|
|
|
|
"There is one store and one broker" is stated as a property of the mesh, and a property enforced by
|
|
nothing is indistinguishable from a wrong one. A single extra `assign` — the ordinary verb an
|
|
operator types — silently produces a divergent second server holding none of the first's data, and
|
|
consumers resolved to it get an empty store. The failure is silent and far from its cause.
|
|
|
|
The exclusive foundation modules are the mesh's clearest case of "there is one of me," yet unlike a
|
|
mesh-scoped seat, an adopted module carries no claim that the resolver would refuse a second holder
|
|
for.
|
|
|
|
## Open questions
|
|
|
|
- Should `postgres`/`lavinmq` claim a mesh-scoped exclusive seat (the way `mesh-controller` claims
|
|
`the-controller`), so the resolver refuses a second assignment by the same mechanism that keeps
|
|
one controller?
|
|
- Or should adoption be explicit — a module that adopts a foundation container declares it, and the
|
|
controller refuses to place it on a node whose foundation did not raise that container?
|
|
- How is "one postgres, one lavinmq" checked, rather than assumed — in the resolver, in `status`, or
|
|
in a bed that tries the second assignment and asserts the refusal?
|
|
|
|
## Resolution (2026-09-17)
|
|
|
|
The foundation modules now claim a mesh-scoped **seat** named after the server each guards —
|
|
`postgres` claims `mesh-store`, `lavinmq` claims `mesh-broker`, and the controller's seat is
|
|
renamed `the-controller` → `mesh-controller` so all three follow one convention
|
|
([ADR 0079](../../02-DECISIONS/0079-the-foundation-seats-are-named-after-their-servers.md)). The
|
|
resolver's `checkClaims` refuses a second holder mesh-wide — the same mechanism that keeps one
|
|
hub and one controller — so a second `assign` is a refusal at resolution (*one per mesh*), not a
|
|
silent second server.
|
|
|
|
Checked by `TestAFoundationModuleCannotBeRaisedOnASecondNode` (each foundation module's second
|
|
assignment is refused) and by the manifests declaring the seat; the two-node adopted-broker bed
|
|
stays green with the seats in place, so the claim does not break single-node adoption.
|