Asked whether the host is built for more than one architecture. It is not, and the reason is worse than a missing feature. A bundle in a compiled language must name a system, must name one of alpine, android or arch, and is refused with a careful message if it gets that wrong. The field is then read by nothing: it does not reach the compiler, no machine is matched against it, and nothing chooses between two artifacts by it. The compile runs with no target named and produces a binary for whatever the build machine happens to be. The host is x86-64 because the build machine is, not because the declaration said so. Correct for this mesh by coincidence — four machines, all x86-64 Arch. A module declaring two systems would get two identical binaries, both published and both pinned, and the one sent to the machine it was not built for would fail at exec. android is the sharp end: not an x86-64 platform, and an artifact declared for it today would be an x86-64 binary wearing the label. A field that is checked and ignored is worse than one that does not exist, because the check is what persuades you it works. Also noted: the processor is a second dimension the manifest has no word for, so even implementing the present field would not answer the question that found this. And since the Go toolchain builds statically, one binary would run on all three systems anyway — so the pin is a policy rather than a necessity, which is a decision and not a fix.
5.7 KiB
142 — the mesh can now build and publish its own host
2026-09-30. Both of ADR 0141's named gaps are closed; the host is not yet placed by the mesh.
What ADR 0141's insight named, and what each cost
The remaining work is a way to build the host and a way to name a version in a path, and until both exist nothing delivers a version and every machine takes the fallback.
1. Nothing could compile it. The toolchain list was a closed set of typescript and python, and its own warning — every language is another implementation of the contracts modules share, so adding one commits to keeping N implementations in step — does not attach to Go. Go is how the host, the control plane and the builder are written, and none of them is a module in that sense: the host is what applies modules.
Closed by a Go toolchain naming a new base module, mesh-tools-go. Named and not pinned, so the mesh
answers with the copy it holds and moving compiler is a build rather than an edit to the control
plane's source (ADR 0044,
0142).
2. A version could not reach the path. An archive named a fixed path and nothing interpolated the
build into it, so nothing could ask for …/versions/<version>/.
Closed by ${version} in any value of a resource that uses an archive or a bundle. The version is
the artifact's digest, short, and not the commit: two builds of one commit are meant to be the same
bytes — the toolchains are -trimpath for that — so a content-addressed version means an unchanged
build resolves to the path it already had, where a commit-named path would move for an identical binary
and recreate everything reading it.
Three more things were in the way, and none was in the record
Found by doing it, in the order they appeared:
sourcesForturned every entrypoint into a.tsfile. One language's file extension, written into the code that serves every language. The extension is the toolchain's now.- The output directory was left to the compiler.
tsc --outDirmakes one;go build -owrites into a directory and does not create it, failing with a message about a path rather than about a build. Made for every toolchain, because which compilers are forgiving is not something a reader should have to know. - A bundle was refused if it named what it is built from. The reason — a bundle is the module's own directory compiled whole — holds for an interpreted language and cannot hold for a compiled one: a Go repository carries several commands, the host and its bootstrap among them, and "the module's own directory" is then not a package at all. A compiled bundle may now say which package; the refusal stands for every interpreted one.
And a fourth, in the base module itself: its first Dockerfile ran apt-get, and the golang image the
mesh holds is Alpine. That is
issue 136 in an image
rather than on a machine, and the build refused rather than a module failing later — which is the
behaviour that issue wants.
Measured: the mesh compiles its own host and publishes it to its own registry
$ mesh-controller build <the host's repository>
host-arch bundle artifact-store://mesh-host/host-arch/blobs/sha256:ad62528c…
mesh-host 1, built on novox from b5196e97
Fetched from the mesh's registry and opened:
mesh-host: ELF 64-bit LSB executable, x86-64, statically linked, stripped
$ ./mesh-host help
mesh-host — the node host
Statically linked matters: what a machine holds is a file rather than a container, so a binary needing a libc it did not bring is a delivery that works until a machine differs.
The host is a module now, with one bundle for arch built from cmd/mesh-host. A system is
required for a compiled artifact because a binary is pinned at link time so a host refuses to touch a
machine it was not built for (ADR 0005); arch is what all
four of this mesh's machines report themselves to be, and another system is another artifact and
another build.
What is left
The host module declares no resources, so nothing places the built bundle on a machine yet. That is
the next piece and it is the one with the interesting question in it: the resource is an archive
unpacked to …/versions/${version}/, applied by the host that is running, and the bootstrap is not
circular because the two are different versions (ADR 0141).
The host half of that mechanism — versions side by side, the newest runs, the running one stands aside
between reconciles, rollback picks a directory — is built and tested and has never had a version to
work on.
One thing worth noticing while writing it. The systems list exists because "the difference between two of them is a C library, not a kernel" — and a static Go binary has no C library. So one build would in fact run on all three. The pin is then a policy (a host refuses a machine it was not built for) rather than a necessity, which is a reasonable thing to keep and is worth knowing is a choice.
And a sharper one, asked as a question and worth its own record. The artifact's system is validated and then read by nothing: it does not reach the compiler, no machine is matched against it, and nothing chooses between two artifacts by it. The host built here is x86-64 because the build machine is, not because anything in the declaration said so — correct for this mesh by coincidence. That is issue 159.