papa-hq reads 01 research -> 03 decision -> 02 design. The order is a scar, not a choice: 02-DESIGN existed from its initial commit, and when adr/ was finally promoted on 2026-07-13 it took the next free number rather than its place in the sequence. By then design was too settled to renumber. hal-hq was three commits old, so it is not. adr/ becomes 02-DECISIONS and 02-DESIGN becomes 03-DESIGN, and following the folder numbers now walks the process in the order it happens: research produces a decision, the decision authorises a design. 00-GENESIS becomes 00-META, matching papa's rename from the same restructure. Every path reference rewritten across documents, frontmatter, playbooks and skills. All links resolve; all 58 frontmatter blocks parse and their path fields still point at files that exist.
64 lines
3.0 KiB
Markdown
64 lines
3.0 KiB
Markdown
---
|
|
status: accepted
|
|
date: 2026-08-04
|
|
deciders: jochen
|
|
reconstructed: true
|
|
---
|
|
|
|
# 13. An artifact is build output, never a source tree
|
|
|
|
> Reconstructed after the fact from the evidence cited below.
|
|
|
|
## Context
|
|
|
|
A module is built once and deployed to every node assigned to it. What travels between those
|
|
two events is the artifact.
|
|
|
|
For a long time the artifact was a filtered copy of the module's source directory. Deploying it
|
|
therefore meant resolving and installing its dependencies **on the target node** — which
|
|
requires the target to reach a package registry, at deploy time, for every node, every deploy.
|
|
A node with no route to the registry could not deploy code that had already been built
|
|
successfully.
|
|
|
|
## Considered options
|
|
|
|
1. **Ship source, install dependencies on the target.** Rejected — it is what existed. Deploy
|
|
becomes a network operation with a failure mode per node, and the code that runs is
|
|
assembled independently on each one.
|
|
2. **Ship source plus its resolved dependency tree.** Rejected: large, slow, and it ships the
|
|
dependency resolution's platform assumptions along with it.
|
|
3. **Ship a self-contained build output; a failed bundle fails the build.** Chosen.
|
|
|
|
## Decision
|
|
|
|
The artifact is the module's **build output directory** — compiled and bundled, with its
|
|
dependency graph inlined. Deploy is extract-and-run and touches no network.
|
|
|
|
A build that cannot produce a self-contained output **fails**. It does not fall back to
|
|
shipping a dependency tree, because a fallback that works is a fallback that is never fixed —
|
|
an application of [ADR 0008](0008-a-failed-step-fails-the-job.md).
|
|
|
|
## Consequences
|
|
|
|
- A node can deploy without reaching a registry. What was built is what runs, identically, on
|
|
every node.
|
|
- Deploys are faster and their failure modes are local.
|
|
- **Everything not in the build output does not ship.** This is the decision's whole cost, and
|
|
it was paid several times before it was understood: migrations that read the source layout,
|
|
provisioning scripts that read the source layout, selection files never packaged at all. Each
|
|
worked in development, where the source is present, and silently did nothing after deploy.
|
|
- Any file a module needs at runtime must be deliberately placed into the build output. The
|
|
rule "the artifact is `dist/`" has to be applied to every file kind, not just compiled code,
|
|
and that generalisation was the expensive part.
|
|
- Bundling has its own failure modes that a compiler will not catch — a bundler can exit
|
|
successfully and produce output that cannot load.
|
|
|
|
## References
|
|
|
|
- `build: bundle artifacts so a deploy is extract-and-run` (#673), 2026-08-04.
|
|
- The consequences, in order: `Provision migrations and seeds read the source layout, not the
|
|
artifact` (#699), `Local migrations read the source layout too` (#700), both 2026-08-07.
|
|
- Knowledge base: `pipeline/artifacts-are-build-output`, `pipeline/bundling`,
|
|
`troubleshooting/shell-migrations-never-packaged`, `troubleshooting/flavors-never-packaged`,
|
|
`troubleshooting/esbuild-silent-tla-breakage`.
|