Files
hq/04-ISSUES/170-assigning-a-module-claims-every-seat-it-could-hold/00-report.md
T
jschoubben d0044cf555 Issue 170: assigning a module claims every seat it could hold
Assigning postgres on ace claimed mesh-store and made novox's own store
assignment unresolvable. The resolver reads a manifest's claims as 'does
hold'; ADR 0110 says the assignment holds, by a deliberate act the controller
already has (seat …, HoldSeat) but resolution does not consult.
2026-09-30 14:29:11 +02:00

2.7 KiB

status, opened, located-in, fixed-by, amended-design
status opened located-in fixed-by amended-design
open 2026-09-30
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)

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:

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.