From 3a9ed9d3fd21b63002e9e585c4f50cff0e9269a5 Mon Sep 17 00:00:00 2001 From: jochen Date: Sun, 13 Sep 2026 01:49:02 +0200 Subject: [PATCH] Two findings from building the catalogue on a live mesh 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. --- .../00-report.md | 71 +++++++++++++++++++ .../00-report.md | 60 ++++++++++++++++ 2 files changed, 131 insertions(+) create mode 100644 04-ISSUES/044-the-runtime-every-module-builds-on-cannot-be-built-by-the-mesh/00-report.md create mode 100644 04-ISSUES/045-a-container-keeps-the-values-it-started-with/00-report.md diff --git a/04-ISSUES/044-the-runtime-every-module-builds-on-cannot-be-built-by-the-mesh/00-report.md b/04-ISSUES/044-the-runtime-every-module-builds-on-cannot-be-built-by-the-mesh/00-report.md new file mode 100644 index 0000000..a70aa91 --- /dev/null +++ b/04-ISSUES/044-the-runtime-every-module-builds-on-cannot-be-built-by-the-mesh/00-report.md @@ -0,0 +1,71 @@ +--- +status: open +opened: 2026-09-13 +located-in: [] +fixed-by: +amended-design: +--- + +# 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? diff --git a/04-ISSUES/045-a-container-keeps-the-values-it-started-with/00-report.md b/04-ISSUES/045-a-container-keeps-the-values-it-started-with/00-report.md new file mode 100644 index 0000000..dbf387e --- /dev/null +++ b/04-ISSUES/045-a-container-keeps-the-values-it-started-with/00-report.md @@ -0,0 +1,60 @@ +--- +status: open +opened: 2026-09-13 +located-in: [] +fixed-by: +amended-design: +--- + +# 045 — A container keeps the values it started with + +## Symptom + +A module reads its database credentials from a file the mesh composes. The file was written, then +rewritten with a different value once the mesh had more to say — the provider's address was not +known the first time and was the second. + +The container went on running with the first version, indefinitely, and reported nothing. Its own +view: + +``` +DATABASE_URL=postgresql://…@:20000/… what the container holds +DATABASE_URL=postgresql://…@:20000/… what the file on disk says +``` + +A module may declare that it restarts when one of its files changes, and this one now does. That +did not help: the restart fires when the file changes *during an apply*, and the change had already +happened before the declaration naming it arrived. Applying again is a no-op, because nothing +changed that time either. The only thing that recovered it was removing the module from the machine +and putting it back. + +## Why this matters + +**Reconciliation compares intentions, not what is actually running.** Two intentions in a row can +both be applied successfully and still leave a container holding values from neither, because a +container captures its environment once, when it is created, and nothing afterwards re-reads it. + +The failure is silent in the worst way: the container is up, the machine reports success, the mesh +reports every module current, and the thing inside is using a credential the mesh no longer +believes in. Nothing in the system is in a position to notice — the host knows what it wrote, and +the module knows what it read, and no one compares the two. + +It is not specific to credentials. Any composed value delivered through a file a container reads at +start has the same shape, which is most of what the mesh delivers. + +## How it would be checked + +A machine reporting a module as running should be able to say *what it is running with* — not what +was last written for it. The check is then a comparison the mesh can make on every heartbeat rather +than a property of one apply: for each container, does what it holds match what the files it was +built from now say. A mismatch is a drift the mesh can act on, and today it is not expressible at +all. + +## Open questions + +- Should the host recreate such a container on its own, or report the drift and let the mesh decide? + Recreating is the obvious repair and is also an unannounced restart of a running service. +- Is "the files a container was created from" something the host already knows, or does a + declaration have to say it? A restart-on list is close to this, but it is written by the module + author and is therefore exactly as complete as they remembered to make it. +- Does the same gap exist for values the mesh delivers by other means than a file?