All four machines run a host the mesh built, published and delivered, the last delivery unattended: each stood aside once for a genuinely newer version and the delivered launcher started it. A following push that delivered nothing new was applied and reported by every machine and stood nobody aside. The crossover needs one restart of the unit per machine, once, because the running launcher executes from its own inode. Measured timing: three seconds on the machine, 17-20 as the operator sees it, the difference being the control plane composing before it sends. 107 is unblocked: a declaration field is now a build and a push.
77 lines
4.7 KiB
Markdown
77 lines
4.7 KiB
Markdown
# 107 — diagnosis: the fix is a flag day, and it should wait for delivery
|
|
|
|
*2026-09-30. Read, measured, and not built — deliberately.*
|
|
|
|
## The premise is confirmed
|
|
|
|
A host parses a declaration with unknown fields refused, and the code says why rather than leaving it
|
|
to be inferred:
|
|
|
|
> `DisallowUnknownFields` is the whole point rather than strictness for its own sake: a field the host
|
|
> does not know is a thing the control plane believes it asked for.
|
|
|
|
So adding `sequence` and `supersedes` is not an additive change. **Any host that has not been upgraded
|
|
refuses the whole declaration and applies nothing** — which is exactly the behaviour that keeps a
|
|
half-understood declaration off a machine, and exactly what makes this expensive.
|
|
|
|
## What has changed since this was filed
|
|
|
|
[Issue 087](../087-the-controller-cannot-tell-a-host-is-too-old/00-report.md) is resolved: the mesh now
|
|
records the host version each machine reports and `status` names every machine running an older host
|
|
than another does. The flag day is visible before it is walked into, which it was not on 2026-09-23.
|
|
|
|
That makes the cost measurable rather than hypothetical, and the measurement is the reason this is not
|
|
being built today.
|
|
|
|
## Why it waits
|
|
|
|
**One machine of four runs an older host, and it cannot be upgraded.** `ace` is adopted, deliberately
|
|
parked until the network and module-assignment work is settled, and **nothing delivers a host version at
|
|
all** — [ADR 0141](../../02-DECISIONS/0141-the-host-delivers-its-own-successor.md) is accepted and not
|
|
built, which is [issue 142](../142-the-host-is-the-one-thing-the-mesh-does-not-deliver/00-report.md).
|
|
Every machine takes a hand-placed binary.
|
|
|
|
So shipping the field means, in order: place a host by hand on three machines, unpark the fourth, place
|
|
it there too, and only then turn the controller half on. A machine missed in that sequence is a machine
|
|
the mesh cannot send anything to at all — not degraded, unreachable.
|
|
|
|
**And the fault it prevents has never been observed.** The record says so itself: *"Not observed;
|
|
constructed from the code, and narrow."* It needs a backlog of more than sixteen declarations queued
|
|
across a `converge`/`adopt` pair, or a broker slow enough to split one, and the host already applies the
|
|
newest of a drained batch and refuses a declaration that is not the last by digest.
|
|
|
|
**Trading a machine's reachability for a replay nobody has seen is the wrong way round.** The right
|
|
order is [issue 142](../142-the-host-is-the-one-thing-the-mesh-does-not-deliver/00-report.md) first —
|
|
when the mesh can deliver a host, a declaration field costs a rollout instead of an expedition — and the
|
|
work order already puts that in its last group, as the proof that the mesh can make another of itself.
|
|
|
|
## What the open questions look like now
|
|
|
|
- *A per-node `sequence` under the controller's node hold, and `supersedes` as the previous digest?*
|
|
Still the right shape. The controller already holds the lock and already records each send, so the
|
|
order exists and is thrown away at the wire — unchanged since this was filed.
|
|
- *Genesis signing its bundle as sequence zero?* Yes, and it is the cheaper half: the bundle is written
|
|
by the host that will read it, so it has no flag day of its own.
|
|
- *Is a sequence enough, or does a mode change deserve its own marker?* A sequence alone does not stop
|
|
a replayed *converged* declaration reaching a node that has since been returned to adopted, which is
|
|
the incident of issue 104 by another door and is what this record names as its real risk. It wants
|
|
both, and the second is the one worth having first.
|
|
- **And one this record did not ask:** should a declaration say which host version it needs? 087 makes
|
|
that comparable for the first time, and it is the general form of the answer — a field that announces
|
|
its own requirement, rather than a flag day per field, for ever.
|
|
|
|
## Status
|
|
|
|
Left `located`. The owner is unchanged, the shape of the fix is agreed, and the gate is
|
|
[issue 142](../142-the-host-is-the-one-thing-the-mesh-does-not-deliver/00-report.md) rather than anything
|
|
in this record. **This is a judgement about order, not a refusal** — it is cheap to overrule, and the
|
|
code is a day's work once a host can be delivered.
|
|
|
|
## The gate has opened (2026-09-30, evening)
|
|
|
|
The mesh delivers the host now — built by its own toolchain, published to its own registry, delivered
|
|
over the bus and started by the launcher, on all four machines
|
|
([issue 142](../142-the-host-is-the-one-thing-the-mesh-does-not-deliver/01-progress.md)). A declaration
|
|
field is a build and a push, not an expedition. The order this record asked for — hosts first, then
|
|
the controller — is now two commands and a status line that says when the first has finished.
|