From eef54917ec4a08479b8eb425aa3137391e670b52 Mon Sep 17 00:00:00 2001 From: jochen Date: Tue, 29 Sep 2026 21:32:52 +0200 Subject: [PATCH] Issue 146: the double enrolment was two consumers sharing a delivery subject Not about enrolment. A push consumer delivers onto an ordinary subject and everything subscribed to it gets a copy; the controller's two consumers were both named after it, so both were given the same subject and the one process acted on every message twice. Enrolment is where it drew blood because a second enrolment mints a second credential. --- .../01-diagnosis.md | 29 +++++++++++++++++-- 1 file changed, 26 insertions(+), 3 deletions(-) diff --git a/04-ISSUES/146-the-foundation-cannot-be-raised-on-the-bus-the-mesh-runs-on/01-diagnosis.md b/04-ISSUES/146-the-foundation-cannot-be-raised-on-the-bus-the-mesh-runs-on/01-diagnosis.md index 6bd82ee..317bb01 100644 --- a/04-ISSUES/146-the-foundation-cannot-be-raised-on-the-bus-the-mesh-runs-on/01-diagnosis.md +++ b/04-ISSUES/146-the-foundation-cannot-be-raised-on-the-bus-the-mesh-runs-on/01-diagnosis.md @@ -103,7 +103,7 @@ reload, which is the module's knowledge and is what the module takes over on the With that, **a first node enrols against the bus it just raised** — measured, from bare, in the lab. -## 6 — and is enrolled twice, keeping a credential the mesh has replaced *(open)* +## 6 — and is enrolled twice, keeping a credential the mesh has replaced *(fixed)* ``` mesh-controller: enrolled anchor @@ -127,8 +127,31 @@ or the second copy is not a copy. This is where the trail stops. Worth saying plainly: **the mint is the fragile part, not the delivery.** An enrolment answered twice is survivable if the answer is the same both times, and it cannot be — the mesh keeps only -the hash, so a second answer is necessarily a different credential. Whatever closes this either -makes the enrolment arrive once, or stops the second arrival from rotating anything. +the hash, so a second answer is necessarily a different credential. + +**Found, and it is not about enrolment at all** *(fixed)*. The bus's own counters settled it: one +message published, one held in the stream, one delivery, nothing redelivered — and the controller +enrolled the machine twice. So the handler ran twice on one delivery. + +A push consumer delivers onto an ordinary subject, and **everything subscribed to that subject gets +a copy**. The controller holds a consumer called `controller` on CONTROL and another called +`controller` on EVENTS, and the delivery subject was derived from the consumer's name alone — so +both were `_DELIVER.controller`, the one process held both subscriptions, and every message from +either stream was acted on twice. + +Enrolment is where it drew blood, because enrolling twice mints twice and the second credential +replaces the first. But it applied to **every report and every event the controller follows**, and +it is the kind of fault that leaves no trace: nothing is redelivered, no counter is wrong, the work +simply happens twice. The comment in the receiving code about a merge that ran the whole catalogue +five times over on 2026-09-28 is the same shape seen from the other end. + +The stream is in the delivery subject now, because the pair is what identifies a consumer — the +server scopes a durable's name to its stream, and this subject was the one place that scoping was +dropped. A subscriber's permission gains the same shape, keeping the bare name so an existing +consumer keeps working until the controller's next assertion moves it. + +*How it is checked:* the consumers the mesh asks for are asserted to deliver onto distinct subjects, +in the controller's own suite. Against a server it would be invisible, which is the point. ## Where it belongs