Merge main into issues/190-controller-writes-no-owned-file; index regenerated
This commit is contained in:
+8
-1
@@ -7,7 +7,7 @@ another — and a mesh you cannot name precisely is a mesh two people describe d
|
||||
|
||||
## The mesh and its machines
|
||||
|
||||
- **node** — a machine in the mesh. There are 0..n of them, and each runs the host agent. A node is
|
||||
- **node** — a machine in the mesh. There are 0..n of them, and each runs the node-engine. A node is
|
||||
just a machine that has joined; being one implies nothing about what it runs.
|
||||
- **operator account** — the login name of the person who works on a node, stated on the node
|
||||
record; empty for a machine nobody logs into. Everything the mesh places under a person's home is
|
||||
@@ -28,6 +28,13 @@ another — and a mesh you cannot name precisely is a mesh two people describe d
|
||||
control-plane/data-plane, and opaque here).
|
||||
- **mesh-controller** — the module that runs the controller. It **claims** the `mesh-controller`
|
||||
seat at mesh scope, which is what makes it singular. Replaces the module name **`mesh-control`**.
|
||||
- **node-engine** — the program on every node that applies what the controller declares: it receives the
|
||||
node's declaration, writes the files, runs the services and containers, and reports what it did. It
|
||||
is the engine, not a module: it owns no file's content, and every file it writes belongs to the module
|
||||
that declared it. Replaces **"host agent"**, **"the host"** and **`mesh-host`**. *Agent* is avoided
|
||||
because the word already means two other things here, the build agent and the operator's coding
|
||||
agent. The code still carries the old name (the `mesh-host` repository, its binary and service
|
||||
unit) until the rename is made there; a record written before the rename keeps the old name.
|
||||
(The git repository has been renamed `mesh-control` -> `mesh-controller` on the forge; the module,
|
||||
container and image it produces are `mesh-controller`.)
|
||||
- **foundation** — the store and the broker, raised at genesis before any module system exists.
|
||||
|
||||
@@ -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
|
||||
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
|
||||
|
||||
- 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)
|
||||
- **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)
|
||||
- **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)
|
||||
- **0222** — [A module is told where a mesh seat's holder is reached, and the controller writes no file a seat's holder owns](0222-a-module-is-told-where-a-mesh-seats-holder-is-reached-and-the-controller-writes-no-file-a-seats-holder-owns.md)
|
||||
|
||||
### Its tiers, from the bottom up
|
||||
|
||||
@@ -4,6 +4,7 @@ status: proposed
|
||||
code: []
|
||||
updated: 2026-10-05
|
||||
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/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
|
||||
@@ -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
|
||||
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 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
|
||||
located-in: [mesh-controller]
|
||||
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
|
||||
|
||||
@@ -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