--- id: DEC-0041 ticket: runtime-owned-variable-glyph-bank-palette-protocol title: Variable Glyph Bank Palette Protocol status: accepted created: 2026-07-14 accepted: 2026-07-14 ref_agenda: AGD-0049 tags: [runtime, gfx, assets, glyph-bank, palette-serialization, protocol] --- ## Status Accepted. ## Contexto `AGD-0049` resolved that the runtime must own the `GLYPH/indexed_v1` palette serialization protocol. `studio` and `packer` may motivate the change, but they do not define the runtime wire contract. Once this decision is accepted, the packer must follow the published runtime spec. The current runtime still contains fixed-palette assumptions: - `docs/specs/runtime/15-asset-management.md` says `palette_count = 64` and validates `palette_count` as exactly `64`; - `docs/specs/runtime/04-gfx-peripheral.md` documents `palette_id` as a runtime-facing palette index; - `crates/console/prometeu-hal/src/glyph_bank.rs` stores palettes as `[[Color; 16]; 64]`; - `crates/console/prometeu-drivers/src/asset.rs` rejects any glyph metadata whose `palette_count` is not `64`; - glyph decode reads a fixed `64 * 16 * 4` byte palette block; - tests and fixtures calculate glyph payload and decoded size with the fixed palette block. Prior decisions remain in force: - `DSC-0022` established `GlyphBank` as the canonical artifact name; - `DSC-0037` established RGBA8888 as the runtime color contract, with alpha as color data and no reserved magic palette index. ## Decisao The runtime SHALL adopt variable glyph-bank palette serialization for `GLYPH/indexed_v1`. For `BankType::GLYPH` in v1: - `palette_count` MUST mean the number of RGBA8888 palettes serialized in the payload and materialized in the resident `GlyphBank`; - `palette_count` MUST be in the inclusive range `1..=64`; - each palette MUST contain exactly `16` RGBA8888 colors in canonical `R, G, B, A` byte order; - the serialized payload MUST contain only `palette_count` palettes, not a fixed 64-palette block; - resident runtime memory MUST materialize exactly `palette_count` palettes for the bank; - `palette_id` MUST be interpreted as a direct palette identity within the loaded glyph bank; - `palette_id` MUST be valid only when `palette_id < palette_count` for the loaded glyph bank being referenced; - the runtime MUST NOT remap sparse authored palette identities into a separate dense identity space; - missing palettes MUST NOT silently resolve to transparent, black, or any other default color in canonical scene/sprite composition; - references to `palette_id >= palette_count` MUST fail explicitly when scene/sprite/composer logic attempts to use that palette against the loaded bank; - the format name remains `GLYPH/indexed_v1`; this is an incompatible v1 correction, not a new v2 format. The v1 payload size formulas SHALL be: ```text serialized_pixel_bytes = ceil(width * height / 2) palette_bytes = palette_count * 16 * 4 size = serialized_pixel_bytes + palette_bytes decoded_size = (width * height) + palette_bytes ``` `width * height` is the number of logical indexed pixels. Serialized pixels remain packed `u4`; decoded runtime pixels may remain expanded to one `u8` index per pixel. ## Rationale This makes `palette_count` a real runtime contract instead of a decorative metadata field. If a glyph bank carries `N` palettes, runtime storage, payload validation, `decoded_size`, and palette lookup all agree on `N`. Keeping a fixed 64-slot resident table while trimming only the payload would preserve two meanings for palette capacity: serialized count and resident capacity. That would keep the ambiguity this decision is intended to remove. Adding sparse-to-dense palette remapping is also rejected. It would introduce a second identity layer and force scenes, sprites, packer output, and runtime lookup to coordinate additional metadata. V1 should keep `palette_id` as a direct identity inside the loaded glyph bank. Keeping the name `GLYPH/indexed_v1` is acceptable because the project is still in v1 and there is no required compatibility owner for the old fixed-padding payload. The runtime should correct the v1 contract now instead of publishing a second format solely to remove padding. ## Invariantes / Contrato - The runtime is the protocol authority for `GLYPH/indexed_v1`. - The packer is a producer of runtime-conforming payloads, not the source of truth for the protocol. - RGBA8888 remains the only valid glyph palette color encoding. - Palette index `0` remains an ordinary palette index. - Color index `0` remains an ordinary color index inside a palette. - Transparency is represented by the RGBA alpha channel. - `palette_count` is both serialized palette count and resident palette count. - `palette_count` has a maximum of `64` in v1. - `palette_id` validity is bank-dependent: `palette_id < palette_count`. - No compatibility mode for the old fixed 64-palette padding is introduced. - Old payloads with `palette_count = 64` remain valid only if they satisfy the new contract directly, not because of a special legacy branch. ## Impactos ### Specs - `docs/specs/runtime/15-asset-management.md` must remove the exact `palette_count = 64` requirement and define `palette_count` as `1..=64`. - The same spec must align `size` and `decoded_size` formulas with variable `palette_count`. - `docs/specs/runtime/04-gfx-peripheral.md` must define `palette_id` validity as dependent on the loaded glyph bank's `palette_count`, not as a standalone global `0..63` acceptance rule. - Any public wording that suggests fixed resident `64` palettes per glyph bank must be updated or marked historical. ### Runtime Code - `GlyphBank` must stop exposing a fixed `[[Color; 16]; 64]` resident palette table as the canonical representation. - Glyph decode must accept `palette_count` in `1..=64`. - Glyph decode must read exactly `palette_count * 16 * 4` palette bytes. - Glyph decode must validate `size` and `decoded_size` using the variable formulas. - Palette lookup must expose enough information for scene/sprite/composer logic to fail invalid `palette_id` explicitly instead of silently resolving a default color. ### Scene, Sprite, and Composer - Scene and sprite composition must treat `palette_id >= palette_count` for the referenced glyph bank as an explicit invalid reference. - The implementation plan must choose the concrete status/fault path for this invalid reference using existing runtime error semantics where possible. - Canonical composition must not continue by substituting transparent/default colors for invalid palette references. ### Firmware / Host / Tooling - Firmware/system surfaces that expose asset metadata or debug information must report the variable `palette_count`. - Packer/studio fixtures must emit runtime-conforming `GLYPH/indexed_v1` payloads after the runtime spec is updated. - Tooling must not generate sparse-to-dense remapping metadata for v1 unless a later decision introduces that feature. ### Tests - Tests must cover minimum and maximum valid palette counts: `1` and `64`. - Tests must reject `palette_count = 0` and `palette_count > 64`. - Tests must validate serialized and decoded size formulas for non-64 counts. - Tests must verify palette bytes are read in RGBA order for variable counts. - Tests must cover invalid `palette_id >= palette_count` behavior for scene or sprite composition. - Residue scans must check for fixed `64 * 16 * 4` payload assumptions that are still active contract text or code. ## Referencias - Agenda: `AGD-0049` - Runtime naming precedent: `DSC-0022` - RGBA8888 contract precedent: `DSC-0037` - Spec target: `docs/specs/runtime/15-asset-management.md` - Spec target: `docs/specs/runtime/04-gfx-peripheral.md` - Code target: `crates/console/prometeu-hal/src/glyph_bank.rs` - Code target: `crates/console/prometeu-drivers/src/asset.rs` ## Propagacao Necessaria This decision must be followed by an executable plan before spec or code changes. The plan must separate: - spec edits; - runtime decode/materialization changes; - scene/sprite/composer invalid-palette handling; - tests and fixtures; - downstream packer/studio alignment after the runtime spec is updated. ## Revision Log - 2026-07-14: Initial decision draft from `AGD-0049`.