The runtime every module compiles against cannot be built by the mesh, so the one rule that would catch it moving can never fire. And a container keeps the values it was created with, so two good applies can leave it running on neither.
3.6 KiB
status, opened, located-in, fixed-by, amended-design
| status | opened | located-in | fixed-by | amended-design |
|---|---|---|---|---|
| open | 2026-09-13 |
044 — The runtime every module builds on cannot be built by the mesh
Symptom
Every module written in the mesh's own toolchain is compiled on top of one shared base image — the tool runtime. The mesh can build the modules. It cannot build the base.
Two things stop it, and each is enough on its own:
-
The base's container definition copies a compiled output directory that is not in the repository. A clean clone has the sources and no compiled output, so the definition refers to something that is not there.
-
The base's dependency on the mesh's own software development kit resolves to a sibling checkout on disk, not to anything a clone can fetch:
"node_modules/@novox/mesh-sdk" -> { "resolved": "../mesh-sdk", "link": true }
Both mean the same thing: the base can only be produced on a workstation that happens to have the neighbouring repositories laid out beside it, and has run a compile step by hand first.
Observed while building four modules through the mesh from a repository and a path. All four succeeded, and all four recorded that they were built on top of the same base — an image reference that no module in the mesh produced, because no module could have.
Why this matters
This is the one artifact the whole build chain rests on, and it is the one artifact outside the chain. Three separate consequences, all visible today:
- The base is pinned by hand. Every module's container definition names it as a literal digest written by a person. Nothing checks that digest against anything.
- Nothing can tell when it moves. A build records what it was built on top of, so an artifact is stale when anything beneath it moved. That rule cannot fire for the base: the graph has edges pointing at it, and no version on the other end, because no build ever registered one. The mesh is therefore unable to answer "what must be rebuilt" for the change that would reach every module at once.
- Nobody can check what is in it. The published base and the definition in the repository have already drifted: the definition names one operating system base, and the image actually serving every module is built on a different one. This was found by running the image, not by reading anything, and it went unnoticed for exactly as long as nobody could rebuild it.
A rule the design states — an artifact is stale when anything it was built against moved — is unenforceable for the artifact it matters most for. That is the shape of a wrong rule, not a missing feature: everything downstream reports "nothing to rebuild" and is believed.
How it would be checked
The check is the fix's own test: clone the repository alone, into an empty directory, and build it. Nothing else present, no neighbouring checkouts, no compile run first. If that produces the base, the mesh can produce it too, because that is all the mesh does.
Open questions
- Where should the software development kit come from, for a build that has only one repository? The mesh already knows how to run a package registry as a module, and it already publishes container images to one of its own — so this may be the same answer twice rather than a new one.
- Is the base a module like any other, or is it one of the few things a new mesh must arrive carrying? It behaves like both: everything is built on top of it, and it is built out of the same sources as everything else.
- If it becomes an ordinary module, what stops the circularity — the base is built by the builder, and the builder is built on the base?