Files
hq/04-ISSUES/029-the-artifact-store-cannot-be-delivered-by-the-artifact-store/00-report.md
T
jschoubben 36d9b38a0d An issue is open, diagnosing, located, resolved or wontfix — nothing else
The playbook, the README and the status skill knew five statuses; the cycle check
knew a sixth, 'fixed', and not 'wontfix'. Eleven issues sat in the sixth for weeks
with their fixes shipped, one step short of closed. They are resolved; the check
refuses the word from now on and accepts the one the playbook allows.
2026-09-21 17:38:17 +02:00

5.0 KiB

status, opened, located-in, fixed-by, amended-design
status opened located-in fixed-by amended-design
resolved 2026-09-01
mesh-control
mesh-control be62f49; mesh-lab f85dbb0

029 — The artifact store cannot be delivered by the artifact store

Symptom

A mesh that has just bootstrapped cannot install a registry. The module describing one resolves, composes and pushes; the build never completes, because there is nowhere to put what it builds.

It has never been seen, because the lab always has a registry standing before the mesh asks for one, and so does any mesh built on a machine that already had one.

What it actually blocks

Not "a registry cannot be installed" — a mesh cannot hold its own modules.

The artifact store is one store for everything a module ships: images, and archives, which are directories from a module's repository packed and pushed as content-addressed blobs. So it is the mesh's module catalogue in artefact form, and the same role a separate object store plays in the arrangement being replaced.

Until it exists, a module can be described and resolved but nothing it carries can be kept anywhere. A mesh that has just bootstrapped can therefore run only what its bundle already holds.

The cycle

Three facts, each correct on its own:

  • A registry module's image is mirrored in. kind: upstream pulls the reference the module names and pushes it under a name of the mesh's own, so what a machine fetches is pinned by a digest this mesh assigned rather than by a tag somebody else can move.
  • The builder publishes to the artifact store, learned from its artifact-store binding — the same binding any consumer of any provision gets.
  • The builder refuses to run without one: "a built artifact nobody can fetch is not built."

So installing the thing that provides artifact-store requires something that provides artifact-store.

Why the design already answers it

The substrate record asks of each candidate can it grant itself the thing it provides? The store cannot create its own database; the broker cannot create its own virtual host; and the registry cannot grant itself a repository. That is why the registry is substrate by role.

The same sentence answers this. A module that provides the artifact store cannot be delivered through the artifact store, so its image is not the mesh's to mirror — it is named directly and pulled from upstream exactly once, which is what the bundle already does for the three images a first node starts from.

The fix

The registry module names its image, and is never built. A container naming registry@sha256:… needs no builder, no binding and no store. Every module after it mirrors normally, into the registry now running.

Nothing new is required: naming an image directly is what most modules do.

What it costs, and what it does not

The machine running the first registry needs to reach a public registry once, to pull that one image by digest. That is already true of a first node, which fetches three images the same way before a mesh exists.

It does not weaken pinning. A digest is exact wherever it came from; what mirroring adds is that the mesh keeps its own copy and does not depend on a tag somebody else controls. For one image, on one machine, once, the bundle already accepts that trade and says why.

The constraint this puts on a registry module

A module providing artifact-store may not build artifacts of its own — not its image, and not a user interface or a tool server shipped beside it. There is nowhere to put them until it is running.

A registry that wants more than the upstream image is therefore two modules: one that provides the store and only names an image, and an ordinary module beside it that builds whatever else and mirrors it in the normal way. That is a real limit on how a registry module can be written, and it should be said out loud rather than discovered.

How it is checked

A manifest that both provides artifact-store and declares built artifacts is refused where it is written, naming the cycle. Otherwise the fault surfaces as a build that never returns, on a mesh too new to have anybody watching it.

Fixed

The registry module names its image and is added, not built. The lab's artifact-store test now walks the only path open to a real first mesh — the manifest goes in directly, no builder and no store involved — and passes.

And the cycle is refused where it is written. A manifest that provides artifact-store and also declares built artifacts is refused at parse, naming the cycle: building publishes to the store, so it asks the mesh to put an artifact into the thing that artifact is needed to create. The provision name became a constant for the rule to turn on.

What surfaced it in the lab is worth keeping: the test had always built the registry module and passed, because the scenario's stand-in for the public registry was standing there to receive the push. A prop that quietly covers for the thing under test is how a bootstrap hole stays invisible.