# Build Artifacts and Deterministic Packing Decision ## Status Accepted ## Date 2026-03-11 ## Context This decision closes the architectural questions raised in [`01.3. Build Artifacts and Deterministic Packing Agenda`](../agendas/01.3.%20Build%20Artifacts%20and%20Deterministic%20Packing%20Agenda.md). The packer must produce build artifacts that are: - deterministic; - aligned with the runtime-facing `assets.pa` contract already established in `../runtime`; - usable by Studio and tooling without creating a second source of truth; - stable enough to support future specs and implementation. The runtime-side contract already establishes that: - `assets.pa` is the runtime-facing artifact; - `asset_table` and `preload` live in the internal JSON header; - offsets are relative to the payload region; - preload is boot-time input only. This decision closes how the packer should produce these artifacts. ## Decision The packer adopts an `assets.pa`-authoritative, deterministically ordered, canonical-header model. ### 1. Artifact authority `assets.pa` is the authoritative runtime-facing artifact. Rules: - the `assets.pa` header is the runtime-facing source of truth for `asset_table` and `preload`; - `build/asset_table.json` and other JSON outputs are companion artifacts only; - runtime must not depend on companion JSON files as its primary contract. ### 2. Companion artifacts The packer emits separate companion artifacts for tooling and debugging. Baseline companion outputs: - `build/asset_table.json` - `build/preload.json` - `build/asset_table_metadata.json` Rules: - `build/asset_table.json` mirrors `header.asset_table` 1:1; - `build/preload.json` mirrors `header.preload` 1:1; - `build/asset_table_metadata.json` is tooling-only and may carry richer packer metadata; - richer tooling data must not be smuggled into the runtime-facing mirror files. ### 3. `assets.pa` v1 prelude The baseline packer-side prelude for `assets.pa` v1 includes: - `magic` - `schema_version` - `header_len` - `payload_offset` - `flags` - `reserved` Rules: - `flags` exists from day 1 for forward compatibility; - `reserved` exists from day 1 for forward compatibility; - `flags = 0` in the current baseline unless a future spec says otherwise; - `reserved = 0` in the current baseline unless a future spec says otherwise; - `header_checksum` is not part of the baseline `assets.pa` envelope contract. ### 4. Checksum policy Header checksum is not part of the baseline runtime-facing envelope. Rules: - runtime validation does not depend on header checksum; - cartridge-level integrity may be handled elsewhere; - Studio/tooling may compute checks or hashes separately if needed; - such checks must not redefine the runtime-facing `assets.pa` envelope. ### 5. Canonical JSON header The JSON header of `assets.pa` must be serialized canonically. Canonicalization rules: - UTF-8 encoding; - no extra whitespace; - object keys sorted lexicographically; - arrays preserve declared order; - canonicalization applies recursively, including nested metadata objects; - runtime-facing header values in v1 must avoid floating-point numbers. This is required so equivalent inputs produce byte-identical headers and therefore byte-reproducible artifacts. ### 6. Ordering and determinism The global `asset_table` order is deterministic by increasing `asset_id`. Rules: - usage-based or hot-first packing is not part of the baseline contract; - format-specific heuristics must not reorder the global asset list; - deterministic ordering is preferred over physical-layout heuristics; - future locality optimization requires a separate explicit decision and spec. ### 7. `asset_id` continuity The `asset_id` used in runtime-facing artifacts is the same stable `asset_id` allocated by the packer registry. Rules: - the packer does not generate a second runtime-only asset identity; - `preload` refers to the same `asset_id` values that appear in `asset_table`; - table position does not define identity; - cross-build identity stability comes from `asset_id`, not from table index. ### 8. Asset table shape `asset_table` is emitted as a deterministically ordered list of asset entries. Rules: - one emitted entry per managed asset in the build set; - no synthetic dense reindexing layer is introduced; - omission of removed assets happens naturally because the emitted table reflects the current build set only; - the runtime sees a normal contiguous list of entries, but the IDs inside it remain the stable packer IDs. ### 9. `asset_name` in runtime-facing artifacts `asset_name` remains present in `asset_table`. Meaning: - `asset_name` is logical descriptive and API-facing metadata; - current runtime/game-facing calls may still use it for normal asset lookup; - preload/bootstrap integrity relies on `asset_id`, not `asset_name`; - renaming `asset_name` is an API-visible/content-visible change, but not an asset identity change. ### 10. Preload mapping Preload emission is derived deterministically from per-asset declaration. Rules: - assets with `preload.enabled = false` do not appear in emitted preload data; - assets with `preload.enabled = true` produce preload entries in the runtime-facing preload list; - emitted preload ordering is deterministic by increasing `asset_id`; - preload is boot-time input only and must be emitted in a form consistent with the runtime contract. ### 11. Alignment Alignment exists only when explicitly required by spec. Rules: - there is no implicit baseline alignment beyond what is required by the envelope and chosen formats; - if a format requires alignment, the requirement must be normative and visible in the relevant spec; - computed offsets must always be emitted explicitly in the runtime-facing descriptor. ### 12. Offsets All emitted asset offsets are relative to the payload region. Rules: - offsets are never relative to the start of the whole `assets.pa` file; - this rule must be preserved consistently across packer outputs and specs; - companion artifacts must mirror the same offset semantics. ## Invariants and Constraints The following invariants now apply: 1. `assets.pa` is the authoritative runtime-facing artifact. 2. Companion JSON files do not replace the internal `assets.pa` header. 3. `build/asset_table.json` mirrors `header.asset_table` 1:1. 4. `build/preload.json` mirrors `header.preload` 1:1. 5. `build/asset_table_metadata.json` is tooling-only. 6. The prelude includes `magic`, `schema_version`, `header_len`, `payload_offset`, `flags`, and `reserved`. 7. `header_checksum` is not part of the baseline envelope contract. 8. Header JSON is canonicalized. 9. Global asset ordering is deterministic by increasing `asset_id`. 10. The runtime-facing `asset_id` is the same stable packer `asset_id`. 11. `asset_table` is a deterministically ordered list, not a second identity system. 12. `asset_name` remains present as logical/API-facing metadata. 13. Preload is emitted deterministically from `preload.enabled`. 14. Offsets are relative to the payload region only. ## Explicit Non-Decisions This decision does not yet define: - the exact field-level metadata contract of each output format; - richer preload policies beyond the current baseline; - future physical locality optimization; - game-language lowering of asset references from names to IDs; - cartridge-level integrity/signature strategy. Those belong to later decisions and specs. ## Propagation Targets This decision must propagate to: - packer artifact and envelope specs; - packer determinism and reproducibility specs; - packer preload emission specs; - Studio tooling expectations for companion artifacts; - future implementation of canonical header generation and companion-file emission. ## Validation Notes Example: artifact relationship ```text assets.pa prelude canonical header JSON asset_table preload payload bytes build/asset_table.json mirrors header.asset_table build/preload.json mirrors header.preload build/asset_table_metadata.json tooling-only enrichment ``` Example: stable identity - packer registry assigns asset IDs `3`, `7`, and `11` - emitted `asset_table` is ordered `[3, 7, 11]` - runtime-facing preload entries reference `3`, `7`, or `11` - no additional dense runtime ID layer is introduced