prometeu-runtime/discussion/workflow/decisions/DEC-0015-frame-composer-public-syscall-surface.md

167 lines
7.8 KiB
Markdown

---
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`.