Merge pull request 'ADR 0221: a push sends no build a policy or a plan holds back, except to the machine it names' (#112) from decision/0221-a-push-sends-no-held-build into main
mesh/delivery held for a person: merged without a passing check: only a person decides that it goes on
mesh/delivery held for a person: merged without a passing check: only a person decides that it goes on
This commit was merged in pull request #112.
This commit is contained in:
@@ -45,6 +45,13 @@ an operator obligation, and an obligation enforced by nothing is issue 057 resta
|
|||||||
declaration is computed from the whole mesh; delivering a mesh that is knowingly inconsistent and
|
declaration is computed from the whole mesh; delivering a mesh that is knowingly inconsistent and
|
||||||
merely saying so would make "push succeeded" mean less than it says.
|
merely saying so would make "push succeeded" mean less than it says.
|
||||||
|
|
||||||
|
> **The mechanism changed — 2026-10-05, by [ADR 0221](0221-a-push-sends-no-build-a-policy-or-a-plan-holds-back-except-to-the-machine-it-names.md).**
|
||||||
|
> A named push still flushes every other machine that is behind, compared against what each was last
|
||||||
|
> sent. A machine whose modules would move to a build their upgrade policy records, or that an open plan
|
||||||
|
> has not sent it yet, is no longer flushed: the push names it and leaves it for `push <node>`. "Behind
|
||||||
|
> for an unrelated reason" no longer covers a held upgrade
|
||||||
|
> ([issue 259](../04-ISSUES/259-a-named-push-sent-every-machine/00-report.md)).
|
||||||
|
|
||||||
## Consequences
|
## Consequences
|
||||||
|
|
||||||
- One push is sufficient for a cross-node consumer: the provider's grants arrive from the same
|
- One push is sufficient for a cross-node consumer: the provider's grants arrive from the same
|
||||||
|
|||||||
+122
@@ -0,0 +1,122 @@
|
|||||||
|
---
|
||||||
|
topic: the mesh
|
||||||
|
status: accepted
|
||||||
|
date: 2026-10-05
|
||||||
|
deciders: jochen
|
||||||
|
reconstructed: false
|
||||||
|
extends: 02-DECISIONS/0083-one-push-leaves-the-mesh-consistent.md
|
||||||
|
---
|
||||||
|
|
||||||
|
# 221. A push sends no build a policy or a plan holds back, except to the machine it names
|
||||||
|
|
||||||
|
## Context
|
||||||
|
|
||||||
|
[ADR 0083](0083-one-push-leaves-the-mesh-consistent.md) makes a named push finish what it starts. After
|
||||||
|
the named machine is sent, every other machine whose declaration differs from what it was last sent is
|
||||||
|
sent too. The case it was written for is a grant: assigning a consumer changes the provider's
|
||||||
|
declaration on another machine. ADR 0083 accepted that a machine behind *for an unrelated reason* is
|
||||||
|
flushed as well, and called that correct rather than a cost.
|
||||||
|
|
||||||
|
On 2026-10-05 that reasoning met an upgrade policy
|
||||||
|
([issue 259](../04-ISSUES/259-a-named-push-sent-every-machine/00-report.md)). A change to the resolver
|
||||||
|
modules was merged with the policy `record`, so that each machine would take it only when pushed, one
|
||||||
|
at a time: the anchor first, each checked before the next. `push <anchor>` sent all four machines the
|
||||||
|
new build, and so did a later `push <laptop>`. A fault in the change
|
||||||
|
([issue 260](../04-ISSUES/260-the-resolver-started-before-its-zones-file-existed/00-report.md)) was met
|
||||||
|
on every machine at once.
|
||||||
|
|
||||||
|
The cascade compares one digest per machine, and a digest cannot say why a machine differs. Under
|
||||||
|
`record`, every machine running the module differs from the merge on, so every machine is flushed. The
|
||||||
|
same holds for a plan's rollout under [ADR 0218](0218-a-plan-sends-grants-before-code-rolls-out-one-machine-first-and-a-newer-merge-takes-over-an-older-plan.md):
|
||||||
|
while the plan waits on its first machine, the rest differ, and any named push elsewhere sends them the
|
||||||
|
build the plan is holding. [Issue 249](../04-ISSUES/249-a-modules-new-state-is-refused-until-a-push-the-merge-did-not-make/00-report.md)
|
||||||
|
met the same confusion for the machine holding the bus, which a send adds when its user list changed.
|
||||||
|
It narrowed that check to the user list, but the machine, once added, is still sent its whole
|
||||||
|
declaration.
|
||||||
|
|
||||||
|
So `record` held a change back from nothing but the merge, and "one machine first" held it back only
|
||||||
|
from the plan's own sends.
|
||||||
|
|
||||||
|
## Considered Options
|
||||||
|
|
||||||
|
1. **Report instead of cascade:** list every machine that is behind and send none. Rejected: it is the
|
||||||
|
option ADR 0083 rejected, and for the same reason. [Issue 057](../04-ISSUES/057-a-cross-node-consumer-is-provisioned-only-when-the-provider-is-pushed-again/00-report.md)'s provider would wait for a second push
|
||||||
|
nothing tells anyone to make.
|
||||||
|
2. **Send a held machine its consequences and keep its held modules at their last build.** The cascade
|
||||||
|
would compose the machine with each held module pinned at the build it was last sent, so a grant
|
||||||
|
still reaches it and the upgrade does not. Rejected: the catalogue resolves every machine against
|
||||||
|
one manifest per module, the current one. Pinning means resolving a machine's set against a mix of
|
||||||
|
current and older manifests, read back from the build records, beside the current settings, seats
|
||||||
|
and grants. The result matches neither what the machine runs nor what the mesh would send it, so
|
||||||
|
neither `plan` nor `status` could show it. A grant composed for the new build may not fit the old
|
||||||
|
one. It is a second composition path to get one edge case right, and the edge case has a one-word
|
||||||
|
remedy: name the machine.
|
||||||
|
3. **Keep, with every send, which build of each module the machine was sent, and leave a machine any
|
||||||
|
of whose modules a policy or a plan holds back.** Chosen.
|
||||||
|
|
||||||
|
## Decision
|
||||||
|
|
||||||
|
**1. A send records the builds it carried.** With the digest of every declaration it sends, the mesh
|
||||||
|
keeps which build of each module the declaration carried: the commit the module's current build was
|
||||||
|
made from. A module left out of the declaration keeps the build it was last sent. A declaration sent by
|
||||||
|
hand records that what it carried is not known.
|
||||||
|
|
||||||
|
**2. A push does not send a machine it did not name a held build.** A machine reached by a named push's
|
||||||
|
cascade, or added because it holds the bus, is not sent when any module it runs would move to a build
|
||||||
|
that:
|
||||||
|
|
||||||
|
- its upgrade policy records rather than rolls out, or
|
||||||
|
- an open plan has not yet sent it: the plan is still building the module, or has sent it to its first
|
||||||
|
machine and this is not that machine.
|
||||||
|
|
||||||
|
A module the machine was never sent counts as a move. A machine whose last send's builds are not known
|
||||||
|
counts as held. It was sent before this was kept, or by hand, so a held upgrade cannot be told apart
|
||||||
|
from anything else.
|
||||||
|
|
||||||
|
**3. It is named, not hidden.** The push says which machine it left, which module and which builds, why,
|
||||||
|
and that `push <node>` sends it. For the machine holding the bus it also says that the bus may refuse
|
||||||
|
what this push's machines were newly granted until that machine is sent.
|
||||||
|
|
||||||
|
**4. Everything else stays as it is.** A machine with nothing held is flushed exactly as ADR 0083
|
||||||
|
decides: a grant, a peer, a setting. The machine a push names is sent everything, held builds included.
|
||||||
|
A push that names no machine sends every machine. `push --behind` still sends every machine that is
|
||||||
|
behind, held or not. It is the remedy `record` names when an upgrade is announced ("`push --behind`
|
||||||
|
when you want them"), and the one command for taking a recorded upgrade everywhere. Narrowing it would
|
||||||
|
leave `record` with no way to say "now".
|
||||||
|
|
||||||
|
## Consequences
|
||||||
|
|
||||||
|
- `record` and "one machine first" hold a change back from every push that does not name the machine.
|
||||||
|
Walking a change through the mesh is `push <anchor>`, check, `push <next>`.
|
||||||
|
- **The cost:** a held machine that is also owed a grant from this push waits for its own push. The
|
||||||
|
provider in issue 057's case, if a held upgrade is pending on it, is not sent its new grant, and its
|
||||||
|
consumer is refused until the provider is pushed. The push names that machine and the remedy, so the
|
||||||
|
wait is announced, not silent. When the holder of the bus is held, a new grant may be refused by the
|
||||||
|
bus until it is sent, and the push says so.
|
||||||
|
- On the first push after this ships, no machine's last send has its builds recorded yet. Each is held
|
||||||
|
from cascades until it is pushed once: by name, in a whole-mesh push, or by `push --behind`.
|
||||||
|
- A manifest handed over by hand does not change the commit a module records, so a cascade still sends
|
||||||
|
its change. Only builds have a commit to compare.
|
||||||
|
- ADR 0083's consequence that a machine behind for an unrelated reason is flushed is narrowed. It still
|
||||||
|
holds for every reason except a build held back.
|
||||||
|
|
||||||
|
## How it is checked
|
||||||
|
|
||||||
|
| Rule | Checked by |
|
||||||
|
|---|---|
|
||||||
|
| a send records the builds it carried, and "not known" | the controller's test: the builds kept with a send round-trip, an empty send is known and empty, a send by hand reads as not known |
|
||||||
|
| a left-out module keeps its last build | the controller's test: a module left out of a declaration records the build it was last sent |
|
||||||
|
| a recorded upgrade holds a machine a push did not name | the controller's test: with a module under `record` moved, the cascade of a push naming the anchor leaves the laptop's last send unchanged and names it, the module, both builds and `push laptop` |
|
||||||
|
| held and owed something else: not sent, both said | the same test: a newly placed machine changes the laptop's peers while the upgrade is held; the laptop is not sent and the output says why and that what else it is owed waits |
|
||||||
|
| a roll-out policy is not held | the same test: with the policy set to roll out, the laptop is sent and its new build recorded |
|
||||||
|
| a consequence nothing holds is still sent (issue 057) | the controller's test: a placed machine's peers reach the others by cascade; a machine whose last send is not known is held |
|
||||||
|
| a plan waiting on its first machine holds the rest | the controller's test: a machine the plan has not reached is held, the first machine is not; a module sent everywhere, failed, or in a closed plan holds nothing |
|
||||||
|
| live | the next change merged under `record`: `push <anchor>` sends the anchor alone and names every other machine running the module |
|
||||||
|
|
||||||
|
## References
|
||||||
|
|
||||||
|
- [Issue 259](../04-ISSUES/259-a-named-push-sent-every-machine/00-report.md), [issue 260](../04-ISSUES/260-the-resolver-started-before-its-zones-file-existed/00-report.md), [issue 249](../04-ISSUES/249-a-modules-new-state-is-refused-until-a-push-the-merge-did-not-make/00-report.md)
|
||||||
|
- [ADR 0083](0083-one-push-leaves-the-mesh-consistent.md): the cascade, narrowed here
|
||||||
|
- [ADR 0218](0218-a-plan-sends-grants-before-code-rolls-out-one-machine-first-and-a-newer-merge-takes-over-an-older-plan.md): one machine first, now held from a push as well
|
||||||
|
- [ADR 0010](0010-delivery.md): delivery, and what `push --behind` answers
|
||||||
|
- [to-be 30](../03-DESIGN/01-to-be/30-the-mesh-updates-itself-on-a-push.md): the design this amends
|
||||||
@@ -196,6 +196,7 @@ python3 00-META/checks/index.py fail if stale
|
|||||||
- **0212** — [A seat says what it receives, and the machine's hotkeys are a seat](0212-a-seat-says-what-it-receives-and-the-machines-hotkeys-are-a-seat.md)
|
- **0212** — [A seat says what it receives, and the machine's hotkeys are a seat](0212-a-seat-says-what-it-receives-and-the-machines-hotkeys-are-a-seat.md)
|
||||||
- **0218** — [A plan sends grants before code, rolls a module out one machine first, and a newer merge takes over an older plan](0218-a-plan-sends-grants-before-code-rolls-out-one-machine-first-and-a-newer-merge-takes-over-an-older-plan.md)
|
- **0218** — [A plan sends grants before code, rolls a module out one machine first, and a newer merge takes over an older plan](0218-a-plan-sends-grants-before-code-rolls-out-one-machine-first-and-a-newer-merge-takes-over-an-older-plan.md)
|
||||||
- **0219** — [The build queue is controlled through the controller and the build seat](0219-the-build-queue-is-controlled-through-the-controller-and-the-build-seat.md)
|
- **0219** — [The build queue is controlled through the controller and the build seat](0219-the-build-queue-is-controlled-through-the-controller-and-the-build-seat.md)
|
||||||
|
- **0221** — [A push sends no build a policy or a plan holds back, except to the machine it names](0221-a-push-sends-no-build-a-policy-or-a-plan-holds-back-except-to-the-machine-it-names.md)
|
||||||
|
|
||||||
### Its tiers, from the bottom up
|
### Its tiers, from the bottom up
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ status: proposed
|
|||||||
code: []
|
code: []
|
||||||
updated: 2026-10-05
|
updated: 2026-10-05
|
||||||
decisions:
|
decisions:
|
||||||
|
- 02-DECISIONS/0221-a-push-sends-no-build-a-policy-or-a-plan-holds-back-except-to-the-machine-it-names.md
|
||||||
- 02-DECISIONS/0218-a-plan-sends-grants-before-code-rolls-out-one-machine-first-and-a-newer-merge-takes-over-an-older-plan.md
|
- 02-DECISIONS/0218-a-plan-sends-grants-before-code-rolls-out-one-machine-first-and-a-newer-merge-takes-over-an-older-plan.md
|
||||||
- 02-DECISIONS/0162-a-merge-produces-a-tiered-plan-the-mesh-keeps.md
|
- 02-DECISIONS/0162-a-merge-produces-a-tiered-plan-the-mesh-keeps.md
|
||||||
- 02-DECISIONS/0157-a-build-says-what-it-does-on-the-bus-as-it-happens.md
|
- 02-DECISIONS/0157-a-build-says-what-it-does-on-the-bus-as-it-happens.md
|
||||||
@@ -149,6 +150,21 @@ What a merge changed is read from the forge whole, page by page
|
|||||||
module directory the mesh does not hold yet is that module's own, not shared code, when its definition is
|
module directory the mesh does not hold yet is that module's own, not shared code, when its definition is
|
||||||
among the changed paths.
|
among the changed paths.
|
||||||
|
|
||||||
|
## What a push does not send (2026-10-05)
|
||||||
|
|
||||||
|
Revision, [ADR 0221](../../02-DECISIONS/0221-a-push-sends-no-build-a-policy-or-a-plan-holds-back-except-to-the-machine-it-names.md).
|
||||||
|
A named push still sends every other machine its work left behind, but no longer a build that an upgrade
|
||||||
|
policy or a plan is holding back
|
||||||
|
([issue 259](../../04-ISSUES/259-a-named-push-sent-every-machine/00-report.md)).
|
||||||
|
|
||||||
|
- **A send records the builds it carried**: which build of each module the machine was sent.
|
||||||
|
- **A machine a push did not name is left** when a module it runs would move to a build its policy
|
||||||
|
records rather than rolls out, or that an open plan has not sent it yet. A machine whose last send's
|
||||||
|
builds are not known is left too. The push names the machine, the module, the builds and the reason,
|
||||||
|
and says `push <node>` sends it.
|
||||||
|
- The machine a push names, a push of every machine, and `push --behind` send held builds as before.
|
||||||
|
Walking a change through the mesh under `record` is one `push <node>` per machine.
|
||||||
|
|
||||||
## Why now, and why not yet
|
## Why now, and why not yet
|
||||||
|
|
||||||
**Why it matters:** self-update is the difference between a mesh a person maintains by typing
|
**Why it matters:** self-update is the difference between a mesh a person maintains by typing
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
---
|
---
|
||||||
status: open
|
status: located
|
||||||
opened: 2026-10-05
|
opened: 2026-10-05
|
||||||
located-in: [mesh-controller]
|
located-in: [mesh-controller]
|
||||||
fixed-by:
|
fixed-by:
|
||||||
amended-design:
|
amended-design: 03-DESIGN/01-to-be/30-the-mesh-updates-itself-on-a-push.md
|
||||||
---
|
---
|
||||||
|
|
||||||
# 259. A push to one machine sent every machine
|
# 259. A push to one machine sent every machine
|
||||||
|
|||||||
@@ -0,0 +1,27 @@
|
|||||||
|
# 259 — Diagnosis
|
||||||
|
|
||||||
|
## 2026-10-05
|
||||||
|
|
||||||
|
**Located in the controller's push.** A named push ends with the cascade of
|
||||||
|
[ADR 0083](../../02-DECISIONS/0083-one-push-leaves-the-mesh-consistent.md): it sends every other machine
|
||||||
|
whose declaration's digest differs from the digest it was last sent. The comparison is the only one the
|
||||||
|
mesh can make from what it keeps. It keeps a digest of each send and nothing about what the send
|
||||||
|
carried, so a machine behind because a module moved under `record` and a machine behind because of a
|
||||||
|
grant read the same.
|
||||||
|
|
||||||
|
**Not only `record`.** A plan rolling a module out one machine first
|
||||||
|
([ADR 0218](../../02-DECISIONS/0218-a-plan-sends-grants-before-code-rolls-out-one-machine-first-and-a-newer-merge-takes-over-an-older-plan.md))
|
||||||
|
leaves the other machines differing while it waits on the first. Any named push elsewhere in that
|
||||||
|
window sends them the build the plan is holding.
|
||||||
|
|
||||||
|
**And the machine holding the bus.** [Issue 249](../249-a-modules-new-state-is-refused-until-a-push-the-merge-did-not-make/00-report.md)
|
||||||
|
narrowed *whether* that machine is added to a push to its user list alone. Once added, it is sent its
|
||||||
|
whole declaration, held builds included.
|
||||||
|
|
||||||
|
**Ruled out:** composing a held machine with its held modules kept at their last build, so it gets the
|
||||||
|
grant and not the upgrade. Reasons in the decision.
|
||||||
|
|
||||||
|
**Decided** in [ADR 0221](../../02-DECISIONS/0221-a-push-sends-no-build-a-policy-or-a-plan-holds-back-except-to-the-machine-it-names.md):
|
||||||
|
each send records which build of each module it carried, and a push does not send a machine it did not
|
||||||
|
name any build a policy or an open plan holds back. It names the machine and the remedy instead. The
|
||||||
|
fix is a pull request on mesh-controller; `fixed-by:` is filled when it merges.
|
||||||
Reference in New Issue
Block a user