Correct the design: archives already work, compiling is what is missing

The first draft said the builder refused archives. It does not. An archive is
packed deterministically, hashed, published by digest, fetched by the machine and
unpacked — the whole path exists. Only the local builder used at genesis refuses
one, and deliberately: an archive is bytes that mean nothing until something
serves them, and at genesis nothing does.

What an archive cannot do is compile. Its source is a directory packed as it
stands, so shipping compiled output means compiling somewhere first, which means
a Dockerfile — the burden this document is about. The gap is not the artifact
kind. It is that no recipe both builds and packs.

Found by reading the builder rather than the manifest schema, which is where the
first draft's claim came from.

Claude-Session: https://claude.ai/code/session_01D6qtiYU3P9jk3pnAXyAFyx
This commit is contained in:
2026-09-15 01:54:43 +02:00
parent 5d1e6d0b09
commit 8a7328c282
+16 -6
View File
@@ -42,11 +42,20 @@ control plane's again. The builder's whole responsibility is the middle.
## What the model is today, and where it does not fit
**A recipe is implicit, singular, and always a Dockerfile.** `build.artifacts[].from` names one, and
producing anything means writing one. **A toolchain is not modelled at all** — it arrives as two
build arguments the module's own Dockerfile declares and the mesh fills in. **A language is not a
concept.** And **an archive is declared and unbuildable**: the manifest has the kind, the builder
refuses it.
**A toolchain is not modelled at all** — it arrives as two build arguments the module's own
Dockerfile declares and the mesh fills in. **A language is not a concept.** And a recipe is
effectively singular: producing anything *compiled* means writing a Dockerfile.
**Archives already work, and that is the corrected half of this.** An earlier draft of this
document said the builder refused them. It does not: an archive is packed deterministically,
hashed, published by digest, fetched by the machine and unpacked. Only the *local* builder used at
genesis refuses one, deliberately — an archive is bytes that mean nothing until something serves
them, and there is no registry yet.
**What an archive cannot do is compile.** `from` names a directory and the directory is packed as
it stands, so shipping compiled output means compiling somewhere first — which means a Dockerfile,
which is the burden this is about. The gap is not the artifact kind. It is that **no recipe both
builds and packs**.
The cost is not theoretical. To add a module that carries its own code today, an author writes a
Dockerfile that: declares two `ARG` bases with no defaults; compiles under a specific working
@@ -72,7 +81,8 @@ modelling one of ten resource kinds and calling it the module.
| recipe | produces | from |
|---|---|---|
| `image` | an image | a Dockerfile, when the software genuinely needs one |
| `archive` | a bundle, fetched by digest and unpacked | this module's source, compiled and bundled |
| `archive` | a bundle, fetched by digest and unpacked | a directory, packed as it stands — **today** |
| `bundle` | the same, fetched and unpacked | this module's source, *compiled* by a toolchain and then packed — **the missing one** |
| `upstream` | a mirror | somebody else's pinned reference |
**Toolchain becomes explicit, and is derived rather than written.** A module says what it is written