The bus in five steps: a decomposition, a breakdown, and progressive insight #134

Merged
jschoubben merged 6 commits from feat/the-bus-in-five-steps into main 2026-09-26 17:05:44 +00:00
Owner

Divides the NATS bus work into five steps, breaks the work down against a measured surface, and records the rule that let two of the resulting corrections land in the decision itself.

What changed

A new decision — the bus is built in five steps (0115). ADR 0106 described the change as one thing: built beside the migration, cut over once. That left the entire build as a single item ending at nothing runnable until it ended at everything. The five steps each end at a bed; the cutover stays a single rollout.

Dividing it is what surfaced three gaps that were invisible while it was one item:

  • No adoption path. Design 25 described the broker as raised at genesis. The mesh this is for is already running, and takes adoption in place (ADR 0100). The design went straight from "built beside" to "one rollout" and never crossed that gap.
  • The wire changes and its specification did not know. Design 25 §8 said a module sees "nothing new" — true of the SDK contract, false of the wire. Design 19 is the specification ADR 0074 asks for and is written entirely in AMQP; neither document cited the other.
  • The seat. mesh-broker, not the product's name. ADR 0079 named the foundation seats after the server's role precisely so the product could change underneath.

A work breakdown (03-DESIGN/01-to-be/28-building-the-bus.md), in the form design 22 uses: why each step sits where it does, tasks, and a "done when" that names a bed rather than a claim. Written against a measured surface, so no step's size is a guess.

Two measurements changed the plan rather than confirming it:

  • The SDK speaks no AMQP and never did — three mentions, all in comments. Keeping the client out of it (ADR 0039) pays off here: no module is rebuilt and the SDK's own diff is three comments. That is why the bus can be replaced under a live mesh.
  • The wire has three implementations, not two, and no suite pins any of them. The Go side is two packages that mirror rather than share, and a search of all four repositories finds no conformance fixtures at all — design 22's Phase 1.2 is still open.

Progressive insight, written down as a rule (02-DECISIONS/README.md, with AGENTS.md and playbook 02 pointing at it). A record can assert a fact that goes stale while the decision it supports stays right. Superseding for that buries a sound record under a second one and makes every reader work out which is live. So a correction of fact is now made in place, marked and dated, quoting what the text said before — under three conditions, and with judgements still superseding.

How the rule is checked

records.py gains a check: every insight is in the dated marked form, and dated no earlier than the decision. Verified to fire on unmarked prose, an unmarked bold label, a missing date, and a back-dated note. What it cannot catch is an edit with no marker at all — nothing mechanical can, and the README says so and hands that one to the reviewer.

The two insights applied

Both to 0115, both corrections of fact about the state of the code that nobody had measured when it was written:

  1. There is no conformance suite to recapture. Step 3 builds one, and builds it first against the bus the mesh has — a suite born on the new bus would certify whatever the new bus happens to do.
  2. The full genesis bed belongs to step 4. A bed that enrols a node, holds a push and rolls out an upgrade needs the controller and host to speak NATS, which is step 3's implementations. A step whose proof cannot run is the exact failure 0115 was written to prevent, so step 1 now ends at the server standing, configured and carrying nothing.

The five steps, their names, their order and the single rollout are unchanged by both.

While reconciling designs 25 and 28 against the amended record, the server-enforced permission checks moved to step 1 — a plain client proves them with no link required, and they are the whole of what ADR 0043 asks for.

Also indexes design 25, which was never listed in 01-to-be/README.md.

Checks

cycle.py, records.py and index.py all green (290 documents, 105 records).

Not in this branch

Design 25 §5 links a source file by its forge URL, which repos.md forbids in this public repository. Pre-existing and unrelated to this work — left for its own change so it can be swept for properly.

Divides the NATS bus work into five steps, breaks the work down against a measured surface, and records the rule that let two of the resulting corrections land in the decision itself. ## What changed **A new decision — the bus is built in five steps** (`0115`). ADR 0106 described the change as one thing: built beside the migration, cut over once. That left the entire build as a single item ending at nothing runnable until it ended at everything. The five steps each end at a bed; the cutover stays a single rollout. Dividing it is what surfaced three gaps that were invisible while it was one item: - **No adoption path.** Design 25 described the broker as raised at genesis. The mesh this is for is already running, and takes adoption in place (ADR 0100). The design went straight from "built beside" to "one rollout" and never crossed that gap. - **The wire changes and its specification did not know.** Design 25 §8 said a module sees "nothing new" — true of the SDK contract, false of the wire. Design 19 is the specification ADR 0074 asks for and is written entirely in AMQP; neither document cited the other. - **The seat.** `mesh-broker`, not the product's name. ADR 0079 named the foundation seats after the server's role precisely so the product could change underneath. **A work breakdown** (`03-DESIGN/01-to-be/28-building-the-bus.md`), in the form design 22 uses: why each step sits where it does, tasks, and a "done when" that names a bed rather than a claim. Written against a measured surface, so no step's size is a guess. Two measurements changed the plan rather than confirming it: - **The SDK speaks no AMQP and never did** — three mentions, all in comments. Keeping the client out of it (ADR 0039) pays off here: no module is rebuilt and the SDK's own diff is three comments. That is why the bus can be replaced under a live mesh. - **The wire has three implementations, not two, and no suite pins any of them.** The Go side is two packages that mirror rather than share, and a search of all four repositories finds no conformance fixtures at all — design 22's Phase 1.2 is still open. **Progressive insight, written down as a rule** (`02-DECISIONS/README.md`, with `AGENTS.md` and playbook 02 pointing at it). A record can assert a fact that goes stale while the decision it supports stays right. Superseding for that buries a sound record under a second one and makes every reader work out which is live. So a correction of fact is now made in place, marked and dated, quoting what the text said before — under three conditions, and with judgements still superseding. ## How the rule is checked `records.py` gains a check: every insight is in the dated marked form, and dated no earlier than the decision. Verified to fire on unmarked prose, an unmarked bold label, a missing date, and a back-dated note. What it cannot catch is an edit with no marker at all — nothing mechanical can, and the README says so and hands that one to the reviewer. ## The two insights applied Both to `0115`, both corrections of fact about the state of the code that nobody had measured when it was written: 1. **There is no conformance suite to recapture.** Step 3 builds one, and builds it first against the bus the mesh has — a suite born on the new bus would certify whatever the new bus happens to do. 2. **The full genesis bed belongs to step 4.** A bed that enrols a node, holds a push and rolls out an upgrade needs the controller and host to speak NATS, which is step 3's implementations. A step whose proof cannot run is the exact failure 0115 was written to prevent, so step 1 now ends at the server standing, configured and carrying nothing. The five steps, their names, their order and the single rollout are unchanged by both. While reconciling designs 25 and 28 against the amended record, the server-enforced permission checks moved to step 1 — a plain client proves them with no link required, and they are the whole of what ADR 0043 asks for. Also indexes design 25, which was never listed in `01-to-be/README.md`. ## Checks `cycle.py`, `records.py` and `index.py` all green (290 documents, 105 records). ## Not in this branch Design 25 §5 links a source file by its forge URL, which `repos.md` forbids in this public repository. Pre-existing and unrelated to this work — left for its own change so it can be swept for properly.
jschoubben added 3 commits 2026-09-26 16:54:19 +00:00
The NATS change was recorded as one undivided item, which hid three gaps:
a mesh already running had no adoption path, the protocol specification did
not know its transport was being replaced, and nothing was runnable until
everything was. Dividing it is what surfaced them.
Counting the surface first changed the plan twice: the genesis bed cannot run
until the links exist, so it belongs to step 4, and there is no conformance
suite to recapture — step 3 builds one against the current bus before moving
it. Both corrections are recorded in the breakdown rather than edited into
ADR 0115. Also indexes design 25, which was never listed.
A record can assert a fact that goes stale while the decision it supports
stays right. Superseding for that buries a sound record under a second one
and makes every reader work out which is live. So a correction of fact is
now made in place, marked and dated, with the old wording quoted — bounded
by three conditions and checked by records.py, which fires on an unmarked,
undated or back-dated note. Judgements still supersede.

Applied to 0115: no conformance suite exists to recapture, and the full
genesis bed cannot run until the links exist. Designs 25 and 28 follow.
jschoubben added 2 commits 2026-09-26 16:56:36 +00:00
PR #133 landed a different 0115 while this branch was open. The bus record
is now 0116, with every citation in designs 19, 25, 28 and the index
following it.

Note: cycle.py and records.py both fail on main as merged, on that record —
nothing cites it, and it rests on 0112, which is still proposed. Both
pre-date this branch and are left for their own change.
Author
Owner

Rebased onto main. Two things a reviewer should know.

The record is now 0116, not 0115. PR #133 landed a different 0115 while this branch was open, so the bus record renumbered and every citation in designs 19, 25, 28 and the index followed it. The body above still says 0115 throughout — read it as 0116.

Both repository checks fail on main as merged, and neither failure is from this branch. 0115-one-assignment-of-a-module-per-node.md (from #133):

  • cycle.py — an accepted decision nothing in the cycle cites. No design's decisions: names it. It extends 0112, which design 27 already cites, so design 27 looks like its intended home; #132 amended that document in the same batch without adding the record to its frontmatter.
  • records.py — rests on ADR 0112, which is 'proposed'. A record may not rest on one that is not accepted, and 0112 is still proposed.

Verified both against a clean origin/main worktree: they reproduce there with this branch nowhere in sight. Left alone rather than bundled in here, per one change per pull request — happy to open a small separate PR for both if that's wanted.

Rebased onto main. Two things a reviewer should know. **The record is now 0116, not 0115.** PR #133 landed a different `0115` while this branch was open, so the bus record renumbered and every citation in designs 19, 25, 28 and the index followed it. The body above still says 0115 throughout — read it as 0116. **Both repository checks fail on main as merged, and neither failure is from this branch.** `0115-one-assignment-of-a-module-per-node.md` (from #133): - `cycle.py` — *an accepted decision nothing in the cycle cites*. No design's `decisions:` names it. It extends 0112, which design 27 already cites, so design 27 looks like its intended home; #132 amended that document in the same batch without adding the record to its frontmatter. - `records.py` — *rests on ADR 0112, which is 'proposed'*. A record may not rest on one that is not accepted, and 0112 is still proposed. Verified both against a clean `origin/main` worktree: they reproduce there with this branch nowhere in sight. Left alone rather than bundled in here, per one change per pull request — happy to open a small separate PR for both if that's wanted.
jschoubben added 1 commit 2026-09-26 17:05:38 +00:00
jschoubben merged commit db4ca9b043 into main 2026-09-26 17:05:44 +00:00
jschoubben deleted branch feat/the-bus-in-five-steps 2026-09-26 17:05:44 +00:00
Sign in to join this conversation.
No Reviewers
No labels
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: novox/hq#134