prometeu-studio/docs/packer/decisions/003-build-artifacts-and-deterministic-packing-decision.md
2026-03-24 13:42:38 +00:00

8.1 KiB

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.

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

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