From 900a7e17dd7bd694b6c497e6d06b9e0b318f0a95 Mon Sep 17 00:00:00 2001 From: bQUARKz Date: Wed, 11 Mar 2026 09:01:48 +0000 Subject: [PATCH] updated packer agendas --- ...- Names vs Compile-Time Lowering Agenda.md | 115 +++++++ docs/compiler/pbs/agendas/README.md | 1 + ...sets, and Virtual Asset Contract Agenda.md | 46 ++- ...ifacts and Deterministic Packing Agenda.md | 76 ++++- ...e-registry-and-stable-identity-decision.md | 8 + ...ets-and-virtual-asset-contract-decision.md | 282 ++++++++++++++++++ ...acts-and-deterministic-packing-decision.md | 250 ++++++++++++++++ 7 files changed, 768 insertions(+), 10 deletions(-) create mode 100644 docs/compiler/pbs/agendas/18.4. Asset References in Game Code - Names vs Compile-Time Lowering Agenda.md create mode 100644 docs/packer/decisions/002-asset-specification-raw-assets-and-virtual-asset-contract-decision.md create mode 100644 docs/packer/decisions/003-build-artifacts-and-deterministic-packing-decision.md diff --git a/docs/compiler/pbs/agendas/18.4. Asset References in Game Code - Names vs Compile-Time Lowering Agenda.md b/docs/compiler/pbs/agendas/18.4. Asset References in Game Code - Names vs Compile-Time Lowering Agenda.md new file mode 100644 index 00000000..2445f2f3 --- /dev/null +++ b/docs/compiler/pbs/agendas/18.4. Asset References in Game Code - Names vs Compile-Time Lowering Agenda.md @@ -0,0 +1,115 @@ +# Asset References in Game Code - Names vs Compile-Time Lowering Agenda + +## Status + +Open + +## Purpose + +Define how game code should reference assets over time: + +- by logical `asset_name`, +- by compile-time lowering to stable `asset_id`, +- or through a more structured resource model inspired by engines that expose named resources while compiling them to stable internal handles. + +## Domain Owner + +`docs/compiler/pbs` + +This is primarily a language/frontend and game-facing API question. +It depends on packer and runtime contracts, but it should be owned here because it affects source authoring, compile-time semantics, and generated runtime calls. + +## Context + +The current runtime still exposes game-facing asset operations by name. + +Examples in `../runtime` today: + +- graphics/runtime calls receive `asset_name`; +- audio/runtime calls receive `asset_name`; +- the runtime internally maps `asset_name -> asset_id` for normal asset use; +- preload/bootstrap was recently tightened around stable `asset_id`. + +At the same time, the packer model already distinguishes: + +- `asset_id` as stable artifact identity; +- `asset_name` as logical code-facing reference label. + +This leaves an open architectural question: + +Should game code continue to use strings/names directly forever, or should the compiler eventually lower asset references to more stable runtime-facing identifiers? + +## Upstream Inputs + +From packer decisions: + +- [`001-asset-workspace-registry-and-stable-identity-decision.md`](../../../packer/decisions/001-asset-workspace-registry-and-stable-identity-decision.md) +- [`002-asset-specification-raw-assets-and-virtual-asset-contract-decision.md`](../../../packer/decisions/002-asset-specification-raw-assets-and-virtual-asset-contract-decision.md) + +From runtime: + +- `preload` now resolves by `asset_id`; +- asset APIs used by game/runtime code still resolve by `asset_name`; +- `asset_table` carries both `asset_id` and `asset_name`. + +## Core Questions + +1. Should source code asset references remain name-based in the long term? +2. Should the compiler resolve known asset references at compile time and lower them to `asset_id`? +3. If compile-time lowering exists, what happens for dynamic/late-bound asset names? +4. Should PBS expose a first-class resource handle abstraction instead of raw string references? +5. What compatibility and tooling story do we want for rename of `asset_name`? +6. How much runtime lookup by name is acceptable once asset identity is already stable in packer/runtime artifacts? + +## Options + +### Option A + +Keep source and runtime calls name-based. + +### Option B + +Keep source authoring name-based, but lower resolvable references to `asset_id` at compile time. + +### Option C + +Introduce a richer resource abstraction in the language/toolchain, with compile-time or build-time resolution to stable handles under the hood. + +## Tradeoffs + +- Option A is simple and close to the current runtime, but keeps rename fragility and runtime lookup cost. +- Option B preserves authoring ergonomics while improving runtime determinism for static references. +- Option C could be the strongest long-term model, but it is also the most invasive and requires coordinated language, compiler, packer, and runtime work. + +## Recommendation + +Do not change the language surface blindly. + +Recommended sequence: + +1. preserve `asset_name` as the current source-level reference model; +2. evaluate compile-time lowering for statically known references as a separate capability; +3. only introduce a richer resource abstraction if the language ergonomics and tooling story justify the additional complexity. + +This keeps current code understandable while leaving room to remove fragile runtime string lookup from hot paths later. + +## Expected Decisions to Produce + +1. Source-level asset reference model for PBS. +2. Whether compile-time lowering to `asset_id` should exist. +3. Boundaries between static references and dynamic references. +4. Rename/refactor expectations in Studio and compiler diagnostics. +5. Relationship between source references, packer outputs, and runtime lookup. + +## Expected Spec Material + +- PBS asset reference model spec or section. +- Compiler lowering rules for asset references. +- Diagnostics/refactoring behavior for asset rename. +- Cross-reference to packer/runtime asset identity contracts. + +## Non-Goals + +- Defining every asset-related syscall in detail. +- Redesigning the entire runtime asset manager. +- Solving preload layout or `assets.pa` packing rules here. diff --git a/docs/compiler/pbs/agendas/README.md b/docs/compiler/pbs/agendas/README.md index 498d0a10..f2808ef7 100644 --- a/docs/compiler/pbs/agendas/README.md +++ b/docs/compiler/pbs/agendas/README.md @@ -10,6 +10,7 @@ Closed agendas are moved to `docs/pbs/agendas/archive`. 2. `18.1. Backend Workshop 1 - IRBackend Input Contract.md` 3. `18.2. Backend Workshop 2 - LowerToIRVM and IRVM Contract.md` 4. `18.3. Backend Workshop 3 - Bytecode Marshaling and Runtime Conformance.md` +5. `18.4. Asset References in Game Code - Names vs Compile-Time Lowering Agenda.md` ## Purpose diff --git a/docs/packer/agendas/01.2. Asset Specification, Raw Assets, and Virtual Asset Contract Agenda.md b/docs/packer/agendas/01.2. Asset Specification, Raw Assets, and Virtual Asset Contract Agenda.md index c0108371..1167fa48 100644 --- a/docs/packer/agendas/01.2. Asset Specification, Raw Assets, and Virtual Asset Contract Agenda.md +++ b/docs/packer/agendas/01.2. Asset Specification, Raw Assets, and Virtual Asset Contract Agenda.md @@ -2,7 +2,9 @@ ## Status -Open +Closed + +Resolved by [`002-asset-specification-raw-assets-and-virtual-asset-contract-decision.md`](../decisions/002-asset-specification-raw-assets-and-virtual-asset-contract-decision.md). ## Purpose @@ -28,6 +30,12 @@ Important example: - one `asset.json` describes the whole managed asset and its final packed output; - the internal source files are inputs of that asset, not separate assets unless explicitly modeled that way. +The runtime-facing extraction path also depends on codec information. +Because codec affects how runtime opens, decodes, or materializes payload bytes, codec must be explicit in the asset contract rather than hidden inside format naming. + +Preload intent is also asset-level information. +Each managed asset should carry an explicit entry indicating whether it participates in preload, so preload inclusion is declared intentionally rather than inferred indirectly later in the pipeline. + ## Source Sections - `5.3 Asset Types (Bank Targets)` @@ -44,6 +52,8 @@ Important example: 5. Is `type` the bank target, the user-facing kind, or both? 6. How should packer version output formats independently from registry and descriptor schemas? 7. How should one `asset.json` declare many internal inputs that together form one virtual asset, such as an atlas plus palettes? +8. Should codec be part of `output.format`, or a separate explicit field in the output contract? +9. How should each asset declare preload intent so the packer can materialize runtime preload entries deterministically? ## Options @@ -75,6 +85,38 @@ Also adopt this modeling direction: - many internal source files may feed that single managed output; - atlas/image-bank style assets should be modeled as one asset with many inputs rather than many implicit sibling assets. +Also adopt this output-contract direction: + +- `output.format` identifies the semantic/runtime format contract; +- `output.codec` identifies how payload bytes are stored for extraction/materialization; +- codec must remain explicit because it affects runtime extraction behavior; +- codec should not be smuggled into format naming when it represents a distinct storage concern. + +Also adopt this preload direction: + +- each managed asset must expose an explicit preload-related declaration entry; +- preload participation must be declared, not inferred from ad hoc conventions; +- packer build must use that declaration to decide whether preload data is emitted into the runtime-facing artifact contract. +- `preload.enabled` should be the required runtime-relevant boolean; +- richer packer-side preload metadata may exist, but it must not change runtime behavior until separately specified. + +Current recommended shape: + +```json +{ + "preload": { + "enabled": true, + "policy": "boot_critical" + } +} +``` + +Direction: + +- `enabled` is the normative yes/no input for runtime preload emission; +- optional fields such as `policy` are packer-side hints for Studio, diagnostics, planning, or future evolution; +- packer-side preload hints must not silently alter the current runtime-facing preload contract. + ## Expected Decisions to Produce 1. Common `asset.json` schema boundary. @@ -82,6 +124,8 @@ Also adopt this modeling direction: 3. Versioning strategy for asset format specs. 4. Rules for defaults and explicit materialization. 5. Multi-input asset declaration model for atlas, bank, and similar grouped assets. +6. Explicit separation between output format and codec in the asset contract. +7. Asset-level preload declaration model. ## Expected Spec Follow-up diff --git a/docs/packer/agendas/01.3. Build Artifacts and Deterministic Packing Agenda.md b/docs/packer/agendas/01.3. Build Artifacts and Deterministic Packing Agenda.md index d15b51ac..8eae0309 100644 --- a/docs/packer/agendas/01.3. Build Artifacts and Deterministic Packing Agenda.md +++ b/docs/packer/agendas/01.3. Build Artifacts and Deterministic Packing Agenda.md @@ -2,7 +2,9 @@ ## Status -Open +Closed + +Resolved by [`003-build-artifacts-and-deterministic-packing-decision.md`](../decisions/003-build-artifacts-and-deterministic-packing-decision.md). ## Purpose @@ -67,36 +69,87 @@ From `../runtime/docs/runtime/specs/15-asset-management.md`: These are already normative runtime-facing requirements and should be treated as baseline constraints for packer output design. +For this agenda, the intended direction is: + +- `assets.pa` is the authoritative runtime-facing artifact; +- `build/asset_table.json` is a companion tooling artifact derived from the same build result; +- runtime must not depend on `build/asset_table.json` as its primary source of truth. + +Current runtime code now resolves preload by `asset_id`, but game-facing runtime APIs still refer to assets by `asset_name`. +Therefore this agenda distinguishes: + +- `asset_id` as stable artifact identity for preload/bootstrap and asset-table integrity; +- `asset_name` as logical API-level identifier used by game/runtime-facing calls today. + +This agenda does not introduce a second runtime-only asset identity. +The `asset_id` emitted by the packer is the same `asset_id` used in the runtime-facing artifact contract. + ## Key Questions 1. How should the packer spec mirror the already normative `assets.pa` v1 envelope from runtime specs 13 and 15? -2. Which fields in `asset_table.json` are still tooling-only if the runtime-facing contract lives primarily inside `assets.pa`? -3. Is asset order always `asset_id` order, or can format-specific constraints override it? +2. Which fields in `build/asset_table.json` are companion tooling data versus runtime-facing contract data? +3. Should global asset packing order be deterministic by `asset_id`, or influenced by usage and format-specific heuristics? 4. How should alignment be expressed and validated? 5. What exactly counts as determinism for virtual asset pipelines? 6. Which inferred values must be written back versus only emitted in build outputs? 7. Which packer-side metadata is intentionally excluded from the runtime-facing contract? 8. How should packer document `preload` lifecycle and `offset` semantics so they match runtime reader behavior? +9. How should per-asset preload declarations be transformed into the `preload` section of `assets.pa` deterministically? +10. How should the packer preserve both `asset_id` integrity and `asset_name` lookup semantics in runtime-facing artifacts? +11. Should `asset_table` be modeled as a deterministically ordered asset list that preserves packer `asset_id` values end-to-end? +12. Which envelope fields are runtime-validated versus emitted only for Studio/tooling use? ## Options ### Option A -Keep `assets.pa` simple and push structure into `asset_table.json`. +Keep `assets.pa` as the authoritative autocontained runtime-facing artifact and emit `build/asset_table.json` as a derived companion artifact for Studio and tooling. ### Option B -Embed more self-description into `assets.pa` itself. +Keep runtime-facing structure split across `assets.pa` and `build/asset_table.json`. ## Tradeoffs -- Option A keeps runtime payload compact and keeps metadata easier to evolve. -- Option A matches the current draft direction and reduces double-modeling. -- Option B may help standalone introspection, but it risks splitting authority across two artifacts. +- Option A matches the runtime specs already in force. +- Option A keeps runtime authority in one artifact and prevents contract drift. +- Option A still allows rich tooling through a derived companion file. +- Option B risks splitting authority across artifacts and making runtime/tooling divergence easier. ## Recommendation -Adopt Option A and make `asset_table.json` the authoritative descriptor for ROM slice structure. +Adopt Option A with these fixed directions: + +- `assets.pa` is the authoritative runtime-facing artifact; +- the `assets.pa` header is the authoritative runtime-facing descriptor; +- `build/asset_table.json` is a derived companion artifact for Studio, debugging, inspection, and builder/tooling integration; +- global packing order is deterministic by increasing `asset_id`; +- preload emission is derived deterministically from per-asset `preload.enabled`; +- alignment exists only when explicitly required by spec; +- offsets are always relative to the payload region, never to the start of the full file; +- checksum is not part of the baseline `assets.pa` envelope contract. + +Also adopt this performance direction: + +- usage-based hot-first packing is not part of the baseline contract; +- deterministic stable ordering is preferred over heuristic physical reordering; +- future locality optimization may be introduced only through an explicit later decision and spec, not as an implementation shortcut now. + +Also adopt this identity direction: + +- runtime-facing preload entries should migrate to stable `asset_id` instead of mutable `asset_name`; +- runtime-facing preload/bootstrap integrity should treat `asset_id` as primary identity; +- `asset_name` remains present in `asset_table` as logical descriptive and API-facing metadata used by current runtime/game-facing calls; +- `asset_table` should be generated deterministically on every build from the current managed asset set; +- `asset_table` should be emitted as a deterministically ordered list of asset entries; +- the runtime-facing `asset_id` is exactly the stable `asset_id` allocated by the packer registry; +- stable cross-build identity comes from `asset_id`, not from table position; +- rename of `asset_name` is therefore an API-visible/content-visible change, but not an identity change. + +Also adopt this companion-artifact direction: + +- `build/asset_table.json` should mirror the runtime-facing header data 1:1 for debugging and inspection; +- if richer tooling artifacts are needed, they should be emitted as separate files instead of overloading `build/asset_table.json`. ## Expected Decisions to Produce @@ -106,6 +159,11 @@ Adopt Option A and make `asset_table.json` the authoritative descriptor for ROM 4. Materialization requirements for inferred values. 5. Runtime-facing artifact contract and reader expectations. 6. Packer-side restatement of the runtime-owned `assets.pa` envelope and slice semantics. +7. Deterministic mapping from asset declarations to runtime preload data. +8. Explicit exclusion of usage-based packing heuristics from the baseline contract. +9. Migration of preload/bootstrap integrity toward `asset_id`-based identity while preserving `asset_name` as current API-facing metadata. +10. Deterministically ordered `asset_table` preserving packer `asset_id` values end-to-end. +11. Separation between runtime-validated envelope fields and non-envelope tooling concerns. ## Expected Spec Follow-up diff --git a/docs/packer/decisions/001-asset-workspace-registry-and-stable-identity-decision.md b/docs/packer/decisions/001-asset-workspace-registry-and-stable-identity-decision.md index 505908b1..66272863 100644 --- a/docs/packer/decisions/001-asset-workspace-registry-and-stable-identity-decision.md +++ b/docs/packer/decisions/001-asset-workspace-registry-and-stable-identity-decision.md @@ -75,6 +75,14 @@ The following are not primary identity: Name and path are mutable presentation or location fields. +However, `asset_name` may still participate in authoring and runtime-facing APIs as a logical reference label. +That does not make it the stable identity of the asset. + +Practical consequence: + +- changing `asset_name` does not create a new asset identity; +- but changing `asset_name` may still require source-level or tooling-level reference updates where game/runtime APIs refer to assets by name. + ### 5. Relocation and rename Moving or renaming an asset root does not create a new asset. diff --git a/docs/packer/decisions/002-asset-specification-raw-assets-and-virtual-asset-contract-decision.md b/docs/packer/decisions/002-asset-specification-raw-assets-and-virtual-asset-contract-decision.md new file mode 100644 index 00000000..50e30b70 --- /dev/null +++ b/docs/packer/decisions/002-asset-specification-raw-assets-and-virtual-asset-contract-decision.md @@ -0,0 +1,282 @@ +# Asset Specification, Raw Assets, and Virtual Asset Contract Decision + +## Status + +Accepted + +## Date + +2026-03-11 + +## Context + +This decision closes the architectural questions raised in [`01.2. Asset Specification, Raw Assets, and Virtual Asset Contract Agenda`](../agendas/01.2.%20Asset%20Specification,%20Raw%20Assets,%20and%20Virtual%20Asset%20Contract%20Agenda.md). + +The packer needs a stable baseline contract for `asset.json` before detailed format-specific specs are written. + +This contract must: + +- support one managed asset root with many internal inputs; +- distinguish raw assets from virtual assets without making the common schema monolithic; +- expose runtime-relevant output information explicitly; +- declare preload intent deterministically; +- leave room for future format families without coupling all formats together. + +## Decision + +The packer adopts a compact common `asset.json` contract with explicit separation between: + +- authoring asset family; +- grouped input declaration; +- runtime-facing output contract; +- preload declaration; +- optional build/process hints. + +### 1. Common top-level shape + +The common `asset.json` contract includes these required top-level fields: + +- `schema_version` +- `name` +- `type` +- `inputs` +- `output` +- `preload` + +The common contract may additionally include: + +- `build` + +`build` is optional in the shared baseline schema. + +### 2. Meaning of `type` + +`type` identifies the authoring-side asset family. + +It is not the runtime bank target. + +Examples of valid family-style values: + +- `image_bank` +- `sound_bank` + +The runtime-facing technical target belongs in `output.format`, not in `type`. + +`name` remains the required logical asset reference label. + +Meaning: + +- `name` is not the stable artifact identity; +- `name` is the human-facing and code-facing reference used by asset-oriented APIs unless a future compile-time rewrite model replaces it; +- renaming `name` is an API-visible change even though it does not change `asset_id`. + +### 3. Input declaration model + +`inputs` is a structured object keyed by semantic role. + +Rules: + +- each key identifies an input role such as `sprites`, `palettes`, or `sources`; +- each value is a list of paths; +- paths are relative to the asset root; +- even a single input is represented as a list, not as a scalar. + +This avoids shape ambiguity and supports grouped virtual assets cleanly. + +Example: + +```json +"inputs": { + "sprites": [ + "sprites/confirm.png", + "sprites/cancel.png" + ], + "palettes": [ + "palettes/ui_main.pal" + ] +} +``` + +### 4. Output contract + +`output` is the runtime-relevant output declaration. + +The common baseline requires: + +- `output.format` +- `output.codec` + +`output.metadata` is optional in the common schema, but becomes required whenever the selected format spec requires additional normative parameters. + +Meaning: + +- `output.format` identifies the semantic/runtime format contract; +- `output.codec` identifies how payload bytes are stored for extraction and materialization; +- `output.metadata` carries format-specific runtime-relevant details. + +Codec must remain explicit. +It must not be hidden inside format naming when it represents a distinct storage concern. + +### 5. Raw and virtual asset contract + +The common schema must support both raw and virtual assets. + +Rules: + +- raw assets may declare a direct input-to-output path with minimal build metadata; +- virtual assets may declare multiple grouped inputs and optional build/process configuration; +- the common schema remains small, while detailed format behavior is defined in dedicated format specs. + +### 6. Build/process hints + +`build` is optional and carries process-oriented configuration. + +Rules: + +- `build` may describe how the packer should transform or organize authoring inputs; +- if a parameter affects the runtime-facing output contract, it belongs in `output.metadata`; +- `build` must not become a hidden substitute for runtime-relevant output definition. + +Practical interpretation: + +- `output.metadata` describes the contract of the produced payload; +- `build` describes how the packer gets there. + +### 7. Preload declaration + +Each managed asset must declare preload intent explicitly. + +The baseline shape is: + +```json +"preload": { + "enabled": true +} +``` + +Rules: + +- `preload.enabled` is required and boolean; +- preload participation is declared, not inferred; +- packer build uses this field to determine whether preload data is emitted into the runtime-facing artifact contract; +- richer preload policy fields are deferred to future decisions and must not be implied silently now. + +### 8. Defaults and materialization + +Defaults may exist in specs, but defaults that affect reproducibility, compatibility, preload, or runtime-visible output must not remain invisible. + +Rules: + +- runtime-relevant defaults should be materialized in `asset.json` whenever practical; +- if materialization occurs later in the pipeline, the resulting artifact must still expose the effective value explicitly; +- packer must not rely on hidden defaults to produce runtime-visible behavior. + +### 9. Versioning boundary + +Versioning is split by concern. + +Rules: + +- `asset.json` carries its own `schema_version`; +- registry schemas are versioned independently; +- runtime-facing artifact schemas are versioned independently; +- format contracts are versioned independently through `output.format` values such as `TILES/indexed_v1` or `SOUNDS/pcm16le_v1`. + +This prevents unrelated schema evolution from being coupled together. + +## Invariants and Constraints + +The following invariants now apply: + +1. The common `asset.json` contract remains compact. +2. `type` is authoring-side family identity, not runtime bank identity. +3. `inputs` is structured by semantic role. +4. Input path values are always lists. +5. `name` remains a logical asset reference label even though it is not the stable artifact identity. +6. `output.format` and `output.codec` are separate required concerns. +7. Runtime-relevant format details belong in `output.metadata`. +8. `build` is optional and must not hide runtime-facing output semantics. +9. `preload.enabled` is the only preload field closed in the current baseline. +10. Defaults affecting runtime-visible behavior must be materialized explicitly. +11. Format evolution is versioned independently from registry and artifact schema evolution. + +## Explicit Non-Decisions + +This decision does not yet define: + +- the full field-level schema of each format family; +- richer preload policies beyond `preload.enabled`; +- globbing support, input discovery shortcuts, or non-path input locators; +- CLI or Studio editor UX for authoring `asset.json`; +- exact `assets.pa` payload layout details; +- exact runtime preload record encoding. + +Those belong to later decisions and specs. + +## Propagation Targets + +This decision must propagate to: + +- common asset declaration spec; +- virtual asset contract spec; +- format-specific specs such as `TILES/indexed_v1` and `SOUNDS/pcm16le_v1`; +- preload emission and artifact mapping specs; +- Studio service contracts for asset authoring and validation; +- future implementation of asset parsing, validation, and deterministic build planning. + +## Validation Notes + +Example: grouped image asset + +```json +{ + "schema_version": 1, + "name": "ui_atlas", + "type": "image_bank", + "inputs": { + "sprites": [ + "sprites/confirm.png", + "sprites/cancel.png" + ], + "palettes": [ + "palettes/ui_main.pal" + ] + }, + "output": { + "format": "TILES/indexed_v1", + "codec": "RAW", + "metadata": { + "tile_size": [8, 8] + } + }, + "preload": { + "enabled": true + }, + "build": { + "layout": "atlas" + } +} +``` + +Example: grouped sound asset + +```json +{ + "schema_version": 1, + "name": "ui_sounds", + "type": "sound_bank", + "inputs": { + "sources": [ + "wav/click.wav", + "wav/confirm.wav" + ] + }, + "output": { + "format": "SOUNDS/pcm16le_v1", + "codec": "RAW" + }, + "preload": { + "enabled": false + } +} +``` diff --git a/docs/packer/decisions/003-build-artifacts-and-deterministic-packing-decision.md b/docs/packer/decisions/003-build-artifacts-and-deterministic-packing-decision.md new file mode 100644 index 00000000..f0768f68 --- /dev/null +++ b/docs/packer/decisions/003-build-artifacts-and-deterministic-packing-decision.md @@ -0,0 +1,250 @@ +# 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