The blocking question was where a container image comes from, and the version that blocked assumed the machine might have no network. That assumption came from the LAB: a scenario is a closed address space by design, which is what lets two scenarios hold the same addresses without meeting. Production is not sealed — a machine being adopted has a network, and one that does not is a machine where very little works anyway. So substrate.lock carries references, not payload: an image name and a digest, fetched at apply time. A first node pulls from upstream because no mesh registry exists yet; every node after that pulls from the mesh's own. The lab is the exception and places images itself, the way it already places the host binary — a property of a test environment, and letting it dictate the production design would be the tail wagging the dog. Pinned by DIGEST rather than tag. Reproducibility comes from pinning the identity of a thing, not from carrying its bytes, which is what makes fetching acceptable rather than a compromise. ADR 0041 survives untouched, which was the point. "Copy it onto a machine and run it" stays literally true — one binary, a few megabytes, which then fetches what it was told to. Carrying images would have quietly redefined the property that decision rests on. Costs accepted and named: an apply can now fail because something is unreachable, which a self-contained artifact could not, so it must fail legibly — naming what it could not fetch and from where. And the lab needs a way to place images into a machine that also has no container runtime, both of which are lab-installation concerns and neither solved here. Research 012's build-time-versus-apply-time reframing narrows accordingly: it still holds for what a tailored installer contains, and no longer has to hold for images.
01-RESEARCH
Investigations that have not yet hardened into design.
Structure
Each effort lives in NNN-descriptive-name/ and must contain 00-overview.md, carrying its
state in YAML frontmatter and a prose summary below it:
---
status: active | graduated | abandoned
initiated: YYYY-MM-DD
touches: [] # design docs, subsystems or areas the effort bears on
became: [] # required when status is terminal — what it turned into
---
The prose says what is being investigated, why, and what it touches. It does not restate the status — status lives in one place, and two places is one too many.
Further documents in the same folder hold the work itself: notes, evidence, option analyses, draft designs.
Lifecycle
| status | Meaning |
|---|---|
active |
Investigation in progress. |
graduated |
Checked against 00-META, decided in 02-DECISIONS/, and specified in 03-DESIGN — see became:. |
abandoned |
Stopped or superseded. Nothing is deleted. |
An effort graduates by producing a decision record and a 03-DESIGN entry. It is abandoned
in place — never deleted. What was rejected, and why, is the more expensive half to
rediscover.
Starting and closing efforts is playbook territory:
00-META/process/01-research.md and
02-graduation.md.
Rules
- Markdown only. Do not skip or reuse a sequence number.
- Evidence, not assertion. An effort that measured nothing has not finished.
- Research describes real observations but never identifies the mesh it observed. The shape of a finding survives anonymisation intact.