prometeu-studio/discussion/workflow/agendas/AGD-0031-studio-frame-composer-syscall-and-sprite-alignment.md

9.1 KiB

id ticket title status created resolved decision tags
AGD-0031 studio-frame-composer-syscall-and-sprite-alignment Studio Alignment with Runtime FrameComposer Syscalls and Sprite Composition in_progress 2026-04-18 2026-04-18 DEC-0027
studio
compiler
pbs
stdlib
runtime-alignment
abi
syscall
frame-composer
sprites

Pain

The sibling runtime has already moved the public frame-orchestration ABI to composer.*.

This repository still exposes the old model through @sdk:gfx and Gfx.set_sprite, which means:

  • the Studio-side compiler and stdlib still teach a legacy public contract;
  • PBS examples and tests still lower sprite composition through the wrong owner;
  • specs still describe a source surface that no longer matches the runtime's canonical syscall boundary;
  • any new Studio work risks reinforcing a dual contract between gfx.* primitives and composer.* frame orchestration.

The user explicitly scoped this discussion to:

  • ABI/syscall alignment with the current ../runtime;
  • FrameComposer convergence for sprite composition;
  • Studio-side propagation across compiler, pbs, and stdlib;
  • @sdk:composer for the sprite-composition path;
  • removal of the legacy Gfx.set_sprite entrypoint;
  • no scene-bank implementation work in this ticket.

Context

Domain owner: studio

Primary affected subdomains:

  • compiler/pbs
  • studio

Expected propagation targets if this discussion closes:

  • docs/specs/compiler-languages/pbs
  • docs/specs/compiler
  • PBS stdlib resources under prometeu-compiler/frontends/prometeu-frontend-pbs/src/main/resources/stdlib
  • compiler/frontend/backend conformance tests
  • Studio-adjacent examples and fixtures that still import @sdk:gfx for sprite composition

Observed current state on 2026-04-18:

  • ../runtime lesson DSC-0026 locks FrameComposer as the canonical frame owner above the render backend.
  • ../runtime lesson DSC-0027 locks the public VM-facing syscall ABI to composer.bind_scene, composer.unbind_scene, composer.set_camera, and composer.emit_sprite, and removes the legacy public gfx.set_sprite path.
  • ../runtime lesson DSC-0028 keeps immediate/debug primitives such as gfx.draw_text outside canonical game composition as a deferred overlay path.
  • this repository still ships @sdk:gfx with LowGfx.set_sprite(...) and Gfx.set_sprite(...);
  • this repository does not yet expose a reserved @sdk:composer module;
  • docs and tests still use @sdk:gfx as the visible source surface for sprite composition.

This creates architectural drift:

  • runtime public ownership says composer.* for frame composition;
  • Studio-side language and stdlib surfaces still say gfx.* for part of that same behavior.

The drift is specifically about syscall and sprite-composer alignment.

Out of scope for this agenda:

  • composer.bind_scene, composer.unbind_scene, and composer.set_camera rollout in Studio;
  • scene-bank authoring workflows;
  • scene asset import/editor design;
  • scene bank build/materialization contracts beyond what is minimally needed to name ABI boundaries;
  • broader scene workspace/product decisions already separated into other discussions.

Open Questions

  • Studio should expose a new reserved module @sdk:composer as the canonical public source surface for sprite composition.
  • @sdk:gfx should remain limited to primitive/overlay/back-end-adjacent operations once sprite composition moves out.
  • PBS should export @sdk:composer using the same source-level shape already used by @sdk:gfx: low-level host owner plus public service facade.
  • Mutating composer operations should remain raw int status returns in v1 for now.
  • Tests, fixtures, examples, and callsites should all migrate in this wave if possible; no compatibility path should be preserved.
  • No temporary compatibility alias is acceptable; Gfx.set_sprite should be removed completely.

Options

Option A - Introduce @sdk:composer now for sprite emission only in this wave

  • Approach: Add a dedicated reserved stdlib module that exposes the sprite-composition path through composer.emit_sprite; migrate sprite composition calls, host metadata, docs, and tests to that module; keep @sdk:gfx for primitives/overlay-style operations only; defer Studio-side bind_scene, unbind_scene, and set_camera.
  • Pro: Matches the runtime's canonical service boundary, preserves the split between frame composition and render primitives, and avoids teaching the retired gfx.set_sprite contract.
  • Con: Introduces a partial first wave of the composer domain, so docs must be explicit that other composer operations are intentionally deferred rather than absent by accident.
  • Maintainability: Strong, because the public source surface mirrors the actual runtime ABI and ownership model.

Option B - Keep @sdk:gfx as the user-facing module and only retarget its internals to composer.*

  • Approach: Preserve the visible Gfx.set_sprite API in Studio while changing lowering metadata underneath to hit composer.emit_sprite.
  • Pro: Smaller immediate source churn in examples and tests.
  • Con: Encodes the wrong owner in the public teaching surface, preserves the exact dual-contract problem the runtime discussion just removed, and makes later cleanup harder.
  • Maintainability: Weak, because it keeps historical naming instead of canonical service ownership.

Option C - Add @sdk:composer but retain temporary Gfx.set_sprite compatibility in parallel

  • Approach: Introduce the new canonical module while leaving Gfx.set_sprite as an alias or transitional wrapper for one or more waves.
  • Pro: Softens migration pressure for existing examples and downstream users.
  • Con: Creates two public ways to express the same operation, invites drift in specs/tests/docs, and conflicts with the runtime lesson that legacy public fallbacks should be removed when they preserve the wrong model.
  • Maintainability: Medium at best in the short term, poor in the long term if the alias survives longer than intended.

Discussion

The runtime side has already made two architectural facts explicit:

  1. frame orchestration belongs to FrameComposer, not to Gfx;
  2. the public syscall namespace must reflect that ownership.

That means this repository is no longer choosing between equivalent naming styles.

It is choosing whether Studio will:

  • align its source-facing contracts with the canonical runtime boundary; or
  • preserve a legacy public façade that the runtime has already declared misleading.

The user's scope also matters.

This ticket is not asking for scene-bank product work, and it also is not asking for Studio-side scene binding or camera rollout. So the migration target should stay narrow:

  • syscall/domain alignment;
  • @sdk:composer surface alignment for sprite emission;
  • compiler/PBS/stdlib propagation;
  • tests and examples updated to stop asserting the retired path.
  • removal of the old Gfx.set_sprite path.

The remaining design work is therefore smaller and more concrete:

  • define the Studio-side shape of @sdk:composer for sprite emission;
  • propagate composer.emit_sprite through stdlib, specs, compiler, and tests;
  • keep the deferred composer calls explicitly out of this ticket so the repository does not accidentally mix sprite convergence with unfinished scene-facing rollout.

The agenda questions are now resolved with explicit user direction:

  1. @sdk:composer should follow the same editorial pattern already used by @sdk:gfx, meaning a low-level host owner plus a public service facade.
  2. composer.emit_sprite should continue returning a raw int status in this wave.
  3. Migration should be broad and immediate across tests, fixtures, and examples where feasible.
  4. Gfx.set_sprite should be removed entirely, with no compatibility alias or dual-path surface.
  5. Specs should document only what this wave actually implements, while leaving room for bind_scene, unbind_scene, and set_camera to be added later using the same pattern.

Resolution

Recommended direction:

  • adopt Option A as the working direction for this discussion;
  • open a Studio-side canonical @sdk:composer surface aligned to the runtime ABI for sprite emission in this wave;
  • retire Gfx.set_sprite from normative Studio-facing contracts instead of preserving a compatibility façade;
  • defer composer.bind_scene, composer.unbind_scene, and composer.set_camera to a later ticket;
  • keep scene-bank authoring/editor work explicitly out of this ticket;
  • keep @sdk:gfx focused on primitive and overlay-style operations.

Recommended next step:

  • treat the sprite-only @sdk:composer wave as the accepted scope of this agenda;
  • write a decision that locks:
    • @sdk:composer as the canonical Studio-side sprite-composition module;
    • the LowComposer + Composer shape matching the established @sdk:gfx pattern;
    • raw int status returns for this wave;
    • complete removal of Gfx.set_sprite with no compatibility path;
    • broad propagation across specs, stdlib, compiler, tests, fixtures, and examples;
    • deferred addition of bind_scene, unbind_scene, and set_camera in later work.