diff --git a/04-ISSUES/087-the-controller-cannot-tell-a-host-is-too-old/00-report.md b/04-ISSUES/087-the-controller-cannot-tell-a-host-is-too-old/00-report.md index aaaf12c..28d2ee0 100644 --- a/04-ISSUES/087-the-controller-cannot-tell-a-host-is-too-old/00-report.md +++ b/04-ISSUES/087-the-controller-cannot-tell-a-host-is-too-old/00-report.md @@ -1,8 +1,8 @@ --- -status: open +status: resolved opened: 2026-09-22 -located-in: [] -fixed-by: +located-in: [mesh-controller internal/link/protocol.go (the report field that was missing), internal/inventory, cmd/mesh-controller (node show and status)] +fixed-by: mesh-controller 7683ba8 amended-design: --- diff --git a/04-ISSUES/087-the-controller-cannot-tell-a-host-is-too-old/01-resolution.md b/04-ISSUES/087-the-controller-cannot-tell-a-host-is-too-old/01-resolution.md new file mode 100644 index 0000000..436b06d --- /dev/null +++ b/04-ISSUES/087-the-controller-cannot-tell-a-host-is-too-old/01-resolution.md @@ -0,0 +1,68 @@ +# 087 — resolved: the mesh knows which host runs a machine + +*2026-09-30.* + +## The field existed and was thrown away on arrival + +The machine has reported its host version since +[ADR 0141](../../02-DECISIONS/0141-the-host-delivers-its-own-successor.md) — `Host` on the report, with +a comment saying why it must be there: *"without it nothing can say a machine is behind."* + +**The controller's own copy of the report did not have the field.** Two structs describe one message, +one on each side of the wire, and only the sending side had it — so it unmarshalled into nothing and the +mesh could not answer a question the machine had been answering for a week. That is the whole of this +issue's mechanism, and it is worth stating plainly because neither side was wrong on its own. + +## What it says now + +`node show` names it per machine: + +``` + last heard from here + host 2026-09-30-0214 +``` + +`not reported — this machine has not said since the mesh began keeping it` where the mesh has not been +told, because a machine that has not said is a different thing from a machine running nothing. + +`status` names the machines that are behind another: + +``` +1 machine(s) run an older host than another machine does: + ace 2026-09-29-0113 + + the newest any machine reports is 2026-09-30-0214. A host refuses a declaration carrying a + field it does not know, whole — so a new field reaches these machines last +``` + +## Disagreement, not staleness, and that is deliberate + +The open questions asked whether the controller should refuse to send a declaration a node cannot +parse. It cannot yet, honestly: **nothing delivers a host version** (ADR 0141 is accepted and not +built, which is [issue 142](../142-the-host-is-the-one-thing-the-mesh-does-not-deliver/00-report.md)), +so the mesh holds no canonical current version and "behind" has no fixed point to be behind. + +What it can say truthfully is that these machines do not all run the same host, and which is newest of +the ones it has been told about. That is the fact that matters before a declaration gains a field: **the +oldest host in the mesh is what the mesh may send.** + +Two deliberate refusals to guess: + +- **A machine that has reported nothing is not called behind.** It may be running anything. `node show` + says it has not said, per machine, which is the honest form. +- **Versions compare as strings.** That suits the timestamps and commits this mesh uses and is wrong + for a scheme where `10` sorts before `9`. Said in the code at the place that would have to learn, + rather than left as a surprise. + +## The open questions, answered as far as they can be + +- *Should a node report the version of its host?* It already did. The gap was the reading. +- *Should the mesh refuse to send a field no node understands yet, or refuse per node and say so?* + Neither, yet — refusing needs the mesh to know which fields need which version, which is the third + question below and is not answered here. What it does is make the disagreement visible before + somebody adds a field. +- *Is there a general shape — a declaration saying which version of the host it needs?* Still open, and + now cheaper to answer: the versions are recorded, so a minimum-version field on a declaration has + something to compare against. It belongs with + [issue 107](../107-a-declaration-carries-no-order/00-report.md), which wants to add a field and is the + first thing this makes safe. diff --git a/04-ISSUES/107-a-declaration-carries-no-order/00-report.md b/04-ISSUES/107-a-declaration-carries-no-order/00-report.md index 01d3f6f..79a530a 100644 --- a/04-ISSUES/107-a-declaration-carries-no-order/00-report.md +++ b/04-ISSUES/107-a-declaration-carries-no-order/00-report.md @@ -40,3 +40,16 @@ exists there and is thrown away at the wire. separate genesis-digest branch is needed on the host? - Is a sequence enough, or does a mode change deserve its own marker, so a replayed converged declaration is refused by mode as well as by order? + +## What has since made this safer to do (2026-09-30) + +Adding a `sequence` to a declaration is adding a field, and a host refuses a declaration carrying a +field it does not know — whole. That was +[issue 087](../087-the-controller-cannot-tell-a-host-is-too-old/00-report.md), and it is resolved: the +mesh now records which host each machine reports and `status` names every machine running an older one +than another does. + +So the flag day is visible before it is walked into, which it was not when this was filed. It does not +make the field free: **the oldest host in the mesh is still what the mesh may send**, and one machine of +four is behind today. A sequence that an old host refuses takes that machine out of the mesh's reach +entirely — worse than the replay it prevents, which has never been observed.