8.2 KiB
| id | ticket | title | status | created | resolved | decision | tags | ||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| AGD-0005 | variable-tile-bank-palette-serialization | Variable Glyph Bank Palette Serialization | accepted | 2026-03-26 | 2026-07-14 | DEC-0038 |
|
Pain
Domain owner: packer, with runtime-facing impact through assets.pa.
The current GLYPH/indexed_v1 glyph-bank contract serializes a fixed block of
64 palettes even when an asset authors far fewer palettes.
After DSC-0038, each palette entry is RGBA8888, so the fixed palette block is
now 64 * 16 * 4 = 4096 bytes. That keeps decoding simple, but it wastes
cartridge space and leaves a deliberate mismatch between authored palette count
and serialized palette count.
Context
Legacy source: docs/packer/agendas/Variable Tile Bank Palette Serialization Agenda.md
Cross-domain dependency:
- runtime
Runtime follow-up:
../runtime/discussion/workflow/decisions/DEC-0041-variable-glyph-bank-palette-protocol.mdis accepted and normative for the runtime side.- Runtime
DSC-0046keepsGLYPH/indexed_v1, adopts variable glyph-bank palette serialization, and treats this as an incompatible v1 correction. - Runtime plans
PLN-0167throughPLN-0172are done and publish the downstream handoff.
Current runtime-owned GLYPH/indexed_v1 contract:
- pixels are serialized as packed
u4; - palettes are serialized as RGBA8888 values in runtime
R,G,B,Abyte order; palette_countis the number of serialized and resident palettes;palette_countmust be in1..=64;- payload size includes exactly
palette_count * 16 * 4palette bytes; - palette index
0is ordinary; - each palette has 16 usable colors;
- transparency is represented by alpha, not by a reserved index or magenta color-key;
- resident runtime memory materializes exactly
palette_countpalettes; palette_idis a direct palette identity inside the loaded glyph bank and is valid only whenpalette_id < palette_count;- sparse-to-dense palette remapping is not part of v1;
- missing palettes must fail explicitly in scene/sprite/composer use, not silently resolve to a default color.
Downstream producers must emit:
- root effective metadata fields
tile_size,width,height, andpalette_count; size = ceil(width * height / 2) + palette_count * 16 * 4;decoded_size = width * height + palette_count * 16 * 4;- exactly
palette_count * 16 * 4RGBA8888 palette bytes; - no
GLYPH/indexed_v2payload for this change; - no fixed 64-palette padding unless
palette_count = 64and the payload directly satisfies the runtime v1 contract; - no effective runtime behavior based on
palette_authored.
DSC-0038 intentionally did not solve variable palette-count serialization.
It changed the color encoding from RGB565-era semantics to RGBA8888 and kept
the fixed 64-palette model stable for that wave.
Runtime DEC-0041 now closes the cross-domain protocol questions that this
agenda previously carried as open. The remaining Studio/packer work is
downstream alignment with the runtime-owned contract.
Open Questions
- Should variable palette serialization arrive as a new payload version or
as an incompatible change to the current one?
- Runtime
DEC-0041resolves this as an incompatible correction toGLYPH/indexed_v1, with no v2 format.
- Runtime
- If
palette_countbecomes variable, should runtime still materialize a 64-slot resident bank, or truly shrink in-memory representation too?- Runtime
DEC-0041resolves this: resident runtime memory materializes exactlypalette_countpalettes.
- Runtime
- Should sparse authored palette indices remain sparse in serialization, or
be canonicalized into a dense runtime block?
- Runtime
DEC-0041rejects sparse-to-dense remapping.palette_idremains direct identity inside the loaded glyph bank.
- Runtime
- Should this repository create the owner agenda/decision for the runtime
side, or should a matching runtime
discussion/artifact be opened before implementation planning?- Runtime
DSC-0046now owns the protocol through acceptedDEC-0041. Studio/packer must follow that handoff.
- Runtime
- Which domain owns compatibility for existing cartridges:
packer,runtime, orshipper?- Runtime
DEC-0041introduces no compatibility mode. Old payloads withpalette_count = 64remain valid only when they satisfy the new contract directly.
- Runtime
Options
Option A - Keep fixed 64-palette serialization in v1
- Approach: Preserve the current fixed v1 payload with zero-filled unused palette slots.
- Pro: No runtime change and current specs/tests remain stable.
- Con: Every glyph bank keeps paying the full 4096-byte palette cost.
- Maintainability: Medium.
Option B - Align packer output with runtime variable palette serialization
- Approach: Keep the
GLYPH/indexed_v1format name, serialize onlypalette_countpalettes, and make packer metadata, payload sizes, fixtures, and Studio projections follow runtimeDEC-0041. - Pro: Removes fixed padding while the project is still in v1, keeps the public format vocabulary stable, and makes runtime metadata match the payload.
- Con: Requires coordinated packer/spec/test changes and fixture regeneration because the current producer still emits the old fixed-padding shape.
- Maintainability: Strong if implemented as an explicit contract update, weak if done as an incidental size tweak. Runtime has already closed the protocol questions.
Option C - Keep fixed external metadata but trim trailing palettes
- Approach: Keep some 64-slot assumptions in metadata or runtime memory, but serialize only a shortened trailing subset of palettes in the payload.
- Pro: Can reduce cartridge size while limiting some runtime changes.
- Con: Creates a split-brain contract where serialized count, logical count, and resident count can disagree.
- Maintainability: Weak. It preserves the ambiguity this agenda is trying to remove.
Discussion
The retained concern is still valid after DSC-0038, but runtime DEC-0041
has now closed the protocol. The problem is no longer an open cross-domain
design question; it is a downstream producer-alignment task for Studio/packer.
The old recommendation favored a versioned follow-up because compatibility and
runtime stability were treated as constraints. Runtime DEC-0041 removes that
constraint: the project is still in v1, keeps GLYPH/indexed_v1, and does not
need compatibility for the old fixed 64-palette payload.
That makes Option B the required direction for this repository. Runtime already
changed the contract directly; Studio/packer must now emit the runtime-owned
shape and stop treating palette_authored or the old 64-padding model as
effective runtime behavior.
Option C should be avoided because it preserves multiple meanings for palette
count. If the payload becomes variable, palette_count should mean the number
of serialized palettes, not an unrelated fixed resident capacity.
Resolution
Recommended direction: adopt Option B.
Updated recommendation:
- keep the format name
GLYPH/indexed_v1; - follow runtime
DEC-0041as the protocol authority; - remove the fixed 64-palette payload block from packer output;
- make packer
palette_countdescribe the serialized and resident RGBA8888 palette count; - emit exactly
palette_count * 16 * 4palette bytes; - update
sizeanddecoded_sizeformulas to use variablepalette_count; - do not create a v2 format solely for this change;
- do not preserve compatibility with the old fixed-padding payload;
- do not introduce sparse-to-dense palette remapping metadata;
- treat
palette_authoredas informative only unless a later runtime decision promotes it to effective metadata; - add downstream fixture coverage for
palette_count = 1, an intermediate count, andpalette_count = 64; - add a negative producer validation case for metadata/payload mismatch.
Next step suggestion: convert this agenda into a Studio/packer decision that
references runtime DEC-0041 and scopes implementation to specs, packer
payload emission, Studio projections if needed, tests, and fixtures.