# pack — design
> **Class:** `design` · **Function axis:** `f1` (AIRGAP1). States only the shape we ship.
## What pack produces
`pack` gathers a product's artifacts (and, optionally, target-identical dependencies) into a
versioned **staging tree** — the input `Archive::pack` (f2) seals. It also records provenance.
## The staging tree
`pub struct Staging { root, version }` (`pack.rs:31`) — the builder.
| method | signature | what it does |
|---|---|---|
| `new` | `Staging::new(root, version) -> Staging` (`pack.rs:38`) | create an empty staging root |
| `add_artifact` | `add_artifact(src, rel) -> String` (`pack.rs:50`) | copy a file in under relative path `rel` |
| `add_component_spec` | `add_component_spec(spec) -> String` (`pack.rs:63`) | write `manifests/<name>.json` |
| `artifacts` | `artifacts() -> Vec<String>` (`pack.rs:73`) | enumerate staged files (sorted) |
## VERSION lives outside the bundle
`pack::write_version_file(beside_bundle, version) -> PathBuf` (`pack.rs:84`) writes a `VERSION`
file **next to** the bundle, not inside it — so bumping the shipped version never requires
repacking the archive.
## Provenance
`pack::pack(staging, product, built_in_container) -> PackManifest` (`pack.rs:95`) records a
`PackManifest { product, version, built_in_container, artifacts }` (`pack.rs:18`) by enumerating
the staging tree — the per-product record of what went in.
## Target-identical dependency capture
`pub trait ContainerBuild { build_into(product, target_triple, into) -> Vec<String> }`
(`pack.rs:107`) is the seam for capturing a component's deps *byte-alike with the destination* by
building it in a container. The real impl is `PodmanBuild` (`pack.rs:124`):
- `new(base_image)` (`pack.rs:139`), `step(run)` (`pack.rs:149`) — builder.
- `containerfile(product, target_triple) -> String` (`pack.rs:157`) — pure Containerfile render.
- `runtime_available() -> bool` — `podman --version` check (the lean/default path only).
- `build_into` — captures the deps into the staging subdir, via one of two engines:
- **default (lean):** `podman build → create → copy /out → cleanup`; **honest bail** if podman is
absent, never a faked capture.
- **`pack-oci` feature:** the same build over draupnir's ONE OCI engine —
`ContainerBoot::build_image` + `extract_path` (the `create`+`cp` twin), zero-shell, one engine
constellation-wide. `copy_tree_contents` flattens the extract to the exact `cp /out/.` layout so
both engines leave `into` byte-identical. See `msi-oci-routing.md`.
This is a **build-host-only** seam — it never runs at airgap-install time.
## Contract (inject-assert tests)
`pack_collects_staging_tree_and_version_file_is_outside` asserts the `VERSION` file lands outside
the bundle tree; `podman_build_renders_containerfile_and_is_honest_when_absent` asserts the exact
Containerfile bytes and the honest failure when podman is absent;
`copy_tree_contents_flattens_extracted_out_dir_into_staging` asserts the `pack-oci` engine's extract
flattens to the same relative paths the `podman cp /out/.` path produced (byte-identical `into`).