ADR 0239 and to-be 47: as built — registered at the walk's start, the forge asked through its tools
mesh/merge-gate pass: the change touches no module of the mesh's graph
mesh/delivery delivered
mesh/merge-gate pass: the change touches no module of the mesh's graph
mesh/delivery delivered
A build registered before its turn is carried by the next send to its machines, so a published delivery asks nothing until its walk starts; the rows the build needed (appeared, adopted, held on no walk, held then go) and Phase B's verbs-without-probe are now said.
This commit is contained in:
+76
-30
@@ -113,6 +113,18 @@ A second linking mechanism would be a second graph to keep acyclic and to show.
|
||||
records the verdict as the delivery's `checked` and asks only for what the controller cannot know: the
|
||||
group's composed check.** Chosen.
|
||||
|
||||
**When a published delivery's builds are registered.**
|
||||
|
||||
1. *At the merge, as before, and the walk held back until its turn.* Rejected. A send carries a machine's
|
||||
whole declaration, and a gated send carries every registered build that waits on its machine
|
||||
([ADR 0236](0236-a-build-is-judged-on-its-first-machine-and-put-back-by-something-other-than-itself-and-so-it-rolls-out-unattended.md)
|
||||
§4a). A build registered before its turn would reach the machines with the next send of anything else
|
||||
there. The group's order would be broken by a send nobody made for it, and a catalogue member registered
|
||||
ahead of its controller is the version skew the order exists to prevent.
|
||||
2. **When its walk starts.** Chosen. The merge opens the walk and asks nothing. Its first tier is asked when
|
||||
the delivery's word comes, and a later tier is asked once the earlier one runs, as before. `published` is
|
||||
the trunk commit accepted with its walk opened and waiting. Its builds are registered in `delivering`.
|
||||
|
||||
**Where a delivery is kept.**
|
||||
|
||||
1. *A database from the store's provider.* Rejected. It would make mesh-delivery depend on a provider whose
|
||||
@@ -145,6 +157,9 @@ walks the table. Each state carries its bound and what healer H2 may do once the
|
||||
|
||||
| From | Event | To | Guard |
|
||||
|---|---|---|---|
|
||||
| (none) | announced | proposed | a pull request's head the forge announced |
|
||||
| (none) | appeared | held | a trunk commit whose walk waits, with no pull request known: merged before the seat was held, or pushed to the trunk |
|
||||
| (none) | adopted | delivering | a walk already running: at the switch, or on the controller's own path |
|
||||
| proposed | checked | checked | the verdict names this commit |
|
||||
| checked | accepted | ready | the gate passed or warned; the repository's own check did not fail |
|
||||
| checked | refused | rejected | the gate failed or could not run |
|
||||
@@ -152,25 +167,33 @@ walks the table. Each state carries its bound and what healer H2 may do once the
|
||||
| ready | recheck | proposed | a person asked, or its group changed |
|
||||
| proposed, checked, ready, rejected | new head | superseded | a newer head of the same pull request |
|
||||
| proposed, checked, ready, rejected | closed | stopped | the pull request closed unmerged |
|
||||
| ready | merged | published | the commit is on the trunk its modules follow; its first tier's builds are registered |
|
||||
| proposed, checked, rejected | merged | held | merged without a passing check: waits for a person |
|
||||
| published | go | delivering | the order of its group allows it; nothing holds it |
|
||||
| published | hold | held | the release backlog, a bus step, a module whose policy records, or a group member before it that did not deliver |
|
||||
| ready | merged | published | merged on the trunk its modules follow, and its walk opened; or nothing for a walk to move |
|
||||
| proposed, checked, rejected | merged unchecked | held | merged without a passing check; a verdict known with it is taken first |
|
||||
| published | done | delivered | nothing for a walk to move |
|
||||
| published, ready | hold | held | merged, and its group's composed check did not pass for the heads that merged, or no walk was opened for it within ten minutes |
|
||||
| published | go | delivering | its walk started: let go by this owner in its group's order, by a person, or on the controller's own path |
|
||||
| held | go | delivering | its walk started on a word that was not this owner's: the controller's own path, or a person's `plans go` |
|
||||
| held | release | delivering | a person's decision, with why |
|
||||
| delivering | done | delivered | every machine of its deploy plan passed or was left as its policy says |
|
||||
| delivering | gate failed | failed | a first machine's gate failed; what it carried was put back (ADR 0236 §3) |
|
||||
| delivering | failed | failed | its walk failed: a first machine's gate (what it carried put back, ADR 0236 §3), a build, a machine |
|
||||
| delivering | stop | stopped | its walk was stopped through this owner |
|
||||
| published, delivering | superseded | superseded | a newer delivery to the same trunk took over its walk (ADR 0218) |
|
||||
| any state not final | stop | stopped | a person, with why |
|
||||
| any state not final | stop | stopped | a person, with why, or its group stopped by a member before it |
|
||||
|
||||
`delivered`, `failed`, `superseded` and `stopped` are final. A delivery never goes back to a state before
|
||||
`published` once it has left one. Inside `delivering`, each machine has its own row in a second table:
|
||||
`sent` → `judging` → `passed` | `failed`, `failed` → `rolled-back`. These are read from the walk's own
|
||||
record (rule 7), never guessed.
|
||||
`published` once it has left one. A row is either *observed*, taken whenever its guard holds, or an *act*,
|
||||
taken only when a person or healer H2 asks (recheck, release, stop). The observed rows are taken in the
|
||||
table's order until none holds. A delivery therefore stands where its facts put it, whatever order the facts
|
||||
arrived in. Inside `delivering`, each machine has its own row in a second table: `sent` → `judging` →
|
||||
`passed` | `failed`, `failed` → `rolled-back`. A step may pass through states between two readings of the
|
||||
walk. A move the table does not reach, such as `passed` → `failed`, is refused. Steps are read from the
|
||||
walk's own record (rule 7), never guessed.
|
||||
|
||||
**3. The trunk rule ([ADR 0238](0238-a-commit-is-the-build-at-hand-one-commit-one-change-plan-checked-off-the-trunk-and-published-only-on-it.md)
|
||||
decision 1) is the guard on `published`.** A commit off the trunk can reach `ready` and no further. Anything
|
||||
built to check it is built in a scratch namespace of the artifact store that registration refuses. Only a
|
||||
commit on the trunk is published, and only a published delivery is delivered.
|
||||
decision 1) is the guard on `published`.** A commit off the trunk can reach `ready` and no further, and the
|
||||
walk that publishes it exists only for a merge into a branch a module follows. Only a commit on the trunk is
|
||||
published, and only a published delivery is delivered. A check builds nothing today. When one does, what it
|
||||
builds goes under a scratch namespace of the artifact store that registration refuses.
|
||||
|
||||
**4. A delivery group.**
|
||||
|
||||
@@ -205,22 +228,33 @@ commit on the trunk is published, and only a published delivery is delivered.
|
||||
all are; `failed` or `stopped` when a member is. Nothing writes a group's state except this derivation.
|
||||
|
||||
**5. Every transition is said four ways, and the owner of each says it.** mesh-delivery keeps the transition
|
||||
in its state before anything else. It emits it as the event `mesh-delivery.transition`, with no secret and no
|
||||
address. It asks the forge's holder to append it to the commit's note under `refs/notes/mesh-plan`: predicted
|
||||
on the head, executed on the commit it landed as. It also asks the forge's holder to reflect it in the
|
||||
delivery's view, one comment on the pull request kept current, which every status of the commit links to as
|
||||
its `target_url`, `mesh/merge-gate` among them. The forge's holder writes notes as the mesh's own forge
|
||||
account, appending: running twice adds nothing.
|
||||
in its state before anything else, and does nothing else for it until it is kept. What it owes outside is
|
||||
kept with the delivery and retried until done:
|
||||
|
||||
- the event `mesh-delivery.transition` (a group's change of state: `mesh-delivery.group`), with no secret and
|
||||
no address;
|
||||
- a line on the commit's note under `refs/notes/mesh-plan`, asked of the forge's holder (`gitea_note_append`).
|
||||
The line goes on the head while the delivery is off the trunk, on the commit it landed as once it is on it,
|
||||
and at its end with what was executed. The forge's holder appends it in its own repository as the forge's
|
||||
own account. A line the note already holds is not appended again;
|
||||
- the delivery's view, one comment on the pull request kept current (`gitea_delivery_view`);
|
||||
- the status `mesh/delivery` on the head, and `mesh/delivery-group` on each member's head
|
||||
(`gitea_commit_status`).
|
||||
|
||||
Every status links to the pull request where the view is, `mesh/merge-gate` among them. The forge's holder
|
||||
also says when a pull request closes unmerged (`pull.closed`), and says the head and its statuses with a
|
||||
merge.
|
||||
|
||||
**6. The boundary.** mesh-delivery never sends to a machine, never writes a declaration, a bus object or a
|
||||
grant, and never registers a build. It asks:
|
||||
|
||||
- **the controller**, through the seat's verbs: `delivery-plan` (the planner's one answer for a diffset),
|
||||
`delivery-order`, `delivery-check` (compose a group's heads), `deliver` (let one published trunk commit's
|
||||
walk start), `delivery-stop` (end a walk, with why), `delivery-walks` (the walks and their steps);
|
||||
`delivery-order`, `delivery-check` (compose a group's heads, or check one head again), `deliver` (let one
|
||||
published trunk commit's walk start), `delivery-stop` (end a walk, with why), `delivery-walks` (the walks
|
||||
and their steps);
|
||||
- **the build seat**, through the controller's `delivery-check`. A group's check is a check ask like any
|
||||
other;
|
||||
- **the forge's holder**, through events it consumes: the notes and the delivery's view.
|
||||
- **the forge's holder**, through its tools: the notes, the view and the statuses.
|
||||
|
||||
The controller keeps composition, registration, the trunk rule, sending, the gate, the rollback and the walk
|
||||
of one commit's tiers across machines, and says each step of a walk as the event `plan-moved`.
|
||||
@@ -250,8 +284,10 @@ be repaired:
|
||||
broken mesh-delivery is checked, merged and delivered without it.
|
||||
|
||||
**9. Durable across restarts.** The state is mesh-delivery's key-value state. A restarted holder reads it back
|
||||
before it takes an event. It then reconciles from the controller's `delivery-walks` and the forge's open pull
|
||||
requests, so an event missed while it was down is found by comparison, never lost. A state held past its
|
||||
before it takes an event. It then reads the controller's `delivery-walks`, and again every half minute, so a
|
||||
walk's move it missed while it was down, or one a command made that says nothing, is found by comparison and
|
||||
never lost. A pull request merged while it was down is made a delivery from the forge's word: its head and
|
||||
the statuses the forge holds on it. A state held past its
|
||||
bound is listed by `stalled`. The controller's self-check reads that list and raises
|
||||
`delivery.<delivery>.stalled`. **Healer H2 works from the table**: it closes a stalled delivery only by a
|
||||
transition the table allows for that state (`superseded` when a newer delivery took over, `delivered` when
|
||||
@@ -274,14 +310,22 @@ waiting for mesh-delivery. Unassigning mesh-delivery returns the mesh to the con
|
||||
- **A merge no longer sends anything until mesh-delivery says so** while it is held, except the core and
|
||||
mesh-delivery itself. A down mesh-delivery means walks wait, said as a condition. A person can still deliver
|
||||
by hand.
|
||||
- **The controller gains six verbs and one event and loses no primitive.** Its release planner's lifecycle,
|
||||
- **The controller gains six verbs, one event (`plan-moved`, in the installer's first user list too) and a
|
||||
`go` for `plans`, and loses no primitive.** Its release planner's lifecycle,
|
||||
supersession and hold decisions remain its code until mesh-delivery is held. After that they run only on the
|
||||
built-in path. Removing them is a later decision, once mesh-delivery has delivered for a while.
|
||||
- **The forge's holder gains the notes and the view.** It needs git on its machine for notes, declared as a
|
||||
package of its module.
|
||||
- **The forge's holder gains the notes, the view and two statuses.** A note is written inside the forge's own
|
||||
container, in the bare repository, as the forge's user. The forge's API reads notes and writes none, and a
|
||||
push from anywhere else would need a credential to the forge that nothing else should hold.
|
||||
- **A module named as its seat says its events as itself.** A consumed `<seat>.<event>` names the seat's event
|
||||
only when the seat emits it. Otherwise it names the event of the module of that name (`mesh-delivery.transition`).
|
||||
The controller derives subscriptions by that rule.
|
||||
- **What is not built by this record**: porting the walk itself into mesh-delivery (option 1 of *where the walk
|
||||
runs*); a web view of deliveries beyond the pull request's comment; requiring `mesh/delivery-group` on the
|
||||
trunks, which is the operator's setting through the forge module's protection tool.
|
||||
runs*); the controller's self-check reading `stalled` and raising `delivery.<delivery>.stalled`, with H2
|
||||
calling `close`, which is to-be 47's Phase B (the verbs exist and are tested, the probe does not); a web view
|
||||
of deliveries beyond the pull request's comment; requiring `mesh/delivery-group` on the trunks, which is the
|
||||
operator's setting through the forge module's protection tool; the scratch namespace, until a check builds
|
||||
something.
|
||||
|
||||
## How it is checked
|
||||
|
||||
@@ -293,8 +337,10 @@ waiting for mesh-delivery. Unassigning mesh-delivery returns the mesh to the con
|
||||
| the trunk rule | mesh-delivery's test that an off-trunk commit never reaches published; the controller's publish-rule test (ADR 0238) |
|
||||
| a group's membership, order, composed check and clean stop | mesh-delivery's group tests: by branch name, declared and inferred order, a cycle rejected, ready only when all are, a failed member stopping those after it and leaving those before it delivered |
|
||||
| a restart resumes | mesh-delivery's test that a holder restarted over the same state resumes each delivery and reconciles a walk it missed |
|
||||
| the bootstrap rule | the controller's tests: a walk moving a core module or mesh-delivery never waits; another waits only while the seat has a holder on record; `plans go` and `push` deliver with mesh-delivery down |
|
||||
| the inferred order | the controller's `delivery-order` test over the real dependency relation: toolchain first, controller before a manifest change, node-engine before controller |
|
||||
| the bootstrap rule | the controller's tests: a walk moving a core module or mesh-delivery never waits; another waits only while the seat has a holder on record and asks no build while it waits, so a push carries nothing of it; `plans go` starts it with mesh-delivery down, with why, recorded as a hand act; unassigned, the mesh is back on the controller's own path |
|
||||
| the inferred order | the controller's `delivery-order` test: built by, version skew, engine before controller, declared, by name the same on every reading, and a contradiction named as a cycle |
|
||||
| a group is checked as one future state | the controller's gate test: a catalogue change needing a provision only another repository's change adds fails alone and passes composed with it; the builder's check test, on a container runtime, clones a group's other head and hands it to the gate, and runs no member's own script |
|
||||
| a walk moved by a verb is said | the controller's test that `delivery go`, run as a command of its own, says `plan-moved` on the bus |
|
||||
| every transition is persisted, said, noted and reflected | mesh-delivery's test that each transition is put before it is emitted; the forge module's note test (append-only, idempotent) and view test (statuses carry its link) |
|
||||
| the seat is in the set and its holder is one | the controller's seat test; the catalogue's manifest test of mesh-delivery |
|
||||
| live | the next merge with mesh-delivery held waits for `deliver`, and `deliveries` shows it from head to delivered; `git log --notes=mesh-plan` shows the note on its merge commit |
|
||||
|
||||
@@ -25,12 +25,13 @@ commit's journey and in what order the steps are allowed.
|
||||
## The parts
|
||||
|
||||
```
|
||||
forge's holder ──pull.updated / pull.merged──► mesh-delivery ◄──plan-moved / checked── controller
|
||||
(statuses, the view, ▲ (deliveries, groups, (planner, gate,
|
||||
the notes) │ the table, its state) registration,
|
||||
▲ │ │ sending, walk)
|
||||
└──── transition ────────┴───────────────────────┘── verbs: delivery-plan, -order, -check,
|
||||
deliver, delivery-stop, delivery-walks
|
||||
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,
|
||||
@@ -68,13 +69,17 @@ allows.
|
||||
| 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 first tier registered; it waits for its turn or its word | 30 minutes | `superseded` when a newer delivery to the same trunk took over its walk |
|
||||
| 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 | 1 day | nothing: it is the operator's |
|
||||
| delivering | its walk runs | 2 hours | `delivered` when the walk's record says done; `superseded` when a newer walk closed it |
|
||||
| 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 | final | — | — |
|
||||
|
||||
The transitions are those of ADR 0239 decision 2. 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.
|
||||
`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. **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
|
||||
@@ -103,15 +108,18 @@ them.
|
||||
In this order, each by its owner:
|
||||
|
||||
1. **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;
|
||||
2. **said**: the event `mesh-delivery.transition`, with the delivery's id, from, to, event, why and plan
|
||||
summary, and no secret or address;
|
||||
3. **noted**: the forge's holder, hearing it, appends a line to the commit's note: the head while the
|
||||
delivery is off the trunk, and the commit it landed as once it is on it. It appends as the mesh's own forge
|
||||
account, and a line already there is not appended again;
|
||||
4. **reflected**: the forge's holder edits the delivery's view, one comment on the pull request with the
|
||||
state, the plan, the machine steps and the group, and sets every status of the commit with the view as its
|
||||
`target_url`.
|
||||
key per group). Nothing is said before it is kept. What it owes outside is kept with it and retried until
|
||||
done;
|
||||
2. **said**: the event `mesh-delivery.transition` (and `mesh-delivery.group` when a group's derived state
|
||||
changes), with the delivery's id, from, to, event, why and plan summary, and no secret or address;
|
||||
3. **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;
|
||||
4. **reflected**: 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 status `mesh/delivery` on the head, and
|
||||
`mesh/delivery-group` on every member's head (`gitea_commit_status`). Every status links to the pull
|
||||
request, `mesh/merge-gate` among them.
|
||||
|
||||
## The verbs
|
||||
|
||||
@@ -131,8 +139,13 @@ In this order, each by its owner:
|
||||
| `close` | H2's only verb: the transition the table names for a stalled delivery, refused otherwise |
|
||||
|
||||
**The controller's verbs for it** (on the mesh-controller seat): `delivery-plan`, `delivery-order`,
|
||||
`delivery-check`, `deliver`, `delivery-stop`, `delivery-walks`. A person has `plans go <plan> --why`, which
|
||||
does what `deliver` does under their name.
|
||||
`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
|
||||
|
||||
@@ -165,8 +178,8 @@ up.
|
||||
|
||||
| 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 and notes; 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 | the self-check reads `stalled`; `delivery.<id>.stalled`; H2 closing by the table | a delivery stalled on purpose is raised and closed by H2 through `close` |
|
||||
| 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 | the self-check reads `stalled`; `delivery.<id>.stalled`; H2 calling `close` (the verbs are built in A) | a delivery stalled on purpose is raised and closed by H2 through `close` |
|
||||
| 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
|
||||
|
||||
Reference in New Issue
Block a user