prometeu-studio/docs/packer/agendas/Variable Tile Bank Palette Serialization Agenda.md
2026-03-24 13:42:56 +00:00

143 lines
4.3 KiB
Markdown

# Variable Tile Bank Palette Serialization Agenda
## Status
Active
## Domain Owner
- `docs/packer`
Cross-domain dependency:
- `../runtime`
## Purpose
Decide whether `tile bank` payloads should keep serializing a fixed block of `64` palettes in v1, or evolve to serialize only the palettes actually authored by the asset.
## Context
The current `tile bank` contract is aligned between `packer` and `runtime`:
- pixels are serialized as packed `u4`;
- palettes are serialized as `RGB565 u16`;
- `palette_count = 64`;
- payload size is derived from `ceil(width * height / 2) + (64 * 16 * 2)`.
This means a `tile bank` with `1` authored palette still serializes `64` palette slots. Unused slots are currently zero-filled, which is valid for the runtime, but wastes cartridge space.
The packer now exposes:
- `metadata.palette_count = 64`
- `metadata.palette_authored = <actual authored count>`
This makes the waste explicit, but does not remove it.
## Problem
The runtime-facing v1 contract favors fixed-size decode simplicity over cartridge efficiency.
We need to decide whether:
1. fixed `64` palette slots remain the normative contract for `tile bank`;
2. `palette_count` becomes variable and payload size shrinks to the authored set;
3. another staged strategy is better.
## Options
### Option A: Keep Fixed 64-Palette Serialization
Keep the current contract unchanged:
- `palette_count` remains `64`;
- every `tile bank` serializes `64 * 16 * 2 = 2048` bytes of palettes;
- authored palettes populate their indexed slots;
- unused slots are zero-filled.
### Option B: Move to Variable Palette Serialization
Evolve the contract so `tile bank` serializes only authored palettes:
- `palette_count` becomes the authored count;
- payload size becomes `ceil(width * height / 2) + (palette_count * 16 * 2)`;
- runtime validates and decodes variable palette blocks.
### Option C: Keep V1 Fixed, Design Variable Serialization for V2
Preserve the current runtime-facing v1 contract now, but explicitly open a v2 format/contract:
- v1 stays fixed at `64`;
- v2 introduces variable palette serialization;
- packer and runtime keep clear compatibility boundaries.
## Tradeoffs
### Option A
Pros:
- no further runtime work;
- simplest decode path;
- current specs and tests stay valid.
Cons:
- every `tile bank` pays the full 2 KB palette cost;
- cartridge size is inflated for small authored palette sets;
- the metadata now exposes a mismatch between authored and serialized counts by design.
### Option B
Pros:
- reduces cartridge size;
- makes `palette_count` semantically tighter;
- removes fixed empty palette padding from the payload.
Cons:
- requires coordinated changes in `packer`, `runtime`, specs, and tests;
- changes the `size` / `decoded_size` formulas;
- raises compatibility and migration questions for existing assets and cartridges.
### Option C
Pros:
- keeps current work stable;
- makes room for a cleaner future contract;
- avoids mixing optimization work into the current tile-bank rollout.
Cons:
- known waste remains in v1;
- adds future format/version management work.
## Recommendation
Recommendation for now: `Option C`.
Reasoning:
- the current fixed-size contract is already implemented and aligned;
- the waste is real, but it is not a correctness bug;
- changing it now would reopen a cross-domain runtime contract that was just stabilized;
- if we want variable palette serialization, it should be introduced deliberately as a versioned follow-up, not as an incidental tweak.
## Open Questions
1. Should variable palette serialization be introduced as a new `tile bank` payload version, or as an incompatible change to the current one?
2. If `palette_count` becomes variable, should runtime still materialize a 64-slot bank in memory, or truly shrink the resident representation too?
3. Should palette slot identity remain sparse by authored `index`, or should serialization canonicalize into a dense runtime block?
4. Which domain owns the compatibility story for existing cartridges: `packer`, `runtime`, or `shipper`?
## Expected Follow-up
If the team wants to eliminate the fixed 64-palette padding:
1. create a corresponding runtime agenda/decision;
2. define the versioning and compatibility story;
3. update `packer` and `runtime` specs together;
4. then plan code changes in both domains.