--- id: AGD-0049 ticket: runtime-owned-variable-glyph-bank-palette-protocol title: Runtime-Owned Variable Glyph Bank Palette Protocol status: accepted created: 2026-07-14 resolved: 2026-07-14 decision: tags: - runtime - gfx - assets - glyph-bank - palette-serialization - protocol --- ## Contexto A agenda `../studio/discussion/workflow/agendas/AGD-0005-variable-tile-bank-palette-serialization.md` levantou o desperdicio do payload atual de `GLYPH/indexed_v1`: todo glyph bank carrega `64 * 16 * 4 = 4096` bytes de paletas RGBA8888, mesmo quando o asset usa poucas paletas. Esse problema toca o `packer`, mas a decisao do protocolo pertence ao `runtime`. A especificacao final deve ser definida aqui, no contrato runtime, e o `packer` deve seguir a spec quando ela estiver pronta. A agenda de `studio` serve como entrada factual e motivacao, nao como autoridade normativa sobre o payload, a memoria residente ou a semantica de `palette_id`. Estado atual no runtime: - `docs/specs/runtime/15-asset-management.md` documenta `palette_count = 64`; - `docs/specs/runtime/04-gfx-peripheral.md` documenta `palette_id` em `0..63`; - `crates/console/prometeu-hal/src/glyph_bank.rs` materializa paletas como `[[Color; 16]; 64]`; - `crates/console/prometeu-drivers/src/asset.rs` rejeita metadata cujo `palette_count` nao seja `64`; - o decode de glyph bank le um bloco fixo de `64 * 16 * 4` bytes em `assets.pa`; - testes de asset e VM ainda calculam payload e decoded size com o bloco fixo. Decisoes anteriores relevantes: - `DSC-0022` estabeleceu `GlyphBank` como nome canonico do artefato grafico; - `DSC-0037` estabeleceu RGBA8888 como contrato runtime, com alpha como dado de cor e sem indice magico reservado. ## Problema O runtime precisa decidir se `GLYPH/indexed_v1` continua sendo um contrato de 64 paletas fixas ou se passa a aceitar uma quantidade variavel de paletas serializadas. Essa decisao nao e apenas uma otimizacao de tamanho de cartucho. Ela muda: - o significado de `palette_count`; - a validacao de `palette_id`; - a formula de `size` e `decoded_size`; - a representacao residente de `GlyphBank`; - o comportamento quando uma cena referencia uma paleta nao carregada; - a fronteira entre contrato de asset, HAL, composer, testes e tooling. ## Pontos Criticos - Autoridade: o runtime decide o protocolo publicado; o `packer` segue. - Compatibilidade: o projeto ainda esta em v1, entao nao ha obrigacao presumida de preservar o padding fixo antigo. - Identidade: `palette_id` pode continuar sendo uma identidade direta ou pode virar indice em uma tabela compactada, mas nao pode ter dois significados. - Materializacao: economizar bytes no payload nao implica automaticamente economizar memoria residente, mas manter uma tabela fixa pode preservar semantica simples para renderizacao e cenas. - Falhas: se `palette_id` apontar para uma paleta ausente, o runtime precisa definir se isso falha no load, na composicao, ou se resolve para cor default. - Propagacao: qualquer decisao precisa mover specs, decode, HAL, fixtures e testes juntos, como ocorreu na migracao RGBA8888. ## Opcoes ### Opcao A - Manter 64 paletas fixas no protocolo runtime - **Abordagem:** Preservar `palette_count = 64`, bloco fixo de 4096 bytes e tabela residente fixa. - **Pro:** Mantem decode, composicao e limites de `palette_id` simples. - **Contra:** O runtime continua publicando um custo obrigatorio de payload que nao representa a maioria dos assets. - **Manutencao:** Boa para estabilidade local, fraca para alinhamento entre metadata autoral e payload real. ### Opcao B - Payload variavel, memoria residente fixa de 64 slots - **Abordagem:** Fazer `palette_count` representar o numero de paletas serializadas, mas expandir para uma tabela residente fixa de 64 paletas no load. Paletas nao serializadas ficam em valor default, e `palette_id` continua sendo identidade direta `0..63`. - **Pro:** Reduz payload mantendo o contrato de composicao e cena simples. - **Contra:** Requer decidir se referencias a paletas nao serializadas sao invalidas no load, invalidas na composicao ou simplesmente resolvem para a paleta default. - **Manutencao:** Boa se a spec declarar que `palette_count` mede somente o prefixo serializado e que o runtime ainda materializa capacidade fixa. ### Opcao C - Payload variavel e memoria residente variavel - **Abordagem:** Fazer `palette_count` controlar tanto o payload quanto a quantidade residente de paletas. `palette_id >= palette_count` passa a ser invalido para aquele glyph bank. - **Pro:** O contrato fica mais fiel ao asset carregado e reduz memoria residente por banco. - **Contra:** A composicao precisa carregar limite por banco e transformar validacao de `palette_id` em regra dependente do asset. - **Manutencao:** Forte se o runtime quiser que o banco carregado seja a unica fonte de verdade; mais invasiva no HAL/composer. ### Opcao D - Paletas compactadas com remapeamento de identidade - **Abordagem:** Serializar somente paletas usadas em uma tabela densa e introduzir um mapa entre identidade autoral/esparsa e indice residente. - **Pro:** Pode minimizar payload mesmo quando indices autorais sao esparsos. - **Contra:** Introduz um segundo contrato de identidade e exige metadata extra ou reescrita de cenas/assets dependentes. - **Manutencao:** Fraca para v1 unless haja uma necessidade clara de preservar indices esparsos sem preencher lacunas. ## Sugestao / Recomendacao Adotar a **Opcao C**. `palette_count` deve ser o contrato real do glyph bank carregado: se o payload serializa `N` paletas, o runtime materializa `N` paletas e `palette_id >= N` e invalido para aquele banco. A **Opcao B** fica descartada porque manter memoria residente fixa preservaria uma segunda nocao de capacidade que nao corresponde ao asset carregado. A **Opcao D** tambem fica descartada porque introduzir remapeamento de identidade transformaria um protocolo simples em uma camada adicional de metadata. ## Perguntas em Aberto - [x] `palette_count` deve definir tambem a quantidade residente de paletas, ou apenas o prefixo serializado no payload? - Resolucao: define tambem a quantidade residente. - [x] `palette_id` deve ser validado contra `palette_count` por glyph bank ou continuar limitado globalmente a `0..63`? - Resolucao: validar contra `palette_count` por glyph bank, mantendo um limite maximo global separado. - [x] Quando uma cena referencia uma paleta ausente, o erro deve ocorrer no load do glyph bank, no load/decode da scene, ou na composicao? - Resolucao: o glyph bank carrega se o proprio payload e valido. A referencia ausente falha quando uma scene/sprite tenta usar `palette_id >= palette_count` contra o banco real; o runtime deve tratar isso como erro explicito, nao como fallback silencioso para transparente/default. - [x] O limite maximo de paletas por glyph bank continua sendo `64` em v1? - Resolucao: sim. A variabilidade deve reduzir `N`, nao abrir uma quantidade ilimitada de paletas em v1. - [x] `decoded_size` deve contar apenas paletas materializadas ou manter alguma nocao de capacidade residente? - Resolucao: contar apenas paletas materializadas: `width * height + palette_count * 16 * 4`. - [x] A mudanca deve manter o nome `GLYPH/indexed_v1` como correcao incompativel de v1, ou o runtime exige uma nova versao de payload? - Resolucao: manter `GLYPH/indexed_v1` como correcao incompativel, sem compatibilidade com o padding fixo antigo. ## Criterio para Encerrar A agenda pode virar decisao quando o runtime escolher: - o significado normativo de `palette_count`; - a relacao entre payload serializado e memoria residente; - a regra de validade de `palette_id`; - o ponto de falha para paletas referenciadas mas ausentes; - a estrategia de versao para `GLYPH/indexed_v1`; - a lista de specs, crates e testes que precisam ser propagados no plano. ## Discussion Entrada do usuario em 2026-07-14: o runtime deve decidir o protocolo com base no que for melhor para o runtime; o `packer` deve seguir a spec quando pronta. Entrada do usuario em 2026-07-14: preferencia pela Opcao C, se possivel. Analise atual: a Opcao C e viavel, mas transforma `palette_id` em validacao dependente do glyph bank carregado. O codigo atual ja centraliza parte desse risco em `GlyphBank::resolve_color`, que hoje retorna transparente quando a paleta nao existe. Para a Opcao C virar contrato robusto, a decisao nao deve depender de fallback silencioso: precisa escolher um ponto explicito de falha para `palette_id >= palette_count`. Entrada do usuario em 2026-07-14: aceitar a recomendacao e seguir com a Opcao C. ## Resolution Fechar a agenda em favor da **Opcao C - Payload variavel e memoria residente variavel**. Contrato a levar para decisao: - o runtime e a autoridade do protocolo `GLYPH/indexed_v1`; - o `packer` deve seguir a spec runtime quando ela estiver publicada; - `palette_count` significa o numero de paletas RGBA8888 serializadas e materializadas no glyph bank carregado; - `palette_count` deve estar no intervalo `1..=64`; - cada paleta continua tendo 16 cores RGBA8888; - `palette_id` e uma identidade direta dentro do glyph bank carregado, valida somente quando `palette_id < palette_count`; - o runtime nao deve remapear paletas esparsas para outra identidade; - `decoded_size` deve contar apenas as paletas materializadas: `width * height + palette_count * 16 * 4`; - a mudanca permanece em `GLYPH/indexed_v1` como correcao incompativel de v1; - payloads antigos com padding fixo e `palette_count = 64` so continuam validos se tambem satisfizerem o novo contrato por coincidencia, nao por uma regra de compatibilidade separada; - referencias a paletas ausentes devem falhar explicitamente quando scene/sprite/composer tentarem usar `palette_id >= palette_count` contra o banco real; - o plano posterior deve propagar specs, `GlyphBank`, decode de assets, validacao de scene/sprite/composer, fixtures e testes.