The operator accepted both on 2026-10-09. Design 47's state table gains covered and what ends a held delivery by itself, and its group the wait for a composed check and the lift; design 45's signals table gains S17 and its planned bus step says the wait is told at once. The glossary's delivery entry names its six final states.
16 KiB
layer, status, code, updated, decisions
| layer | status | code | updated | decisions | |||||||
|---|---|---|---|---|---|---|---|---|---|---|---|
| to-be | designed | 2026-10-09 |
|
47 — Delivery: from a commit to delivered
A delivery is one commit in one repository, from the moment its pull request's head is announced to the
moment every machine of its deploy plan runs it, or to the moment it fails, is superseded or is stopped. A
delivery group is two or more deliveries that share a head branch name, delivered as one unit in order. Both
are owned by one module, mesh-delivery, which records every step and asks the controller for each act.
(ADR 0239.)
This is the delivery of to-be 10 carried out. To-be 10 says what is built: the comparison of source and artifacts decides, and nothing here changes that. This design says who answers for one commit's journey and in what order the steps are allowed.
The parts
forge's holder ──pull.updated / .merged / .closed──► mesh-delivery ◄──checked / plan-moved── controller
(statuses, the view, (deliveries, groups, (planner, gate,
the notes) the table, its state) registration,
▲ │ │ sending, walk)
└── its tools: note, view, status ◄───────────────┘ └── its verbs: delivery-plan, -order,
-check, deliver, delivery-stop,
delivery-walks
- The controller stays the only writer of what it owns: machine declarations, bus objects, grants, registration. It keeps the primitives: the planner (one function, ADR 0238 decision 3), the gate, the trunk rule, a gated send, the rollback and the walk of one trunk commit's tiers across machines. It still answers every pull request's head with its check itself, so a check never depends on mesh-delivery.
- mesh-delivery is a Go bundle holding the mesh-scoped seat
mesh-delivery. It owns the delivery, the group, the state table and their state, and nothing else. - The forge's holder sets a commit's statuses, keeps the delivery's view as one comment on the pull
request, and appends to the commit's note under
refs/notes/mesh-plan. - The build seat builds and checks, asked by the controller as before.
A delivery
Its id is <owner>/<repository>@<twelve characters of its commit>. It holds:
- the pull request (number, base, head branch, description), or none for a commit that reached the trunk without one;
- its delivery plan: build plan, deploy plan and verdict, as the controller's planner computed them for its diffset (what ADR 0238 called the "change plan", under the glossary's name);
- its state, its transitions (the last hundred, each with when, the event, from, to and why), and its machine steps while delivering;
- once merged, the commit it landed on the trunk as, and the walk that delivers it.
The state table
One table, compiled into mesh-delivery, read by its code, its test, its table verb, the controller's
self-check and healer H2. Each state has a bound: how long it may be held before stalled lists it.
Each state also says what H2 may do after the bound, which is only ever a transition the table already
allows.
| State | Means | Bound | H2 after the bound |
|---|---|---|---|
| proposed | a head was announced and is being checked | 1 hour | nothing: the check's own watchdog (S6) speaks |
| checked | a verdict arrived | 1 minute | nothing: it is decided at once |
| ready | it passed; it waits to be merged | none | — |
| rejected | it failed its check | none | — |
| published | merged on the trunk its modules follow, its walk opened and asking nothing; it waits for its turn or its word | 30 minutes | superseded when a newer delivery took over its walk; go when its walk started |
| held | it waits for a person; read again each tick, so it ends by itself when it moves nothing or a later merge covers it (ADR 0270) | 1 day | nothing: it is the operator's |
| delivering | its walk runs; its builds are asked and registered tier by tier | 2 hours | delivered, failed or superseded, as the walk's record says |
| delivered, failed, superseded, stopped, retired, covered | final | — | — |
The transitions are those of ADR 0239 decision 2 and ADR 0270. A delivery that is
merged while not ready goes to held. Its check did not pass, and only a person decides that it goes on. A
delivery merged with no walk opened for it within ten minutes is held too, saying so: nothing it moves follows
that branch, or the merge was not heard. Nothing waits silently.
What needs no person ends by itself (ADR 0270):
- a merge that moves nothing (its plan builds nothing, or only adds a module the controller builds and
sends nowhere) is
deliveredas soon as it is merged, whatever its check said; - a merge a later delivered merge contains is
covered: every module it moves was sent to every machine running it by the walk of a later merge into the same trunk, delivered on its own passing check, and the forge says that later merge commit contains it (gitea_contains, asked once per pair and kept). Merge order is only the first filter, and a forge that cannot answer means not yet covered.mesh/deliverysayscovered: a later merge that contains it was deliveredas a success. A module that runs on one machine only gets no "rest" step and is never covered; - the covered row is tried before
go, fromheldand fromreadypast the ten minutes.
History is retired, not held (ADR 0250).
A delivery made from the forge's word at its merge, heard fifteen minutes or more after that merge, with no walk
of it open, was replayed from the bus's history: it reached the machines before this owner was there. It goes
to retired at adoption, before any check, hold or walk, and its pull request is not told. A held delivery that
fits the same rule is retired by a person's retire-history, never released. Nothing of a published delivery is registered before its walk
starts, because a send carries every registered build that waits on its machine (ADR 0236 §4a), and a
build registered before its turn would be carried by somebody else's send.
The machine steps. While a delivery is delivering, each machine its walk reaches has a row with the
module and the build: sent (the first machine's send, or the rest's), judging (the gate's healthy
readings so far), passed, failed, rolled-back. They are read from the walk's own record in the
controller's plan-moved event, never inferred from time.
A delivery group
- Membership: the pull request's head branch name, across the mesh's repositories, among open pull requests. Two or more make a group. A group that has started delivering takes no new member.
- Order:
after: <repository>lines in a member's description, and the controller'sdelivery-orderover the graph (ADR 0239 decision 4). The plan shows the order and why each pair is ordered: declared, built by, version skew, engine before controller, by name. - Precedence (ADR 0249): when rules order one pair both ways, the higher one decides. Declared comes
first, then built by and version skew, then engine before controller. The pair shows the rule that
won and the rules it won over. Rules of one rank both ways are a contradiction. The group is
rejected, and the reason names both members, both rules and theafter:line that would settle it. - Check: the members' heads composed together, one gate over every machine with all their definitions. It
is asked by mesh-delivery through
delivery-checkwhen the group forms or a member's head moves, and posted on every member's head asmesh/delivery-group. - Delivering: in order. A member waits in
publisheduntil the one before isdeliveredorcovered. A member published while its group's composed check is asked and not answered waits there for the answer; one held because that check had not passed is lifted back topublishedonce it passes or warns for the heads that merged and its own walk is still open (ADR 0270). - A failed member: the members after it are
stopped, naming it. The members before it stay delivered. Its own builds were put back at its gate.
A group's state is derived from its members and its composed check, and is shown, never stored apart from them.
What every transition does
In this order, each by its owner:
- kept: mesh-delivery puts the delivery in its state (
deliveries, one key per delivery;groups, one key per group). Nothing is said before it is kept. What it owes outside is kept with it and retried, later each time, from ten seconds doubling to an hour. The forge's answer that what it is for does not exist ends it at once, and sixty failed tries end it too, each said among the owner's refusals (ADR 0250); - said: the event
mesh-delivery.transition(andmesh-delivery.groupwhen a group's derived state changes), with the delivery's id, from, to, event, why and plan summary, and no secret or address; - noted: mesh-delivery asks the forge's holder (
gitea_note_append) to append a line to the commit's note: the head while the delivery is off the trunk, the commit it landed as once it is on it, and at its end a line of what was executed there. The forge's holder writes it in its own repository as the forge's own account, and a line already there is not appended again; - reflected (not for history, whose pull request the forge may no longer hold): the delivery's view, one comment on the pull request with the state, the plan, the machine
steps and the group, kept current (
gitea_delivery_view); the statusmesh/deliveryon the head, andmesh/delivery-groupon every member's head (gitea_commit_status). Every status links to the pull request,mesh/merge-gateamong them.
The verbs
mesh-delivery's seat (served by its holder; the first five read):
| Verb | Answers or does |
|---|---|
deliveries |
every delivery not final, and the final ones of the last day, one line each; filtered by state, repository or group |
show |
one delivery or group whole: plan, transitions, machine steps, order, the walk |
groups |
every group with its members in order and its derived state |
what-if |
the delivery plan a diffset would have, asked of the controller's planner, kept nowhere |
table |
the state table and the machine-step table, with bounds and H2's repairs |
stalled |
every delivery held past its bound, with the transition H2 may take |
recheck |
a rejected or ready delivery back to proposed, with why |
release |
a held delivery to delivering, with why: a person's word |
stop |
any delivery not final to stopped, with why; its walk is ended through the controller |
close |
H2's only verb: the transition the table names for a stalled delivery, refused otherwise |
retire-history |
held history to retired, with why: one by id, refused when the rule does not take it, or every held one, answering how many and naming those it left; dry changes nothing |
The controller's verbs for it (on the mesh-controller seat): delivery-plan, delivery-order,
delivery-check (a group's heads composed, or one head checked again), deliver, delivery-stop,
delivery-walks. A person has plans go <plan> --why, which does what deliver does under their name and
is recorded as a hand act. The controller says every walk it keeps as plan-moved, from a verb's command
too.
The forge's holder's tools for it: gitea_note_append, gitea_delivery_view, gitea_commit_status. It
also announces pull.closed, and a merge's head and the statuses the forge holds on it.
The store
Key-value state on the bus, declared by the module (ADR 0201): deliveries and groups. One writer, the
seat's holder, whose code changes state from a single goroutine. A final delivery is kept for thirty days and
then removed. Its note on the commit keeps its record after that. The bus's own snapshot (ADR 0235) backs it
up.
The bootstrap
- A walk that moves the controller, the node-engine, the tool runner, the bus or mesh-delivery is the controller's own, started by the merge and witnessed on the machine. mesh-delivery records it.
- Any other walk waits for
deliveronly while the seat has a holder on record. With none on record, the controller starts it as it always did. - A waiting walk is said by the controller whatever mesh-delivery says of itself: S16 raises
plan.<walk>.waitingafter 30 minutes, urgent after 4 hours, namingplans go <walk> --whyas the way on. A holder that is down is also D3'sholder-silent; one that is up and never says go is said by S16 alone.
The switch
- The controller's change (the seat, its verbs,
plan-moved, the wait for a holder's word,plans go) is merged and rolls out as the core does. With no holder on record it behaves exactly as before. - The catalogue's change (mesh-delivery, the forge holder's notes and view) is merged. mesh-delivery is built and published.
- A person assigns mesh-delivery to the control node. The seat now has a holder on record. Walks that start
from then on wait for its word. Walks already open finish on their own and are adopted as deliveries in
delivering. - To step back, unassign it. Waiting walks are then started by the controller at its next pass.
Phases
| Phase | Delivers | Done when |
|---|---|---|
| A — the owner | mesh-delivery with its table, state, verbs, events and adoption; the controller's seat, verbs, plan-moved and the wait; the forge holder's view, notes and statuses; the group's order and composed check |
the tests of ADR 0239's How it is checked pass; a merge on the live mesh with mesh-delivery held is delivered by it and shown by deliveries |
| B — the conditions | S16, the controller's own plan.<walk>.waiting; probe D14 reads stalled and raises delivery.<id>.stalled; H2 calling close — built 2026-10-07, on a branch |
a delivery stalled on purpose is raised and closed by H2 through close; a walk never let go is raised by S16 |
| C — the walk itself | the per-tier walk moved into mesh-delivery behind single-send verbs, the controller's planner kept only for the built-in path | decided by its own record once Phase A has delivered for a while |
What is not decided here
- A web view of deliveries beyond the pull request's comment.
- Whether
mesh/delivery-groupis required on the trunks. That is the operator's setting, through the forge module's protection tool. - Moving the per-tier walk out of the controller (Phase C).