Merge pull request 'Issue 208: a seat's worker is made only when the controller starts, so a holder assigned later finds none' (#312) from issues/208-a-holder-assigned-later-finds-no-worker into main

This commit was merged in pull request #312.
This commit is contained in:
2026-10-03 09:33:28 +00:00
@@ -0,0 +1,42 @@
---
status: located
opened: 2026-10-03
located-in:
- mesh-controller
fixed-by:
amended-design:
---
# 208 — A seat's worker is made only when the controller starts, so a holder assigned later finds none
## What was observed
2026-10-03, assigning the first holders of `node-build-agent` ([ADR 0190](../../02-DECISIONS/0190-a-seats-work-is-shared-by-its-holders-and-building-is-the-first-such-role.md))
to four machines and pushing them. Every agent came up, authenticated, bound its seat, and restarted:
```
taking build work as a holder of node-build-agent
mesh-builder: this machine cannot take work from node-build-agent: nats: consumer not found. The mesh
creates that queue and this machine's worker on it, and a build machine may not create one
```
The seat's stream existed; its worker did not. The controller makes a seat's worker where it raises
the bus's objects — on start — for the seats that have a holder at that moment, by design: *the queue
before the holder, so work queues until somebody arrives*. Nothing makes the worker when a holder
arrives later: a push asserts the module's own consumers (what it consumes) and not the seat's worker.
The remedy was a controller restart, so the raise ran again with the holder known.
## Why it matters beyond this instance
A seat's first holder is assigned after the controller started in every case but genesis, so every
new role's first holder meets this. The build machine met it on 2026-09-28 the same way ("left the
build machine bound to a consumer nothing had created") and the fix then was to pass the holders at
the raise — which fixed the start, not the arrival. The holder says the right thing and cannot do
anything about it, because a holder may not create its worker (design 25 §3).
## Diagnosis
Owner mesh-controller: the raise runs once (`RaiseSeats` with the holders of the moment); `push` and
`assign` run `EnsureConsumer` only for a module's declared consumption. **Fix direction:** when a
module claiming a seat with `accepts` is assigned, or on every push that composes a holder for such a
seat, ensure the seat's worker as the raise does — the same derivation, the same idempotent assertion.