novox/hq issue 208, and the live symptom of 2026-10-06: messenger, carried by the runtime on novox, assigned after the controller started, said binding messenger's consumer novox_messenger: nats: consumer not found; D6 confirmed novox_messenger on EVENTS is not on the bus.
Cause
assertBusObjects (streams, seat workers, every module's consumer) ran only in raiseTheBus at controller start. A push ensured a module's consumer only inside issueWith, when a bus credential is minted, and a module carried by the runtime is never minted one. A seat holder assigned later (issue 208, the build agents on 2026-10-03) had the same gap for its worker.
Fix
overTheBus.grant, the one step every real send passes through (push, the push's cascade, sendTo/sendToEach: plan sends, rotate, secret, upgrades), now calls assertOnSend before the memberships: the same assertBusObjects derivation the start and the self-check use, no second list. Idempotent; the JetStream Note is printed as at start.
A failure is said in the send's output (THE BUS DOES NOT HOLD WHAT THIS SEND IMPLIES: …) and raised as condition bus.objects.unasserted (source bus-objects, Reconcile), which the next send that asserts everything clears. The send goes on: the objects are the mesh's, and holding every machine back for one consumer would turn one fault into all.
assertBusObjects tries every module consumer and joins the failures, instead of stopping at the first.
The start raise is unchanged and still refuses to serve without its objects.
Three files: busobjects.go, a 7-line hook in push.go, and a new busobjects_test.go, so this rebases easily against the Phase 2 work.
Tests
TestASendAssertsWhatWasAssignedAfterStart: a carried consumer (runtime and messenger on laptop) and a late node-build-agent holder are not in the start's assertion and are in the send's.
TestASendThatCannotAssertTheBusSaysSoAndRaisesACondition: a refused consumer is said in the output and raised with its evidence. The seat worker after it is still asked for. The next good send clears the condition.
TestNatsAModuleAssignedAfterStartGetsItsConsumerAtItsFirstSend: against a real bus, through overTheBus.grant. Both the consumer and the worker exist after the send. Without the hook it fails with laptop_messenger on EVENTS is not on the bus after a send: nats: consumer not found, the live symptom.
The full suite (go test -p 1 ./...) passes with MESH_TEST_POSTGRES (postgres:17) and MESH_TEST_NATS (nats:2.11 -js), and vet and gofmt are clean.
Rollout
Once merged and the controller is delivered, push novox creates novox_messenger and D6's bus.EVENTS.novox_messenger.missing clears at the next self-check. No restart is needed beyond the controller's own upgrade, and that upgrade's start raise would also create it.
novox/hq issue 208, and the live symptom of 2026-10-06: messenger, carried by the runtime on novox, assigned after the controller started, said `binding messenger's consumer novox_messenger: nats: consumer not found`; D6 confirmed `novox_messenger on EVENTS is not on the bus`.
## Cause
`assertBusObjects` (streams, seat workers, every module's consumer) ran only in `raiseTheBus` at controller start. A push ensured a module's consumer only inside `issueWith`, when a bus credential is minted, and a module carried by the runtime is never minted one. A seat holder assigned later (issue 208, the build agents on 2026-10-03) had the same gap for its worker.
## Fix
- `overTheBus.grant`, the one step every real send passes through (push, the push's cascade, `sendTo`/`sendToEach`: plan sends, rotate, secret, upgrades), now calls `assertOnSend` before the memberships: the same `assertBusObjects` derivation the start and the self-check use, no second list. Idempotent; the JetStream `Note` is printed as at start.
- A failure is said in the send's output (`THE BUS DOES NOT HOLD WHAT THIS SEND IMPLIES: …`) and raised as condition `bus.objects.unasserted` (source `bus-objects`, Reconcile), which the next send that asserts everything clears. The send goes on: the objects are the mesh's, and holding every machine back for one consumer would turn one fault into all.
- `assertBusObjects` tries every module consumer and joins the failures, instead of stopping at the first.
- The start raise is unchanged and still refuses to serve without its objects.
Three files: `busobjects.go`, a 7-line hook in `push.go`, and a new `busobjects_test.go`, so this rebases easily against the Phase 2 work.
## Tests
- `TestASendAssertsWhatWasAssignedAfterStart`: a carried consumer (runtime and messenger on laptop) and a late `node-build-agent` holder are not in the start's assertion and are in the send's.
- `TestASendThatCannotAssertTheBusSaysSoAndRaisesACondition`: a refused consumer is said in the output and raised with its evidence. The seat worker after it is still asked for. The next good send clears the condition.
- `TestNatsAModuleAssignedAfterStartGetsItsConsumerAtItsFirstSend`: against a real bus, through `overTheBus.grant`. Both the consumer and the worker exist after the send. Without the hook it fails with `laptop_messenger on EVENTS is not on the bus after a send: nats: consumer not found`, the live symptom.
The full suite (`go test -p 1 ./...`) passes with MESH_TEST_POSTGRES (postgres:17) and MESH_TEST_NATS (nats:2.11 -js), and vet and gofmt are clean.
## Rollout
Once merged and the controller is delivered, `push novox` creates `novox_messenger` and D6's `bus.EVENTS.novox_messenger.missing` clears at the next self-check. No restart is needed beyond the controller's own upgrade, and that upgrade's start raise would also create it.
A module or seat holder assigned after the controller started was sent
its declaration and found nothing to bind: messenger on novox
("consumer novox_messenger not found", 2026-10-06) and every first
build-agent holder (2026-10-03). assertBusObjects ran only in the start
raise; a push ensured a module's consumer only when a bus credential was
minted, which a module carried by the runtime never is.
The send's grant now runs the same derivation (assertOnSend) before the
memberships, on every push, cascade, plan send and rotation. A failure
is said in the send's output and raised as bus.objects.unasserted, which
the next send that asserts everything clears; the send itself goes on,
because the objects are the mesh's and holding every machine back for
one would turn one fault into all. Module consumers are each tried and
every failure named. The start raise stays as it was.
build-agent keeps data (ADR 0233): what it holds is backed up before it moves
route-proxy provides route: its consumers are sent again after it
route-proxy keeps data (ADR 0233): what it holds is backed up before it moves
Transitions
2026-10-06 23:05 (new) → proposed (announced): novox/mesh-controller#81 merged; its head was not heard by this owner, so it is made from the forge's word
2026-10-06 23:05 proposed → held (merged-unchecked): merged without a passing check — a verdict known with it is taken first: only a person decides that it goes on
The commit's note under refs/notes/mesh-plan keeps every transition: git log --notes=mesh-plan.
<!-- mesh-delivery:view -->
**Delivery** `novox/mesh-controller@722682f1c4ca` — **held** since 2026-10-06T23:05:28Z
Held for a person: merged without a passing check: only a person decides that it goes on — `mesh-delivery.release` with why lets it go on.
**Delivery plan** — builds build-agent, mesh-controller, route-proxy → ace, g14, novox, shanks; no bus step
- tier 0: mesh-controller
- tier 1: build-agent
- tier 2: route-proxy
- ace: receives build-agent, route-proxy
- g14: receives build-agent
- novox: receives mesh-controller, build-agent, route-proxy
- shanks: receives build-agent
- build-agent keeps data (ADR 0233): what it holds is backed up before it moves
- route-proxy provides route: its consumers are sent again after it
- route-proxy keeps data (ADR 0233): what it holds is backed up before it moves
**Transitions**
- 2026-10-06 23:05 (new) → proposed (announced): novox/mesh-controller#81 merged; its head was not heard by this owner, so it is made from the forge's word
- 2026-10-06 23:05 proposed → held (merged-unchecked): merged without a passing check — a verdict known with it is taken first: only a person decides that it goes on
The commit's note under `refs/notes/mesh-plan` keeps every transition: `git log --notes=mesh-plan`.
This repo is archived. You cannot comment on pull requests.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
novox/hq issue 208, and the live symptom of 2026-10-06: messenger, carried by the runtime on novox, assigned after the controller started, said
binding messenger's consumer novox_messenger: nats: consumer not found; D6 confirmednovox_messenger on EVENTS is not on the bus.Cause
assertBusObjects(streams, seat workers, every module's consumer) ran only inraiseTheBusat controller start. A push ensured a module's consumer only insideissueWith, when a bus credential is minted, and a module carried by the runtime is never minted one. A seat holder assigned later (issue 208, the build agents on 2026-10-03) had the same gap for its worker.Fix
overTheBus.grant, the one step every real send passes through (push, the push's cascade,sendTo/sendToEach: plan sends, rotate, secret, upgrades), now callsassertOnSendbefore the memberships: the sameassertBusObjectsderivation the start and the self-check use, no second list. Idempotent; the JetStreamNoteis printed as at start.THE BUS DOES NOT HOLD WHAT THIS SEND IMPLIES: …) and raised as conditionbus.objects.unasserted(sourcebus-objects, Reconcile), which the next send that asserts everything clears. The send goes on: the objects are the mesh's, and holding every machine back for one consumer would turn one fault into all.assertBusObjectstries every module consumer and joins the failures, instead of stopping at the first.Three files:
busobjects.go, a 7-line hook inpush.go, and a newbusobjects_test.go, so this rebases easily against the Phase 2 work.Tests
TestASendAssertsWhatWasAssignedAfterStart: a carried consumer (runtime and messenger on laptop) and a latenode-build-agentholder are not in the start's assertion and are in the send's.TestASendThatCannotAssertTheBusSaysSoAndRaisesACondition: a refused consumer is said in the output and raised with its evidence. The seat worker after it is still asked for. The next good send clears the condition.TestNatsAModuleAssignedAfterStartGetsItsConsumerAtItsFirstSend: against a real bus, throughoverTheBus.grant. Both the consumer and the worker exist after the send. Without the hook it fails withlaptop_messenger on EVENTS is not on the bus after a send: nats: consumer not found, the live symptom.The full suite (
go test -p 1 ./...) passes with MESH_TEST_POSTGRES (postgres:17) and MESH_TEST_NATS (nats:2.11 -js), and vet and gofmt are clean.Rollout
Once merged and the controller is delivered,
push novoxcreatesnovox_messengerand D6'sbus.EVENTS.novox_messenger.missingclears at the next self-check. No restart is needed beyond the controller's own upgrade, and that upgrade's start raise would also create it.A module or seat holder assigned after the controller started was sent its declaration and found nothing to bind: messenger on novox ("consumer novox_messenger not found", 2026-10-06) and every first build-agent holder (2026-10-03). assertBusObjects ran only in the start raise; a push ensured a module's consumer only when a bus credential was minted, which a module carried by the runtime never is. The send's grant now runs the same derivation (assertOnSend) before the memberships, on every push, cascade, plan send and rotation. A failure is said in the send's output and raised as bus.objects.unasserted, which the next send that asserts everything clears; the send itself goes on, because the objects are the mesh's and holding every machine back for one would turn one fault into all. Module consumers are each tried and every failure named. The start raise stays as it was.Delivery
novox/mesh-controller@722682f1c4ca— held since 2026-10-06T23:05:28ZHeld for a person: merged without a passing check: only a person decides that it goes on —
mesh-delivery.releasewith why lets it go on.Delivery plan — builds build-agent, mesh-controller, route-proxy → ace, g14, novox, shanks; no bus step
Transitions
The commit's note under
refs/notes/mesh-plankeeps every transition:git log --notes=mesh-plan.