161 resolved and verified on a machine: the workstation runs a host the mesh compiled, published, delivered and started, applying declarations and reporting the version it was delivered as. The system it was built for comes from the artifact — the one thing a toolchain takes from a module, which 0142 already allowed because the target is a property of the artifact. The version comes from where the binary sits, which 0142 decided and nothing had implemented. Two mistakes on the way, both caught by reading the output rather than the line that claimed success. A second -ldflags does not merge with the first: the binary gained its system and lost -s -w, 12.2MB against 8.5MB. And the delivered binary was named after its package, so the first delivery was correct, reported success and was invisible to the launcher. A delivered host that cannot apply is a machine the mesh cannot repair, because the declaration that would fix it is the one it cannot apply. The launcher's fallback is what made that an inconvenience instead of an expedition. 162 is new and not about the host: an archive has no removal, so a module using one can never be unassigned, and the attempt takes the whole apply with it — the machine applies nothing else either. It is how undoing the first delivery froze the workstation.
96 lines
4.5 KiB
Markdown
96 lines
4.5 KiB
Markdown
---
|
|
status: resolved
|
|
opened: 2026-09-30
|
|
located-in:
|
|
- mesh-host cmd/mesh-host/main.go (version and builtFor, both set at link time)
|
|
- mesh-controller internal/builder (the toolchain, which deliberately takes nothing from the module)
|
|
fixed-by: mesh-controller (the system stamp, and one linker flag rather than two), mesh-host (the version read from the path) — verified on a machine 2026-09-30, 01-resolution.md
|
|
amended-design:
|
|
---
|
|
|
|
# 161 — A host the mesh built carries none of the facts its Makefile stamps in
|
|
|
|
## What was observed
|
|
|
|
*2026-09-30, on the workstation, having just made the host self-updating.*
|
|
|
|
The mesh compiled the host, published it, delivered it and the launcher started it. It ran, read the
|
|
machine correctly, and **would have refused the first declaration it was asked to apply.**
|
|
|
|
The host's own Makefile links in two facts:
|
|
|
|
```
|
|
LDFLAGS := -s -w -X main.builtFor=$(SYSTEM) -X main.version=$(VERSION)
|
|
```
|
|
|
|
The mesh's Go toolchain links in neither, on purpose: a toolchain accepts nothing from the module,
|
|
because anything a module could override there it would be writing a Dockerfile to override
|
|
([ADR 0142](../../02-DECISIONS/0142-the-mesh-delivers-its-own-components-as-binaries.md)). So a
|
|
delivered host has `builtFor = ""` and `version = "development build"`.
|
|
|
|
**`builtFor` empty is the one that bites.** Before applying anything, the host asks which system it
|
|
was built for:
|
|
|
|
```go
|
|
sys, err := system.For(builtFor)
|
|
```
|
|
|
|
and that answers, for an empty name:
|
|
|
|
```
|
|
this host was built for "", which is not a system it knows. Built hosts are: …
|
|
```
|
|
|
|
It is called before any resource is applied, so the failure is in the safe direction — the machine is
|
|
not half-configured. It is still a host that cannot do its job, and nothing about it looks wrong: the
|
|
unit is active, the link to the bus is up, and the log says it is hearing what the node should be.
|
|
|
|
Measured: after the crossover the machine logged nothing further, where the previous host had written
|
|
a reconcile line every five minutes.
|
|
|
|
## Why this was found rather than reported
|
|
|
|
Nothing reports it. The host does not check its own stamps at start, the mesh does not ask, and the
|
|
declaration that would fail is the same declaration that would deliver a fix — so **a machine in this
|
|
state cannot be repaired by the mesh.** It was restored by moving the delivered versions aside and
|
|
letting the launcher fall back to the hand-placed binary, which is the fallback working exactly as
|
|
designed.
|
|
|
|
## What the records already say about half of it
|
|
|
|
[ADR 0142](../../02-DECISIONS/0142-the-mesh-delivers-its-own-components-as-binaries.md) settles the
|
|
version and its answer is not implemented:
|
|
|
|
> A component's version comes from where it sits, not from its linker. It is unpacked into a directory
|
|
> named for its version, so it can read its own version from its path. The stamp goes, and with it the
|
|
> need for a build to know what it will be called.
|
|
|
|
That is exactly right and would also fix what the mesh reports: a delivered host would say
|
|
`637f65559d16` rather than `development build`, and
|
|
[issue 087](../087-the-controller-cannot-tell-a-host-is-too-old/00-report.md)'s host comparison would
|
|
mean something for delivered hosts.
|
|
|
|
**The system pin has no answer yet**, and it needs one before any mesh-built host can apply anything.
|
|
The tension is real: the target is a property of the artifact and 0142 says so, but a toolchain that
|
|
passed it would be linking a value into a variable whose name belongs to the module — which is the
|
|
coupling the toolchain exists to avoid. Candidates, none decided:
|
|
|
|
- the path carries it as well as the version, so the host reads both from where it sits, as 0142 does
|
|
for the version;
|
|
- the bundle carries a small file beside the binary saying what it was built for, written by the
|
|
builder from the artifact's declaration;
|
|
- the host stops being pinned at link time and refuses on a fact it reads from the machine instead —
|
|
which changes what [ADR 0005](../../02-DECISIONS/0005-the-node-host.md) decided and is the biggest of
|
|
the three.
|
|
|
|
## What is true in the meantime
|
|
|
|
Self-update works end to end and is one fact short of usable: the mesh builds the host, publishes it,
|
|
delivers it to a machine, the running host stands aside, and the launcher starts the delivered one. The
|
|
machine is left on its hand-placed binary until this is answered, which is one command to undo.
|
|
|
|
## How a fix is checked
|
|
|
|
A host the mesh built and delivered applies a declaration on a machine, shown by the machine's own
|
|
reconcile line; and it reports a version that names the build it came from rather than a placeholder.
|