Issue 142: the mesh compiles its own host and publishes it to its registry
Both of the things ADR 0141's insight named as remaining are built. A Go
toolchain based on a new mesh-tools-go module, so the compiler is named
and not pinned; and ${version} in any value of a resource that uses an
archive or a bundle.
Measured rather than asserted: the mesh built the host through its own
toolchain, published it to its own registry, and the bundle fetched back
out is a statically linked stripped binary that runs and says it is the
host.
The cost was larger again than 0141's note said. Three more things in the
path assumed one language or one shape — an entrypoint became a .ts file
whatever the language, the output directory was the compiler's to create,
and a bundle was refused if it named what it is built from — and a fourth
was in the base image, which is Alpine where the first Dockerfile ran
apt-get. That last one is issue 136 in an image, and the build refused
rather than a module failing later.
The version in a path is the digest, not the commit: two builds of one
commit are the same bytes, so a content-addressed version keeps the path
an unchanged build already had.
Still nothing delivers a version to a machine. The host module declares no
resources, so the bundle sits in the registry and no machine is asked to
take it. 0141 carries the insight and 142 the account.
This commit is contained in:
@@ -109,6 +109,23 @@ understated as none. The remaining work is a way to build the host and a way to
|
||||
path, and until both exist nothing delivers a version and every machine takes the fallback — which is
|
||||
what every machine does today.
|
||||
|
||||
> **Progressive insight — 2026-09-30. Both of those exist now.** The paragraph above named two missing
|
||||
> things and they are built: a Go toolchain, based on a new `mesh-tools-go` module so the compiler is
|
||||
> named and not pinned, and `${version}` in any value of a resource that uses an archive or a bundle.
|
||||
> The mesh compiles its own host and publishes it to its own registry, measured — a statically linked
|
||||
> stripped binary, fetched back out and run. **The cost was larger again than this note said**: three
|
||||
> more things in the path assumed one language or one shape, and a fourth was in the base image.
|
||||
> The account is [issue 142](../04-ISSUES/142-the-host-is-the-one-thing-the-mesh-does-not-deliver/01-progress.md).
|
||||
>
|
||||
> The version in a path is the artifact's **digest**, not the commit this note's own wording would
|
||||
> suggest. Two builds of one commit are meant to be the same bytes, so a content-addressed version
|
||||
> means an unchanged build keeps the path it had; a commit-named one would move for an identical binary
|
||||
> and recreate everything reading it.
|
||||
>
|
||||
> **Still nothing delivers a version to a machine.** The host is a module and builds, and declares no
|
||||
> resources, so the bundle sits in the registry and no machine is asked to take it. That is the next
|
||||
> piece, and the decision above is unchanged by any of this.
|
||||
|
||||
## Consequences
|
||||
|
||||
- **The host becomes a build target and a module** — a module whose resource is the next host, applied
|
||||
|
||||
@@ -0,0 +1,91 @@
|
||||
# 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](../../02-DECISIONS/0044-a-public-name-is-provisioned-like-any-capability.md),
|
||||
[0142](../../02-DECISIONS/0142-the-mesh-delivers-its-own-components-as-binaries.md)).
|
||||
|
||||
**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:
|
||||
|
||||
- **`sourcesFor` turned every entrypoint into a `.ts` file.** 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 --outDir` makes one; `go build -o` writes 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](../136-a-module-may-name-a-program-the-machine-does-not-have/00-report.md) 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](../../02-DECISIONS/0005-the-node-host.md)); `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](../../02-DECISIONS/0141-the-host-delivers-its-own-successor.md)).
|
||||
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.
|
||||
Reference in New Issue
Block a user