Merge pull request 'Issue 142: the mesh compiles its own host and publishes it to its registry' (#207) from issue/142-the-mesh-can-build-its-own-host into main
This commit was merged in pull request #207.
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