diff --git a/03-DESIGN/01-to-be/28-building-the-bus.md b/03-DESIGN/01-to-be/28-building-the-bus.md index 7c16fea..f07d98c 100644 --- a/03-DESIGN/01-to-be/28-building-the-bus.md +++ b/03-DESIGN/01-to-be/28-building-the-bus.md @@ -284,17 +284,51 @@ pays for itself furthest away. manifest and authority cannot come from a declaration that does not exist. Still outstanding: a build's own shape, which travels with the builder in step 4. -- [~] 3.5 the host's link on NATS — **the outbound half is through a seam**, mirroring the +- [x] 3.5 the host's link on NATS — **all three halves are through seams**, mirroring the controller's and still importing nothing of the mesh's own (ADR 0005): the host's own - interface over its own libraries, agreeing with the controller only because a fixture holds + interfaces over its own libraries, agreeing with the controller only because a fixture holds both to one envelope. A report goes through JetStream because it is the message the - store-window guarantee is about; a heartbeat stays on core, because a heartbeat in a stream - is the mesh's least valuable message competing for retention with its most valuable. + store-window guarantee is about; a heartbeat stays on core, because a heartbeat in a stream is + the mesh's least valuable message competing for retention with its most valuable. - Still on the old client: dialling, the declaration consumer, and enrolment. The host's - **"newest wins" window narrows at the rollout rather than disappearing** — last-per-subject - makes catch-up the stream's and sequence orders definitively, but three pushes to a - connected node are still three deliveries. Recorded in the code where it is read. + `Link` is dialling, hearing and saying in one interface, because **dialling is where the + transport is chosen** and choosing it twice is how one half of a node ends up on a different + bus from the other. `Asking` is the enrolment conversation, and it is separate for the + opposite reason: almost nothing about it is the same, and a node that fails there is not in + the mesh at all. + + **What the new bus took away, and what it would not give.** A host declares nothing here: on + the old bus it declares its own queue, because a queue that is not there means a node that + hears nothing, but the object it reads through now is a durable consumer and a host's account + reaches no part of the JetStream API. So it **binds** to one the mesh made, and a missing one + is said as the mesh's to answer rather than quietly created with whatever the client defaults + to. Two things that had to be built for that: a node's declaration consumer (named after the + node, because its ack grant is derived from the node's name, so any other name is a delivery + it cannot acknowledge), and the enrolment user's **inbox** — design 25 §6 names it and the + composer granted none, so an enrolling node would have published its request and waited out + its timeout against a mesh that answered. + + **The reply address travels in the payload, and that is now proved from both ends.** The + controller reads it from there (3.4) and the host writes it there and waits on it, and the + test asserts the transport's own reply field held the *consumer's ack address* by the time the + request arrived — so a future server that stopped claiming that field fails a test rather than + letting the reason quietly become folklore. + + The host's **"newest wins" window narrows at the rollout rather than disappearing**, and that + is now measured rather than predicted: three declarations pushed to an absent node leave one + on the stream and it is the newest, so the catch-up half is the stream's — but three pushes to + a connected node are still three deliveries, which is the half that stays. + + **The pin turned out easier here than in the tool runtime, not harder.** The Go client takes a + `*tls.Config`, so the same pinned configuration with the same verify callback does the work; + the subject-alternative-name constraint recorded under 3.6 is that client's, because it takes + PEM strings with no verify hook. A host checks the fingerprint and nothing else. + + Still outstanding: **something that composes an enrolment user per live token.** Nothing does, + on either bus — on the old one the account is made imperatively through the broker's + management API when a token is issued, and here there is no management API, so issuing a token + has to recompose the server's configuration. That is the last piece of enrolment on the new + bus, and it is the only thing between the two links and a mesh raised on NATS from nothing. - [x] 3.6 the tool runtime's client on NATS, behind the unchanged sdk contract — round-tripped against a real server: a tool answered across two connections, a throwing handler reaching the caller as an error rather than a timeout, an event delivered once with its key, body, @@ -380,6 +414,9 @@ it, and the beds that need a mesh living on NATS can finally run. held by a `nak`-with-delay cycle still reaches the enrolling node, proving the reply travels in the payload and not the transport field the consumer's ack has claimed. The server-enforced permissions were proved at step 1 and are not re-proved here + — **waiting on one thing only**: an enrolment user composed per live token (3.5). Both links + speak NATS and every claim above has a unit test or a check against a running server behind + it; what no test can stand in for is a mesh raising itself, which is what this bed is - [ ] 4.2 a build source's change reaches the builder over the bus, and the build that follows is the one the change asked for — **blocked by [issue 127](../../04-ISSUES/127-a-module-event-derives-a-subject-nothing-publishes/00-report.md)**