frame composer - abi adjustments

This commit is contained in:
bQUARKz 2026-04-17 17:43:25 +01:00
parent f4260d0cf4
commit 240fe65da7
Signed by: bquarkz
SSH Key Fingerprint: SHA256:Z7dgqoglWwoK6j6u4QC87OveEq74WOhFN+gitsxtkf8
7 changed files with 819 additions and 1 deletions

View File

@ -1,4 +1,4 @@
{"type":"meta","next_id":{"DSC":27,"AGD":27,"DEC":15,"PLN":22,"LSN":31,"CLSN":1}}
{"type":"meta","next_id":{"DSC":28,"AGD":28,"DEC":16,"PLN":26,"LSN":31,"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"}]}
@ -19,6 +19,7 @@
{"type":"discussion","id":"DSC-0024","status":"done","ticket":"generic-memory-bank-slot-contract","title":"Agenda - Generic Memory Bank Slot Contract","created_at":"2026-04-10","updated_at":"2026-04-10","tags":["runtime","asset","memory-bank","slots","host"],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0029","file":"lessons/DSC-0024-generic-memory-bank-slot-contract/LSN-0029-slot-first-bank-telemetry-belongs-in-asset-manager.md","status":"done","created_at":"2026-04-10","updated_at":"2026-04-10"}]}
{"type":"discussion","id":"DSC-0025","status":"done","ticket":"scene-bank-and-viewport-cache-refactor","title":"Scene Bank and Viewport Cache Refactor","created_at":"2026-04-11","updated_at":"2026-04-14","tags":["gfx","tilemap","runtime","render"],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0030","file":"lessons/DSC-0025-scene-bank-and-viewport-cache-refactor/LSN-0030-canonical-scene-cache-and-resolver-split.md","status":"done","created_at":"2026-04-14","updated_at":"2026-04-14"}]}
{"type":"discussion","id":"DSC-0026","status":"open","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-15","tags":["gfx","runtime","render","camera","scene"],"agendas":[{"id":"AGD-0026","file":"workflow/agendas/AGD-0026-render-all-scene-cache-and-camera-integration.md","status":"accepted","created_at":"2026-04-14","updated_at":"2026-04-15"}],"decisions":[{"id":"DEC-0014","file":"workflow/decisions/DEC-0014-frame-composer-render-integration.md","status":"accepted","created_at":"2026-04-14","updated_at":"2026-04-15","ref_agenda":"AGD-0026"}],"plans":[{"id":"PLN-0017","file":"workflow/plans/PLN-0017-frame-composer-core-and-hardware-ownership.md","status":"accepted","created_at":"2026-04-14","updated_at":"2026-04-15","ref_decisions":["DEC-0014"]},{"id":"PLN-0018","file":"workflow/plans/PLN-0018-sprite-controller-and-frame-emission-model.md","status":"accepted","created_at":"2026-04-14","updated_at":"2026-04-14","ref_decisions":["DEC-0014"]},{"id":"PLN-0019","file":"workflow/plans/PLN-0019-scene-binding-camera-and-scene-status.md","status":"accepted","created_at":"2026-04-14","updated_at":"2026-04-15","ref_decisions":["DEC-0014"]},{"id":"PLN-0020","file":"workflow/plans/PLN-0020-cache-refresh-and-render-frame-path.md","status":"accepted","created_at":"2026-04-14","updated_at":"2026-04-15","ref_decisions":["DEC-0014"]},{"id":"PLN-0021","file":"workflow/plans/PLN-0021-service-retirement-callsite-migration-and-regression.md","status":"accepted","created_at":"2026-04-14","updated_at":"2026-04-15","ref_decisions":["DEC-0014"]}],"lessons":[]}
{"type":"discussion","id":"DSC-0027","status":"open","ticket":"frame-composer-public-syscall-surface","title":"Agenda - FrameComposer Public Syscall Surface","created_at":"2026-04-17","updated_at":"2026-04-17","tags":["gfx","runtime","syscall","abi","frame-composer","scene","camera","sprites"],"agendas":[{"id":"AGD-0027","file":"workflow/agendas/AGD-0027-frame-composer-public-syscall-surface.md","status":"accepted","created_at":"2026-04-17","updated_at":"2026-04-17"}],"decisions":[{"id":"DEC-0015","file":"workflow/decisions/DEC-0015-frame-composer-public-syscall-surface.md","status":"accepted","created_at":"2026-04-17","updated_at":"2026-04-17","ref_agenda":"AGD-0027"}],"plans":[{"id":"PLN-0022","file":"workflow/plans/PLN-0022-composer-syscall-domain-and-spec-propagation.md","status":"accepted","created_at":"2026-04-17","updated_at":"2026-04-17","ref_decisions":["DEC-0015"]},{"id":"PLN-0023","file":"workflow/plans/PLN-0023-composer-runtime-dispatch-and-legacy-removal.md","status":"accepted","created_at":"2026-04-17","updated_at":"2026-04-17","ref_decisions":["DEC-0015"]},{"id":"PLN-0024","file":"workflow/plans/PLN-0024-composer-cartridge-tooling-and-regression-migration.md","status":"accepted","created_at":"2026-04-17","updated_at":"2026-04-17","ref_decisions":["DEC-0015"]},{"id":"PLN-0025","file":"workflow/plans/PLN-0025-final-ci-validation-and-polish.md","status":"accepted","created_at":"2026-04-17","updated_at":"2026-04-17","ref_decisions":["DEC-0015"]}],"lessons":[]}
{"type":"discussion","id":"DSC-0014","status":"open","ticket":"perf-vm-allocation-and-copy-pressure","title":"Agenda - [PERF] VM Allocation and Copy Pressure","created_at":"2026-03-27","updated_at":"2026-03-27","tags":[],"agendas":[{"id":"AGD-0013","file":"workflow/agendas/AGD-0013-perf-vm-allocation-and-copy-pressure.md","status":"open","created_at":"2026-03-27","updated_at":"2026-03-27"}],"decisions":[],"plans":[],"lessons":[]}
{"type":"discussion","id":"DSC-0015","status":"open","ticket":"perf-cartridge-boot-and-program-ownership","title":"Agenda - [PERF] Cartridge Boot and Program Ownership","created_at":"2026-03-27","updated_at":"2026-03-27","tags":[],"agendas":[{"id":"AGD-0014","file":"workflow/agendas/AGD-0014-perf-cartridge-boot-and-program-ownership.md","status":"open","created_at":"2026-03-27","updated_at":"2026-03-27"}],"decisions":[],"plans":[],"lessons":[]}
{"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,214 @@
---
id: AGD-0027
ticket: frame-composer-public-syscall-surface
title: Agenda - FrameComposer Public Syscall Surface
status: accepted
created: 2026-04-17
updated: 2026-04-17
tags: [gfx, runtime, syscall, abi, frame-composer, scene, camera, sprites]
---
## Contexto
`DEC-0014` e os planos `PLN-0017` a `PLN-0021` fecharam a migração interna do pipeline de frame para `FrameComposer`:
- `FrameComposer` virou o orquestrador canônico do frame;
- `Hardware` passou a agregá-lo ao lado de `Gfx`;
- scene, camera, cache, resolver e sprite emission migraram para ownership interno dele;
- o frame loop do runtime passou a renderizar via `FrameComposer.render_frame()`.
Isso resolveu a base operacional interna, mas não fechou a superfície pública equivalente para a VM. A ABI pública ainda expõe apenas o contrato legado de `gfx.set_sprite(...)`, enquanto `bind_scene(...)` e `set_camera(...)` existem apenas como APIs internas do driver.
Na prática, hoje temos uma assimetria:
- a base canônica do frame está em `FrameComposer`;
- mas a ABI pública ainda não trata `FrameComposer` como serviço canônico para scene, camera e sprites.
Essa lacuna impede a migração do restante da stack e também impede um stress cartridge que atravesse de verdade o pipeline novo por syscall pública.
## Problema
Precisamos definir a nova superfície pública de syscall para o pipeline canônico de `FrameComposer` sem reabrir a decisão já aceita sobre ownership interno do frame.
O problema concreto não é “adicionar 2 ou 3 syscalls”. Precisamos decidir:
- quais operações de `FrameComposer` viram ABI pública agora;
- se `gfx.set_sprite(...)` continua como shim legado ou perde status canônico;
- qual é o contrato mínimo de scene/camera que a VM pode observar/controlar;
- como nomear e versionar essa superfície pública sem criar um segundo modelo canônico concorrente;
- qual é a estratégia de transição para cartridge, runtime tests e stress tests;
- como propagar essa mudança para a spec canônica e, se necessário, para contratos de ABI e `ISA_CORE`.
## Pontos Criticos
- `DEC-0014` já fechou `FrameComposer` como base canônica interna; esta agenda não deve reabrir isso.
- A ABI pública atual ainda expõe `gfx.set_sprite(...)` com semântica herdada de índice/slot, mesmo que a implementação interna já use frame emission.
- `bind_scene(scene_bank_id)` e `set_camera(x, y)` já existem no driver, mas ainda não existem como syscalls públicas.
- Se a nova ABI expuser demais logo de início, vamos congelar cedo demais detalhes que ainda não provaram valor operacional.
- Se a nova ABI expuser de menos, manteremos um modelo híbrido por tempo demais:
- canônico internamente via `FrameComposer`;
- legado externamente via `Gfx`/`set_sprite`.
- Precisamos decidir se o namespace público continua em `gfx.*` por estabilidade do domínio, ou se devemos introduzir algo como `frame.*`.
- A transição precisa preservar compatibilidade suficiente para não quebrar cartridges e testes existentes antes da migração do restante.
- O contrato de sprite precisa deixar claro se o chamador ainda informa índice, se informa `layer`, e se `active` continua existindo na superfície pública.
- A mudança não pode ficar só em código/runtime; a spec canônica precisa ser atualizada para refletir o novo serviço público.
- Se o contrato público afetar superfícies documentadas de ABI ou o material de `ISA_CORE`, essa propagação precisa ser tratada como parte da mesma thread, não como follow-up solto.
## Opcoes
### Opcao 1 - Expor um núcleo mínimo canônico em `gfx.*`
**Como seria:**
Adicionar apenas a superfície mínima para a VM controlar o pipeline novo:
- `gfx.bind_scene(bank_id)`
- `gfx.unbind_scene()`
- `gfx.set_camera(x, y)`
- `gfx.emit_sprite(...)`
`gfx.set_sprite(...)` permaneceria por um período como shim legado de compatibilidade.
**Vantagens:**
- fecha rapidamente a lacuna operacional;
- habilita stress real do pipeline novo;
- reduz o tempo de convivência entre modelo canônico e legado;
- mantém o domínio público em `gfx`, evitando churn de namespace.
**Desvantagens:**
- introduz ABI nova que precisará de migração coordenada;
- exige definir `emit_sprite(...)` com cuidado para não herdar sem querer o modelo de slot.
### Opcao 2 - Expor scene/camera agora e adiar o contrato novo de sprite
**Como seria:**
Publicar apenas:
- `gfx.bind_scene(bank_id)`
- `gfx.unbind_scene()`
- `gfx.set_camera(x, y)`
Sprites continuariam publicamente via `gfx.set_sprite(...)` até uma segunda fase.
**Vantagens:**
- menor mudança imediata de ABI;
- desbloqueia o stress do world path e da câmera;
- reduz o volume inicial da migração pública.
**Desvantagens:**
- mantém dois modelos públicos de sprite por mais tempo;
- prolonga a semântica de compatibilidade do syscall legado;
- adia exatamente uma das partes centrais da migração para `FrameComposer`.
### Opcao 3 - Criar um novo namespace público separado, como `composer.*`
**Como seria:**
O pipeline novo ganha syscalls em um domínio separado, por exemplo:
- `composer.bind_scene`
- `composer.unbind_scene`
- `composer.set_camera`
- `composer.emit_sprite`
`gfx.*` ficaria como superfície legacy/low-level.
**Vantagens:**
- deixa explícita a mudança de serviço canônico;
- evita sobrecarregar semanticamente `gfx`.
**Desvantagens:**
- adiciona churn conceitual e de nomenclatura;
- fragmenta demais a superfície pública neste momento;
- cria um custo de transição maior sem benefício operacional evidente.
## Sugestao / Recomendacao
Seguir com a **Opcao 3**.
Direção recomendada:
- a superfície pública canônica deve migrar para o domínio `composer.*`;
- `FrameComposer` vira a base canônica também na ABI pública, com namespace próprio em vez de continuar semanticamente preso a `gfx.*`;
- o núcleo mínimo público deve ser:
- `composer.bind_scene(bank_id) -> status`
- `composer.unbind_scene()`
- `composer.set_camera(x, y)`
- `composer.emit_sprite(...) -> status`
- `gfx.set_sprite(...)` deve morrer e ser removido completamente do contrato público.
Para sprites, a recomendação provisória é:
- a nova ABI pública não deve exigir índice explícito;
- `composer.emit_sprite(...)` deve receber o payload completo necessário para o frame:
- `glyph_id`
- `palette_id`
- `x`
- `y`
- `layer`
- `bank_id`
- `flip_x`
- `flip_y`
- `priority`
- a ABI pode futuramente agrupar esse payload se isso melhorar ergonomia, mas o contrato mínimo deve nascer completo;
- `active` não deve continuar no contrato canônico novo;
- overflow continua sendo ignorado com status/telemetria adequada, sem trapar o runtime.
Para scene/camera, a recomendação provisória é:
- manter o contrato mínimo já aceito internamente;
- `bind_scene` por bank id;
- `unbind_scene` explícito;
- `set_camera(x, y)` em pixel space com top-left viewport.
- `bind_scene(...)`, `unbind_scene(...)` e `emit_sprite(...)` devem usar `ComposerOpStatus` como retorno operacional canônico.
## Perguntas em Aberto
- Resolvido:
- o nome público canônico de sprite será `composer.emit_sprite(...)`;
- o syscall novo de sprite nasce completo com `glyph_id`, `palette_id`, `x`, `y`, `layer`, `bank_id`, `flip_x`, `flip_y`, `priority`;
- `gfx.set_sprite(...)` deve morrer e ser removido completamente;
- não haverá leitura de estado nesta primeira fase;
- `bind_scene(...)`, `unbind_scene(...)` e `emit_sprite(...)` usarão `ComposerOpStatus`;
- A ABI nova precisa expor refresh explícito, ou isso deve continuar totalmente interno ao `FrameComposer`?
- Resolvido:
- a ABI nova não deve expor refresh explícito;
- o domínio público canônico será `composer.*`, não `gfx.*`.
## Criterio para Encerrar
Esta agenda pode ser encerrada quando houver acordo explícito sobre:
- a lista mínima de syscalls públicas canônicas do `FrameComposer`;
- o nome canônico da operação pública de sprite;
- a remoção completa de `gfx.set_sprite(...)` do contrato público;
- o formato de retorno/status das novas operações;
- a estratégia de transição necessária para decisão, plano e migração do restante da stack.
## Resolucao em Andamento
Direção atualmente acordada nesta agenda:
- o namespace público canônico será `composer.*`;
- o núcleo mínimo inicial será:
- `composer.bind_scene(bank_id) -> ComposerOpStatus`
- `composer.unbind_scene() -> ComposerOpStatus`
- `composer.set_camera(x, y)`
- `composer.emit_sprite(glyph_id, palette_id, x, y, layer, bank_id, flip_x, flip_y, priority) -> ComposerOpStatus`
- não haverá introspecção pública nesta primeira fase;
- refresh/cache policy continua interno ao `FrameComposer`;
- `gfx.set_sprite(...)` não terá caminho de compatibilidade e deve ser removido.
## Resolucao
Esta agenda fica aceita com os seguintes pontos fechados:
- o namespace público canônico do serviço será `composer.*`;
- a superfície mínima inicial será:
- `composer.bind_scene(bank_id) -> ComposerOpStatus`
- `composer.unbind_scene() -> ComposerOpStatus`
- `composer.set_camera(x, y)`
- `composer.emit_sprite(glyph_id, palette_id, x, y, layer, bank_id, flip_x, flip_y, priority) -> ComposerOpStatus`
- não haverá introspecção pública nesta primeira fase;
- não haverá refresh/cache policy público;
- `gfx.set_sprite(...)` deve ser removido completamente, sem shim de compatibilidade;
- a transição deve introduzir `composer.*` e remover `gfx.set_sprite(...)` na mesma thread de migração, com atualização coordenada de bytecode, cartridges, tests e runtime;
- a mesma thread deve atualizar a spec canônica do assunto e propagar a mudança para contratos de ABI e `ISA_CORE` quando essas superfícies forem impactadas pelo novo serviço público.

View File

@ -0,0 +1,166 @@
---
id: DEC-0015
ticket: frame-composer-public-syscall-surface
title: FrameComposer Public Syscall Surface
status: accepted
created: 2026-04-17
accepted: 2026-04-17
agenda: AGD-0027
plans: [PLN-0022, PLN-0023, PLN-0024, PLN-0025]
tags: [gfx, runtime, syscall, abi, frame-composer, scene, camera, sprites]
---
## Status
Accepted.
## Contexto
`DEC-0014` locked `FrameComposer` as the canonical internal frame orchestration service and `PLN-0017` through `PLN-0021` completed that internal migration path. `Hardware` now owns `FrameComposer`, the runtime renders through `FrameComposer.render_frame()`, and scene/camera/cache/resolver/sprite ownership no longer belongs canonically to `Gfx`.
That migration did not define the equivalent public syscall contract for VM code. The public ABI still exposed legacy `gfx`-domain sprite control while the canonical scene/camera operations existed only as internal driver APIs.
This decision closes that public ABI gap without reopening the already accepted internal ownership model.
## Decisao
The canonical public syscall surface for frame orchestration SHALL move to the `composer.*` namespace.
Normatively:
- The canonical public service domain for `FrameComposer` operations SHALL be `composer`.
- The initial canonical syscall set SHALL be:
- `composer.bind_scene(bank_id) -> ComposerOpStatus`
- `composer.unbind_scene() -> ComposerOpStatus`
- `composer.set_camera(x, y)`
- `composer.emit_sprite(glyph_id, palette_id, x, y, layer, bank_id, flip_x, flip_y, priority) -> ComposerOpStatus`
- `composer.emit_sprite(...)` SHALL be the canonical public sprite submission path.
- `composer.emit_sprite(...)` MUST NOT require a caller-provided sprite index.
- `composer.emit_sprite(...)` MUST carry `layer` and `priority`.
- `composer.emit_sprite(...)` MUST NOT expose `active` as part of the canonical contract.
- `composer.bind_scene(...)`, `composer.unbind_scene()`, and `composer.emit_sprite(...)` SHALL return `ComposerOpStatus`.
- `composer.set_camera(x, y)` SHALL keep the minimal V1 camera contract already accepted by `DEC-0014`:
- `x` and `y` are `i32` pixel coordinates;
- they represent the top-left viewport origin in world space.
- The public ABI MUST NOT expose cache refresh policy or explicit refresh controls.
- The public ABI MUST NOT expose scene/camera introspection in this first phase.
- `gfx.set_sprite(...)` MUST be removed completely from the public contract.
- No compatibility shim for `gfx.set_sprite(...)` SHALL remain as part of the canonical migration target.
- Introduction of `composer.*` and removal of `gfx.set_sprite(...)` SHALL be executed in the same migration thread.
## Rationale
The public ABI must reflect the accepted ownership model rather than preserve a misleading legacy shape.
Keeping the canonical public surface under `gfx.*` would continue to tie orchestration semantics to the wrong service boundary. The new namespace makes the ownership change explicit:
- `Gfx` is the visual backend;
- `FrameComposer` is the frame orchestration service.
Removing `gfx.set_sprite(...)` completely avoids prolonging a dual public sprite model. A compatibility shim would preserve legacy slot/index semantics in the public contract after those semantics had already ceased to be canonical internally.
Returning `ComposerOpStatus` for operational mutating calls preserves status-first behavior while keeping the public contract aligned with the new service boundary. Reusing `GfxOpStatus` would leak backend-domain semantics into orchestration-domain syscalls after that separation had already been made explicit.
Deferring introspection and explicit refresh controls keeps the first public ABI focused on control, not diagnostics or internal policy leakage.
## Invariantes / Contrato
### 1. Namespace
- Public frame-orchestration syscalls MUST live under `composer.*`.
- `composer.*` SHALL be treated as the canonical public orchestration surface.
- `gfx.*` SHALL NOT remain the canonical public orchestration namespace for scene/camera/sprite submission.
### 2. Scene Control
- `composer.bind_scene(bank_id)` MUST bind by scene bank id.
- Binding semantics MUST remain aligned with `DEC-0014`:
- scene resolution through the scene bank pool;
- explicit bind/unbind lifecycle;
- no implicit per-frame rebinding.
- `composer.unbind_scene()` MUST leave no-scene rendering valid.
- `ComposerOpStatus` SHALL be the canonical operational status family for composer-domain mutating syscalls.
### 3. Camera
- `composer.set_camera(x, y)` MUST remain the minimal V1 camera API.
- Camera follow, smoothing, shake, transitions, and readback are OUT OF SCOPE for this decision.
### 4. Sprite Submission
- `composer.emit_sprite(...)` MUST be frame-emission based.
- The caller MUST NOT provide sprite slot/index information.
- The public payload MUST include:
- `glyph_id`
- `palette_id`
- `x`
- `y`
- `layer`
- `bank_id`
- `flip_x`
- `flip_y`
- `priority`
- The canonical public sprite contract MUST NOT include `active`.
- Overflow behavior SHALL remain aligned with `DEC-0014`:
- excess sprites are ignored;
- overflow is not a hard VM fault in V1.
### 5. Non-Goals for V1 Public ABI
- No public refresh/invalidate syscalls.
- No public cache inspection syscalls.
- No public `scene_status()` syscall.
- No public `get_camera()` syscall.
### 6. Migration Contract
- Migration MUST update:
- syscall registry and ABI resolution;
- runtime dispatch;
- bytecode/cartridge declarations;
- tests;
- stress cartridges and related tooling where applicable.
- Migration MUST NOT leave `gfx.set_sprite(...)` as a supported public fallback after the new contract lands.
## Impactos
### HAL
- The syscall enum, registry, metadata, and resolver will need a new `composer` domain surface.
- `gfx.set_sprite(...)` must be removed from the public ABI contract.
- A new `ComposerOpStatus` contract will need to be introduced for composer-domain operational returns.
### Runtime / VM
- Runtime dispatch must route public scene/camera/sprite orchestration through `FrameComposer`.
- Existing bytecode declarations and cartridges that rely on `gfx.set_sprite(...)` will need coordinated migration.
### Spec / ABI / ISA_CORE
- The canonical spec for the public VM-facing graphics/composition surface must be updated to reflect `composer.*`.
- ABI-facing documentation and contracts must be updated wherever syscall domain, names, arguments, or return semantics are specified.
- `ISA_CORE` must be updated if and where it normatively references the public syscall surface affected by this decision.
### Drivers / Hardware
- `FrameComposer` already has the required internal base; execution work will focus on public ABI exposure rather than internal ownership redesign.
### Tooling / Stress
- Stress cartridges and bytecode generators can only exercise the canonical frame path publicly after `composer.*` exists.
## Referencias
- [AGD-0027-frame-composer-public-syscall-surface.md](/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/discussion/workflow/agendas/AGD-0027-frame-composer-public-syscall-surface.md)
- [DEC-0014-frame-composer-render-integration.md](/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/discussion/workflow/decisions/DEC-0014-frame-composer-render-integration.md)
## Propagacao Necessaria
- A new implementation plan MUST be created from this decision before code changes.
- The plan MUST cover ABI introduction, legacy syscall removal, cartridge/test migration, regression coverage, and canonical spec propagation.
- The plan MUST explicitly assess and update ABI and `ISA_CORE` artifacts where this decision changes documented public behavior.
- Stress tooling SHOULD be updated as part of the migration thread so the public ABI can exercise the canonical frame path end-to-end.
## Revision Log
- 2026-04-17: Initial accepted decision from `AGD-0027`.

View File

@ -0,0 +1,122 @@
---
id: PLN-0022
ticket: frame-composer-public-syscall-surface
title: Plan - Composer Syscall Domain and Spec Propagation
status: accepted
created: 2026-04-17
completed:
tags: [gfx, runtime, syscall, abi, spec, isa-core, frame-composer]
---
## Objective
Introduce the canonical `composer.*` syscall domain, define `ComposerOpStatus`, and propagate the new public contract through the canonical spec, ABI documentation, and `ISA_CORE` artifacts where affected.
## Background
`DEC-0015` locks the public orchestration surface on `composer.*`, requires `ComposerOpStatus` for mutating composer-domain calls, and requires propagation beyond code into canonical spec, ABI-facing documentation, and `ISA_CORE` where the public syscall surface is described normatively.
## Scope
### Included
- add the `composer` syscall domain and ids
- define `ComposerOpStatus`
- remove `gfx.set_sprite(...)` from the public ABI contract
- update canonical spec documentation for the new public surface
- update ABI-facing documentation and `ISA_CORE` wherever the public syscall contract is described
### Excluded
- runtime dispatch implementation
- cartridge and stress program migration
- final repository-wide CI execution
## Execution Steps
### Step 1 - Define the public `composer` syscall contract
**What:**
Add the new canonical public syscall surface to the HAL syscall contract.
**How:**
- Extend the syscall enum, registry, metadata, and resolver with a new `composer` domain.
- Allocate explicit syscall ids for:
- `composer.bind_scene`
- `composer.unbind_scene`
- `composer.set_camera`
- `composer.emit_sprite`
- Remove `gfx.set_sprite` from the public syscall contract and registry.
- Keep syscall metadata explicit for arg/ret slots and capability requirements.
**File(s):**
- `crates/console/prometeu-hal/src/syscalls.rs`
- `crates/console/prometeu-hal/src/syscalls/domains/*`
- `crates/console/prometeu-hal/src/syscalls/registry.rs`
- `crates/console/prometeu-hal/src/syscalls/resolver.rs`
### Step 2 - Introduce `ComposerOpStatus`
**What:**
Create the status family for composer-domain mutating operations.
**How:**
- Define a `ComposerOpStatus` type in HAL with explicit operational states needed by:
- scene binding
- scene unbinding
- sprite emission
- Ensure the enum is semantically composer-domain specific rather than a rename wrapper around `GfxOpStatus`.
- Update public API references so composer syscalls return `ComposerOpStatus` where required by `DEC-0015`.
**File(s):**
- `crates/console/prometeu-hal/src/*`
- any shared status exports used by runtime/VM code
### Step 3 - Propagate the contract into spec, ABI docs, and `ISA_CORE`
**What:**
Update normative documentation so the public contract no longer describes legacy `gfx.set_sprite`.
**How:**
- Identify canonical spec files that describe VM graphics/composition syscalls.
- Replace public references to legacy sprite orchestration with `composer.*`.
- Update ABI-facing docs to pin:
- namespace
- names
- arg order
- return semantics
- Update `ISA_CORE` if and where it references the affected syscall surface.
- Keep published spec content in English per repository policy.
**File(s):**
- canonical spec location(s)
- ABI contract documentation
- `ISA_CORE` artifact(s) if affected
## Test Requirements
### Unit Tests
- syscall registry tests pin the new `composer.*` entries and reject removed legacy identities
- `ComposerOpStatus` values are pinned where public return semantics are asserted
### Integration Tests
- declared syscall resolution accepts `composer.*` declarations and rejects removed `gfx.set_sprite`
### Manual Verification
- inspect canonical spec, ABI docs, and `ISA_CORE` references to confirm the public contract matches `DEC-0015`
## Acceptance Criteria
- [ ] The public syscall registry exposes `composer.bind_scene`, `composer.unbind_scene`, `composer.set_camera`, and `composer.emit_sprite`.
- [ ] `ComposerOpStatus` exists as the canonical status family for composer-domain mutating syscalls.
- [ ] `gfx.set_sprite` is removed from the public ABI contract.
- [ ] Canonical spec documentation is updated to describe `composer.*`.
- [ ] ABI-facing docs and `ISA_CORE` are updated wherever the affected public surface is documented.
## Dependencies
- Source decision: `DEC-0015`
## Risks
- Missing a normative doc location would leave the code and published contract divergent.
- Reusing `GfxOpStatus` semantics by accident would weaken the service-boundary separation required by `DEC-0015`.
- Removing the legacy syscall contract incompletely could leave resolver or ABI ambiguity behind.

View File

@ -0,0 +1,112 @@
---
id: PLN-0023
ticket: frame-composer-public-syscall-surface
title: Plan - Composer Runtime Dispatch and Legacy Removal
status: accepted
created: 2026-04-17
completed:
tags: [runtime, syscall, frame-composer, dispatch, migration]
---
## Objective
Route the new public `composer.*` syscalls through `FrameComposer`, remove legacy `gfx.set_sprite` handling, and align runtime-side operational behavior with `DEC-0015`.
## Background
`DEC-0015` closes the public contract around `composer.*` and requires that `gfx.set_sprite` be removed completely rather than kept as a compatibility shim. The internal `FrameComposer` ownership model already exists from `DEC-0014` and plans `PLN-0017` through `PLN-0021`.
## Scope
### Included
- runtime syscall dispatch for `composer.*`
- operational mapping from syscall args to `FrameComposer`
- removal of legacy `gfx.set_sprite` runtime handling
- runtime-facing tests for composer-domain behavior
### Excluded
- spec and ABI doc propagation
- cartridge/tooling migration
- final `make ci` closure
## Execution Steps
### Step 1 - Add runtime dispatch for `composer.*`
**What:**
Teach VM runtime dispatch to call `FrameComposer` through the new public contract.
**How:**
- Add dispatch arms for:
- `composer.bind_scene`
- `composer.unbind_scene`
- `composer.set_camera`
- `composer.emit_sprite`
- Parse arguments exactly as pinned by the HAL metadata.
- Return `ComposerOpStatus` for mutating composer-domain syscalls.
**File(s):**
- `crates/console/prometeu-system/src/virtual_machine_runtime/dispatch.rs`
- any adjacent runtime helpers
### Step 2 - Map operational outcomes cleanly onto `ComposerOpStatus`
**What:**
Make runtime failures and normal outcomes reflect the new composer-domain status model.
**How:**
- Bind runtime-side operational checks to status outcomes such as:
- scene bank unavailable
- bank invalid
- argument range invalid
- layer invalid
- sprite overflow if surfaced operationally
- Keep non-fatal overflow behavior aligned with `DEC-0015`.
**File(s):**
- `crates/console/prometeu-system/src/virtual_machine_runtime/dispatch.rs`
- `crates/console/prometeu-hal/src/*` as needed for shared status meaning
### Step 3 - Remove legacy `gfx.set_sprite` runtime support
**What:**
Delete the old public runtime path for slot-style sprite submission.
**How:**
- Remove dispatch support for `gfx.set_sprite`.
- Remove runtime assumptions about `active`, caller-provided indices, and legacy sprite ABI shape.
- Keep no private compatibility hook behind the public API.
**File(s):**
- `crates/console/prometeu-system/src/virtual_machine_runtime/dispatch.rs`
- adjacent tests and public syscall references
## Test Requirements
### Unit Tests
- runtime dispatch returns `ComposerOpStatus` for bind, unbind, and emit operations
- `composer.set_camera` stores the minimal V1 camera coordinates correctly
### Integration Tests
- a VM/runtime test can bind a scene, set camera, emit a sprite, reach `FRAME_SYNC`, and render through the canonical frame path
- public runtime behavior rejects removed `gfx.set_sprite` declarations/calls
### Manual Verification
- inspect dispatch code to confirm all public orchestration now routes through `FrameComposer` rather than a legacy `gfx` sprite syscall path
## Acceptance Criteria
- [ ] Runtime dispatch supports all canonical `composer.*` syscalls.
- [ ] Mutating composer-domain calls return `ComposerOpStatus`.
- [ ] `gfx.set_sprite` is removed from runtime public handling.
- [ ] Runtime tests cover scene bind, camera set, sprite emit, and frame rendering through the public path.
## Dependencies
- Depends on `PLN-0022`
- Source decision: `DEC-0015`
## Risks
- Removing legacy handling before all runtime references are migrated can strand tests or bytecode fixtures.
- Poor `ComposerOpStatus` mapping could collapse useful operational distinctions into generic failures.

View File

@ -0,0 +1,107 @@
---
id: PLN-0024
ticket: frame-composer-public-syscall-surface
title: Plan - Composer Cartridge, Tooling, and Regression Migration
status: accepted
created: 2026-04-17
completed:
tags: [runtime, bytecode, tooling, stress, regression, frame-composer]
---
## Objective
Migrate bytecode declarations, cartridges, stress tooling, and regression coverage from legacy public sprite orchestration to the canonical `composer.*` surface.
## Background
`DEC-0015` requires the new public composer-domain ABI to land without leaving `gfx.set_sprite` as a fallback. That means the migration must cover the generated bytecode, test cartridges, and stress tooling that still assume the old public contract.
## Scope
### Included
- bytecode declaration updates for `composer.*`
- cartridge and stress generator migration
- regression coverage for the public composer-domain path
- removal of legacy syscall usage from test and tooling surfaces
### Excluded
- canonical spec propagation
- runtime dispatch implementation
- final repository-wide CI closure
## Execution Steps
### Step 1 - Migrate declared syscall users and fixtures
**What:**
Update code and fixtures that declare public syscalls so they target `composer.*`.
**How:**
- Replace legacy public sprite syscall declarations with composer-domain declarations.
- Update ABI expectations in bytecode-related tests and fixtures.
- Ensure removal of `gfx.set_sprite` is reflected in any declaration validation snapshots.
**File(s):**
- bytecode tests and fixtures
- syscall declaration users across runtime and tools
### Step 2 - Migrate stress and cartridge tooling
**What:**
Make the stress cartridge and related generators exercise the canonical public frame path.
**How:**
- Update `pbxgen-stress` and any cartridge generators to declare and call `composer.*`.
- Replace legacy sprite-path usage with `composer.emit_sprite`.
- Add scene bind and camera usage where needed so the stress path reaches the real canonical pipeline.
**File(s):**
- `crates/tools/pbxgen-stress/src/*`
- `test-cartridges/stress-console/*`
- related scripts such as `scripts/run-stress.sh`
### Step 3 - Expand regression coverage around the public path
**What:**
Lock the new public orchestration contract with regression tests.
**How:**
- Add tests that cover:
- composer-domain declaration resolution
- public bind/unbind/camera/emit behavior
- scene rendering through the public path
- stress/tooling integration using `composer.*`
- Ensure no regression fixture still relies on removed `gfx.set_sprite`.
**File(s):**
- runtime tests
- HAL syscall tests
- tooling tests where available
## Test Requirements
### Unit Tests
- bytecode and syscall declaration tests pin `composer.*` names and slot counts
### Integration Tests
- stress or cartridge-facing tests exercise scene bind, camera set, and sprite emit through `composer.*`
- regression fixtures fail if `gfx.set_sprite` is reintroduced
### Manual Verification
- inspect generated stress cartridge declarations and program behavior to confirm the public path is truly composer-domain based
## Acceptance Criteria
- [ ] Bytecode declarations and fixtures use `composer.*` instead of legacy public sprite orchestration.
- [ ] Stress tooling and test cartridges exercise the canonical public `FrameComposer` path.
- [ ] Regression coverage protects against fallback to `gfx.set_sprite`.
## Dependencies
- Depends on `PLN-0022` and `PLN-0023`
- Source decision: `DEC-0015`
## Risks
- Partial cartridge/tooling migration could leave the repository with hidden legacy public ABI usage.
- Stress tooling may appear to pass while still missing scene/camera coverage if it only migrates sprite calls.

View File

@ -0,0 +1,96 @@
---
id: PLN-0025
ticket: frame-composer-public-syscall-surface
title: Plan - Final CI Validation and Polish
status: accepted
created: 2026-04-17
completed:
tags: [ci, validation, regression, polish]
---
## Objective
Run the final repository validation path, including `make ci`, and perform the last compatibility, formatting, lint, and regression fixes required to close the composer-domain migration cleanly.
## Background
`DEC-0015` requires a coordinated migration across ABI, runtime, tooling, cartridges, spec, and documentation. After the implementation plans land, the repository still needs a final closure pass so no residual breakage survives in formatting, linting, tests, generated artifacts, or CI expectations.
## Scope
### Included
- final repository validation with `make ci`
- fixups required by formatting, lint, tests, snapshots, or generated artifacts
- final consistency pass across migrated files
### Excluded
- introducing new contract changes beyond `DEC-0015`
- reopening ABI or service-boundary decisions
## Execution Steps
### Step 1 - Run the final validation entrypoint
**What:**
Execute the repositorys final CI validation path.
**How:**
- Run `make ci` after `PLN-0022`, `PLN-0023`, and `PLN-0024` are complete.
- Capture failures from formatting, lint, tests, coverage setup, generation steps, or artifact drift.
**File(s):**
- repository-wide validation entrypoints
### Step 2 - Apply closure fixes without reopening scope
**What:**
Resolve residual breakage surfaced by final validation.
**How:**
- Fix formatting and lint issues.
- Update snapshots or generated artifacts only where the migrated public contract requires it.
- Repair any remaining tests or documentation references that fail under `make ci`.
- Do not widen scope beyond the accepted composer-domain migration.
**File(s):**
- any files directly implicated by final validation failures
### Step 3 - Confirm final repository consistency
**What:**
Leave the migration in a stable publishable state.
**How:**
- Re-run `make ci` until it passes cleanly.
- Verify no legacy public `gfx.set_sprite` usage remains in code, tests, tooling, or docs.
- Confirm the worktree reflects only intended migration changes.
**File(s):**
- repository-wide
## Test Requirements
### Unit Tests
- whatever unit coverage is exercised by `make ci` must remain green
### Integration Tests
- repository integration coverage under `make ci` must pass after the migration
### Manual Verification
- inspect the tree for residual `gfx.set_sprite` references and incomplete composer-domain propagation
## Acceptance Criteria
- [ ] `make ci` passes after the composer-domain migration family lands.
- [ ] Final fixups do not reopen contract scope beyond `DEC-0015`.
- [ ] No residual public `gfx.set_sprite` usage remains in the repository.
## Dependencies
- Depends on `PLN-0022`, `PLN-0023`, and `PLN-0024`
- Source decision: `DEC-0015`
## Risks
- If this final closure pass is skipped, small residual regressions can survive across formatting, lint, or generated artifacts even when the core implementation is correct.
- Late fixes can accidentally widen scope unless kept strictly bounded to validation fallout.