prometeu-runtime/discussion/workflow/decisions/DEC-0041-variable-glyph-bank-palette-protocol.md

8.1 KiB

id ticket title status created accepted ref_agenda tags
DEC-0041 runtime-owned-variable-glyph-bank-palette-protocol Variable Glyph Bank Palette Protocol accepted 2026-07-14 2026-07-14 AGD-0049
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:

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.