251 lines
8.1 KiB
Markdown
251 lines
8.1 KiB
Markdown
# 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
|