ADR 0236: no build reaches a machine without a gate, and a release plan walks what waits
The coordinator's review: at the switch to roll, every send would carry the old default's backlog unjudged. Measured: 88 of the 103 rebuilt modules were byte-identical, and no build waited on any machine.
This commit is contained in:
+37
-2
@@ -126,6 +126,39 @@ resulting policy of every module the mesh held on 2026-10-06:
|
||||
The private network itself is provided by the controller and moves only with it; the modules that run on
|
||||
no machine move nothing.
|
||||
|
||||
**4a. No build reaches a machine without a gate — the backlog included.** A send carries a machine's
|
||||
whole declaration, so a plan sending one module, a cascade, a healer's resend or a whole-mesh push would
|
||||
carry every other build waiting there. Under the old default builds were registered and sent nowhere;
|
||||
on the day the default becomes `roll`, the next send of anything would restart them all at once, on every
|
||||
machine. So:
|
||||
|
||||
- **a gated send carries everything waiting on its machine, and its gate judges all of it** — a plan's
|
||||
first machine, a release plan's machine; a pass is each build's verdict, a failure puts back what was
|
||||
found wanting, on the machines that were sent it;
|
||||
- a module a send exists for may move where it goes — a policy of *together*, a rollback; a build that
|
||||
passed a gate on one machine may go to the others;
|
||||
- a person's send naming a machine (`push <node>`, the bus step) carries what it carries;
|
||||
- **every other send is refused, or leaves the machine, while a build no gate has seen waits there** —
|
||||
a plan's "rest", a cascade, a healer's, a whole-mesh push, the bus's user list carried — said with what
|
||||
waits and the remedy;
|
||||
- **a rebuild that made the same artifacts from the same manifest is no move.**
|
||||
|
||||
**The release plan walks what waits.** Whenever builds no gate has seen wait on machines and no plan that
|
||||
has started walks them, the mesh opens a release plan: every such machine heard from, **one at a time,
|
||||
the control node last**, each sent everything waiting there and judged by the gate before the next is
|
||||
sent. A machine not heard from when its turn comes is left. A build asked outside a plan (a `rebuild`)
|
||||
waits for it too, instead of being sent one machine after another unjudged. **A release plan that fails
|
||||
puts back what failed and stops; the next one opens only when a person says `upgrade release-backlog
|
||||
--why`**, and until then `release-held` says what waits. `upgrade backlog` lists it, read-only.
|
||||
|
||||
Chosen over holding the whole backlog for a person's release (safer by one human glance, but every
|
||||
merge after the switch would then stall behind it) and over waves of a few modules (a send cannot carry
|
||||
part of a declaration — ADR 0221's second option — so the bound that can be kept is one machine at a
|
||||
time, which is the one kept). Measured on 2026-10-06 at the switch: the catalogue merge that rebuilt
|
||||
103 modules for a change to the build agent made **88 of them byte-identical** to the builds before
|
||||
(no move) and 15 different; every machine had already been sent all of them by hand that evening, so
|
||||
**no build waited on any of the four machines** when this was decided.
|
||||
|
||||
**5. The controller's rollback is the node-engine's on its machine; the contract is written once on
|
||||
each side.** mesh-controller `internal/lease/witness.go` and mesh-host `internal/witness/contract.go`,
|
||||
held field for field:
|
||||
@@ -200,8 +233,9 @@ not say which files went, marks the module deleted in its plan, which goes on.
|
||||
node-engine reports container state, which is mesh-host's to add. A build whose migration cannot be
|
||||
undone is put back all the same; marking such a build `not-reversible` for the witness is not composed
|
||||
yet.
|
||||
- **A build asked by hand that rolls out** (a `rebuild` outside a plan) is still sent one machine at a
|
||||
time by the upgrade handler, without the gate; only plans are gated.
|
||||
- **A merge after a release plan failed may stall** on a machine where a build waits for the person's
|
||||
release: its first send carries and judges what waits there, but its "rest" waits. Said in the plan
|
||||
and by `release-held`.
|
||||
- **Rollout order**: mesh-host first (its genesis user list, and the witness, which reads nothing the
|
||||
controller does not yet grant until then); the controller second, whose migration turns the store's
|
||||
default `record` rows into no choice; the catalogue third — its manifests carry `upgrade`, which a
|
||||
@@ -217,6 +251,7 @@ not say which files went, marks the module deleted in its plan, which goes on.
|
||||
| the health definitions | the controller's test per component: tools not served, a condition since the send, a witness's verdict, node tools not answering, a lease held by an older controller or one not ready |
|
||||
| the policy | the catalogue's test: default roll, a module's word, irreplaceable data, the bus whatever it says; a record without why refused; the store's test: the current builds read the derived policy |
|
||||
| the bus is never rolled out | the controller's test: the bus records whatever it says, a person's roll-out is refused, a plan sends nothing, no send may reach its machine while a new bus build waits — a rebuild with the same artifacts and manifest excepted — the step refuses without its word on reversibility and without its snapshot, and starts with both |
|
||||
| no build without a gate | the controller's test: the backlog released one machine at a time, the first judged before the second is sent, each pass kept, a rebuild with the same bytes no move, a send that judges nothing refused; a release that fails puts back what it carried on its first machine, goes no further, holds the next until a person releases it with why; a cascade does not carry a build no gate has seen, and does once one passed |
|
||||
| a deleted module is not built | the controller's test: a merge deleting a module's manifest asks no build and forgets it; a build finding no manifest leaves the plan going |
|
||||
| the witness's contract | the lease package's test of the host's rule; the broker's test of the grants (the ping on every machine, the lease's key where the controller runs, no write); the controller's test that a witness's verdict is its condition while reports carry it and cleared after |
|
||||
| live | the next merge to the catalogue sends one machine first and the rest after its gate, with no push; `plans <id>` shows the gate's record; the next week's hand-act log has no push for a build that rolled out |
|
||||
|
||||
@@ -445,6 +445,11 @@ the other machines follow. "Reported applied" is not enough.
|
||||
the gate sending the previous build. A witness says its verdict in `rollbacks` on every report while it
|
||||
stands; the controller raises `core.<component>.<machine>.<outcome>` from it — urgent for rolled-back,
|
||||
not-reversible, restore-failed and halted — and clears it with the first report without it.
|
||||
- **No build reaches a machine without a gate**: a gated send carries and judges everything waiting on
|
||||
its machine; every other send — a plan's rest, a cascade, a healer's, a whole-mesh push — is refused
|
||||
or leaves the machine while a build no gate has seen waits there; a rebuild with the same artifacts and
|
||||
manifest is no move. What waits is walked by a **release plan**, one machine at a time, the control
|
||||
node last, each judged; one that fails holds the next until `upgrade release-backlog --why`.
|
||||
- **A new controller that passes its gate sends the bus's machine the user list it composes**, when that
|
||||
changed and nothing held back would go with it.
|
||||
- **The default policy is to roll** (ADR 0236 §4); `record` stays where a module says why, keeps
|
||||
@@ -623,8 +628,7 @@ installer's grants. In mesh-catalog, the modules that keep `record` say why, and
|
||||
says which files a merge deleted. On branches, not yet merged. **Not yet:** R3, R7, R8 on a lab mesh, and
|
||||
so the *done when*; container state in the node-engine's report, without which a container that
|
||||
crash-loops after its compose applied is seen only through what it breaks; composing `not-reversible` for
|
||||
a build whose migration cannot be undone; the gate for a build asked by hand outside a plan; the next
|
||||
three core rollouts' verdicts.
|
||||
a build whose migration cannot be undone; the next three core rollouts' verdicts.
|
||||
|
||||
### Phase 5 — Checks before merge, and the replays
|
||||
|
||||
|
||||
Reference in New Issue
Block a user