housekeep DSC-0029 scene glyph binding leak discussion
All checks were successful
Intrepid/Prometeu/Runtime/pipeline/head This commit looks good
Intrepid/Prometeu/Runtime/pipeline/pr-master This commit looks good

This commit is contained in:
bQUARKz 2026-04-24 15:57:52 +01:00
parent 0c8de434cf
commit 1c91d1c2df
Signed by: bquarkz
SSH Key Fingerprint: SHA256:Z7dgqoglWwoK6j6u4QC87OveEq74WOhFN+gitsxtkf8
7 changed files with 72 additions and 695 deletions

View File

@ -1,4 +1,4 @@
{"type":"meta","next_id":{"DSC":30,"AGD":30,"DEC":22,"PLN":43,"LSN":38,"CLSN":1}}
{"type":"meta","next_id":{"DSC":30,"AGD":30,"DEC":22,"PLN":43,"LSN":39,"CLSN":1}}
{"type":"discussion","id":"DSC-0023","status":"done","ticket":"perf-full-migration-to-atomic-telemetry","title":"Agenda - [PERF] Full Migration to Atomic Telemetry","created_at":"2026-04-10","updated_at":"2026-04-10","tags":["perf","runtime","telemetry"],"agendas":[{"id":"AGD-0021","file":"workflow/agendas/AGD-0021-full-migration-to-atomic-telemetry.md","status":"done","created_at":"2026-04-10","updated_at":"2026-04-10"}],"decisions":[{"id":"DEC-0008","file":"workflow/decisions/DEC-0008-full-migration-to-atomic-telemetry.md","status":"accepted","created_at":"2026-04-10","updated_at":"2026-04-10"}],"plans":[{"id":"PLN-0007","file":"workflow/plans/PLN-0007-full-migration-to-atomic-telemetry.md","status":"done","created_at":"2026-04-10","updated_at":"2026-04-10"}],"lessons":[{"id":"LSN-0028","file":"lessons/DSC-0023-perf-full-migration-to-atomic-telemetry/LSN-0028-converging-to-single-atomic-telemetry-source.md","status":"done","created_at":"2026-04-10","updated_at":"2026-04-10"}]}
{"type":"discussion","id":"DSC-0020","status":"done","ticket":"jenkins-gitea-integration","title":"Jenkins Gitea Integration and Relocation","created_at":"2026-04-07","updated_at":"2026-04-07","tags":["ci","jenkins","gitea"],"agendas":[{"id":"AGD-0018","file":"workflow/agendas/AGD-0018-jenkins-gitea-integration-and-relocation.md","status":"done","created_at":"2026-04-07","updated_at":"2026-04-07"}],"decisions":[{"id":"DEC-0003","file":"workflow/decisions/DEC-0003-jenkins-gitea-strategy.md","status":"accepted","created_at":"2026-04-07","updated_at":"2026-04-07"}],"plans":[{"id":"PLN-0003","file":"workflow/plans/PLN-0003-jenkins-gitea-execution.md","status":"done","created_at":"2026-04-07","updated_at":"2026-04-07"}],"lessons":[{"id":"LSN-0021","file":"lessons/DSC-0020-jenkins-gitea-integration/LSN-0021-jenkins-gitea-integration.md","status":"done","created_at":"2026-04-07","updated_at":"2026-04-07"}]}
{"type":"discussion","id":"DSC-0021","status":"done","ticket":"asset-entry-codec-enum-with-metadata","title":"Asset Entry Codec Enum Contract","created_at":"2026-04-09","updated_at":"2026-04-09","tags":["asset","runtime","codec","metadata"],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0024","file":"lessons/DSC-0021-asset-entry-codec-enum-contract/LSN-0024-string-on-the-wire-enum-in-runtime.md","status":"done","created_at":"2026-04-09","updated_at":"2026-04-09"}]}
@ -21,7 +21,7 @@
{"type":"discussion","id":"DSC-0026","status":"done","ticket":"render-all-scene-cache-and-camera-integration","title":"Integrate render_all with Scene Cache and Camera","created_at":"2026-04-14","updated_at":"2026-04-18","tags":["gfx","runtime","render","camera","scene"],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0031","file":"lessons/DSC-0026-render-all-scene-cache-and-camera-integration/LSN-0031-frame-composition-belongs-above-the-render-backend.md","status":"done","created_at":"2026-04-18","updated_at":"2026-04-18"}]}
{"type":"discussion","id":"DSC-0027","status":"done","ticket":"frame-composer-public-syscall-surface","title":"Agenda - FrameComposer Public Syscall Surface","created_at":"2026-04-17","updated_at":"2026-04-18","tags":["gfx","runtime","syscall","abi","frame-composer","scene","camera","sprites"],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0032","file":"lessons/DSC-0027-frame-composer-public-syscall-surface/LSN-0032-public-abi-must-follow-the-canonical-service-boundary.md","status":"done","created_at":"2026-04-18","updated_at":"2026-04-18"}]}
{"type":"discussion","id":"DSC-0028","status":"done","ticket":"deferred-overlay-and-primitive-composition","title":"Deferred Overlay and Primitive Composition over FrameComposer","created_at":"2026-04-18","updated_at":"2026-04-18","tags":["gfx","runtime","render","frame-composer","overlay","primitives","hud"],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0033","file":"lessons/DSC-0028-deferred-overlay-and-primitive-composition/LSN-0033-debug-primitives-should-be-a-final-overlay-not-part-of-game-composition.md","status":"done","created_at":"2026-04-18","updated_at":"2026-04-18"}]}
{"type":"discussion","id":"DSC-0029","status":"open","ticket":"scene-bank-glyph-runtime-binding-leak","title":"Scene Bank Glyph Runtime Binding Leak","created_at":"2026-04-24","updated_at":"2026-04-24","tags":["gfx","runtime","asset","scene","glyph","format","architecture"],"agendas":[{"id":"AGD-0029","file":"AGD-0029-scene-bank-glyph-runtime-binding-leak.md","status":"accepted","created_at":"2026-04-24","updated_at":"2026-04-24"}],"decisions":[{"id":"DEC-0021","file":"DEC-0021-scene-bank-glyph-dependencies-must-bind-by-asset-id.md","status":"in_progress","created_at":"2026-04-24","updated_at":"2026-04-24","ref_agenda":"AGD-0029"}],"plans":[{"id":"PLN-0040","file":"PLN-0040-scene-glyph-dependency-spec-and-wire-layout.md","status":"done","created_at":"2026-04-24","updated_at":"2026-04-24","ref_decisions":["DEC-0021"]},{"id":"PLN-0041","file":"PLN-0041-scene-glyph-runtime-resolution-and-fatal-paths.md","status":"done","created_at":"2026-04-24","updated_at":"2026-04-24","ref_decisions":["DEC-0021"]},{"id":"PLN-0042","file":"PLN-0042-scene-glyph-tooling-and-fixture-migration.md","status":"done","created_at":"2026-04-24","updated_at":"2026-04-24","ref_decisions":["DEC-0021"]}],"lessons":[]}
{"type":"discussion","id":"DSC-0029","status":"done","ticket":"scene-bank-glyph-runtime-binding-leak","title":"Scene Bank Glyph Runtime Binding Leak","created_at":"2026-04-24","updated_at":"2026-04-24","tags":["gfx","runtime","asset","scene","glyph","format","architecture"],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0038","file":"lessons/DSC-0029-scene-bank-glyph-runtime-binding-leak/LSN-0038-cold-scene-dependencies-must-bind-by-asset-identity.md","status":"done","created_at":"2026-04-24","updated_at":"2026-04-24"}]}
{"type":"discussion","id":"DSC-0014","status":"done","ticket":"perf-vm-allocation-and-copy-pressure","title":"Agenda - [PERF] VM Allocation and Copy Pressure","created_at":"2026-03-27","updated_at":"2026-04-20","tags":[],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0035","file":"lessons/DSC-0014-perf-vm-allocation-and-copy-pressure/LSN-0035-first-materialization-is-not-the-same-as-hot-path-copy-pressure.md","status":"done","created_at":"2026-04-20","updated_at":"2026-04-20"}]}
{"type":"discussion","id":"DSC-0015","status":"abandoned","ticket":"perf-cartridge-boot-and-program-ownership","title":"Agenda - [PERF] Cartridge Boot and Program Ownership","created_at":"2026-03-27","updated_at":"2026-04-20","tags":[],"agendas":[{"id":"AGD-0014","file":"workflow/agendas/AGD-0014-perf-cartridge-boot-and-program-ownership.md","status":"abandoned","created_at":"2026-03-27","updated_at":"2026-04-20","_override_reason":"User explicitly chose to close the discussion without decision because FS->memory copy for the program is already acceptable."}],"decisions":[],"plans":[],"lessons":[],"_override_reason":"User explicitly chose to abandon the discussion without creating a decision because FS->memory copy for the program is already acceptable."}
{"type":"discussion","id":"DSC-0016","status":"done","ticket":"tilemap-empty-cell-vs-tile-id-zero","title":"Tilemap Empty Cell vs Tile ID Zero","created_at":"2026-03-27","updated_at":"2026-04-09","tags":[],"agendas":[{"id":"AGD-0015","file":"workflow/agendas/AGD-0015-tilemap-empty-cell-vs-tile-id-zero.md","status":"done","created_at":"2026-03-27","updated_at":"2026-04-09"}],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0022","file":"lessons/DSC-0016-tilemap-empty-cell-semantics/LSN-0022-tilemap-empty-cell-convergence.md","status":"done","created_at":"2026-04-09","updated_at":"2026-04-09"}]}

View File

@ -0,0 +1,70 @@
---
id: LSN-0038
ticket: scene-bank-glyph-runtime-binding-leak
title: Cold Scene Dependencies Must Bind by Asset Identity, Not Runtime Residency
created: 2026-04-24
tags: [gfx, runtime, asset, scene, glyph, format, architecture]
---
## Context
`SCENE` payloads had started to serialize a per-layer `glyph_bank_id`, and the runtime was consuming that byte as if it were the authoritative glyph residency binding. That meant a cold scene asset was no longer just describing its dependencies; it was leaking the runtime slot topology that happened to exist when the asset was authored.
The implementation work for `DSC-0029` replaced that contract end to end. Scene layers now carry glyph dependencies by canonical `AssetId (i32)`, the runtime owns the reverse residency lookup, and scene activation/composition fail fatally when required glyph assets are not currently resident.
## Key Decisions
### Scene Assets Must Describe Dependencies, Not Slot Topology
**What:**
Each `SceneLayer` now declares its glyph dependency by canonical `AssetId`, and the `SCENE` wire format serializes that dependency as `i32`.
**Why:**
Runtime slot ids are operational state. They can change with preload order, slot reuse, and runtime relocation. Putting them on the wire couples a cold asset to an unstable residency layout and breaks the intended separation between authored content and runtime execution state.
**Trade-offs:**
The payload widened and old payload compatibility was intentionally dropped. That makes the migration more abrupt, but it restores the correct contract boundary instead of preserving an invalid one.
### Runtime Residency Must Be Resolved Through Runtime-Owned Indexes
**What:**
The runtime now owns the authoritative `asset_id -> slot` reverse index for committed glyph assets, and scene bind/draw paths consult that index instead of trusting scene bytes as slot bindings.
**Why:**
Residency is a runtime concern. A reverse index gives the renderer and scene binder the correct primitive while keeping slot ownership inside the asset system where preload, commit, overwrite, and invalidation already live.
**Trade-offs:**
The asset manager has more bookkeeping responsibility, but the model becomes coherent and future public lookup APIs can emerge from the same primitive.
### Missing Scene Dependencies Are Fatal, Not Passive Status Errors
**What:**
If `bind_scene` cannot resolve a declared glyph dependency, or if composition later loses a required dependency, the machine fails fatally with explicit logging.
**Why:**
A bound scene without its declared glyph dependencies is not operationally meaningful. Treating that condition as a soft status error would let the system continue from a broken render contract.
**Trade-offs:**
This is stricter than a passive operational rejection. The runtime becomes less forgiving, but it also becomes more honest: malformed residency state cannot masquerade as a valid scene activation path.
## Patterns and Algorithms
- Keep authored asset formats in cold identity space and runtime systems in residency space.
- Use `AssetId` as the handoff boundary between content and runtime resolution.
- Maintain reverse residency indexes inside the asset manager whenever runtime services need dependency lookup by identity.
- Re-resolve runtime bindings in the active path when residency can change after activation.
- Prefer fatal failure over passive degradation when a declared scene dependency is mandatory for correct composition.
## Pitfalls
- A one-byte field can look harmless while still encoding the wrong domain concept; width is less dangerous than semantics.
- Migrating the wire format without updating tooling and generated fixtures leaves the runtime correct but the stress assets incoherent.
- Freezing slot bindings too early would turn runtime residency changes into stale scene state.
- Introducing a reverse lookup only as an optimization shortcut invites future API and ownership problems; it should be modeled as a first-class runtime primitive.
## Takeaways
- Cold scene payloads should carry dependency identity, never runtime residency topology.
- Runtime slot lookup belongs to the asset manager, not to authored scene data.
- A reverse `asset_id -> slot` index is the clean bridge between authored dependencies and runtime composition.
- Missing scene dependencies should fail loudly because the render contract is broken, not merely unavailable.

View File

@ -1,193 +0,0 @@
---
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.

View File

@ -1,141 +0,0 @@
---
id: DEC-0021
ticket: scene-bank-glyph-runtime-binding-leak
title: Scene Bank glyph dependencies MUST bind by asset_id, not runtime slot
status: in_progress
created: 2026-04-24
accepted: 2026-04-24
agenda: AGD-0029
plans: [PLN-0040, PLN-0041, PLN-0042]
tags: [gfx, runtime, asset, scene, glyph, format, architecture]
---
## Status
Accepted on 2026-04-24.
## Contexto
The current `SCENE` binary payload serializes `glyph_bank_id` per layer and the runtime uses that serialized value as the operational key to resolve the resident glyph bank during rendering.
That design leaks runtime residency topology into a cold asset format. A scene asset is therefore coupled to whichever glyph slot layout happened to exist when the payload was authored, which violates the intended separation between:
- cold asset description;
- runtime residency and slot assignment;
- frame-time composition.
The repository discussion in `AGD-0029` concluded that this contract is incorrect and must be replaced.
## Decisao
The `SCENE` asset contract MUST stop serializing runtime glyph slot identifiers.
From this decision forward:
1. Each scene layer MUST declare its glyph dependency by `AssetId`.
2. `SceneBank` MUST NOT carry a runtime glyph slot id as part of its canonical loaded model.
3. The runtime MUST resolve `AssetId -> glyph slot` through runtime-owned residency state, not through scene payload bytes interpreted as slot ids.
4. The runtime MUST maintain an internal reverse index `AssetId -> slot` for committed glyph assets.
5. The lookup mechanism MAY become a public API later, but in this stage it MUST remain internal.
6. The `SCENE` payload field used for the glyph dependency MUST widen to carry canonical `AssetId = i32`.
7. The scene payload MUST keep the dependency attached directly to each layer; no shared dependency table is introduced in this decision.
8. No compatibility layer and no format version migration are introduced in this stage.
## Rationale
The previous contract was wrong at the boundary level, not only at the implementation level.
Why this decision is correct:
- runtime slot ids are operational state and MUST remain runtime-owned;
- `AssetId` is the stable cold identity already used by the asset system;
- resolving dependencies at runtime preserves freedom of preload, commit, relocation, and slot reuse;
- a reverse index gives the runtime the correct primitive for both internal use and possible future API exposure;
- keeping the dependency per layer is the lowest-risk migration path and avoids speculative structure growth.
This decision deliberately prefers a clean contract over temporary compatibility because the current behavior is architecturally invalid.
## Invariantes / Contrato
### Canonical scene contract
- A `SCENE` asset MUST describe glyph dependencies in cold asset terms only.
- A `SCENE` asset MUST NOT encode runtime slot topology.
- A scene layer MUST own exactly one glyph dependency reference.
- That dependency reference MUST be serialized as `AssetId` and MUST use `i32` width.
### Runtime residency contract
- The asset manager MUST own the authoritative mapping from committed glyph residency to slot.
- The runtime MUST maintain a reverse index from committed glyph `AssetId` to glyph slot.
- The reverse index MUST be updated whenever glyph preload or glyph commit changes slot ownership.
- The reverse index MUST be treated as internal runtime state in this stage.
### Bind-time and draw-time contract
- `bind_scene` MUST validate that every glyph dependency referenced by the target scene resolves to a currently committed glyph slot.
- If any dependency cannot be resolved during `bind_scene`, the machine MUST fail fatally and emit a clear log describing the missing dependency.
- Render-time composition MAY consult the reverse index again while drawing a layer instead of relying on a frozen slot snapshot.
- If a dependency becomes unresolved during draw/composition, the machine MUST fail fatally and emit a clear log describing the missing dependency.
- The runtime MUST NOT continue scene composition after a missing dependency is detected at bind time or draw time.
### Error semantics
- `ERROR_MISSING_DEPENDENCIES` is not part of the accepted contract.
- Missing scene glyph dependencies are not passive operational rejections in the accepted model.
- Missing scene glyph dependencies MUST escalate as fatal machine errors with explicit logging.
### Non-goals for this decision
- This decision does NOT expose the reverse lookup as a public API yet.
- This decision does NOT introduce payload compatibility with the old serialized `glyph_bank_id`.
- This decision does NOT introduce a dependency table shared across scene layers.
- This decision does NOT define the later public guest ABI for querying `asset_id -> slot`.
## Impactos
### Spec
- The `SCENE` binary payload specification MUST be updated to replace per-layer runtime slot ids with per-layer `AssetId`.
- The payload layout MUST reflect widened field width for `AssetId = i32`.
- Runtime/spec text that implies scene glyph dependencies are operational status returns rather than fatal errors MUST be corrected.
### Runtime
- `SceneLayer` and related scene/cache structures MUST stop carrying canonical runtime glyph slot ids.
- The asset manager MUST maintain the reverse glyph residency index.
- `bind_scene` MUST validate scene glyph dependencies against the reverse index and fatalize on absence.
- The draw path MUST resolve or revalidate layer dependencies against runtime residency and fatalize on absence.
### Host
- Fatal machine logging for missing scene glyph dependencies MUST be clear enough to identify:
- the scene being bound or drawn;
- the layer involved;
- the missing glyph dependency `AssetId`.
### Tooling
- Scene encoders, packers, fixtures, and stress tools MUST serialize per-layer glyph dependency as `AssetId`, not runtime slot id.
- Existing tests and fixtures that publish `glyph_bank_id` in `SCENE` payloads MUST be rewritten.
## Referencias
- Agenda: `AGD-0029-scene-bank-glyph-runtime-binding-leak.md`
- Related runtime area: `DSC-0025` lesson on scene/canonical/cache separation
- Related asset identity context: `DSC-0018` lesson on asset load asset id int contract
## Propagacao Necessaria
- Update the canonical `SCENE` payload layout in specs.
- Update HAL scene types to reflect `AssetId` dependency semantics.
- Update asset decode/encode logic for `SCENE`.
- Introduce and maintain reverse glyph residency index in the asset manager.
- Update `FrameComposer` bind path and draw path to use runtime dependency resolution and fatal logging.
- Rewrite affected tests, fixtures, and tooling payload writers.
- Create an execution plan before spec/code changes.
## Revision Log
- 2026-04-24: Initial accepted decision derived from AGD-0029.
- 2026-04-24: Moved to in_progress after plan family creation (`PLN-0040`, `PLN-0041`, `PLN-0042`).

View File

@ -1,104 +0,0 @@
---
id: PLN-0040
ticket: scene-bank-glyph-runtime-binding-leak
title: Scene glyph dependency spec and wire layout migration
status: done
created: 2026-04-24
completed: 2026-04-24
tags: [gfx, runtime, asset, scene, glyph, format, spec]
---
## Briefing
Implement the specification-side portion of `DEC-0021` by rewriting the `SCENE` payload contract so that each scene layer serializes a glyph dependency by canonical `AssetId (i32)` instead of a runtime glyph slot id. This plan covers only normative docs and wire-layout definition. It does not implement runtime code.
## Decisions de Origem
- `DEC-0021` — Scene Bank glyph dependencies MUST bind by `asset_id`, not runtime slot.
## Alvo
- Canonical runtime specs under `docs/specs/runtime/`.
- Shared payload constants and comments under `crates/console/prometeu-hal/` only where needed to reflect the normative wire layout.
## Escopo
- Rewrite the `SCENE` payload description to replace per-layer runtime slot semantics with per-layer `AssetId`.
- Define widened field width for serialized scene glyph dependencies.
- Remove any spec language implying passive missing-dependency status for scene composition.
- Align related comments/constants with the new payload field width and meaning.
## Fora de Escopo
- Runtime bind/draw implementation.
- Reverse index implementation in `AssetManager`.
- Test fixture rewrites and tool migration.
- Any compatibility or versioning path for the old payload.
## Plano de Execucao
### Step 1 - Rewrite the normative `SCENE` payload contract
**What:**
Define the scene-layer dependency field as `AssetId (i32)` and remove all remaining wording that treats scene glyph linkage as runtime slot topology.
**How:**
Update the relevant `docs/specs/runtime` sections so the payload layout, field meaning, and operational consequences all match `DEC-0021`. State explicitly that the scene asset is cold-description only and MUST NOT encode runtime slot ids.
**File(s):**
- `docs/specs/runtime/15-asset-management.md`
- any scene/gfx spec chapter that documents `SCENE` payload fields or scene dependency semantics.
### Step 2 - Update shared HAL wire-layout constants and inline documentation
**What:**
Bring shared constants and comments into sync with the widened scene dependency field.
**How:**
Review `crates/console/prometeu-hal/src/asset.rs` and any nearby scene-related code comments. Update layer-header sizing constants and field comments if the payload header width changes from the previous single-byte dependency representation.
**File(s):**
- `crates/console/prometeu-hal/src/asset.rs`
- neighboring scene payload comments when affected.
### Step 3 - Tighten the published fatal-error semantics
**What:**
Make the public documentation consistent with the accepted fatal behavior for missing scene glyph dependencies.
**How:**
Remove proposed/legacy wording that frames missing dependencies as recoverable status returns for scene activation/composition. Describe the bind-time and draw-time dependency absence as fatal machine errors with clear logging expectations.
**File(s):**
- `docs/specs/runtime/04-gfx-peripheral.md`
- `docs/specs/runtime/16-host-abi-and-syscalls.md`
- any other spec chapter that describes `composer.bind_scene`.
## Criterios de Aceite
- [ ] The published `SCENE` payload contract defines per-layer glyph dependency as `AssetId (i32)`.
- [ ] No normative spec text claims that `SCENE` serializes runtime glyph slot ids.
- [ ] No normative spec text retains `ERROR_MISSING_DEPENDENCIES` as the accepted contract for scene dependency failures.
- [ ] Shared HAL constants/comments reflect the revised payload layout where applicable.
## Tests / Validacao
### Unit Tests
- Add or update compile-time/runtime assertions only if shared payload constants are exercised by existing tests.
### Integration Tests
- None in this plan; verification is doc/contract oriented.
### Manual Verification
- Review the updated spec text to ensure every `SCENE` glyph dependency reference uses `AssetId` language.
- Verify that the documented payload width matches `AssetId = i32`.
- Verify that fatal semantics for missing dependencies are stated consistently across spec chapters.
## Riscos
- Spec-only edits can drift from the runtime implementation if later plans are not executed promptly.
- Scene payload layout changes may require touching multiple docs; missing one will leave contradictory contract text.
- If HAL constants are updated here before runtime code, temporary compile or test fallout may appear in later plans and must be handled intentionally.

View File

@ -1,140 +0,0 @@
---
id: PLN-0041
ticket: scene-bank-glyph-runtime-binding-leak
title: Scene glyph runtime resolution, reverse index, and fatal paths
status: done
created: 2026-04-24
completed: 2026-04-24
tags: [gfx, runtime, asset, scene, glyph, render]
---
## Briefing
Implement the runtime half of `DEC-0021`: remove canonical runtime glyph slot ids from scene types, widen scene dependency serialization to `AssetId (i32)`, introduce and maintain the internal reverse glyph residency index, and enforce fatal machine behavior when scene dependencies are missing at bind time or draw time.
## Decisions de Origem
- `DEC-0021` — Scene Bank glyph dependencies MUST bind by `asset_id`, not runtime slot.
## Alvo
- `crates/console/prometeu-hal/`
- `crates/console/prometeu-drivers/`
- `crates/console/prometeu-system/` only if runtime-visible behavior or tests require updates.
## Escopo
- Replace scene-layer glyph slot semantics with `AssetId` semantics in HAL/runtime types.
- Widen `SCENE` decode/encode logic to serialize `AssetId (i32)` per layer.
- Maintain an internal reverse index `AssetId -> glyph slot` for committed glyph assets.
- Enforce fatal handling with explicit logging when dependencies are missing during `bind_scene` or draw/composition.
## Fora de Escopo
- Public guest ABI for reverse lookup.
- Compatibility with old `glyph_bank_id` scene payloads.
- Tooling/stress-fixture migration beyond the runtime code needed to compile.
## Plano de Execucao
### Step 1 - Change canonical scene types to cold dependency identity
**What:**
Remove canonical runtime glyph slot ids from scene-layer related types and replace them with glyph dependency `AssetId`.
**How:**
Refactor `SceneLayer`, scene cache entries, viewport cache state, resolver helpers, and tests so the scene model stores dependency identity rather than slot identity. Preserve only the information needed for cold scene description plus runtime materialization.
**File(s):**
- `crates/console/prometeu-hal/src/scene_layer.rs`
- `crates/console/prometeu-hal/src/scene_viewport_cache.rs`
- `crates/console/prometeu-hal/src/scene_viewport_resolver.rs`
- scene-related tests under `prometeu-hal`.
### Step 2 - Update `SCENE` decode/encode path to `AssetId (i32)`
**What:**
Rewrite the binary `SCENE` decoder and local encoders to read/write `AssetId` instead of single-byte glyph slot ids.
**How:**
Adjust header width constants, field offsets, and validation in `AssetManager::decode_scene_bank_*` and any local test encoders. Ensure decode rejects malformed payloads under the new layout and that any helper fixture builder writes `i32` dependencies per layer.
**File(s):**
- `crates/console/prometeu-drivers/src/asset.rs`
- any scene payload helpers under tests.
### Step 3 - Introduce reverse glyph residency index
**What:**
Add a runtime-owned reverse mapping from committed glyph `AssetId` to glyph slot.
**How:**
Extend `AssetManager` so glyph preload, glyph commit, shutdown, and any slot replacement paths update both:
- the existing `slot -> asset_id` tracking;
- the new reverse `asset_id -> slot` index.
Keep this mechanism internal in this stage. Remove stale entries when a slot is overwritten or cleared.
**File(s):**
- `crates/console/prometeu-drivers/src/asset.rs`
- `crates/console/prometeu-hal/src/asset_bridge.rs` only if an internal-facing trait hook is required.
### Step 4 - Enforce fatal dependency validation in `bind_scene`
**What:**
Make scene activation fail fatally when any scene glyph dependency does not resolve to a committed glyph slot.
**How:**
Update the `FrameComposer` bind path and any caller path so bind checks every layer dependency against the reverse index before activating the scene. Emit a clear fatal log naming the scene context, layer index, and missing dependency `AssetId`.
**File(s):**
- `crates/console/prometeu-drivers/src/frame_composer.rs`
- `crates/console/prometeu-drivers/src/hardware.rs`
- `crates/console/prometeu-system/src/virtual_machine_runtime/dispatch.rs` if behavior shaping is needed.
### Step 5 - Enforce fatal dependency validation in draw/composition
**What:**
Make render-time scene composition fail fatally if a previously bindable dependency later becomes unresolved.
**How:**
Update the draw path so each layer resolves or revalidates the current glyph slot for the layer dependency through the reverse index instead of trusting old scene slot data. If resolution fails, emit the same class of fatal log and abort machine progress.
**File(s):**
- `crates/console/prometeu-drivers/src/gfx.rs`
- `crates/console/prometeu-drivers/src/frame_composer.rs`
## Criterios de Aceite
- [ ] No canonical scene type stores runtime glyph slot id as scene dependency state.
- [ ] `SCENE` decode/encode paths serialize per-layer dependency as `AssetId (i32)`.
- [ ] `AssetManager` maintains a reverse glyph index updated by preload and commit.
- [ ] `bind_scene` fatalizes with clear logging when a dependency is missing.
- [ ] Draw/composition fatalizes with clear logging when a dependency is missing.
- [ ] No runtime path continues scene composition after missing dependency detection.
## Tests / Validacao
### Unit Tests
- Add/update tests for scene decode under the widened `AssetId` field.
- Add/update tests for reverse index maintenance across preload, commit, overwrite, and shutdown.
- Add/update tests for `FrameComposer` bind failure on missing glyph dependency.
### Integration Tests
- Add/update runtime integration tests covering:
- scene bind with all dependencies present;
- fatal bind when a dependency is absent;
- fatal draw when a dependency becomes unresolved after bind, if that transition is constructible in tests.
### Manual Verification
- Load a cartridge with scene and glyph dependencies committed in non-matching slot order and confirm bind still resolves correctly.
- Confirm fatal logs identify the missing `AssetId` and layer when dependency resolution fails.
## Riscos
- Runtime fatalization may expose pre-existing tests or flows that assumed passive failure.
- Reverse-index maintenance can become incorrect if any overwrite/clear path is missed.
- Removing slot ids from scene/cache types can cascade into a larger render refactor than expected if code paths implicitly rely on them.

View File

@ -1,115 +0,0 @@
---
id: PLN-0042
ticket: scene-bank-glyph-runtime-binding-leak
title: Scene glyph tooling, fixtures, and test payload migration
status: done
created: 2026-04-24
completed: 2026-04-24
tags: [gfx, runtime, asset, scene, glyph, tooling, tests]
---
## Briefing
Complete the implementation surface of `DEC-0021` by migrating all scene payload producers, fixtures, stress tools, and test data away from serialized runtime glyph slots and onto per-layer glyph dependency `AssetId (i32)`.
## Decisions de Origem
- `DEC-0021` — Scene Bank glyph dependencies MUST bind by `asset_id`, not runtime slot.
## Alvo
- Runtime tests and helpers under `crates/console/prometeu-drivers/`
- Runtime tests under `crates/console/prometeu-system/`
- Tooling and stress generators under `crates/tools/`
## Escopo
- Rewrite scene payload writers in tests and tools.
- Rewrite test fixtures and expectations that still name or assert `glyph_bank_id`.
- Ensure stress and fixture content uses valid `AssetId` dependencies and exercises runtime resolution order independence.
## Fora de Escopo
- Core runtime implementation of reverse index and fatal semantics.
- Public API exposure of reverse lookup.
- Backward-compatible scene payload generation.
## Plano de Execucao
### Step 1 - Rewrite local scene payload builders in driver tests
**What:**
Update every driver-side scene helper and binary payload builder that still writes per-layer runtime slot ids.
**How:**
Search all `SceneLayer` builders and `SCENE` payload encoders in driver tests. Replace slot-oriented setup with per-layer dependency `AssetId`, then adjust assertions accordingly.
**File(s):**
- `crates/console/prometeu-drivers/src/asset.rs`
- `crates/console/prometeu-drivers/src/frame_composer.rs`
- `crates/console/prometeu-drivers/src/gfx.rs`
- `crates/console/prometeu-drivers/src/hardware.rs`
### Step 2 - Rewrite system/runtime integration fixtures
**What:**
Migrate integration fixtures so scene setup reflects asset-id dependencies and runtime slot resolution.
**How:**
Update helper functions and tests under `prometeu-system` that construct scenes or assume direct slot semantics. Ensure tests explicitly preload/commit glyph assets under varying slot orders and verify correct resolution behavior.
**File(s):**
- `crates/console/prometeu-system/src/virtual_machine_runtime/tests.rs`
- other runtime test modules that build scene fixtures.
### Step 3 - Rewrite tooling and stress generators
**What:**
Update scene-producing tools so published binary payloads match the accepted scene dependency contract.
**How:**
Rewrite stress/payload builders to write `AssetId (i32)` per layer and to generate coherent asset tables/preload data that prove runtime resolution by dependency identity rather than baked slot topology.
**File(s):**
- `crates/tools/pbxgen-stress/src/lib.rs`
- any other local scene payload generators discovered during implementation.
### Step 4 - Add regression coverage for former slot leakage
**What:**
Add focused regression cases that fail if scene payloads again leak runtime glyph slot ids.
**How:**
Introduce tests that deliberately load glyph dependencies into different slots from their prior fixture order and verify scene bind/draw behavior depends on `AssetId` resolution only.
**File(s):**
- affected test modules under `prometeu-drivers`, `prometeu-system`, and tool tests if present.
## Criterios de Aceite
- [ ] No test or tooling payload writer serializes per-layer runtime glyph slot id for `SCENE`.
- [ ] Scene fixtures express glyph dependencies by `AssetId`.
- [ ] At least one regression test proves glyph slot order does not matter for scene activation.
- [ ] At least one regression test would fail if old slot-leak behavior returned.
## Tests / Validacao
### Unit Tests
- Update existing scene codec/fixture tests to assert `AssetId`-based dependency behavior.
### Integration Tests
- Run runtime integration coverage where scene dependencies resolve correctly despite different glyph slot placement.
- Run regression coverage for fatal behavior when dependencies are absent.
### Manual Verification
- Inspect representative generated payload bytes to confirm widened dependency field writing.
- Verify stress/tool outputs remain consumable by the updated runtime.
## Riscos
- Test helper churn may be broad because many fixtures were written around the leaked slot model.
- Tool outputs may silently drift if any scene payload writer is missed.
- Regression tests can become brittle if they depend on incidental slot ordering instead of declared dependency identity.