4.5 done: the catch-up needed nothing built, which was the answer

Three ways to do the replay were weighed and the right answer was that the bus being
moved to already does it. A queue on the old bus receives only what is published after
it is bound, so everything built before the catalogue existed was announced to nobody. A
stream is a log and a consumer is a position in it: a consumer created later starts at
the beginning and the builds are simply there. Checked against a running server, because
the decision rested on it.

So "who replays" has no answer because nothing replays. The mechanism was never about
builds — it was about a queue that could not remember, and carrying it across would have
carried a workaround for a limitation that no longer exists, with nothing looking wrong.

Retiring it belongs to step 5, with the rest of what only the old bus needs.
This commit is contained in:
2026-09-27 17:23:49 +02:00
parent fc64a2c1a4
commit 51f5ce5c0f
+25 -15
View File
@@ -591,23 +591,33 @@ it, and the beds that need a mesh living on NATS can finally run.
> critical path for nothing and blocked by nothing, and the bed it waits for is 4.1's. If the
> bed changes what a person's client should be, this is what gets changed.
- [~] 4.5 reports and catch-up: a node that was unreachable catches up rather than losing them —
**the reports half is in and proved against a server** (3.4): held through the store's absence
by the server rather than by the controller, superseded ones settled by the digest they carry.
- [x] 4.5 reports and catch-up: a node that was unreachable catches up rather than losing them.
**The catch-up half is a decision, and issue 127 narrowed it.** The controller answers a
catalogue's request by re-publishing builds under its *own* name, which nothing subscribing the
builder's subject hears, and for which it holds no grant. Publishing them under the builder's
subject would be the controller signing an event as another module, which the derived namespace
exists to prevent. And it cannot become a reply to the catalogue's inbox either: answering a
module's inbox needs `_INBOX.>`, the blanket grant design 25 §4 refuses — found while giving the
controller the one narrow inbox it does need, to answer enrolments.
**The reports half is in and proved against a server** (3.4): held through the store's absence by
the server rather than by the controller, superseded ones settled by the digest they carry.
So two options are left, and they differ in kind. A subject the controller may publish and a
catalogue may subscribe — the mesh's own event space, which does not exist yet. Or a durable
consumer that starts at the beginning of the stream, which removes the need to ask at all and
leans on retention instead: sound while the events are still there, and silent when they have
aged out, which is the failure the request was invented to avoid.
**The catch-up half needed nothing built, and that was the answer.** It existed because a queue on
the bus the mesh runs on today receives only what is published after it is bound, so everything
built before the catalogue existed was announced to nobody — and on a fresh mesh that is always
the foundation, because those are the things the catalogue needed in order to exist
([issue 050](../../04-ISSUES/050-the-catalogue-knows-nothing-built-before-it/00-report.md)). A
whole mechanism followed: the catalogue asks, the controller re-publishes.
A stream is a log and a consumer is a position in it. A consumer created later starts at the
beginning, so the builds are simply there — asked of a running server rather than assumed, since
the decision rested on it: three builds published with nothing listening, then a consumer created,
and all three waiting for it. So the question of *who replays* has no answer because nothing
replays.
> **This is the shape of the whole change, in one task.** Three ways to do the replay were weighed
> — a namespace for the mesh's own voice, the controller answering a question, a consumer reading
> from the start — and the right answer was that the bus being moved to already does it. The
> mechanism was never about builds; it was about a queue that could not remember. **A conversion
> that carried it across would have carried a workaround for a limitation that no longer exists**,
> and nothing would have looked wrong.
Retiring it is step 5's, with the rest of what only the old bus needs: the request, the
re-publishing, and the `replay` flag that told a consumer to register history without acting on it.
**Done when.** Each converted flow is proved against the behaviour it replaced, and the full genesis
bed is green. **Observation is not in this step** — heartbeats, conditions and key-value state are