prometeu-runtime/discussion/workflow/agendas/AGD-0029-scene-bank-glyph-runtime-binding-leak.md

194 lines
11 KiB
Markdown

---
id: AGD-0029
ticket: scene-bank-glyph-runtime-binding-leak
title: Scene Bank vazando glyph bank id runtime para o formato binario
status: accepted
created: 2026-04-24
resolved: 2026-04-24
decision: DEC-0021
tags: [gfx, runtime, asset, scene, glyph, format, architecture]
---
## Contexto
Hoje o payload binario `SCENE` carrega `glyph_bank_id` por layer e o runtime usa esse valor como chave operacional para resolver o `GlyphBank` residente durante o render.
A cadeia atual eh:
- o decoder de `SCENE` le `glyph_bank_id` do payload;
- `SceneLayer` preserva esse campo no modelo canonico carregado;
- `SceneViewportCache` copia o mesmo id para a cache;
- o renderer consulta `GlyphBankPoolAccess` por esse slot/id para desenhar a layer.
Isso cria um acoplamento direto entre formato frio de asset e topologia de residencia runtime. A suspeita levantada eh que esse campo nao deveria existir no wire-format, porque a referencia correta ao glyph bank deveria ser resolvida apenas pelo runtime.
## Problema
O contrato atual mistura duas camadas que deveriam permanecer separadas:
- o asset `SCENE` como descricao fria de composicao;
- o binding de slot/banco residente como estado operacional do runtime.
Se `glyph_bank_id` realmente for um detalhe exclusivamente runtime, o formato binario atual esta errado e o runtime passou a depender de um identificador que nao deveria ser serializado nem publicado como parte do asset.
Isso deixa perguntas abertas sobre:
- como uma layer de cena passa a apontar para um glyph source sem carregar um slot runtime no payload;
- onde esse binding deve viver;
- como preload, install e bind de cena passam a cooperar sem reintroduzir ambiguidade.
## Pontos Criticos
- O renderer atual resolve a bank diretamente a partir de `layer_cache.glyph_bank_id`, entao qualquer correcao toca formato, modelo em memoria e caminho de render.
- O payload `SCENE` ja foi materializado em testes e tooling com esse byte no header da layer, entao a mudanca implica migracao/versionamento ou ruptura controlada.
- O contrato de asset management enfatiza slots como conceito runtime e resolve contexto de banco via `asset_table` e preload, o que conflita com `SCENE` carregar referencia operacional propria.
- Precisamos evitar uma "correcao" que apenas mova o mesmo acoplamento para outro nome sem restaurar a fronteira correta entre asset frio e binding runtime.
## Opcoes
### Opcao 1 - Manter `glyph_bank_id` dentro do formato `SCENE`
- **Abordagem:** aceitar explicitamente que cada layer da cena referencia um slot/runtime glyph bank no proprio payload e documentar isso como contrato oficial.
- **Pros:** menor mudanca imediata; preserva compatibilidade com decoder, tests e tooling atuais.
- **Contras:** cristaliza o vazamento arquitetural; faz o asset depender de topologia runtime; dificulta relocacao, preload flexivel e reuso de cena em contextos diferentes.
- **Trade-off:** simples agora, mais rigido e mais fragil como contrato de longo prazo.
### Opcao 2 - Remover o id do wire-format e resolver o binding por runtime ao ativar a cena
- **Abordagem:** o payload `SCENE` deixa de carregar slot/id de glyph bank; a associacao layer -> fonte grafica passa a ser injetada por metadados de runtime, por preload derivado, ou por um binding explicito durante `bind_scene`.
- **Pros:** restaura a separacao asset frio vs residencia runtime; permite relocacao de slots e politica de preload sem contaminar o formato.
- **Contras:** exige definir uma nova fonte de verdade para o binding; impacta decoder, modelo de cena, renderer, specs e ferramentas.
- **Trade-off:** maior custo de migracao, mas fronteira arquitetural mais coerente.
### Opcao 3 - Manter referencia serializada, mas trocar de slot runtime para identidade fria
- **Abordagem:** o payload `SCENE` deixa de carregar `glyph_bank_id` runtime e passa a carregar uma referencia fria estavel por layer, como `asset_id` ou handle logico de glyph source; o runtime resolve essa identidade para slot residente quando a cena eh ativada.
- **Pros:** preserva auto-descricao da cena sem serializar topologia de residencia; reduz dependencia de slot fixo.
- **Contras:** ainda precisamos decidir se a cena deve conhecer assets frios diretamente; adiciona etapa de resolucao e falha operacional nova.
- **Trade-off:** melhor que serializar slot runtime, mas ainda pode acoplar demais o asset `SCENE` ao catalogo de assets.
## Sugestao / Recomendacao
Direcao escolhida nesta agenda:
- seguir pela **Opcao 3** com identidade fria por `asset_id`;
- remover `glyph_bank_id` runtime do formato binario `SCENE`;
- fazer o `SCENE` carregar, por layer, o `asset_id` do glyph dependency;
- resolver `asset_id -> glyph slot` no momento de `bind_scene`;
- falhar operacionalmente se qualquer dependencia grafica da cena nao estiver comprometida em algum slot glyph;
- a ordem de carregamento dos assets nos bancos nao importa;
- **sem versionamento e sem compatibilidade retroativa por enquanto**.
Motivo:
- slot de glyph bank eh conceito runtime e nao deve viver no wire-format;
- `asset_id` eh identidade fria e estavel dentro do contrato de assets;
- bind-time resolution preserva a liberdade de preload/commit e evita acoplamento do asset `SCENE` a uma topologia fixa de slots;
- a falha operacional em `bind_scene` mantem o problema na fronteira correta de ativacao.
Cravado nesta agenda:
- `SceneBank` canonico nao deve carregar slot runtime de glyph;
- o payload `SCENE` deve declarar dependencias frias, nao residencia;
- a vinculacao layer -> glyph slot pertence ao runtime no momento de ativacao da cena;
- o runtime deve validar dependencias no `bind_scene`, mas nao deve persistir um snapshot resolvido como dado canonico da cena;
- no draw de cada layer, o runtime pode consultar novamente qual slot contem o `asset_id` referido pela cena;
- ausencia da dependencia em qualquer ponto relevante do fluxo deve produzir erro operacional.
- a resolucao `asset_id -> slot` fica interna nesta etapa;
- a resolucao interna deve ser suportada por indice reverso `asset_id -> slot`, nao depender apenas de scan linear dos slots;
- o payload `SCENE` deve aumentar a largura do campo para comportar `AssetId = i32`;
- cada layer publica sua propria dependencia glyph diretamente;
- falha de dependencia no caminho de draw/composition deve ser tratada como erro fatal da maquina, com log claro.
- falha de dependencia no `bind_scene` tambem deve ser tratada como erro fatal da maquina, com log claro.
## Perguntas em Aberto
## Criterio para Encerrar
Esta agenda pode ser encerrada quando houver resposta clara e defendivel para:
- como o `SCENE` publica dependencias por `asset_id`;
- como o runtime consulta `asset_id -> slot` durante bind e draw;
- qual representacao binaria carregara o `asset_id` por layer;
- como o contrato de erro fatal e log claro se aplica em bind e draw.
## Discussao
Estado inicial da investigacao:
- ha vazamento real hoje no codigo e no tooling;
- nao encontrei decisao normativa registrada que feche explicitamente esse acoplamento;
- portanto o tema continua aberto e precisa de decisao arquitetural antes de qualquer correcao de spec ou codigo.
Atualizacao de 2026-04-24:
O caminho proposto pelo usuario parece tecnicamente viavel com a infraestrutura atual, embora ainda nao exista como contrato explicito.
O que ja existe hoje:
- o `AssetManager` mantem deduplicacao/residencia por `asset_id`;
- no commit/preload, cada slot fisico passa a registrar qual `asset_id` esta instalado nele;
- portanto o runtime ja possui as duas metades da informacao:
- `asset_id -> resident object`;
- `slot -> asset_id`.
O que ainda nao existe:
- uma API canonica `asset_id -> slot` para lookup de um asset ja comprometido em um banco;
- uma forma de `SceneBank` carregar dependencias por `asset_id` em vez de `glyph_bank_id`;
- um `bind_scene` capaz de validar todas as dependencias da cena e falhar operacionalmente se alguma nao estiver residente em slot algum.
Leitura atual da proposta:
- o payload `SCENE` carrega, por layer, o `asset_id` do glyph dependency;
- `composer.bind_scene(scene_slot)` continua selecionando a cena residente;
- durante o bind, o runtime resolve cada `asset_id` dependente para o slot glyph atualmente comprometido;
- durante o draw de cada layer, o runtime pode consultar novamente em qual slot o `asset_id` esta residente;
- a ordem de carregamento deixa de importar porque a resolucao eh feita contra o estado runtime no momento da operacao;
- se qualquer dependencia nao estiver carregada em algum slot glyph, `bind_scene` retorna falha operacional e nao ativa a cena.
Essa direcao preserva a fronteira correta melhor do que o modelo atual:
- o `SCENE` deixa de carregar topologia runtime;
- a cena continua auto-descritiva o suficiente para declarar suas dependencias frias;
- o runtime continua dono da residencia e da escolha de slot efetivo.
Ponto de atencao:
- essa direcao prefere nao manter snapshot resolvido como dado persistido da cena;
- portanto o contrato precisa dizer com clareza como o sistema reage se uma dependencia desaparecer entre bind e draw.
Direcao aceita na discussao atual:
- seguir com dependencia fria por `asset_id` no `SCENE`;
- resolver para slot glyph somente no `bind_scene`;
- permitir nova consulta `asset_id -> slot` tambem no draw das layers;
- nao expor lookup como API publica nesta etapa;
- manter indice reverso interno `asset_id -> slot` desde ja, para evitar acoplamento da solucao a scan linear de poucos slots;
- aumentar a largura do payload para carregar `AssetId = i32` no `SCENE`;
- tratar dependencia ausente no `bind_scene` como falha fatal da maquina, com log claro;
- tratar dependencia ausente no draw/composition como falha fatal da maquina, com log claro;
- nao fazer versionamento nem camada de compatibilidade nesta etapa.
Resposta consolidada do usuario na discussao:
- nao devemos materializar esse binding como dado resolvido persistente;
- devemos checar no bind e tambem quando formos desenhar a layer;
- a resolucao `asset_id -> slot` pode e deve evoluir para API publica futuramente, mas fica interna por enquanto;
- como essa resolucao tende a virar API publica, a base interna deve nascer como indice reverso e nao como mero loop sobre 16 slots;
- como `AssetId` canonico eh `i32`, o payload precisa aumentar a largura do campo serializado;
- cada layer carrega sua propria dependencia glyph;
- se a dependencia faltar ou nao puder ser resolvida no `bind_scene`, isso deve quebrar a maquina com log claro;
- se a dependencia sumir ou nao puder ser resolvida no caminho de draw/composition, isso tambem deve quebrar a maquina com log claro, porque nao ha como prosseguir corretamente sem as dependencias da cena.
## Resolution
Encerrada em 2026-04-24.
Resolucao aceita:
- `SCENE` deixa de carregar slot runtime de glyph e passa a carregar `AssetId` por layer;
- o runtime resolve `asset_id -> slot` via indice reverso interno;
- falta de dependencia fataliza a maquina tanto no `bind_scene` quanto no draw/composition, com log claro;
- nao ha versionamento nem compatibilidade retroativa nesta etapa.