--- status: open opened: 2026-09-30 located-in: - mesh-controller internal/catalogue/resolve.go (holdings are derived from every resolved assignment's manifest `claims`) - mesh-controller cmd/mesh-controller/seats.go (the deliberate act exists — HoldSeat, "recording … as its standing holder" — beside it) fixed-by: amended-design: --- # 170 — Assigning a module claims every seat it could hold ## What was observed ace's migration needs a postgres of its own: the operator's decision is that a `postgres` module assigned on ace provides `postgres-database` to ace's modules and has **nothing to do with the `mesh-store` seat**, which novox's assignment holds by a deliberate act already taken ("make novox's postgres the mesh-store"). `assign ace postgres` (2026-09-30): ``` ace is assigned postgres AND 1 other machine(s) cannot be worked out as things stand, so nothing will be sent to them: novox - postgres on novox claims "mesh-store", which postgres on ace already holds — one per mesh mesh-controller: these assignments cannot be applied: - postgres on ace claims "mesh-store", which postgres on novox already holds — one per mesh ``` The second assignment did not merely fail: it made **the control plane's own store's assignment unresolvable** until unassigned. Nothing was pushed; the state is restored. ## Why `resolve.go` derives what a node holds from the manifest's `claims` of every module resolved on it, so a claim in a definition is a claim by every assignment of that module. The deliberate act ADR 0110 describes exists beside it — `seat …` records "X on Y as its standing holder" (`HoldSeat`) — but resolution does not consult that record; it consults the manifests. ## What was decided [ADR 0110](../../02-DECISIONS/0110-a-seat-is-a-module-assignment-from-a-closed-set.md): > **A definition says which seats a module *can* hold. An assignment says which it *does* > hold.** The store module can hold `mesh-store`, and it may be assigned to every node. Exactly > one of those assignments holds the seat, because that assignment said so. The manifest's `claims` is being read as *does hold*. ## What would be right Resolution takes the holder of a seat from the recorded holding (the seat's standing holder), not from the manifests: a module whose definition can hold a seat is assignable anywhere, and only the assignment recorded as holder claims it — with the refusal reserved for a second *recorded* holder at the seat's scope. Assigning postgres to ace is then exactly what the operator said it is: a database provider on ace, and no more. ## Until then `postgres` cannot be assigned on any second node; ace's database windows (baserow, letta, n8n, car-hunter, txt-game) wait on this.