Files
hq/02-DECISIONS/0097-a-vendor-image-is-a-declared-build-input.md
T
jochen 59bc551b5b
mesh/merge-gate pass: the change touches no module of the mesh's graph
mesh/repo-check pass: its merge-check.sh passed
mesh/delivery superseded: a newer head of the same pull request
ADR 0257, issues 321-323, research 035: record the bases builds copy, and say what the pre-mesh images are
The store's tools counted 23.8 GiB nothing records: copied bases the sweep could never
let go of, platforms a let-go index left behind, and images from before the mesh. Package
retention read no lockfile, so it kept versions by age alone.
2026-10-08 14:08:45 +02:00

4.0 KiB

topic, status, date, deciders, reconstructed, extends
topic status date deciders reconstructed extends
building it accepted 2026-09-21 jochen false 02-DECISIONS/0096-an-upstream-image-is-copied-between-registries.md

97. A vendor image is a declared build input, and a recipe fetches nothing undeclared

Context

Three modules could not be built by the mesh's builder because their recipes reached for what no manifest named: a public package, or a binary copied out of a public image (issue 064). A module already names the bases it stands on — another module's artifact, by name — and the builder answers with what the mesh holds; a vendor's image had no such declaration, so a recipe named it directly and the build worked when the public registry answered, which is sometimes.

Considered Options

  1. Let the build environment reach public registries. Rejected: a build that fetches from somebody else's registry on its own is one the mesh cannot rebuild the same way twice.
  2. A vendor image is a base like any other, declared under build.on with the argument the recipe reads it from, pinned by digest, copied into the mesh's registry before the build (ADR 0096). Adopted.

Decision

A build's on entry is either a module's artifact or an image published elsewhere, pinned by digest, read from one build argument. Before the build the image is copied into the mesh's registry under the module's repository and the recipe is handed the copy; genesis, with no registry, pulls it into the first machine's store. A recipe whose COPY --from names a registry image the manifest did not declare is refused before the build, naming the image and the remedy; its own stages, declared arguments and scratch are not fetches. An unpinned vendor image is refused: a tag is what somebody else can move.

The mechanism changed — 2026-10-08, by ADR 0257. A declared image is still copied into the mesh's registry before the build, and the recipe is still handed the copy. What moved is where the copy goes. It no longer goes "under the module's repository" (<module>/on-<argument>). It goes into one repository per upstream image, upstream/<host>/<path>, whichever modules stand on it. Each copy is also recorded where it is made, so the store's sweep can let it go.

A recipe whose FROM names an undeclared base was at first said, not refused: the mesh's own images — the control plane's, the tool runtime's, the route proxy's — started from a public base and declared none, and refusing those refuses genesis. Amended the same day: those three declare their bases now, and an undeclared FROM is refused like an undeclared copy. The builder's own image and the examples are built by make, not by the mesh, and take arguments with defaults.

The package half of the issue is not decided here: the mesh's package registry already proxies the public one, and the failure the report saw has to be run again to be placed.

Consequences

A module's build inputs are all in its manifest, and every one of them is something the mesh holds a copy of. What got harder: a recipe that used to name a base image on its first line now names an argument, and the manifest names the image.

How it is checked

A builder test declares a pinned vendor image, asserts it is copied under the module's repository and handed to the recipe as the argument, and asserts an unpinned one is refused. A recipe test asserts an undeclared FROM, an undeclared COPY --from and an undeclared argument are named, and that stages, declared arguments and scratch are not.

References