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.
5.3 KiB
status, opened, located-in, fixed-by, amended-design
| status | opened | located-in | fixed-by | amended-design | |||
|---|---|---|---|---|---|---|---|
| resolved | 2026-08-28 |
|
|
009 — A digest-pinned image cannot be placed in the lab, so container cannot be tested there
Symptom
Two accepted decisions collide, and the collision makes one resource shape untestable.
-
ADR 0006 pins images by digest, and the host refuses an image reference that is not pinned:
resource "store": image "alpine:3.20" is not pinned. Write it as name@sha256:... -
The lab cannot place a digest-pinned image. A sealed scenario cannot reach a registry, so the lab exports an image from the workstation and loads it in the machine — and that loses the digest.
So a container resource is refused by the host if it names a tag, and unusable if it names a
digest. There is no declaration the lab can currently raise that exercises the shape.
What was measured
Not inferred. docker save alpine@sha256:d9e8… produces an archive with no repo tag, because
a repo digest exists only for an image a registry served. Loading it says:
Loaded image ID: sha256:63f227… (not "Loaded image: alpine:3.20")
and docker images then lists nothing — the image is there but dangling. A container declaring
that digest therefore falls through to the registry:
Unable to find image 'alpine@sha256:d9e8…' locally
dial tcp: lookup registry-1.docker.io: no such host
which is correct behaviour on a machine with no route out.
What is not affected
Everything else placed in the same sealed machine works, and was verified there:
| shape | |
|---|---|
package |
applied, idempotent |
service incl. boot: enabled |
applied, read back as enabled |
action |
ran, verified |
container |
blocked by this issue |
Why it matters more than one shape
The container shape is the substrate. Every step of raising a mesh past the container runtime is
a container (07-the-foundation.md), so the
bootstrap cannot be tested end-to-end until this is resolved — which is the thing the lab exists
for.
How it was fixed
2026-08-29. A registry inside the scenario, as below — and it turned out to be the shape the resolution predicted rather than a compromise on it.
A scenario declares images: by tag. The lab stocks a registry on the workstation, where
there is a network, then raises one inside the scenario as scenery and serves them from it.
What a declaration pins is reported when the scenario is raised, because the digest belongs to
that registry and is not knowable before it exists.
The digests are the lab registry's own, and that is correct rather than a workaround. What ADR 0006 requires is a reference that is exact and cannot move. A digest this registry assigned is both.
Verified in a machine confirmed to have no route out: package, service including boot state,
a container pinned by digest, and an action inside that container — applied, idempotent on
re-apply, and read back from the machine rather than from the apply's own report.
One fault is worth keeping, because it is this repository's own subject arriving in the
tooling built to catch it. The read-back checked that the registry's catalog endpoint answered,
by looking for the substring repositories — which {"repositories":[]} also contains. So it
passed on a registry holding nothing, and the failure surfaced much later as a container that
could not be pulled, a long way from its cause. It now asks for each image's manifest by
digest, which is what a machine actually does.
The shape of a resolution
A registry inside the scenario, on its public segment, that machines pull from. That is not a workaround: it is what the real mesh does — ADR 0006 names an OCI registry as substrate, and every node after the first pulls from the mesh's own. Testing against a registry is testing the real path rather than a stand-in for it.
It also removes the lab's export-and-push mechanism rather than fixing it, which is the better outcome: pushing image tarballs over the hypervisor was always a lab-only invention.
Not decided here, because it is design rather than repair: where the registry runs, whether it is scenery like the router (ADR 0016) or a placed artifact, and how images get into it.
Incidental, and already fixed
The lab's own check on the load was too weak: it matched "Loaded image", which is a prefix of
both Loaded image: and Loaded image ID:. So a load that produced an unusable dangling image
reported success, and the failure surfaced later as a container that would not start. It now
matches Loaded image: exactly and says what the runtime actually said.
That is this repository's own subject arriving in its own tooling: a check that passes on the wrong thing is worse than no check, because it moves the failure away from its cause.