Issue 208: the bus's objects asserted on every send; fix pointer, the module half, Phase 3 note

This commit is contained in:
jochen
2026-10-06 11:46:27 +02:00
parent 358cce00a7
commit e6e9d4dcc3
@@ -3,7 +3,7 @@ status: located
opened: 2026-10-03
located-in:
- mesh-controller
fixed-by:
fixed-by: novox/mesh-controller#81 (b853439)
amended-design:
---
@@ -40,3 +40,43 @@ Owner mesh-controller: the raise runs once (`RaiseSeats` with the holders of the
`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.
## Seen again, 2026-10-06: the module half of the same gap
A module carried by the runtime, which consumes the controller's condition events, was assigned to a
machine and pushed. It said `binding messenger's consumer …: nats: consumer not found`, and the
self-check's D6 confirmed that the consumer it reads through was not on the bus. The cause was the one
diagnosed above, on the other side. The controller asserted the bus's objects (streams, seat workers,
every module's consumer) only when it started. A push created a module's consumer only when it minted
that module a bus credential, and the runtime carries a module's traffic under its own credential, so
the module was never minted one and its consumer was never created.
## Fix
The bus's objects that a declaration implies are now asserted whenever a declaration is sent: on a
push, on the machines the push cascades to, and on a plan's or a rotation's sends. They are not
asserted only at start. The send asserts them through the same derivation the start and the
self-check use, before the memberships. There is no second list of what a send needs. Every part is
idempotent, so asserting the whole set again changes nothing that already holds.
A failure to assert is said in the send's own output and raised as a condition (`bus.objects.unasserted`).
The next send that asserts everything clears it. The send itself goes on. The objects belong to the
mesh, not to the machines being sent, and holding every machine back for one consumer would turn one
fault into all of them. The start still refuses to serve without its objects.
Checked by mesh-controller's `busobjects_test.go`. A module carried by the runtime and a seat's holder,
both assigned after the start's assertion, are asserted by the next send. Against a real bus, through
the send's own grant step, both exist after it. That test fails without the change, with the
`consumer not found` seen live. A refused consumer is said in the output and raised as a condition.
The consumers after it are still asked for, and the next good send clears the condition.
## Healing what no send reaches (to-be 45 Phase 3)
The fix covers every object a send implies at the moment it is sent. It does not cover an object lost
between sends: a consumer somebody deleted, or a bus whose data directory was replaced. D6 (a module's
consumer) and D3 (a holder without its worker) find these. Until the next send or a controller
restart, nothing makes them again. H3 in to-be 45 is the healer for D3's half ("raise the seat's
objects again"). Its repair is now exactly the assertion a send makes, so it can be the same call for
D6's missing consumer as well: one healer for "an object the mesh defines is not on the bus", braked
per object, rather than two. This is noted for Phase 3 and not built here.