diff --git a/02-DECISIONS/0141-the-host-delivers-its-own-successor.md b/02-DECISIONS/0141-the-host-delivers-its-own-successor.md index c32bd6c..4289114 100644 --- a/02-DECISIONS/0141-the-host-delivers-its-own-successor.md +++ b/02-DECISIONS/0141-the-host-delivers-its-own-successor.md @@ -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 diff --git a/04-ISSUES/142-the-host-is-the-one-thing-the-mesh-does-not-deliver/01-progress.md b/04-ISSUES/142-the-host-is-the-one-thing-the-mesh-does-not-deliver/01-progress.md new file mode 100644 index 0000000..e683953 --- /dev/null +++ b/04-ISSUES/142-the-host-is-the-one-thing-the-mesh-does-not-deliver/01-progress.md @@ -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//`. + +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 + 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.