---
id: AGD-0005
ticket: variable-tile-bank-palette-serialization
title: Variable Tile Bank Palette Serialization
status: open
created: 2026-03-26
resolved:
decision:
tags:
  - packer
  - legacy-import
  - tile-bank
  - palette-serialization
  - versioning
---

## Pain

The current tile-bank contract serializes a fixed block of `64` palettes in v1 even when an asset authors far fewer palettes.

That keeps decoding simple, but it wastes cartridge space and leaves the system with a deliberate mismatch between authored and serialized palette counts.

## Context

Legacy source: `docs/packer/agendas/Variable Tile Bank Palette Serialization Agenda.md`

Domain owner: `docs/packer`
Cross-domain dependency:

- runtime

Current aligned v1 contract:

- pixels are serialized as packed `u4`;
- palettes are serialized as `RGB565 u16`;
- `palette_count = 64`;
- payload size includes a fixed `64 * 16 * 2` palette block.

The packer now exposes:

- `metadata.palette_count = 64`
- `metadata.palette_authored = <actual authored count>`

## Open Questions

- [ ] Should variable palette serialization arrive as a new payload version or as an incompatible change to the current one?
- [ ] If `palette_count` becomes variable, should runtime still materialize a 64-slot resident bank, or truly shrink in-memory representation too?
- [ ] Should sparse authored palette indices remain sparse in serialization, or be canonicalized into a dense runtime block?
- [ ] Which domain owns compatibility for existing cartridges: `packer`, `runtime`, or `shipper`?

## Options

### Option A - Keep fixed 64-palette serialization
- **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 tile bank keeps paying the full palette cost.
- **Maintainability:** Medium.

### Option B - Move to variable palette serialization now
- **Approach:** Serialize only authored palettes and shrink payload size immediately.
- **Pro:** Better cartridge efficiency and tighter semantics for `palette_count`.
- **Con:** Reopens a just-stabilized cross-domain runtime contract and forces compatibility decisions now.
- **Maintainability:** Medium if done carefully, risky if done incidentally.

### Option C - Keep v1 fixed and design variable serialization for v2
- **Approach:** Preserve v1 stability now and open a later versioned follow-up for variable palette serialization.
- **Pro:** Keeps current work stable while preserving a clean path for future optimization.
- **Con:** Known waste remains in v1.
- **Maintainability:** Strong.

## Discussion

The retained agenda recommendation is already clear: the waste is real, but it is not a correctness bug, and reopening the runtime-facing contract immediately would mix optimization work into a freshly stabilized path.

That makes versioned follow-up a cleaner vehicle than incidental mutation of the current contract.

## Resolution

Recommended direction: adopt **Option C**.

Imported retained recommendation:

1. keep the current fixed 64-palette contract for v1;
2. if variable serialization is desired, design it explicitly as a versioned follow-up;
3. treat compatibility, runtime representation, and sparse-vs-dense palette identity as explicit next-wave questions rather than silent payload tweaks.

Next step suggestion: if the team wants to remove the fixed padding, open the corresponding runtime-side discussion and close the versioning/compatibility story before planning implementation.
