98 lines
4.3 KiB
Markdown
98 lines
4.3 KiB
Markdown
---
|
|
id: LSN-0055
|
|
ticket: runtime-owned-variable-glyph-bank-palette-protocol
|
|
title: Runtime-Owned Asset Protocols Must Align Payload, Residency, and Lookup
|
|
created: 2026-07-14
|
|
tags: [runtime, assets, glyph-bank, palette-serialization, protocol]
|
|
decision: DEC-0041
|
|
---
|
|
|
|
## Context
|
|
|
|
The runtime changed the `GLYPH/indexed_v1` glyph-bank palette contract from a
|
|
fixed 64-palette payload and resident table to variable palette serialization
|
|
and variable resident palette storage.
|
|
|
|
The initiating pressure came from packer/studio: fixed RGBA8888 palette padding
|
|
made small glyph banks pay for `64 * 16 * 4` palette bytes even when they used
|
|
far fewer palettes. The important architectural point was that the runtime, not
|
|
the packer, had to decide the protocol. The packer can only emit payloads that
|
|
conform to the runtime contract once the runtime spec is published.
|
|
|
|
## Key Decisions
|
|
|
|
### Variable Glyph Bank Palette Protocol
|
|
|
|
**What:**
|
|
`palette_count` became the number of serialized palettes and the number of
|
|
resident palettes in the loaded `GlyphBank`. The valid range is `1..=64`.
|
|
`palette_id` remains a direct palette identity and is valid only when
|
|
`palette_id < palette_count` for the referenced resident bank.
|
|
|
|
**Why:**
|
|
Keeping serialized count variable while retaining a fixed 64-slot resident
|
|
table would preserve two meanings for palette capacity. The runtime would save
|
|
payload bytes but still carry a split contract between payload shape, resident
|
|
shape, and lookup validity. Making all three agree gives the runtime one
|
|
source of truth.
|
|
|
|
**Trade-offs:**
|
|
Palette validity is now bank-dependent. Scene and sprite composition must check
|
|
the referenced loaded bank instead of relying on a global `0..63` rule. This
|
|
adds validation work, but it prevents invalid references from silently becoming
|
|
transparent or default colors.
|
|
|
|
## Patterns and Algorithms
|
|
|
|
Let the runtime own runtime-facing asset protocols. Tooling can discover pain,
|
|
but the runtime spec must define effective metadata, payload shape, resident
|
|
shape, and failure semantics.
|
|
|
|
Make count fields material. A count such as `palette_count` should not describe
|
|
only what the producer authored or only what the payload happens to include. If
|
|
runtime lookup depends on it, the count must also define resident state and
|
|
validation boundaries.
|
|
|
|
Keep identity direct unless a real remapping problem exists. Sparse-to-dense
|
|
palette remapping was rejected because it would add a second identity layer
|
|
across scenes, sprites, packer output, and runtime lookup. V1 keeps palette id
|
|
`N` as palette slot `N` in the resident bank.
|
|
|
|
Separate transparent color from invalid lookup. RGBA alpha is valid color data.
|
|
An invalid palette reference must be observable as invalid; it must not be
|
|
collapsed into `Color::TRANSPARENT`.
|
|
|
|
Use residue scans after protocol migrations. Search for fixed byte formulas,
|
|
old constants, fixture helpers, and spec phrases. Legitimate hits should be
|
|
renamed as maximum-bound concepts, not left as accidental active contracts.
|
|
|
|
## Pitfalls
|
|
|
|
Partially variable specs are worse than fixed specs. The asset spec already had
|
|
variable size formulas in some places but still required `palette_count = 64`
|
|
elsewhere. That contradiction made it unclear which rule was canonical.
|
|
|
|
Resident data structures can preserve obsolete protocol assumptions after the
|
|
payload changes. A fixed array in `GlyphBank` would have kept the old model
|
|
alive even if decode accepted variable payloads.
|
|
|
|
Fallback rendering hides contract errors. Returning transparent for an invalid
|
|
palette id makes bad assets and bad scene references look like intentional
|
|
alpha, which is exactly the wrong failure mode for a runtime protocol.
|
|
|
|
Fixture generators are part of the contract surface. Stress cartridges and
|
|
test payload builders must express whether they are using a variable count or
|
|
the v1 maximum; otherwise they reintroduce fixed-padding assumptions.
|
|
|
|
## Takeaways
|
|
|
|
- Runtime-facing asset protocols should align payload size, resident memory,
|
|
and lookup validity.
|
|
- `palette_count` is effective runtime metadata, not producer commentary.
|
|
- Direct identity is simpler than remapping until a concrete remapping need
|
|
exists.
|
|
- Invalid palette references should fail explicitly; transparent remains a
|
|
valid RGBA color, not an error substitute.
|
|
- Protocol migrations need spec edits, code changes, fixture updates, and
|
|
residue scans in the same workflow.
|