prometeu-runtime/discussion/workflow/agendas/AGD-0027-frame-composer-public-syscall-surface.md

9.6 KiB

id ticket title status created updated tags
AGD-0027 frame-composer-public-syscall-surface Agenda - FrameComposer Public Syscall Surface accepted 2026-04-17 2026-04-17
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.