It reported "N machines run an older host than another" by comparing versions as strings. A host reports its version as a commit, and commits have no order. On the live mesh it named the three machines running the NEWER host as the ones behind — ced54d4 sorts above 04a27ca and that is all it means. The code even carried a caveat saying versions compare as strings and that this "is enough for the timestamps and commits this mesh uses". That was the error, written down and not noticed: enough for timestamps, meaningless for commits, and the mesh reports commits. It now reports the split and claims no ordering, which is more useful as well as more honest — the reader sees who is on which side, and that is what decides whether a field can be sent. Ordering is left with the host, which would have to report something ordered for anybody to have it. This is issue 145 arriving by my own door an hour after I closed it: a report that confidently says the opposite of the truth is worse than one that says less.
144 lines
7.1 KiB
Markdown
144 lines
7.1 KiB
Markdown
# 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.
|
|
|
|
## What I shipped first was wrong, and the mesh said so within the hour
|
|
|
|
The first version reported *"N machine(s) run an older host than another machine does"* and worked out
|
|
which by comparing versions as strings. **A host reports its version as a commit, and commits have no
|
|
order.**
|
|
|
|
On the live mesh, with the adopted machine pushed for the first time:
|
|
|
|
```
|
|
3 machine(s) run an older host than another machine does:
|
|
g14 04a27ca
|
|
novox 04a27ca
|
|
shanks 04a27ca
|
|
```
|
|
|
|
Those three run the **newer** host — installed 09:18, against the adopted machine's 01:13. `ced54d4`
|
|
sorts above `04a27ca` and that is all it means. An arbitrary lexicographic result, presented as a fact,
|
|
about the one thing this record exists to make trustworthy.
|
|
|
|
The code carried a caveat saying versions compare as strings and that this "is enough for the timestamps
|
|
and commits this mesh uses". That was the error, written down and not noticed: it is enough for
|
|
timestamps and it is **meaningless** for commits, and the mesh reports commits.
|
|
|
|
It now reports the split and claims no ordering:
|
|
|
|
```
|
|
4 machine(s) do not all run the same host:
|
|
04a27ca g14, novox, shanks
|
|
ced54d4 ace
|
|
|
|
a host refuses a declaration carrying a field it does not know, whole — so the mesh may
|
|
send only what every one of these understands. Which of them is newer is not readable
|
|
from a commit; that needs a version the host reports as ordered
|
|
```
|
|
|
|
More useful as well as more honest — the reader sees who is on which side of the split, which is what
|
|
decides whether a field can be sent — and it leaves the ordering where it belongs: with the host, which
|
|
would have to report something ordered for anybody to have it.
|
|
|
|
**This is [issue 145](../145-a-machine-reads-healthy-while-its-modules-cannot-reach-each-other/00-report.md)
|
|
arriving by my own door**, an hour after closing it: a report that confidently says the opposite of the
|
|
truth is worse than one that says less, because it trains a reader to distrust the whole surface.
|
|
|
|
## Measured on the mesh, and one limitation it exposed
|
|
|
|
All four machines run the identical host binary — same digest, installed within eighteen seconds of each
|
|
other — and at first only one reported its version. The other three said *not reported*, which read as a
|
|
difference between machines where there was none.
|
|
|
|
**A machine states its host version only when the mesh sends it a declaration.** The report is published
|
|
after an apply; the periodic reconcile that runs every five minutes publishes nothing, because it is the
|
|
machine keeping itself as declared rather than answering anything. So a machine that is current and idle
|
|
never says, and the mesh cannot distinguish that from a machine running something ancient.
|
|
|
|
Confirmed by pushing: before, `not reported`; after, `04a27ca` — the same version the machine that had
|
|
been pushed already reported.
|
|
|
|
```
|
|
novox host 04a27ca
|
|
shanks host 04a27ca
|
|
g14 host 04a27ca
|
|
ace host not reported — this machine has not said since the mesh began keeping it
|
|
```
|
|
|
|
`ace` has not been pushed since the field existed; it is adopted and parked.
|
|
|
|
**This is enough for the purpose and not enough for the claim.** For deciding whether a new declaration
|
|
field is safe it is sufficient, because pushing is what the mesh is about to do anyway and the answer
|
|
arrives with the act. For *knowing what the mesh is running*, it is not: a long-idle machine's entry is
|
|
as old as its last push, and the honest reading of `not reported` is "nobody has asked recently" rather
|
|
than "this machine is silent". The words say the first, which is why they are those words.
|
|
|
|
Making a heartbeat carry it would close the gap and is a change to what a heartbeat is — a bare word
|
|
that the node is there, deliberately carrying nothing else. Left alone rather than widened in passing.
|
|
|
|
## 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.
|