diff --git a/docs/packer/agendas/Tile Bank Packing Materialization Agenda.md b/docs/packer/agendas/Tile Bank Packing Materialization Agenda.md index b1560364..b23e0adb 100644 --- a/docs/packer/agendas/Tile Bank Packing Materialization Agenda.md +++ b/docs/packer/agendas/Tile Bank Packing Materialization Agenda.md @@ -138,6 +138,12 @@ Regras recomendadas: - a ordem de agregação dos artifacts deve ser determinística by `artifacts[*].index`; - for v1, `1 artifact = 1 tile`; - for the current target, the canonical tile-bank sheet is always `256 x 256`; +- tile placement inside that fixed sheet is row-major; +- `tile_id` is the linear row-major slot and therefore matches the normalized `artifacts[*].index`; +- resulting capacity is therefore: + - `tile_size = 8` -> `32 x 32 = 1024` tiles + - `tile_size = 16` -> `16 x 16 = 256` tiles + - `tile_size = 32` -> `8 x 8 = 64` tiles - o payload final do asset deve ter fronteiras e interpretação definidas pelo próprio contrato do formato, não por convenção incidental de concatenação; - para `TILES/indexed_v1`, o payload v1 já deve assumir: 1. plano de pixels packed `u4`; @@ -173,6 +179,10 @@ Baseline now fixed by the runtime consumer: - `palette_count = 64` - `width` and `height` are bank-sheet helpers, not per-artifact dimensions - with the current v1 target, the emitted bank sheet is fixed at `256 x 256` +- producer-side metadata normalization must emit what the consumer requires while preserving segmented authoring meaning: + - `asset.json.output.metadata` -> `AssetEntry.metadata` + - `asset.json.output.codec_configuration` -> `AssetEntry.metadata.codec` + - `asset.json.output.pipeline` -> `AssetEntry.metadata.pipeline` ### Metadata Recommendation @@ -185,10 +195,10 @@ Direção inicial recomendada: - `width` - `height` - `palette_count`; -- `AssetEntry.metadata` should aggregate normalized maps derived from: - - `asset.json.output.metadata` - - `asset.json.output.codec_configuration` - - `asset.json.output.pipeline`; +- `AssetEntry.metadata` should aggregate normalized maps using this structure: + - `asset.json.output.metadata` -> `metadata` + - `asset.json.output.codec_configuration` -> `metadata.codec` + - `asset.json.output.pipeline` -> `metadata.pipeline` - bank palettes are declared in `asset.json.output.pipeline.palettes` using explicit `{ index, palette }` entries and emitted in ascending numeric `index` order; - any tile in the bank may be rendered with any palette in the bank; - palette assignment is therefore not a per-artifact packing contract and remains a runtime draw-time concern; @@ -208,10 +218,14 @@ O build de `tile bank` deve falhar quando qualquer uma das seguintes condições Additional first-wave diagnostic expectations: -- bank without declared palettes in `asset.json.output.pipeline.palettes` must emit a diagnostic; -- tile banks whose declared palette list exceeds `64` must fail; -- tiles that use fragile indices, meaning indices not represented safely across the full declared bank palette set, should emit a `WARNING`; -- that fragile-index warning is advisory in the first wave and should not block pack by itself unless later promoted by decision. +- duplicate `artifacts[*].index` is `blocking`; +- gap in normalized `artifacts[*].index` ordering is `blocking`; +- sheet-capacity overflow for the fixed `256 x 256` target is `blocking`; +- bank without declared palettes in `asset.json.output.pipeline.palettes` is `blocking`; +- declared palette list above `64` is `blocking`; +- malformed palette declarations are `blocking`; +- tiles that use fragile indices, meaning indices not represented safely across the full declared bank palette set, emit a `WARNING`; +- that fragile-index warning is advisory in the first wave and does not block pack by itself unless later promoted by decision. ### Packing Boundary Recommendation @@ -231,13 +245,7 @@ Regras: ## Open Questions -1. Given the fixed `256 x 256` bank target, what is the canonical tile placement rule inside that sheet for `tile_size = 8`, `16`, and `32`? -2. Which normalization diagnostics should be `blocking` versus `warning` specifically for: - - artifact index gaps or duplicates - - sheet capacity overflow - - palette list overflow beyond `64` - - banks without declared palettes - - fragile tile indices across the declared bank palette set? +1. None at this stage for the tile-bank v1 producer contract. ## Expected Follow-up diff --git a/docs/packer/decisions/README.md b/docs/packer/decisions/README.md index b34aa66a..2a9d5bb5 100644 --- a/docs/packer/decisions/README.md +++ b/docs/packer/decisions/README.md @@ -6,8 +6,10 @@ Retained packer decision records: - [`Concurrency, Observability, and Studio Adapter Boundary Decision.md`](./Concurrency,%20Observability,%20and%20Studio%20Adapter%20Boundary%20Decision.md) - [`Filesystem-First Operational Runtime and Reconcile Boundary Decision.md`](./Filesystem-First%20Operational%20Runtime%20and%20Reconcile%20Boundary%20Decision.md) +- [`Metadata Convergence to AssetEntry.metadata Decision.md`](./Metadata%20Convergence%20to%20AssetEntry.metadata%20Decision.md) - [`Pack Wizard Summary and Validation Contracts Decision.md`](./Pack%20Wizard%20Summary%20and%20Validation%20Contracts%20Decision.md) - [`Pack Wizard Pack Execution Semantics Decision.md`](./Pack%20Wizard%20Pack%20Execution%20Semantics%20Decision.md) +- [`Tile Bank Packing Materialization Decision.md`](./Tile%20Bank%20Packing%20Materialization%20Decision.md) The first packer decision wave was already consolidated into: diff --git a/docs/packer/decisions/Tile Bank Packing Materialization Decision.md b/docs/packer/decisions/Tile Bank Packing Materialization Decision.md new file mode 100644 index 00000000..83d57652 --- /dev/null +++ b/docs/packer/decisions/Tile Bank Packing Materialization Decision.md @@ -0,0 +1,211 @@ +# Tile Bank Packing Materialization Decision + +Status: Accepted +Date: 2026-03-20 +Domain Owner: `docs/packer` +Cross-Domain Impact: `../runtime`, `docs/studio` + +## Context + +The packer execution contract for `packWorkspace(...)` is already closed. + +What remained open for `tile bank` was the format-specific producer contract: + +- which selected files become part of the packed asset; +- how those files become the canonical `TILES/indexed_v1` payload; +- how `AssetEntry` fields are derived for runtime consumption; +- how bank palettes are declared and normalized; +- which diagnostics block the build for this format. + +The agenda that closed this discussion is: + +- [`../agendas/Tile Bank Packing Materialization Agenda.md`](../agendas/Tile%20Bank%20Packing%20Materialization%20Agenda.md) + +Relevant upstream references are: + +- [`../decisions/Pack Wizard Pack Execution Semantics Decision.md`](../decisions/Pack%20Wizard%20Pack%20Execution%20Semantics%20Decision.md) +- [`../specs/3. Asset Declaration and Virtual Asset Contract Specification.md`](../specs/3.%20Asset%20Declaration%20and%20Virtual%20Asset%20Contract%20Specification.md) +- [`../specs/4. Build Artifacts and Deterministic Packing Specification.md`](../specs/4.%20Build%20Artifacts%20and%20Deterministic%20Packing%20Specification.md) +- [`../pull-requests/PR-32-palette-declarations-with-explicit-index-contract.md`](../pull-requests/PR-32-palette-declarations-with-explicit-index-contract.md) +- [`../../../runtime/docs/runtime/specs/04-gfx-peripheral.md`](../../../runtime/docs/runtime/specs/04-gfx-peripheral.md) +- [`../../../runtime/docs/runtime/specs/15-asset-management.md`](../../../runtime/docs/runtime/specs/15-asset-management.md) +- [`../../../runtime/docs/runtime/agendas/024-asset-entry-metadata-normalization-contract.md`](../../../runtime/docs/runtime/agendas/024-asset-entry-metadata-normalization-contract.md) + +## Decision + +The first-wave packer materialization contract for `tile bank` adopts the following direction: + +1. `TILES/indexed_v1` emits one canonical payload per asset. +2. `1 artifact = 1 tile` in the first wave. +3. Artifacts are ordered by normalized `artifacts[*].index`. +4. Tile placement is row-major in one fixed `256 x 256` sheet. +5. `tile_id` is the linear row-major slot and therefore matches the normalized artifact index. +6. Tile pixels are serialized as packed `u4` indices. +7. Bank palettes are serialized as `RGB565` `u16` values. +8. Palette declarations use explicit semantic identity through `{ index, palette }`. +9. `AssetEntry.metadata` keeps required runtime fields readable at the root while preserving segmented codec and pipeline subtrees. +10. Format-structural diagnostics are raised in the walker/materialization path and therefore participate in validation before pack execution reruns the gate. + +## Adopted Constraints + +### 1. Canonical Payload Shape + +- the payload is produced from build-selected artifacts only; +- the payload is the canonical bank sheet raster, not a concatenation of per-artifact binary fragments; +- for `TILES/indexed_v1`, the serialized payload shape is: + 1. packed `u4` pixel indices for the full emitted sheet; + 2. one palette block of `64 * 16 * 2` bytes; +- palettes are always materialized to `RGB565` during pack emission; +- the producer-side payload contract is aligned to what the runtime loader already requires. + +### 2. Artifact-to-Tile Contract + +- `1 artifact = 1 tile` in v1; +- artifacts are normalized by `artifacts[*].index`; +- `tile_id = artifacts[*].index` after normalization; +- the canonical emitted sheet is always `256 x 256`; +- placement is row-major within that fixed sheet. + +Resulting tile capacities: + +- `tile_size = 8` -> `32 x 32 = 1024` tiles +- `tile_size = 16` -> `16 x 16 = 256` tiles +- `tile_size = 32` -> `8 x 8 = 64` tiles + +### 3. Runtime Entry Contract + +Each emitted `tile bank` runtime entry must populate: + +- `asset_id` +- `asset_name` +- `bank_type = TILES` +- `offset` +- `size` +- `decoded_size` +- `codec = NONE` +- `metadata` + +For v1: + +- `size = ceil(width * height / 2) + 2048` +- `decoded_size = (width * height) + 2048` +- `width = 256` +- `height = 256` +- `palette_count = 64` + +### 4. Palette Contract + +- bank palettes are declared in `asset.json.output.pipeline.palettes`; +- each palette declaration must use explicit shape `{ index, palette }`; +- semantic ordering is ascending numeric `index`, never raw array position; +- palette ids are the normalized declared `index` values; +- any tile in the bank may be rendered with any palette in the bank; +- palette choice is a runtime draw-time concern and is not embedded per tile in the packed payload. + +### 5. Metadata Normalization Contract + +`AssetEntry.metadata` keeps runtime-required fields readable while preserving authoring segmentation: + +- `asset.json.output.metadata` -> `AssetEntry.metadata` +- `asset.json.output.codec_configuration` -> `AssetEntry.metadata.codec` +- `asset.json.output.pipeline` -> `AssetEntry.metadata.pipeline` + +For tile-bank v1 this means: + +- `tile_size`, `width`, `height`, and `palette_count` remain directly readable at the metadata root; +- codec-specific data is nested under `metadata.codec`; +- pipeline-derived data is nested under `metadata.pipeline`. + +This packer decision intentionally aligns with the runtime-side follow-up agenda rather than flattening everything into one ambiguous map. + +### 6. Diagnostics and Failure Semantics + +The following conditions are blocking for tile-bank v1: + +- duplicate `artifacts[*].index` +- gaps in normalized `artifacts[*].index` +- fixed-sheet capacity overflow +- bank without declared palettes +- palette declaration count above `64` +- malformed palette declarations +- missing or invalid required format metadata +- any failure to normalize artifacts into one deterministic payload + +The following condition is warning-only in the first wave: + +- fragile tile indices, meaning tile indices that are not safely represented across the full declared bank palette set + +### 7. Walker and Validation Boundary + +- family walkers remain discovery-oriented; +- tile-bank structural diagnostics must be produced in the walker/materialization path; +- validation consumes those diagnostics naturally; +- pack execution reruns the validation gate on a newly created frozen execution snapshot before materialization begins. + +## Why This Direction Was Chosen + +- It matches the runtime consumer contract instead of inventing a producer-local interpretation. +- It keeps `tile bank` payload semantics explicit and deterministic. +- It avoids embedding per-artifact or per-draw palette assignment into the packed bytes. +- It preserves stable palette identity through explicit `index` declarations. +- It keeps validation early without weakening the pack-time rerun gate. +- It gives the runtime a metadata shape that is readable and still semantically segmented. + +## Explicit Non-Decisions + +This decision does not yet define: + +- future support for `1 artifact -> many tiles`; +- non-`256 x 256` tile-bank targets; +- alternative tile-bank codecs beyond `NONE`; +- future palette compaction or palette-id remapping strategies; +- the runtime-side final decision for general `AssetEntry.metadata` normalization helpers; +- future sprite or tilemap semantic adjustments unrelated to packer-owned payload production. + +## Implications + +- tile-bank packing implementation must materialize a full sheet raster rather than artifact fragments; +- tile-bank payload generation must pack `u4` indices explicitly in the packer; +- palette declarations and palette overhauling flows must preserve explicit palette `index`; +- runtime-entry metadata emission must preserve both root-required fields and segmented nested maps; +- tile-bank validation logic belongs in the walker/materialization path and must be reused by pack execution gate reruns. + +## Propagation Targets + +Specs: + +- [`../specs/3. Asset Declaration and Virtual Asset Contract Specification.md`](../specs/3.%20Asset%20Declaration%20and%20Virtual%20Asset%20Contract%20Specification.md) +- [`../specs/4. Build Artifacts and Deterministic Packing Specification.md`](../specs/4.%20Build%20Artifacts%20and%20Deterministic%20Packing%20Specification.md) + +Plans: + +- [`../pull-requests/PR-32-palette-declarations-with-explicit-index-contract.md`](../pull-requests/PR-32-palette-declarations-with-explicit-index-contract.md) +- future packer PR for tile-bank payload materialization +- future packer PR for tile-bank validation diagnostics + +Cross-domain references: + +- [`../../../runtime/docs/runtime/specs/04-gfx-peripheral.md`](../../../runtime/docs/runtime/specs/04-gfx-peripheral.md) +- [`../../../runtime/docs/runtime/specs/15-asset-management.md`](../../../runtime/docs/runtime/specs/15-asset-management.md) +- [`../../../runtime/docs/runtime/agendas/023-tilemap-empty-cell-vs-tile-id-zero.md`](../../../runtime/docs/runtime/agendas/023-tilemap-empty-cell-vs-tile-id-zero.md) +- [`../../../runtime/docs/runtime/agendas/024-asset-entry-metadata-normalization-contract.md`](../../../runtime/docs/runtime/agendas/024-asset-entry-metadata-normalization-contract.md) + +Implementation surfaces: + +- `prometeu-packer-v1` tile-bank payload materializer +- `prometeu-packer-v1` tile-bank diagnostics in walker/materialization path +- `prometeu-packer-v1` metadata convergence for `AssetEntry` +- Studio tile-bank authoring and inspection surfaces that expose palettes or bank composition + +## Validation Notes + +This decision is correctly implemented only when all of the following are true: + +- artifact normalization produces one deterministic row-major `256 x 256` bank sheet; +- emitted tile ids match normalized artifact indices; +- emitted pixel bytes are packed as `u4`; +- emitted palette bytes are `RGB565` `u16`; +- palette declarations are read and written by explicit `index`; +- runtime-required metadata fields remain readable at the root; +- codec and pipeline metadata survive under `metadata.codec` and `metadata.pipeline`; +- structural blockers are visible during validation and are rerun by pack execution before emission.