dev/render-all-scene-cache-and-camera-integration #16

Merged
bquarkz merged 21 commits from dev/render-all-scene-cache-and-camera-integration into master 2026-04-18 16:20:50 +00:00
25 changed files with 248 additions and 2748 deletions
Showing only changes of commit 73cf96ed6c - Show all commits

View File

@ -0,0 +1,29 @@
{"type":"meta","next_id":{"DSC":29,"AGD":29,"DEC":17,"PLN":30,"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"}]}
{"type":"discussion","id":"DSC-0022","status":"done","ticket":"tile-bank-vs-glyph-bank-domain-naming","title":"Glyph Bank Domain Naming Contract","created_at":"2026-04-09","updated_at":"2026-04-10","tags":["gfx","runtime","naming","domain-model"],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0025","file":"lessons/DSC-0022-glyph-bank-domain-naming/LSN-0025-rename-artifact-by-meaning-not-by-token.md","status":"done","created_at":"2026-04-10","updated_at":"2026-04-10"}]}
{"type":"discussion","id":"DSC-0001","status":"done","ticket":"legacy-runtime-learn-import","title":"Import legacy runtime learn into discussion lessons","created_at":"2026-03-27","updated_at":"2026-03-27","tags":["migration","tech-debt"],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0001","file":"lessons/DSC-0001-runtime-learn-legacy-import/LSN-0001-prometeu-learn-index.md","status":"done","created_at":"2026-03-27","updated_at":"2026-03-27"},{"id":"LSN-0002","file":"lessons/DSC-0001-runtime-learn-legacy-import/LSN-0002-historical-asset-status-first-fault-and-return-contract.md","status":"done","created_at":"2026-03-27","updated_at":"2026-03-27"},{"id":"LSN-0003","file":"lessons/DSC-0001-runtime-learn-legacy-import/LSN-0003-historical-audio-status-first-fault-and-return-contract.md","status":"done","created_at":"2026-03-27","updated_at":"2026-03-27"},{"id":"LSN-0004","file":"lessons/DSC-0001-runtime-learn-legacy-import/LSN-0004-historical-cartridge-boot-protocol-and-manifest-authority.md","status":"done","created_at":"2026-03-27","updated_at":"2026-03-27"},{"id":"LSN-0005","file":"lessons/DSC-0001-runtime-learn-legacy-import/LSN-0005-historical-game-memcard-slots-surface-and-semantics.md","status":"done","created_at":"2026-03-27","updated_at":"2026-03-27"},{"id":"LSN-0006","file":"lessons/DSC-0001-runtime-learn-legacy-import/LSN-0006-historical-gfx-status-first-fault-and-return-contract.md","status":"done","created_at":"2026-03-27","updated_at":"2026-03-27"},{"id":"LSN-0007","file":"lessons/DSC-0001-runtime-learn-legacy-import/LSN-0007-historical-retired-fault-and-input-decisions.md","status":"done","created_at":"2026-03-27","updated_at":"2026-03-27"},{"id":"LSN-0008","file":"lessons/DSC-0001-runtime-learn-legacy-import/LSN-0008-historical-vm-core-and-assets.md","status":"done","created_at":"2026-03-27","updated_at":"2026-03-27"},{"id":"LSN-0009","file":"lessons/DSC-0001-runtime-learn-legacy-import/LSN-0009-mental-model-asset-management.md","status":"done","created_at":"2026-03-27","updated_at":"2026-03-27"},{"id":"LSN-0010","file":"lessons/DSC-0001-runtime-learn-legacy-import/LSN-0010-mental-model-audio.md","status":"done","created_at":"2026-03-27","updated_at":"2026-03-27"},{"id":"LSN-0011","file":"lessons/DSC-0001-runtime-learn-legacy-import/LSN-0011-mental-model-gfx.md","status":"done","created_at":"2026-03-27","updated_at":"2026-03-27"},{"id":"LSN-0012","file":"lessons/DSC-0001-runtime-learn-legacy-import/LSN-0012-mental-model-input.md","status":"done","created_at":"2026-03-27","updated_at":"2026-03-27"},{"id":"LSN-0013","file":"lessons/DSC-0001-runtime-learn-legacy-import/LSN-0013-mental-model-observability-and-debugging.md","status":"done","created_at":"2026-03-27","updated_at":"2026-03-27"},{"id":"LSN-0014","file":"lessons/DSC-0001-runtime-learn-legacy-import/LSN-0014-mental-model-portability-and-cross-platform.md","status":"done","created_at":"2026-03-27","updated_at":"2026-03-27"},{"id":"LSN-0015","file":"lessons/DSC-0001-runtime-learn-legacy-import/LSN-0015-mental-model-save-memory-and-memcard.md","status":"done","created_at":"2026-03-27","updated_at":"2026-03-27"},{"id":"LSN-0016","file":"lessons/DSC-0001-runtime-learn-legacy-import/LSN-0016-mental-model-status-first-and-fault-thinking.md","status":"done","created_at":"2026-03-27","updated_at":"2026-03-27"},{"id":"LSN-0017","file":"lessons/DSC-0001-runtime-learn-legacy-import/LSN-0017-mental-model-time-and-cycles.md","status":"done","created_at":"2026-03-27","updated_at":"2026-03-27"},{"id":"LSN-0018","file":"lessons/DSC-0001-runtime-learn-legacy-import/LSN-0018-mental-model-touch.md","status":"done","created_at":"2026-03-27","updated_at":"2026-03-27"}]}
{"type":"discussion","id":"DSC-0002","status":"open","ticket":"runtime-edge-test-plan","title":"Agenda - Runtime Edge Test Plan","created_at":"2026-03-27","updated_at":"2026-03-27","tags":[],"agendas":[{"id":"AGD-0001","file":"workflow/agendas/AGD-0001-runtime-edge-test-plan.md","status":"open","created_at":"2026-03-27","updated_at":"2026-03-27"}],"decisions":[],"plans":[],"lessons":[]}
{"type":"discussion","id":"DSC-0003","status":"open","ticket":"packed-cartridge-loader-pmc","title":"Agenda - Packed Cartridge Loader PMC","created_at":"2026-03-27","updated_at":"2026-03-27","tags":[],"agendas":[{"id":"AGD-0002","file":"workflow/agendas/AGD-0002-packed-cartridge-loader-pmc.md","status":"open","created_at":"2026-03-27","updated_at":"2026-03-27"}],"decisions":[],"plans":[],"lessons":[]}
{"type":"discussion","id":"DSC-0004","status":"open","ticket":"system-run-cart","title":"Agenda - System Run Cart","created_at":"2026-03-27","updated_at":"2026-03-27","tags":[],"agendas":[{"id":"AGD-0003","file":"workflow/agendas/AGD-0003-system-run-cart.md","status":"open","created_at":"2026-03-27","updated_at":"2026-03-27"}],"decisions":[],"plans":[],"lessons":[]}
{"type":"discussion","id":"DSC-0005","status":"open","ticket":"system-fault-semantics-and-control-surface","title":"Agenda - System Fault Semantics and Control Surface","created_at":"2026-03-27","updated_at":"2026-03-27","tags":[],"agendas":[{"id":"AGD-0004","file":"workflow/agendas/AGD-0004-system-fault-semantics-and-control-surface.md","status":"open","created_at":"2026-03-27","updated_at":"2026-03-27"}],"decisions":[],"plans":[],"lessons":[]}
{"type":"discussion","id":"DSC-0006","status":"open","ticket":"vm-owned-random-service","title":"Agenda - VM-Owned Random Service","created_at":"2026-03-27","updated_at":"2026-03-27","tags":[],"agendas":[{"id":"AGD-0005","file":"workflow/agendas/AGD-0005-vm-owned-random-service.md","status":"open","created_at":"2026-03-27","updated_at":"2026-03-27"}],"decisions":[],"plans":[],"lessons":[]}
{"type":"discussion","id":"DSC-0007","status":"open","ticket":"app-home-filesystem-surface-and-semantics","title":"Agenda - App Home Filesystem Surface and Semantics","created_at":"2026-03-27","updated_at":"2026-03-27","tags":[],"agendas":[{"id":"AGD-0006","file":"workflow/agendas/AGD-0006-app-home-filesystem-surface-and-semantics.md","status":"open","created_at":"2026-03-27","updated_at":"2026-03-27"}],"decisions":[],"plans":[],"lessons":[]}
{"type":"discussion","id":"DSC-0008","status":"done","ticket":"perf-runtime-telemetry-hot-path","title":"Agenda - [PERF] Runtime Telemetry Hot Path","created_at":"2026-03-27","updated_at":"2026-04-10","tags":[],"agendas":[{"id":"AGD-0007","file":"workflow/agendas/AGD-0007-perf-runtime-telemetry-hot-path.md","status":"done","created_at":"2026-03-27","updated_at":"2026-04-10"}],"decisions":[{"id":"DEC-0005","file":"workflow/decisions/DEC-0005-perf-push-based-telemetry-model.md","status":"accepted","created_at":"2026-04-10","updated_at":"2026-04-10"}],"plans":[{"id":"PLN-0005","file":"workflow/plans/PLN-0005-perf-push-based-telemetry-implementation.md","status":"done","created_at":"2026-04-10","updated_at":"2026-04-10"}],"lessons":[{"id":"LSN-0026","file":"lessons/DSC-0008-perf-runtime-telemetry-hot-path/LSN-0026-push-based-telemetry-model.md","status":"done","created_at":"2026-04-10","updated_at":"2026-04-10"}]}
{"type":"discussion","id":"DSC-0009","status":"open","ticket":"perf-async-background-work-lanes-for-assets-and-fs","title":"Agenda - [PERF] Async Background Work Lanes for Assets and FS","created_at":"2026-03-27","updated_at":"2026-03-27","tags":[],"agendas":[{"id":"AGD-0008","file":"workflow/agendas/AGD-0008-perf-async-background-work-lanes-for-assets-and-fs.md","status":"open","created_at":"2026-03-27","updated_at":"2026-03-27"}],"decisions":[],"plans":[],"lessons":[]}
{"type":"discussion","id":"DSC-0010","status":"open","ticket":"perf-host-desktop-frame-pacing-and-presentation","title":"Agenda - [PERF] Host Desktop Frame Pacing and Presentation","created_at":"2026-03-27","updated_at":"2026-03-27","tags":[],"agendas":[{"id":"AGD-0009","file":"workflow/agendas/AGD-0009-perf-host-desktop-frame-pacing-and-presentation.md","status":"open","created_at":"2026-03-27","updated_at":"2026-03-27"}],"decisions":[],"plans":[],"lessons":[]}
{"type":"discussion","id":"DSC-0011","status":"open","ticket":"perf-gfx-render-pipeline-and-dirty-regions","title":"Agenda - [PERF] GFX Render Pipeline and Dirty Regions","created_at":"2026-03-27","updated_at":"2026-03-27","tags":[],"agendas":[{"id":"AGD-0010","file":"workflow/agendas/AGD-0010-perf-gfx-render-pipeline-and-dirty-regions.md","status":"open","created_at":"2026-03-27","updated_at":"2026-03-27"}],"decisions":[],"plans":[],"lessons":[]}
{"type":"discussion","id":"DSC-0012","status":"open","ticket":"perf-runtime-introspection-syscalls","title":"Agenda - [PERF] Runtime Introspection Syscalls","created_at":"2026-03-27","updated_at":"2026-03-27","tags":[],"agendas":[{"id":"AGD-0011","file":"workflow/agendas/AGD-0011-perf-runtime-introspection-syscalls.md","status":"open","created_at":"2026-03-27","updated_at":"2026-03-27"}],"decisions":[],"plans":[],"lessons":[]}
{"type":"discussion","id":"DSC-0013","status":"done","ticket":"perf-host-debug-overlay-isolation","title":"Agenda - [PERF] Host Debug Overlay Isolation","created_at":"2026-03-27","updated_at":"2026-04-10","tags":[],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0027","file":"lessons/DSC-0013-perf-host-debug-overlay-isolation/LSN-0027-host-debug-overlay-isolation.md","status":"done","created_at":"2026-04-10","updated_at":"2026-04-10"}]}
{"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-0028","status":"open","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":[{"id":"AGD-0028","file":"workflow/agendas/AGD-0028-deferred-overlay-and-primitive-composition.md","status":"accepted","created_at":"2026-04-18","updated_at":"2026-04-18"}],"decisions":[{"id":"DEC-0016","file":"workflow/decisions/DEC-0016-deferred-gfx-overlay-outside-frame-composer.md","status":"accepted","created_at":"2026-04-18","updated_at":"2026-04-18","ref_agenda":"AGD-0028"}],"plans":[{"id":"PLN-0026","file":"workflow/plans/PLN-0026-gfx-overlay-contract-and-spec-propagation.md","status":"accepted","created_at":"2026-04-18","updated_at":"2026-04-18","ref_decisions":["DEC-0016"]},{"id":"PLN-0027","file":"workflow/plans/PLN-0027-deferred-gfx-overlay-subsystem.md","status":"accepted","created_at":"2026-04-18","updated_at":"2026-04-18","ref_decisions":["DEC-0016"]},{"id":"PLN-0028","file":"workflow/plans/PLN-0028-runtime-frame-end-overlay-integration-and-parity.md","status":"accepted","created_at":"2026-04-18","updated_at":"2026-04-18","ref_decisions":["DEC-0016"]},{"id":"PLN-0029","file":"workflow/plans/PLN-0029-final-overlay-ci-validation-and-polish.md","status":"accepted","created_at":"2026-04-18","updated_at":"2026-04-18","ref_decisions":["DEC-0016"]}],"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"}]}
{"type":"discussion","id":"DSC-0017","status":"done","ticket":"asset-entry-metadata-normalization-contract","title":"Asset Entry Metadata Normalization Contract","created_at":"2026-03-27","updated_at":"2026-04-09","tags":[],"agendas":[{"id":"AGD-0016","file":"workflow/agendas/AGD-0016-asset-entry-metadata-normalization-contract.md","status":"done","created_at":"2026-03-27","updated_at":"2026-04-09"}],"decisions":[{"id":"DEC-0004","file":"workflow/decisions/DEC-0004-asset-entry-metadata-normalization-contract.md","status":"accepted","created_at":"2026-04-09","updated_at":"2026-04-09"}],"plans":[],"lessons":[{"id":"LSN-0023","file":"lessons/DSC-0017-asset-metadata-normalization/LSN-0023-typed-asset-metadata-helpers.md","status":"done","created_at":"2026-04-09","updated_at":"2026-04-09"}]}
{"type":"discussion","id":"DSC-0018","status":"done","ticket":"asset-load-asset-id-int-contract","title":"Asset Load Asset ID Int Contract","created_at":"2026-03-27","updated_at":"2026-03-27","tags":["asset","runtime","abi"],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0019","file":"lessons/DSC-0018-asset-load-asset-id-int-contract/LSN-0019-asset-load-id-abi-convergence.md","status":"done","created_at":"2026-03-27","updated_at":"2026-03-27"}]}
{"type":"discussion","id":"DSC-0019","status":"done","ticket":"jenkinsfile-correction","title":"Jenkinsfile Correction and Relocation","created_at":"2026-04-07","updated_at":"2026-04-07","tags":["ci","jenkins"],"agendas":[{"id":"AGD-0017","file":"workflow/agendas/AGD-0017-jenkinsfile-correction.md","status":"done","created_at":"2026-04-07","updated_at":"2026-04-07"}],"decisions":[{"id":"DEC-0002","file":"workflow/decisions/DEC-0002-jenkinsfile-strategy.md","status":"accepted","created_at":"2026-04-07","updated_at":"2026-04-07"}],"plans":[{"id":"PLN-0002","file":"workflow/plans/PLN-0002-jenkinsfile-execution.md","status":"done","created_at":"2026-04-07","updated_at":"2026-04-07"}],"lessons":[{"id":"LSN-0020","file":"lessons/DSC-0019-jenkins-ci-standardization/LSN-0020-jenkins-standard-relocation.md","status":"done","created_at":"2026-04-07","updated_at":"2026-04-07"}]}

View File

@ -0,0 +1,29 @@
{"type":"meta","next_id":{"DSC":29,"AGD":29,"DEC":17,"PLN":30,"LSN":32,"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"}]}
{"type":"discussion","id":"DSC-0022","status":"done","ticket":"tile-bank-vs-glyph-bank-domain-naming","title":"Glyph Bank Domain Naming Contract","created_at":"2026-04-09","updated_at":"2026-04-10","tags":["gfx","runtime","naming","domain-model"],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0025","file":"lessons/DSC-0022-glyph-bank-domain-naming/LSN-0025-rename-artifact-by-meaning-not-by-token.md","status":"done","created_at":"2026-04-10","updated_at":"2026-04-10"}]}
{"type":"discussion","id":"DSC-0001","status":"done","ticket":"legacy-runtime-learn-import","title":"Import legacy runtime learn into discussion lessons","created_at":"2026-03-27","updated_at":"2026-03-27","tags":["migration","tech-debt"],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0001","file":"lessons/DSC-0001-runtime-learn-legacy-import/LSN-0001-prometeu-learn-index.md","status":"done","created_at":"2026-03-27","updated_at":"2026-03-27"},{"id":"LSN-0002","file":"lessons/DSC-0001-runtime-learn-legacy-import/LSN-0002-historical-asset-status-first-fault-and-return-contract.md","status":"done","created_at":"2026-03-27","updated_at":"2026-03-27"},{"id":"LSN-0003","file":"lessons/DSC-0001-runtime-learn-legacy-import/LSN-0003-historical-audio-status-first-fault-and-return-contract.md","status":"done","created_at":"2026-03-27","updated_at":"2026-03-27"},{"id":"LSN-0004","file":"lessons/DSC-0001-runtime-learn-legacy-import/LSN-0004-historical-cartridge-boot-protocol-and-manifest-authority.md","status":"done","created_at":"2026-03-27","updated_at":"2026-03-27"},{"id":"LSN-0005","file":"lessons/DSC-0001-runtime-learn-legacy-import/LSN-0005-historical-game-memcard-slots-surface-and-semantics.md","status":"done","created_at":"2026-03-27","updated_at":"2026-03-27"},{"id":"LSN-0006","file":"lessons/DSC-0001-runtime-learn-legacy-import/LSN-0006-historical-gfx-status-first-fault-and-return-contract.md","status":"done","created_at":"2026-03-27","updated_at":"2026-03-27"},{"id":"LSN-0007","file":"lessons/DSC-0001-runtime-learn-legacy-import/LSN-0007-historical-retired-fault-and-input-decisions.md","status":"done","created_at":"2026-03-27","updated_at":"2026-03-27"},{"id":"LSN-0008","file":"lessons/DSC-0001-runtime-learn-legacy-import/LSN-0008-historical-vm-core-and-assets.md","status":"done","created_at":"2026-03-27","updated_at":"2026-03-27"},{"id":"LSN-0009","file":"lessons/DSC-0001-runtime-learn-legacy-import/LSN-0009-mental-model-asset-management.md","status":"done","created_at":"2026-03-27","updated_at":"2026-03-27"},{"id":"LSN-0010","file":"lessons/DSC-0001-runtime-learn-legacy-import/LSN-0010-mental-model-audio.md","status":"done","created_at":"2026-03-27","updated_at":"2026-03-27"},{"id":"LSN-0011","file":"lessons/DSC-0001-runtime-learn-legacy-import/LSN-0011-mental-model-gfx.md","status":"done","created_at":"2026-03-27","updated_at":"2026-03-27"},{"id":"LSN-0012","file":"lessons/DSC-0001-runtime-learn-legacy-import/LSN-0012-mental-model-input.md","status":"done","created_at":"2026-03-27","updated_at":"2026-03-27"},{"id":"LSN-0013","file":"lessons/DSC-0001-runtime-learn-legacy-import/LSN-0013-mental-model-observability-and-debugging.md","status":"done","created_at":"2026-03-27","updated_at":"2026-03-27"},{"id":"LSN-0014","file":"lessons/DSC-0001-runtime-learn-legacy-import/LSN-0014-mental-model-portability-and-cross-platform.md","status":"done","created_at":"2026-03-27","updated_at":"2026-03-27"},{"id":"LSN-0015","file":"lessons/DSC-0001-runtime-learn-legacy-import/LSN-0015-mental-model-save-memory-and-memcard.md","status":"done","created_at":"2026-03-27","updated_at":"2026-03-27"},{"id":"LSN-0016","file":"lessons/DSC-0001-runtime-learn-legacy-import/LSN-0016-mental-model-status-first-and-fault-thinking.md","status":"done","created_at":"2026-03-27","updated_at":"2026-03-27"},{"id":"LSN-0017","file":"lessons/DSC-0001-runtime-learn-legacy-import/LSN-0017-mental-model-time-and-cycles.md","status":"done","created_at":"2026-03-27","updated_at":"2026-03-27"},{"id":"LSN-0018","file":"lessons/DSC-0001-runtime-learn-legacy-import/LSN-0018-mental-model-touch.md","status":"done","created_at":"2026-03-27","updated_at":"2026-03-27"}]}
{"type":"discussion","id":"DSC-0002","status":"open","ticket":"runtime-edge-test-plan","title":"Agenda - Runtime Edge Test Plan","created_at":"2026-03-27","updated_at":"2026-03-27","tags":[],"agendas":[{"id":"AGD-0001","file":"workflow/agendas/AGD-0001-runtime-edge-test-plan.md","status":"open","created_at":"2026-03-27","updated_at":"2026-03-27"}],"decisions":[],"plans":[],"lessons":[]}
{"type":"discussion","id":"DSC-0003","status":"open","ticket":"packed-cartridge-loader-pmc","title":"Agenda - Packed Cartridge Loader PMC","created_at":"2026-03-27","updated_at":"2026-03-27","tags":[],"agendas":[{"id":"AGD-0002","file":"workflow/agendas/AGD-0002-packed-cartridge-loader-pmc.md","status":"open","created_at":"2026-03-27","updated_at":"2026-03-27"}],"decisions":[],"plans":[],"lessons":[]}
{"type":"discussion","id":"DSC-0004","status":"open","ticket":"system-run-cart","title":"Agenda - System Run Cart","created_at":"2026-03-27","updated_at":"2026-03-27","tags":[],"agendas":[{"id":"AGD-0003","file":"workflow/agendas/AGD-0003-system-run-cart.md","status":"open","created_at":"2026-03-27","updated_at":"2026-03-27"}],"decisions":[],"plans":[],"lessons":[]}
{"type":"discussion","id":"DSC-0005","status":"open","ticket":"system-fault-semantics-and-control-surface","title":"Agenda - System Fault Semantics and Control Surface","created_at":"2026-03-27","updated_at":"2026-03-27","tags":[],"agendas":[{"id":"AGD-0004","file":"workflow/agendas/AGD-0004-system-fault-semantics-and-control-surface.md","status":"open","created_at":"2026-03-27","updated_at":"2026-03-27"}],"decisions":[],"plans":[],"lessons":[]}
{"type":"discussion","id":"DSC-0006","status":"open","ticket":"vm-owned-random-service","title":"Agenda - VM-Owned Random Service","created_at":"2026-03-27","updated_at":"2026-03-27","tags":[],"agendas":[{"id":"AGD-0005","file":"workflow/agendas/AGD-0005-vm-owned-random-service.md","status":"open","created_at":"2026-03-27","updated_at":"2026-03-27"}],"decisions":[],"plans":[],"lessons":[]}
{"type":"discussion","id":"DSC-0007","status":"open","ticket":"app-home-filesystem-surface-and-semantics","title":"Agenda - App Home Filesystem Surface and Semantics","created_at":"2026-03-27","updated_at":"2026-03-27","tags":[],"agendas":[{"id":"AGD-0006","file":"workflow/agendas/AGD-0006-app-home-filesystem-surface-and-semantics.md","status":"open","created_at":"2026-03-27","updated_at":"2026-03-27"}],"decisions":[],"plans":[],"lessons":[]}
{"type":"discussion","id":"DSC-0008","status":"done","ticket":"perf-runtime-telemetry-hot-path","title":"Agenda - [PERF] Runtime Telemetry Hot Path","created_at":"2026-03-27","updated_at":"2026-04-10","tags":[],"agendas":[{"id":"AGD-0007","file":"workflow/agendas/AGD-0007-perf-runtime-telemetry-hot-path.md","status":"done","created_at":"2026-03-27","updated_at":"2026-04-10"}],"decisions":[{"id":"DEC-0005","file":"workflow/decisions/DEC-0005-perf-push-based-telemetry-model.md","status":"accepted","created_at":"2026-04-10","updated_at":"2026-04-10"}],"plans":[{"id":"PLN-0005","file":"workflow/plans/PLN-0005-perf-push-based-telemetry-implementation.md","status":"done","created_at":"2026-04-10","updated_at":"2026-04-10"}],"lessons":[{"id":"LSN-0026","file":"lessons/DSC-0008-perf-runtime-telemetry-hot-path/LSN-0026-push-based-telemetry-model.md","status":"done","created_at":"2026-04-10","updated_at":"2026-04-10"}]}
{"type":"discussion","id":"DSC-0009","status":"open","ticket":"perf-async-background-work-lanes-for-assets-and-fs","title":"Agenda - [PERF] Async Background Work Lanes for Assets and FS","created_at":"2026-03-27","updated_at":"2026-03-27","tags":[],"agendas":[{"id":"AGD-0008","file":"workflow/agendas/AGD-0008-perf-async-background-work-lanes-for-assets-and-fs.md","status":"open","created_at":"2026-03-27","updated_at":"2026-03-27"}],"decisions":[],"plans":[],"lessons":[]}
{"type":"discussion","id":"DSC-0010","status":"open","ticket":"perf-host-desktop-frame-pacing-and-presentation","title":"Agenda - [PERF] Host Desktop Frame Pacing and Presentation","created_at":"2026-03-27","updated_at":"2026-03-27","tags":[],"agendas":[{"id":"AGD-0009","file":"workflow/agendas/AGD-0009-perf-host-desktop-frame-pacing-and-presentation.md","status":"open","created_at":"2026-03-27","updated_at":"2026-03-27"}],"decisions":[],"plans":[],"lessons":[]}
{"type":"discussion","id":"DSC-0011","status":"open","ticket":"perf-gfx-render-pipeline-and-dirty-regions","title":"Agenda - [PERF] GFX Render Pipeline and Dirty Regions","created_at":"2026-03-27","updated_at":"2026-03-27","tags":[],"agendas":[{"id":"AGD-0010","file":"workflow/agendas/AGD-0010-perf-gfx-render-pipeline-and-dirty-regions.md","status":"open","created_at":"2026-03-27","updated_at":"2026-03-27"}],"decisions":[],"plans":[],"lessons":[]}
{"type":"discussion","id":"DSC-0012","status":"open","ticket":"perf-runtime-introspection-syscalls","title":"Agenda - [PERF] Runtime Introspection Syscalls","created_at":"2026-03-27","updated_at":"2026-03-27","tags":[],"agendas":[{"id":"AGD-0011","file":"workflow/agendas/AGD-0011-perf-runtime-introspection-syscalls.md","status":"open","created_at":"2026-03-27","updated_at":"2026-03-27"}],"decisions":[],"plans":[],"lessons":[]}
{"type":"discussion","id":"DSC-0013","status":"done","ticket":"perf-host-debug-overlay-isolation","title":"Agenda - [PERF] Host Debug Overlay Isolation","created_at":"2026-03-27","updated_at":"2026-04-10","tags":[],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0027","file":"lessons/DSC-0013-perf-host-debug-overlay-isolation/LSN-0027-host-debug-overlay-isolation.md","status":"done","created_at":"2026-04-10","updated_at":"2026-04-10"}]}
{"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":"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":"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-0028","status":"open","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":[{"id":"AGD-0028","file":"workflow/agendas/AGD-0028-deferred-overlay-and-primitive-composition.md","status":"accepted","created_at":"2026-04-18","updated_at":"2026-04-18"}],"decisions":[{"id":"DEC-0016","file":"workflow/decisions/DEC-0016-deferred-gfx-overlay-outside-frame-composer.md","status":"accepted","created_at":"2026-04-18","updated_at":"2026-04-18","ref_agenda":"AGD-0028"}],"plans":[{"id":"PLN-0026","file":"workflow/plans/PLN-0026-gfx-overlay-contract-and-spec-propagation.md","status":"accepted","created_at":"2026-04-18","updated_at":"2026-04-18","ref_decisions":["DEC-0016"]},{"id":"PLN-0027","file":"workflow/plans/PLN-0027-deferred-gfx-overlay-subsystem.md","status":"accepted","created_at":"2026-04-18","updated_at":"2026-04-18","ref_decisions":["DEC-0016"]},{"id":"PLN-0028","file":"workflow/plans/PLN-0028-runtime-frame-end-overlay-integration-and-parity.md","status":"accepted","created_at":"2026-04-18","updated_at":"2026-04-18","ref_decisions":["DEC-0016"]},{"id":"PLN-0029","file":"workflow/plans/PLN-0029-final-overlay-ci-validation-and-polish.md","status":"accepted","created_at":"2026-04-18","updated_at":"2026-04-18","ref_decisions":["DEC-0016"]}],"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"}]}
{"type":"discussion","id":"DSC-0017","status":"done","ticket":"asset-entry-metadata-normalization-contract","title":"Asset Entry Metadata Normalization Contract","created_at":"2026-03-27","updated_at":"2026-04-09","tags":[],"agendas":[{"id":"AGD-0016","file":"workflow/agendas/AGD-0016-asset-entry-metadata-normalization-contract.md","status":"done","created_at":"2026-03-27","updated_at":"2026-04-09"}],"decisions":[{"id":"DEC-0004","file":"workflow/decisions/DEC-0004-asset-entry-metadata-normalization-contract.md","status":"accepted","created_at":"2026-04-09","updated_at":"2026-04-09"}],"plans":[],"lessons":[{"id":"LSN-0023","file":"lessons/DSC-0017-asset-metadata-normalization/LSN-0023-typed-asset-metadata-helpers.md","status":"done","created_at":"2026-04-09","updated_at":"2026-04-09"}]}
{"type":"discussion","id":"DSC-0018","status":"done","ticket":"asset-load-asset-id-int-contract","title":"Asset Load Asset ID Int Contract","created_at":"2026-03-27","updated_at":"2026-03-27","tags":["asset","runtime","abi"],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0019","file":"lessons/DSC-0018-asset-load-asset-id-int-contract/LSN-0019-asset-load-id-abi-convergence.md","status":"done","created_at":"2026-03-27","updated_at":"2026-03-27"}]}
{"type":"discussion","id":"DSC-0019","status":"done","ticket":"jenkinsfile-correction","title":"Jenkinsfile Correction and Relocation","created_at":"2026-04-07","updated_at":"2026-04-07","tags":["ci","jenkins"],"agendas":[{"id":"AGD-0017","file":"workflow/agendas/AGD-0017-jenkinsfile-correction.md","status":"done","created_at":"2026-04-07","updated_at":"2026-04-07"}],"decisions":[{"id":"DEC-0002","file":"workflow/decisions/DEC-0002-jenkinsfile-strategy.md","status":"accepted","created_at":"2026-04-07","updated_at":"2026-04-07"}],"plans":[{"id":"PLN-0002","file":"workflow/plans/PLN-0002-jenkinsfile-execution.md","status":"done","created_at":"2026-04-07","updated_at":"2026-04-07"}],"lessons":[{"id":"LSN-0020","file":"lessons/DSC-0019-jenkins-ci-standardization/LSN-0020-jenkins-standard-relocation.md","status":"done","created_at":"2026-04-07","updated_at":"2026-04-07"}]}

View File

@ -1,4 +1,4 @@
{"type":"meta","next_id":{"DSC":29,"AGD":29,"DEC":17,"PLN":30,"LSN":31,"CLSN":1}}
{"type":"meta","next_id":{"DSC":29,"AGD":29,"DEC":17,"PLN":30,"LSN":34,"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"}]}
@ -18,9 +18,9 @@
{"type":"discussion","id":"DSC-0013","status":"done","ticket":"perf-host-debug-overlay-isolation","title":"Agenda - [PERF] Host Debug Overlay Isolation","created_at":"2026-03-27","updated_at":"2026-04-10","tags":[],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0027","file":"lessons/DSC-0013-perf-host-debug-overlay-isolation/LSN-0027-host-debug-overlay-isolation.md","status":"done","created_at":"2026-04-10","updated_at":"2026-04-10"}]}
{"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-0028","status":"open","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":[{"id":"AGD-0028","file":"workflow/agendas/AGD-0028-deferred-overlay-and-primitive-composition.md","status":"accepted","created_at":"2026-04-18","updated_at":"2026-04-18"}],"decisions":[{"id":"DEC-0016","file":"workflow/decisions/DEC-0016-deferred-gfx-overlay-outside-frame-composer.md","status":"accepted","created_at":"2026-04-18","updated_at":"2026-04-18","ref_agenda":"AGD-0028"}],"plans":[{"id":"PLN-0026","file":"workflow/plans/PLN-0026-gfx-overlay-contract-and-spec-propagation.md","status":"accepted","created_at":"2026-04-18","updated_at":"2026-04-18","ref_decisions":["DEC-0016"]},{"id":"PLN-0027","file":"workflow/plans/PLN-0027-deferred-gfx-overlay-subsystem.md","status":"accepted","created_at":"2026-04-18","updated_at":"2026-04-18","ref_decisions":["DEC-0016"]},{"id":"PLN-0028","file":"workflow/plans/PLN-0028-runtime-frame-end-overlay-integration-and-parity.md","status":"accepted","created_at":"2026-04-18","updated_at":"2026-04-18","ref_decisions":["DEC-0016"]},{"id":"PLN-0029","file":"workflow/plans/PLN-0029-final-overlay-ci-validation-and-polish.md","status":"accepted","created_at":"2026-04-18","updated_at":"2026-04-18","ref_decisions":["DEC-0016"]}],"lessons":[]}
{"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-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,74 @@
---
id: LSN-0031
ticket: render-all-scene-cache-and-camera-integration
title: Frame Composition Belongs Above the Render Backend
created: 2026-04-18
tags: [gfx, runtime, render, camera, scene, sprites, frame-composer]
---
## Context
`DSC-0025` split canonical scene ownership from viewport caching and resolver policy, but the runtime still treated `Gfx.render_all()` as the operational frame entrypoint. That left scene binding, camera state, cache refresh, and sprite submission spread across the wrong layer.
`DSC-0026` completed the integration by making `FrameComposer` the owner of frame orchestration and reducing `Gfx` to a backend that consumes already prepared render state.
## Key Decisions
### Frame Orchestration Must Not Live in the Backend
**What:**
`FrameComposer.render_frame()` became the canonical frame service, while `Gfx.render_all()` was retired from the runtime-facing flow.
**Why:**
The backend should execute composition, not decide scene binding, camera policy, cache refresh, or sprite lifecycle. Keeping those responsibilities above `Gfx` preserves a cleaner ownership model and avoids re-entangling policy with raster code.
**Trade-offs:**
This adds an explicit orchestration layer between runtime callsites and the renderer, but the resulting boundaries are easier to evolve and test.
### Scene Binding, Camera, Cache, and Sprites Form One Operational Unit
**What:**
`FrameComposer` owns:
- active scene binding by bank id and shared scene reference;
- camera coordinates in top-left world pixel space;
- `SceneViewportCache` and `SceneViewportResolver`;
- a frame-emission `SpriteController`.
**Why:**
These concerns all define what a frame is. Splitting them across multiple owners would recreate stale-state bugs and make no-scene behavior ambiguous.
**Trade-offs:**
The composer becomes a richer subsystem, but it carries policy in one place instead of leaking it into unrelated APIs.
### The World Path Must Stay Tile-Size Agnostic
**What:**
The integrated frame path derives cache sizing, resolver math, and world-copy behavior from per-layer scene metadata instead of a hard-coded `16x16` assumption.
**Why:**
The scene contract already allows canonical `8x8`, `16x16`, and `32x32` tile sizes. The frame service has to consume that contract faithfully or it becomes a hidden compatibility break.
**Trade-offs:**
The integration and tests need to exercise more than the legacy default path, but the renderer no longer bakes in a false invariant.
## Patterns and Algorithms
- Put frame policy in a dedicated orchestration layer and keep the renderer backend-oriented.
- Treat scene binding, camera state, cache lifetime, and sprite submission as one cohesive frame model.
- Refresh cache state inside the orchestrator before composition instead of letting the renderer discover refresh policy.
- Prefer frame-emission sprite submission with internal ordering over caller-owned sprite slots.
- Keep the no-scene path valid so world composition remains optional, not mandatory.
## Pitfalls
- Leaving `render_all()` alive as a canonical path creates a fragile dual-service model.
- Letting `Gfx` own cache refresh semantics collapses the boundary between policy and execution.
- Requiring a scene for every frame quietly breaks sprite-only or fade-only operation.
- Testing only `16x16` scenes hides regressions against valid `8x8` or `32x32` content.
## Takeaways
- Frame composition belongs in a subsystem that owns policy, not in the backend that draws pixels.
- Scene binding, camera, cache, resolver, and sprite submission should converge under one frame owner.
- No-scene rendering is part of the contract and should stay valid throughout integration work.
- Tile-size assumptions must be derived from canonical scene metadata, never from renderer habit.

View File

@ -0,0 +1,56 @@
---
id: LSN-0032
ticket: frame-composer-public-syscall-surface
title: Public ABI Must Follow the Canonical Service Boundary
created: 2026-04-18
tags: [gfx, runtime, syscall, abi, frame-composer, scene, camera, sprites]
---
## Context
`DSC-0026` finished the internal migration to `FrameComposer` as the canonical frame-orchestration owner, but the public VM-facing ABI still exposed part of that behavior through legacy `gfx`-domain calls. That left the codebase with a mismatch between the real runtime ownership model and the surface visible to cartridges, tooling, and syscall declarations.
`DSC-0027` closed that gap by introducing the `composer.*` public domain and removing the old public sprite path.
## Key Decisions
### Public Syscalls Must Expose the Real Owner
**What:**
Scene binding, camera control, and sprite emission now live under `composer.*`, and the legacy public `gfx.set_sprite` path is gone.
**Why:**
Once `FrameComposer` became the canonical orchestration service, keeping public orchestration under `gfx.*` would preserve the wrong mental model and encourage callers to treat the render backend as the owner of frame policy.
**Trade-offs:**
This forces migration across ABI declarations, runtime dispatch, tests, and tooling, but it removes the long-term cost of a misleading public boundary.
### Domain-Specific Status Types Preserve Architectural Meaning
**What:**
Mutating public composer operations return `ComposerOpStatus` instead of reusing backend-oriented status naming.
**Why:**
Operational outcomes for scene binding or sprite emission are not backend-domain results. Reusing `GfxOpStatus` would blur the boundary that the migration was trying to make explicit.
**Trade-offs:**
This adds one more status family to maintain, but it keeps the public ABI semantically aligned with the actual service contract.
## Patterns and Algorithms
- Promote internal ownership changes into the public ABI as part of the same migration thread.
- Use syscall domains to encode service boundaries, not just namespace aesthetics.
- Remove obsolete public fallbacks completely when they preserve the wrong operational model.
- Keep runtime dispatch, bytecode declarations, and tooling aligned so the public path is exercised end to end.
## Pitfalls
- Leaving a legacy public syscall alive after the internal model changes creates a dual-contract system that is harder to remove later.
- Migrating runtime dispatch without migrating declarations and tooling can leave hidden ABI drift in tests and generators.
- Reusing backend-specific status names in the wrong domain quietly leaks old ownership assumptions into new APIs.
## Takeaways
- The public ABI should mirror the canonical service boundary, not historical implementation leftovers.
- Namespace changes are architectural when they change who is responsible for a behavior.
- Removing a legacy public entrypoint is often safer than preserving a compatibility shim that encodes the wrong model.

View File

@ -0,0 +1,56 @@
---
id: LSN-0033
ticket: deferred-overlay-and-primitive-composition
title: Debug Primitives Should Be a Final Overlay, Not Part of Game Composition
created: 2026-04-18
tags: [gfx, runtime, render, frame-composer, overlay, primitives, hud, debug]
---
## Context
After `FrameComposer.render_frame()` became the canonical game-frame entrypoint, immediate `gfx.*` primitive writes were no longer stable. Scene-backed composition could rebuild the framebuffer after `draw_text(...)` or other debug primitives had already written to it.
`DSC-0028` resolved that conflict by moving `gfx.*` primitives into a deferred overlay/debug stage outside `FrameComposer`, drained only after canonical game composition and fades are complete.
## Key Decisions
### Debug Overlay Must Stay Outside the Canonical Game Pipeline
**What:**
`FrameComposer` keeps ownership of canonical game composition, while debug/text/primitive commands are captured separately and drained later as a final overlay.
**Why:**
Game composition and debug overlay have different purposes. The first must remain canonical and deterministic; the second must remain opportunistic, screen-space, and independent from scene or sprite semantics.
**Trade-offs:**
The renderer needs a second deferred path, but the game pipeline no longer depends on transient debug state.
### Final Visual Ordering Matters More Than Immediate Writes
**What:**
Overlay/debug commands are drained after scene composition, sprite composition, and fades, with parity between scene-bound and no-scene frame paths.
**Why:**
The stable user-visible contract is that debug primitives appear on top. Immediate writes were only an implementation detail, and they stopped preserving that contract once frame composition became deferred and canonical.
**Trade-offs:**
This changes primitive semantics from "write now" to "show at frame end," but it produces the behavior users actually rely on.
## Patterns and Algorithms
- Separate canonical composition state from debug-overlay state even when both reuse the same raster backend.
- Capture primitives as commands first, then drain them at the final stage where visual priority is unambiguous.
- Preserve the same overlay semantics whether a scene is bound or not.
- Keep implementation reuse internal while maintaining a clear semantic boundary in the public model.
## Pitfalls
- Treating debug primitives as part of HUD or scene composition will eventually couple tooling/debug behavior to gameplay pipeline rules.
- Draining overlay before fades or before final frame composition breaks the visible "always on top" contract.
- Reusing `FrameComposer` storage for overlay state collapses the ownership split that prevents these bugs.
## Takeaways
- Immediate framebuffer writes are not a reliable contract once final composition is orchestrated elsewhere.
- Debug primitives work best as a dedicated final overlay layer.
- Ownership separation is what keeps debug behavior stable while the canonical render pipeline evolves.

View File

@ -1,405 +0,0 @@
---
id: AGD-0026
ticket: render-all-scene-cache-and-camera-integration
title: Agenda - Integrate render_all with Scene Cache and Camera
status: accepted
created: 2026-04-14
updated: 2026-04-15
tags: [gfx, runtime, render, camera, scene]
---
## Contexto
A thread `DSC-0025` fechou a base arquitetural para `SceneBank`, `SceneViewportCache`, `SceneViewportResolver` e o decoder binário de `SCENE`. O renderer já possui um caminho explícito `render_scene_from_cache(&SceneViewportCache, &ResolverUpdate)`, mas o loop operacional do runtime ainda chama apenas `render_all()`.
Hoje, em [tick.rs](/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/crates/console/prometeu-system/src/virtual_machine_runtime/tick.rs:148), o frame segue pelo `hw.gfx_mut().render_all()`. Isso significa que o caminho novo de world render ainda não está integrado ao ciclo normal do runtime.
Ao mesmo tempo, a integração correta depende de fechar o contrato mínimo da câmera, porque o `SceneViewportResolver` já assume uma posição de câmera em pixel space e produz `ResolverUpdate` a partir dela. Sem essa integração, o runtime fica com duas verdades práticas:
- a arquitetura aceita para world rendering;
- o caminho ainda efetivamente usado pelo frame loop.
## Problema
Precisamos integrar `render_scene_from_cache()` ao `render_all()` e ao ciclo real do runtime sem reabrir a arquitetura já aceita para `SceneBank` / `SceneViewportCache` / `SceneViewportResolver`.
O problema concreto não é só “chamar uma função”. É decidir:
- quem é dono do estado de câmera mínimo;
- onde `SceneBank`, `SceneViewportCache` e `SceneViewportResolver` passam a residir em runtime;
- quando o cache é atualizado;
- como o `render_all()` deixa de ser um caminho “scene-blind” e vira o entrypoint normal da composição final.
## Pontos Criticos
- `render_all()` deve continuar funcional mesmo quando nenhuma scene estiver carregada.
- O `render_all()` atual não desenha world layers; ele só compõe sprites de prioridade 0 e fades.
- O modelo atual de `Sprite.priority` mistura duas responsabilidades:
- em qual faixa de composição o sprite entra;
- qual a ordem relativa entre sprites naquela faixa.
- `render_scene_from_cache()` existe, mas exige `SceneViewportCache` e `ResolverUpdate` já preparados por fora.
- O modelo atual de sprites ainda é slot-first para o chamador:
- há armazenamento fixo;
- o dev informa índice;
- e o renderer precisa filtrar `active`.
- O `SceneViewportResolver` já carrega política importante:
- câmera em pixel space
- anchors
- clamp
- histerese
- refresh requests
- copy requests
- Ainda não existe um dono explícito do estado operacional:
- cena ativa
- cache ativo
- resolver ativo
- câmera ativa
- O `FrameComposer` não pode regredir o contrato já aceito no scene model:
- `SceneLayer.tile_size` já é por-layer e aceita `8x8`, `16x16` e `32x32`;
- o decoder de `SCENE` já materializa esses tamanhos;
- fixar o pipeline em `16x16` dentro do orquestrador de frame criaria uma restrição artificial que não existe no modelo canônico.
- Se a integração for mal feita, o renderer pode voltar a misturar:
- política de câmera
- atualização de cache
- composição final
## Opcoes
### Opcao 1 - Integrar tudo diretamente dentro de `Gfx`
**Como seria:**
`Gfx` passa a possuir a scene ativa, o cache, o resolver e a câmera; `render_all()` atualiza resolver/cache e já compõe tudo.
**Vantagens:**
- caminho curto de integração;
- menos objetos atravessando o runtime;
- fácil de chamar a partir do tick.
**Desvantagens:**
- empurra para `Gfx` responsabilidade demais;
- mistura composição com estado de cena/câmera;
- reduz clareza para testes e evolução futura.
### Opcao 2 - Integrar no runtime com um controlador explícito de scene viewport
**Como seria:**
O runtime ou um pequeno controlador operacional passa a possuir:
- scene ativa
- cache
- resolver
- câmera
Esse controlador atualiza o cache quando a câmera muda e entrega ao `Gfx` apenas o que ele precisa para compor.
**Vantagens:**
- separa melhor estado operacional de composição;
- mantém `Gfx` mais focado em render;
- preserva a ideia de que o resolver é dono da política de movimento/rematerialização.
- permite manter um caminho explícito de `render_all()` sem scene carregada.
**Desvantagens:**
- adiciona mais um objeto operacional no runtime;
- exige definir uma superfície clara entre runtime e renderer.
### Opcao 3 - Fazer uma integração mínima temporária em `render_all()` e postergar a arquitetura do dono da câmera
**Como seria:**
Criar um caminho temporário para que `render_all()` receba ou consulte estado suficiente para chamar `render_scene_from_cache()`, mas sem ainda fechar onde mora a câmera a longo prazo.
**Vantagens:**
- acelera a ligação do caminho novo ao frame loop;
- destrava testes end-to-end rapidamente.
**Desvantagens:**
- alto risco de solução transitória virar definitiva;
- deixa ambiguidade operacional exatamente no ponto mais sensível da integração.
## Sugestao / Recomendacao
Seguir com a **Opcao 2**.
Ou seja:
- `FrameComposer` passa a ser o orquestrador de frame/scene;
- `FrameComposer` deve morar em `hardware/drivers`;
- `Hardware` passa a agregar `FrameComposer` ao lado de `Gfx`;
- `Gfx` permanece como backend de composição e blit;
- a política do frame não deve ficar presa ao hardware atual;
- isso preserva espaço para:
- fast paths com diretivas/capacidades de GPU quando existirem;
- uma futura implementação mais próxima de PPU / bare metal;
- `render_all()` deve continuar sendo o entrypoint normal de composição;
- `render_all()` deve continuar funcionando mesmo sem scene ativa;
- mas ele não deve virar dono da câmera nem do ciclo de atualização do cache;
- precisamos de um orquestrador operacional no runtime, ou imediatamente adjacente a ele, que:
- mantenha a scene ativa opcional;
- mantenha a câmera / viewport mínima;
- mantenha o controlador de sprites do frame;
- atualize o `SceneViewportResolver` quando houver scene;
- aplique refreshes ao `SceneViewportCache` quando houver scene;
- e entregue ao `Gfx` o estado pronto para compor.
Mais explicitamente:
- `FrameComposer` passa a ser dono de:
- scene ativa;
- câmera / viewport;
- `SceneViewportCache`;
- `SceneViewportResolver`;
- sprites emitidos no frame;
- o state de scene/sprite que hoje esteja em `Gfx` deve migrar para `FrameComposer`;
- `Gfx` deve ficar focado em:
- composição;
- blit;
- raster;
- execução visual do frame preparado.
Para V1, o contrato mínimo de câmera pode continuar pequeno:
- `camera_x_px: i32`
- `camera_y_px: i32`
- representando o canto superior esquerdo da viewport no mundo
Sem follow/smoothing/shake/cut nesta etapa.
O comportamento mínimo recomendado fica:
- sem scene ativa:
- `FrameComposer` continua válido;
- `render_all()` compõe apenas o que já existe fora do pipeline de world (`sprites`, `fades`, e futuramente `HUD` quando aplicável);
- não existe `clear` implícito;
- limpar o `back` continua sendo responsabilidade explícita do chamador / dev;
- com scene ativa:
- `FrameComposer` atualiza resolver/cache;
- `render_all()` compõe o world a partir do cache e preserva a ordem já aceita.
Esta direção é provisoriamente aceita mesmo sem a figura final completa, justamente para permitir que a integração avance e revele os pontos onde a separação runtime/backend ainda precise de ajuste.
Para sprites, a direção provisória recomendada fica:
- cada `Sprite` deve carregar:
- `layer`
- `priority`
- `Sprite.active` deve ser removido;
- `layer` define em qual faixa de composição o sprite entra;
- `priority` define a ordenação entre sprites daquela mesma faixa;
- a composição observável passa a ser por camada:
- `(sprites -> scene) layer_0`
- `(sprites -> scene) layer_1`
- `(sprites -> scene) layer_2`
- `(sprites -> scene) layer_3`
Isso substitui o modelo atual em que um único `priority` tenta representar ao mesmo tempo posição macro na composição e ordenação fina.
O modelo operacional recomendado para sprites passa a ser:
- capacidade máxima interna de `512` sprites por frame;
- contador zerado a cada frame;
- o dev não informa mais índice de sprite;
- cada emissão ocupa o próximo slot interno disponível;
- o registro já coloca o sprite no bucket correto da layer;
- a composição consome apenas os sprites emitidos naquele frame.
## Perguntas em Aberto
- Fechado provisoriamente:
- `FrameComposer` em `hardware/drivers`;
- `Hardware` agrega `FrameComposer` e `Gfx`;
- `Gfx` atua como backend operacional de composição.
- O contrato mínimo do `FrameComposer` precisa ser fechado normativamente.
- Fechado:
- o subsistema interno de sprites se chama `SpriteController`.
- `Sprite.layer` deve ser um enum fechado (`Layer0..Layer3`) ou um tipo mais genérico?
- fechado provisoriamente:
- manter numérico;
- usar o mesmo tipo/referência de layer do `SceneBank`.
- A composição por camada deve ser:
- `sprites -> scene` dentro de cada layer, como direção inicial,
- ou `scene -> sprites` para alguma camada específica?
- A ordenação entre sprites de uma mesma layer será:
- fechado:
- `priority` menor blita primeiro;
- em empate, FIFO por ordem de registro.
- Overflow de sprite no frame:
- fechado: excedentes são ignorados;
- deve existir espaço para log/telemetria;
- futuramente isso pode virar sinal negativo para certificação.
- `emit_sprite(...)` precisa retornar algo, ou ter reset separado além de `begin_frame()`?
- fechado por enquanto:
- não;
- usar apenas log do sistema para overflow/eventos operacionais;
- não introduzir reset extra além do fluxo normal do frame.
- `render_all()` deve:
- continuar sem parâmetros e consultar estado já preparado,
- ou ganhar uma nova superfície interna para receber o scene state preparado?
- direção aceita:
- `FrameComposer` chama o entrypoint de composição do backend visual;
- `Gfx.render_all()` deve morrer;
- o serviço deve migrar para `FrameComposer.renderFrame()`.
## Contrato Minimo Proposto
Direção proposta para V1 do `FrameComposer`:
- `bind_scene(...)`
- recebe um `scene bank id`;
- `FrameComposer` deve possuir acesso a `SceneBankPoolAccess`;
- resolve a scene ativa através do pool;
- o acesso ao bank deve ser sempre por ponteiro / referência compartilhada, nunca por cópia;
- ao bindar, o compositor guarda:
- `scene_bank_id`;
- `Arc<SceneBank>` já resolvido;
- consegue verificar se a scene está carregada;
- inicializa ou reinicializa cache/resolver conforme necessário.
- `unbind_scene()`
- remove a scene ativa;
- invalida o pipeline de world;
- descarta o cache associado à scene bindada;
- mantém o compositor funcional para `sprites + fades`.
- `set_camera(x, y)`
- atualiza a posição da câmera em pixel space;
- `x, y` representam o canto superior esquerdo da viewport no mundo.
- `begin_frame()`
- zera o contador de sprites emitidos;
- limpa buckets internos de sprite;
- prepara o estado transitório do frame.
- `emit_sprite(...)`
- registra um sprite no próximo slot interno disponível;
- associa o sprite à sua `layer`;
- insere no bucket correspondente;
- overflow é ignorado com espaço para log/telemetria.
- `compose_frame()`
- se houver scene ativa:
- atualiza `SceneViewportResolver`;
- aplica `CacheRefreshRequest`s ao `SceneViewportCache`;
- aciona o caminho de composição world + sprites;
- se não houver scene ativa:
- aciona o caminho `sprites + fades`;
- delega a composição efetiva ao `Gfx`.
### Observacoes
- `end_frame()` não parece obrigatório na V1.
- `begin_frame()` + `compose_frame()` já cobrem o ciclo mínimo.
- `FrameComposer` decide e prepara;
`Gfx` executa a composição.
- o binding de scene deve ser por `scene bank id`, não por ownership direto de `SceneBank`.
- o `SceneViewportCache` vive dentro do `FrameComposer` enquanto a scene estiver bindada.
- troca do conteúdo do slot/bank exige novo `bind_scene(...)`;
o `FrameComposer` não deve ficar fazendo polling constante do pool para revalidar a scene ativa.
- o fluxo operacional aceito é:
- `FrameComposer.compose_frame()`
- chama o serviço `FrameComposer.renderFrame()`.
- `FrameComposer` deve ser capaz de renderizar algo 100% do tempo:
- cache/resolver ficam `None` sem bind;
- deve existir uma forma explícita de saber se a scene está disponível para render.
- `bind_scene(...)` substitui completamente a scene anterior.
## Sugestao / Recomendacao Atualizada
Aceitar o contrato mínimo acima como base de fechamento da agenda, a menos que apareça alguma necessidade concreta de:
- separar `compose_frame()` em múltiplas fases públicas;
- expor refresh manual de cache para o chamador;
- ou introduzir um `end_frame()` com semântica real além do reset que já ocorre em `begin_frame()`.
- manter o binding de scene como:
- `scene_bank_id + Arc<SceneBank>`;
- com rebind explícito quando o slot mudar.
- Quem é responsável por aplicar `CacheRefreshRequest` ao `SceneViewportCache`:
- fechado: sempre o `FrameComposer`.
- Qual é o contrato explícito de “nenhuma scene carregada”:
- fechado: `sprites + fades`, sem `clear` implícito.
- Como a cena ativa é selecionada e trocada no ciclo real:
- fechado: `bind_scene(scene_bank_id)` com resolução através de `SceneBankPoolAccess`.
- O HUD entra nesta integração já agora, ou o foco da primeira integração é apenas world + sprites + fades?
- fechado: sem HUD nesta primeira integração.
## Reabertura 2026-04-15
### Contexto adicional
Ao revisitar a thread, apareceu uma restrição indevida: tratar o `FrameComposer` como se aceitasse apenas tilesets `16x16`.
Isso conflita com o estado atual do runtime:
- `TileSize` no HAL já enumera `Size8`, `Size16` e `Size32`;
- `SceneLayer` carrega `tile_size` por layer;
- o decoder de `SCENE` já aceita `8`, `16` e `32`;
- `SceneViewportResolver` e `SceneViewportCache` já calculam offsets, anchors e cópia a partir do `tile_size` da própria layer.
O risco aqui não é apenas de implementação. Se o contrato do `FrameComposer` assumir `16x16` como pré-condição, ele quebra a neutralidade do orquestrador e reabre uma limitação artificial acima do scene model.
### Problema reaberto
Precisamos fechar explicitamente que o `FrameComposer` aceita cenas/layers com `tile_size` `8x8` e não impõe `16x16` como tamanho mínimo ou obrigatório para o world path.
### Opcoes adicionais
### Opcao 4 - Fixar `16x16` no `FrameComposer` e tratar `8x8` como fora de escopo
**Vantagens:**
- reduz casos de teste imediatos;
- simplifica implementação inicial se alguém estiver assumindo viewport/caches calibrados manualmente para `16`.
**Desvantagens:**
- contradiz o scene model já aceito;
- introduz restrição artificial no orquestrador;
- obriga futura revisão de contrato para reaceitar algo que a base já suporta.
### Opcao 5 - Manter `FrameComposer` tile-size agnostic e aceitar `8x8` desde V1
**Vantagens:**
- preserva o contrato canônico já existente em `SceneLayer`;
- mantém o `FrameComposer` como orquestrador, não como redefinidor de formato;
- evita bifurcação entre pipeline de scene e pipeline de composição.
**Desvantagens:**
- exige deixar isso explícito na decisão e nos planos;
- aumenta a exigência de testes para viewport/cache/cópia com `8x8`.
### Recomendacao adicional
Seguir com a **Opcao 5**.
Norma proposta para fechamento desta reabertura:
- `FrameComposer` deve aceitar scenes/layers cujo `tile_size` resolvido seja `8x8`, `16x16` ou `32x32`;
- `FrameComposer` nao deve impor `16x16` como pré-condição para bind, cache, resolver ou composição;
- qualquer validação de compatibilidade deve ser derivada do `tile_size` declarado pela própria layer / glyph bank, nunca de um default rígido no compositor;
- os planos derivados desta thread precisam citar testes explícitos para `8x8`.
## Criterio para Encerrar
Esta agenda pode ser encerrada quando estiver explícito:
- quem é dono do estado mínimo de câmera;
- quem é dono da scene/cache/resolver ativos;
- como funciona o bind/unbind da scene ativa;
- quando o cache é atualizado;
- como `render_all()` passa a compor o world path aceito;
- que o `FrameComposer` permanece agnóstico ao `tile_size` canônico da layer e aceita `8x8` sem downgrade contratual;
- e qual é a superfície mínima de integração para implementação sem reabrir a arquitetura base.
## Resolucao
Esta agenda fica aceita com a seguinte direcao:
- `Gfx.render_all()` deve ser aposentado;
- o fluxo operacional deve convergir para `FrameComposer.render_frame()`;
- `FrameComposer` vive em `hardware/drivers`, ao lado de `Gfx`, e passa a ser dono do estado operacional do frame;
- `FrameComposer` deve manter:
- scene ativa opcional;
- camera/viewport;
- `SceneViewportCache`;
- `SceneViewportResolver`;
- `SpriteController`;
- scene ativa e acessada por `scene_bank_id + Arc<SceneBank>` via `SceneBankPoolAccess`, sem copias;
- troca de slot exige novo `bind_scene(...)`;
- sem scene ativa, o frame continua valido com `sprites + fades`, sem `clear` implicito;
- sprites passam a ser emitidos por frame, sem `Sprite.active`, com capacidade maxima de `512`, overflow ignorado e ordenacao por `layer`, `priority`, e FIFO em empate;
- HUD fica fora desta primeira integracao.

View File

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

@ -1,140 +0,0 @@
---
id: AGD-0028
ticket: deferred-overlay-and-primitive-composition
title: Deferred Overlay and Primitive Composition over FrameComposer
status: accepted
created: 2026-04-18
updated: 2026-04-18
resolved: 2026-04-18
decision: DEC-0016
tags: [gfx, runtime, render, frame-composer, overlay, primitives, hud]
---
## Contexto
`FrameComposer.render_frame()` hoje recompõe o `back` no fim da logical frame. Quando há scene bound, o caminho `render_scene_from_cache(...)` limpa o buffer e desenha scene + sprites, o que apaga qualquer primitive ou `draw_text(...)` emitido antes via `gfx`.
Isso expôs um conflito de modelo:
- `composer.*` já é o caminho canônico de orquestração de frame;
- `gfx.draw_text(...)` e demais primitives ainda escrevem diretamente no `back`;
- o runtime só chama `render_frame()` no final do frame, então a escrita imediata em `back` deixou de ser semanticamente estável.
- As primitives de `gfx` não são o mecanismo desejado para composição de jogos com scene/tile/sprite; elas existem principalmente como debug, instrumentação visual e artefatos rápidos.
Conteúdo relevante migrado de [AGD-0010](/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/discussion/workflow/agendas/AGD-0010-perf-gfx-render-pipeline-and-dirty-regions.md):
- a arquitetura aceita continua sendo de framebuffer destrutivo em memória, não scene graph ou renderer tipo GPU;
- otimizações em primitives devem preservar a semântica observável, mesmo quando ganharem fast paths internos;
- existe preocupação explícita com custo por classe de primitive e com orçamento de memória no alvo handheld;
- caminhos de spans/linhas/clears são desejáveis como aceleração interna, mas sem reabrir o modelo operacional do pipeline do jogo.
## Problema
Precisamos decidir qual é o modelo canônico para primitives e texto no pipeline pós-`FrameComposer`.
Sem isso:
- texto e primitives continuam com comportamento dependente da ordem interna do renderer;
- o stress test e qualquer cartridge que combine `composer.*` com `gfx.*` terão resultado inconsistente;
- fica indefinido se primitives pertencem ao mundo, ao HUD, ou a um overlay final.
## Pontos Criticos
- `draw_text(...)` e primitives screen-space não podem depender de escrita imediata em `back`.
- Para esta thread, primitives de `gfx` devem permanecer agnósticas ao pipeline canônico de render do jogo e não devem ser mescladas semanticamente com tiles/sprites.
- A ordem de composição precisa ser explícita e estável: `scene -> sprites -> HUD -> primitives/debug overlay`, ou outra ordem formal equivalente.
- Precisamos decidir se o contrato público de `gfx.*` muda semanticamente sem mudar ABI, ou se parte dessa superfície migra para `composer.*`.
- A solução deve preservar o caminho sem scene bound.
- A implementação deve evitar contaminar a infraestrutura de `gfx` responsável por scene, sprites e HUD com estado misto de overlay/debug; se necessário, o overlay deve ter fila/fase própria.
- melhorias internas de primitive path devem continuar permitidas, desde que não mudem a semântica de overlay final e não exijam buffers extras incompatíveis com o orçamento de memória aceito.
## Opcoes
### Opcao 1 - Manter escrita direta em `back`
- **Abordagem:** manter `gfx.draw_text(...)` e primitives rasterizando imediatamente.
- **Pro:** zero mudança estrutural agora.
- **Contra:** o modelo continua quebrado sempre que `render_frame()` recompõe o buffer depois.
- **Tradeoff:** só funciona de forma confiável fora do caminho canônico do `FrameComposer`.
### Opcao 2 - Fila única de draw commands pós-scene/pós-sprite
- **Abordagem:** transformar texto e primitives em comandos diferidos, drenados depois de `scene + sprites`.
- **Pro:** resolve o problema imediato de overlay/HUD e estabiliza o stress test.
- **Contra:** mistura HUD e primitives/debug sob o mesmo conceito, reduzindo clareza contratual mesmo quando a ordem prática for a mesma.
- **Tradeoff:** simples para V1, mas semanticamente mais fraco do que separar overlay de jogo e overlay de debug.
### Opcao 3 - Separar HUD diferido de primitives/debug overlay final
- **Abordagem:** tratar `gfx.draw_text(...)` e demais primitives de `gfx` como overlay/debug final, separado da composição canônica de jogo (`scene + sprites + HUD`).
- **Pro:** casa com a intenção declarada para `gfx.*`: debug, artefato rápido e instrumentação visual acima do frame do jogo.
- **Contra:** exige modelar explicitamente uma fase extra no pipeline.
- **Tradeoff:** aumenta a clareza contratual e evita mesclar primitives com o domínio de jogo.
### Opcao 4 - Manter HUD e primitives no mesmo estágio final, mas com categorias separadas
- **Abordagem:** drenar HUD e primitives ambos no fim do frame, porém com filas/categorias distintas e ordem formal `HUD -> primitives`.
- **Pro:** preserva implementação próxima entre caminhos similares, mantendo contrato separado.
- **Contra:** é mais custoso que a opção 3 sem entregar muito valor adicional imediato.
- **Tradeoff:** bom se já houver expectativa de HUD canônico separado no curtíssimo prazo.
## Sugestao / Recomendacao
Seguir com a **Opcao 3**.
Minha recomendação é:
- retirar a escrita direta em `back` como contrato operacional para `gfx.draw_text(...)` e demais primitives de `gfx`;
- introduzir uma fila diferida canônica de primitives/debug overlay drenada no fim do frame;
- tratar `gfx.*` primitive/text como superfície agnóstica ao pipeline de jogo e explicitamente acima da composição canônica;
- não misturar semanticamente primitives com scene/tile/sprite/HUD.
- evitar compartilhar indevidamente o mesmo mecanismo operacional de composição entre overlay/debug e os caminhos de scene/sprite/HUD, mesmo quando o backend de rasterização reutilizado for o mesmo.
Ordem recomendada para o frame canônico:
1. limpar/compor scene;
2. compor sprites;
3. compor HUD canônico, se existir;
4. aplicar `scene_fade`;
5. aplicar `hud_fade`;
6. drenar primitives/debug overlay de `gfx.*`.
## Perguntas em Aberto
- `draw_text(...)` e as demais primitives de `gfx` entram todas na mesma família de overlay final já na V1, ou começamos só com `draw_text(...)`?
- `render_no_scene_frame()` deve usar a mesma fila diferida para manter semântica idêntica com e sem scene?
- HUD canônico precisa existir explicitamente nesta mesma thread, ou pode continuar implícito/externo enquanto as primitives já migram para overlay final?
- quais fast paths internos de primitives continuam desejáveis nessa nova fase, por exemplo spans horizontais/verticais, fills e clears, sem misturar isso com a composição do jogo?
- o overlay/debug final precisa de dirtying próprio por classe de primitive ou isso pode ficar fora da primeira migração?
## Criterio para Encerrar
Esta agenda pode ser encerrada quando tivermos uma resposta explícita para:
- o destino semântico de `draw_text(...)`;
- se haverá uma fila própria para primitives/debug overlay e qual a relação dela com HUD;
- a ordem canônica de composição do frame;
- o escopo exato da primeira migração implementável sem reabrir o restante do pipeline.
## Resolucao Parcial
Direção já aceita nesta agenda:
- primitives e `draw_text(...)` de `gfx.*` devem ser tratadas como overlay/debug final;
- esse overlay deve ser drenado **depois** de `hud_fade`;
- scene, sprites e HUD canônico não devem ser semanticamente misturados com o overlay/debug;
- a implementação deve preservar separação operacional suficiente para que o `gfx` usado pelo pipeline do jogo não passe a depender do estado transitório de primitives/debug;
- otimizações de primitive path discutidas na `AGD-0010` continuam válidas, mas passam a operar dentro do domínio de overlay/debug final, não como parte da composição canônica de scene/sprite/HUD.
## Resolucao
Esta agenda fica aceita com os seguintes pontos fechados:
- `gfx.draw_text(...)` e as demais primitives públicas de `gfx.*` pertencem à mesma família V1 de overlay/debug final;
- esse overlay/debug fica **fora** do `FrameComposer`;
- `FrameComposer` continua restrito à composição canônica do jogo (`scene`, `sprites` e HUD canônico quando existir);
- o overlay/debug deve ser drenado depois de `hud_fade`;
- o caminho sem scene bound deve observar a mesma semântica final de overlay/debug;
- HUD canônico explícito não faz parte desta thread e pode permanecer implícito/externo por enquanto;
- fast paths internos de primitives continuam permitidos, desde que preservem a semântica observável do overlay/debug final;
- dirtying granular ou otimizações finas por classe de primitive não fazem parte da primeira migração normativa desta thread.

View File

@ -1,205 +0,0 @@
---
id: DEC-0014
ticket: render-all-scene-cache-and-camera-integration
title: Frame Composer Render Integration
status: accepted
created: 2026-04-14
accepted: 2026-04-14
agenda: AGD-0026
plans: [PLN-0017, PLN-0018, PLN-0019, PLN-0020, PLN-0021]
tags: [gfx, runtime, render, camera, scene, sprites]
---
## Status
Accepted.
## Contexto
`DSC-0025` closed the canonical scene model around `SceneBank`, `SceneViewportCache`, and `SceneViewportResolver`, but the operational frame loop still remained split. `Gfx` still exposed `render_all()`, while the new world path already existed separately as `render_scene_from_cache(...)`.
This left the runtime with an incomplete composition model:
- canonical scene/camera/cache architecture had already changed;
- the normal frame entrypoint had not yet been integrated with that architecture;
- sprite ownership was still too coupled to `Gfx` and to a slot-first `active` model.
This decision closes the ownership and composition model for the next integration phase.
## Decisao
The runtime SHALL converge to a `FrameComposer`-owned frame orchestration model.
Normatively:
- `Gfx.render_all()` MUST be retired as the canonical frame service.
- The canonical operational frame entrypoint SHALL become `FrameComposer.render_frame()`.
- `FrameComposer` SHALL live in `hardware/drivers`, alongside `Gfx`.
- `Hardware` SHALL aggregate both `FrameComposer` and `Gfx`.
- `FrameComposer` SHALL own the frame-operational state:
- active scene binding;
- camera / viewport state;
- `SceneViewportCache`;
- `SceneViewportResolver`;
- sprite submission state through `SpriteController`.
- `Gfx` SHALL remain a low-level visual backend responsible for composition, blit, and raster execution.
- `Gfx` MUST NOT remain the owner of scene state or sprite submission state.
## Rationale
This split preserves a clean ownership model:
- `FrameComposer` decides what the frame is;
- `Gfx` executes how the frame is drawn.
Keeping orchestration in `FrameComposer` avoids re-entangling renderer code with camera policy, cache refresh policy, and scene binding. Keeping `FrameComposer` in `hardware/drivers` instead of `hal` preserves room for backend-specific acceleration while avoiding a policy-heavy abstraction in HAL.
This also preserves future backend freedom:
- software path today;
- hardware-assisted blit path later;
- or a more PPU-like backend in bare-metal environments.
It also preserves the scene-model contract already accepted below the frame layer:
- tile size is a property of each scene layer;
- the frame orchestrator must consume that contract, not redefine it;
- `FrameComposer` must therefore remain tile-size agnostic rather than hard-coding `16x16` assumptions.
## Invariantes / Contrato
### 1. Frame Entry
- The canonical public frame orchestration path SHALL be `FrameComposer.render_frame()`.
- `FrameComposer.render_frame()` SHALL be capable of producing a valid frame 100% of the time.
- A valid frame MUST NOT require a scene to be bound.
### 2. No-Scene Behavior
- If no scene is bound, `FrameComposer.render_frame()` SHALL compose only:
- emitted sprites;
- fades already owned by the visual backend.
- No implicit clear SHALL be performed.
- Clearing the back buffer SHALL remain the responsibility of the caller / developer.
- In the no-scene state:
- cache MUST be absent or inert;
- resolver MUST be absent or inert;
- the system SHALL expose explicit scene-availability status.
### 3. Scene Binding
- Scene binding SHALL be performed by `bind_scene(scene_bank_id)`.
- `FrameComposer` SHALL depend on `SceneBankPoolAccess`.
- `FrameComposer` MUST resolve scenes through the pool, not through copied scene values.
- Scene access MUST be pointer-based / shared-reference based only.
- On bind, `FrameComposer` SHALL store:
- `scene_bank_id`;
- `Arc<SceneBank>` for the resolved scene.
- The `SceneViewportCache` SHALL live inside `FrameComposer` while the scene remains bound.
- `unbind_scene()` SHALL:
- remove the active scene;
- discard the associated cache;
- invalidate the world path;
- keep the frame path valid for no-scene composition.
- Replacing the contents of a bound scene slot SHALL require a new explicit bind.
- `FrameComposer` MUST NOT poll the scene bank pool each frame to revalidate the binding.
- A new `bind_scene(...)` SHALL replace the previous bound scene completely.
### 4. Camera
- The V1 camera contract SHALL be minimal.
- `set_camera(x, y)` SHALL accept `i32` pixel coordinates.
- `x` and `y` SHALL represent the top-left of the viewport in world space.
- Camera follow, smoothing, shake, cinematic transitions, and similar behaviors are OUT OF SCOPE for this decision.
### 5. Cache and Resolver
- `FrameComposer` SHALL own both `SceneViewportCache` and `SceneViewportResolver`.
- `FrameComposer` SHALL apply `CacheRefreshRequest`s to the cache.
- `Gfx` MUST NOT own cache refresh policy.
- `Gfx` MUST only consume already prepared render state.
### 5A. Tile Size Contract
- `FrameComposer` SHALL remain tile-size agnostic.
- `FrameComposer` MUST accept scene layers whose canonical `tile_size` is `8x8`, `16x16`, or `32x32`.
- `FrameComposer` MUST NOT impose `16x16` as a bind-time, cache-time, resolver-time, or render-time precondition.
- Cache sizing, resolver math, and world-copy preparation SHALL derive from the `tile_size` declared by each bound scene layer.
- Compatibility checks, when needed, MUST be derived from canonical scene-layer and glyph-bank metadata rather than from a hard-coded compositor default.
- Any implementation path that only works for `16x16` tiles is NON-COMPLIANT with this decision.
### 6. Sprite Model
- `Sprite.active` MUST be removed from the canonical operational model.
- Sprite submission SHALL become frame-emission based.
- `SpriteController` SHALL be the sprite submission subsystem owned by `FrameComposer`.
- The sprite frame capacity SHALL remain capped at `512` for V1.
- The sprite counter SHALL be reset at the start of each frame.
- The caller MUST NOT provide sprite indices directly.
- Each `emit_sprite(...)` call SHALL occupy the next available internal slot.
- Overflow beyond capacity SHALL be ignored.
- Overflow SHOULD leave room for system logging / telemetry.
- Future certification MAY penalize sprite overflow, but that is not part of this decision.
- `emit_sprite(...)` SHALL NOT require a dedicated reset API beyond the normal frame lifecycle.
### 7. Sprite Ordering
- Each sprite SHALL carry:
- `layer`;
- `priority`.
- `layer` SHALL remain numeric for now.
- The sprite `layer` type SHALL match the scene layer reference type used by the scene model.
- Composition SHALL be layer-based.
- Within a layer:
- lower `priority` SHALL render first;
- ties SHALL resolve FIFO by emission order.
### 8. Composition Scope
- HUD integration is OUT OF SCOPE for the first integration phase covered by this decision.
- The first integration phase SHALL focus on:
- world scene path;
- sprites;
- fades.
## Impactos
### HAL
- `GfxBridge` and adjacent visual contracts will need to stop treating `render_all()` as the canonical operational frame path.
### Drivers / Hardware
- `Hardware` will need to aggregate `FrameComposer` next to `Gfx`.
- `Gfx` will need to lose ownership of scene/sprite operational state.
- Sprite submission state will need to move into `SpriteController`.
- `FrameComposer`, cache, and resolver integration must preserve per-layer `tile_size` semantics, including `8x8`.
### Runtime / VM
- The VM runtime will eventually trigger frame composition through the new `FrameComposer` path rather than depending on `Gfx.render_all()`.
- The VM/runtime side should not own the detailed cache or scene orchestration policy directly once `FrameComposer` exists in hardware/drivers.
### Asset / Scene Flow
- Scene activation will become explicit through bank-id binding.
- Scene slot replacement will require explicit rebinding behavior from callers.
- Scene-driven tile-size metadata must propagate unchanged into `FrameComposer` orchestration and backend copy preparation.
## Referencias
- [AGD-0026-render-all-scene-cache-and-camera-integration.md](/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/discussion/workflow/agendas/AGD-0026-render-all-scene-cache-and-camera-integration.md)
- [LSN-0030-canonical-scene-cache-and-resolver-split.md](/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/discussion/lessons/DSC-0025-scene-bank-and-viewport-cache-refactor/LSN-0030-canonical-scene-cache-and-resolver-split.md)
## Propagacao Necessaria
- A new implementation plan MUST be created from this decision before code changes.
- `FrameComposer` and `SpriteController` need explicit planning and migration sequencing.
- `Gfx.render_all()` retirement MUST be planned rather than removed ad hoc.
- The frame service rename and integration path MUST be propagated through the frame loop callsites.
- Plan steps and tests that cover world composition MUST explicitly include `8x8` tile-size coverage.
## Revision Log
- 2026-04-14: Initial accepted decision from `AGD-0026`.
- 2026-04-15: Revision accepted to make `FrameComposer` explicitly tile-size agnostic and to require `8x8` support alongside `16x16` and `32x32`.

View File

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

@ -1,150 +0,0 @@
---
id: DEC-0016
ticket: deferred-overlay-and-primitive-composition
title: Deferred GFX Overlay Outside FrameComposer
status: accepted
created: 2026-04-18
accepted: 2026-04-18
agenda: AGD-0028
plans: [PLN-0026, PLN-0027, PLN-0028, PLN-0029]
tags: [gfx, runtime, render, frame-composer, overlay, primitives, hud]
---
## Status
Accepted.
## Contexto
`DEC-0014` and `DEC-0015` established `FrameComposer` as the canonical orchestration path for game-frame composition and exposed that orchestration publicly through `composer.*`.
That migration left `gfx.draw_text(...)` and other `gfx` primitives with their historical immediate-write behavior against the working framebuffer. Once the runtime moved to end-of-frame composition through `FrameComposer.render_frame()`, those immediate writes became unstable: scene-backed frame composition can rebuild the backbuffer after primitive calls have already touched it.
The resulting conflict is not about whether primitives should remain available. It is about their semantic place in the pipeline. The accepted direction of this thread is that `gfx` primitives are not part of the canonical game composition model. They are primarily for debug, quick visual instrumentation, and rapid artifacts, and they must remain agnostic to scene/tile/sprite/HUD composition.
Relevant performance context migrated from `AGD-0010` also remains in force:
- the renderer continues to be a destructive software framebuffer model, not a retained scene graph or GPU-style renderer;
- internal primitive fast paths remain desirable;
- memory growth must remain constrained for the handheld target;
- optimization of primitive execution must not alter observable semantics.
## Decisao
`gfx.*` primitives and text SHALL move to a deferred final overlay model that lives outside `FrameComposer`.
Normatively:
- `FrameComposer` SHALL remain responsible only for canonical game-frame composition:
- scene composition;
- sprite composition;
- canonical HUD composition when such a HUD stage exists.
- `FrameComposer` MUST NOT become the owner of debug/primitive overlay state.
- Public `gfx.*` primitives, including `gfx.draw_text(...)`, SHALL belong to a V1 `gfx` overlay/debug family.
- That overlay/debug family SHALL be deferred rather than written immediately as the stable operational contract.
- The deferred overlay/debug stage SHALL be drained after `hud_fade`.
- The deferred overlay/debug stage SHALL be above scene, sprites, and canonical HUD in final visual order.
- The no-scene path MUST preserve the same final overlay/debug semantics.
- `gfx.*` primitives MUST remain semantically separate from scene/tile/sprite/HUD composition.
- The implementation MUST preserve operational separation sufficient to prevent the canonical game pipeline from depending on transient primitive/debug state.
## Rationale
This decision keeps the architectural boundary clean.
`FrameComposer` exists to own the canonical game frame. Debug primitives do not belong to that contract. Pulling them into `FrameComposer` would make the orchestration service responsible for a second semantic domain with different goals:
- game composition must be deterministic and canonical;
- primitive/text overlay must be opportunistic, screen-space, and pipeline-agnostic.
Keeping overlay/debug outside `FrameComposer` also aligns with the stated product intent: these primitives are useful helpers, but they are not meant to become a second composition language for games.
Draining them after `hud_fade` preserves the user-visible requirement that debug/overlay content stay truly on top and legible. This is more faithful to the accepted intent than treating primitives as part of HUD or world composition.
Finally, separating semantic ownership still leaves room for implementation reuse. Raster backends, span paths, and buffer-writing helpers may still be shared internally, provided the public operational model remains separate.
## Invariantes / Contrato
### 1. Ownership Boundary
- `FrameComposer` MUST own only canonical game-frame composition.
- Primitive/debug overlay state MUST live outside `FrameComposer`.
- The canonical game pipeline MUST NOT depend on primitive/debug overlay state for correctness.
### 2. Overlay Semantics
- `gfx.draw_text(...)` and sibling `gfx` primitives SHALL be treated as deferred final overlay/debug operations.
- Immediate direct writes to `back` MUST NOT remain the stable operational contract for these primitives.
- Final overlay/debug output MUST appear after:
- scene composition;
- sprite composition;
- canonical HUD composition, if present;
- `scene_fade`;
- `hud_fade`.
### 3. Separation from Game Composition
- Primitive/debug overlay MUST NOT be reinterpreted as scene content.
- Primitive/debug overlay MUST NOT be reinterpreted as sprite content.
- Primitive/debug overlay MUST NOT be the vehicle for canonical HUD composition.
- The public `gfx.*` primitive surface SHALL remain pipeline-agnostic relative to `composer.*`.
### 4. Consistency Across Frame Paths
- The scene-bound path and no-scene path MUST expose the same final overlay/debug behavior.
- Users MUST NOT need to know whether a scene is bound for `gfx.*` primitives to appear as final overlay/debug content.
### 5. Internal Optimization Contract
- Internal fast paths for lines, spans, fills, clears, or similar primitive operations MAY be introduced.
- Such fast paths MUST preserve the observable deferred overlay/debug semantics.
- This decision DOES NOT require fine-grained dirtying or per-primitive-class invalidation in the first migration.
## Impactos
### Runtime / Drivers
- The runtime frame-end sequence must gain a distinct overlay/debug drain stage outside `FrameComposer`.
- `gfx.draw_text(...)` and peer primitives can no longer rely on stable immediate framebuffer writes once this migration lands.
### GFX Backend
- `Gfx` will need an explicit deferred overlay/debug command path or equivalent subsystem boundary.
- Shared raster helpers remain allowed, but the overlay/debug phase must stay semantically distinct from scene/sprite/HUD composition.
### FrameComposer
- `FrameComposer` must remain free of primitive/debug overlay ownership.
- Any future HUD integration must not collapse that boundary.
### Spec / Docs
- The canonical graphics/runtime spec must describe `gfx.*` primitives as deferred final overlay/debug operations rather than stable immediate backbuffer writes.
- Documentation that describes frame ordering must show overlay/debug after `hud_fade`.
### Performance Follow-up
- `AGD-0010` remains the home for broader renderer performance work, dirtying strategy, and low-level primitive optimization policy.
- Primitive optimization carried out under that thread must respect the normative separation established here.
## Referencias
- [AGD-0028-deferred-overlay-and-primitive-composition.md](/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/discussion/workflow/agendas/AGD-0028-deferred-overlay-and-primitive-composition.md)
- [AGD-0010-perf-gfx-render-pipeline-and-dirty-regions.md](/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/discussion/workflow/agendas/AGD-0010-perf-gfx-render-pipeline-and-dirty-regions.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)
- [DEC-0015-frame-composer-public-syscall-surface.md](/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/discussion/workflow/decisions/DEC-0015-frame-composer-public-syscall-surface.md)
## Propagacao Necessaria
- A new implementation plan MUST be created before code changes.
- That plan MUST cover:
- deferred overlay/debug ownership outside `FrameComposer`;
- runtime frame-end ordering changes;
- no-scene path parity;
- spec/documentation updates for `gfx.*` primitive semantics.
- The implementation plan MUST NOT reopen the ownership boundary accepted here.
## Revision Log
- 2026-04-18: Initial accepted decision from `AGD-0028`.
- 2026-04-18: Linked implementation plan family `PLN-0026` through `PLN-0029`.

View File

@ -1,121 +0,0 @@
---
id: PLN-0017
ticket: render-all-scene-cache-and-camera-integration
title: Plan - FrameComposer Core and Hardware Ownership
status: accepted
created: 2026-04-14
completed:
tags: [gfx, runtime, render, hardware, frame-composer]
---
## Objective
Introduce `FrameComposer` as a first-class hardware-side subsystem and move canonical frame orchestration ownership out of `Gfx`.
## Background
`DEC-0014` locks `FrameComposer` as the canonical frame orchestration service. The first implementation step is to create the owning type, place it in `hardware/drivers`, and make `Hardware` aggregate it next to `Gfx` without yet completing the full render-path migration.
## Scope
### Included
- Create the `FrameComposer` type in `crates/console/prometeu-drivers`.
- Define the minimal owned state shape:
- active scene binding state;
- camera / viewport state;
- optional cache;
- optional resolver;
- owned `SpriteController`.
- Preserve scene-layer metadata naming aligned with the world path contract, including `parallax_factor` as the canonical per-layer camera multiplier field.
- Aggregate `FrameComposer` inside `Hardware`.
- Expose the minimum driver-facing surface required for subsequent plans.
### Excluded
- full sprite-model migration
- full scene binding implementation
- cache refresh application
- render-path retirement of `Gfx.render_all()`
## Execution Steps
### Step 1 - Introduce the `FrameComposer` module and owned state
**What:**
Create `FrameComposer` as a concrete driver-side subsystem.
**How:**
- Add a new module such as `crates/console/prometeu-drivers/src/frame_composer.rs`.
- Define a `FrameComposer` struct with explicit placeholders for:
- `active_scene_id`
- `active_scene`
- `scene_status`
- `camera_x_px`
- `camera_y_px`
- `SceneViewportCache`
- `SceneViewportResolver`
- `SpriteController`
- Keep scene/cache/resolver fields optional where no-scene operation is required.
- Do not introduce any fixed `16x16` assumption into owned state; tile-size-sensitive behavior must derive from bound scene metadata.
**File(s):**
- `crates/console/prometeu-drivers/src/frame_composer.rs`
- `crates/console/prometeu-drivers/src/lib.rs`
### Step 2 - Aggregate `FrameComposer` in `Hardware`
**What:**
Make `Hardware` own `FrameComposer` alongside `Gfx`.
**How:**
- Extend `Hardware` with a `frame_composer` field.
- Wire construction so `FrameComposer` receives the shared bank access it needs for later plans.
- Keep ownership boundaries explicit: `FrameComposer` prepares frame state, `Gfx` remains backend.
**File(s):**
- `crates/console/prometeu-drivers/src/hardware.rs`
- `crates/console/prometeu-drivers/src/memory_banks.rs`
### Step 3 - Define the minimum public driver-facing surface
**What:**
Give the driver layer a stable initial surface for `FrameComposer`.
**How:**
- Expose minimal constructor and accessor paths.
- Do not yet overdesign HAL-facing traits.
- Ensure the code compiles with no implicit dependence on `Gfx.render_all()` ownership for frame state.
**File(s):**
- `crates/console/prometeu-drivers/src/frame_composer.rs`
- `crates/console/prometeu-drivers/src/hardware.rs`
- `crates/console/prometeu-drivers/src/lib.rs`
## Test Requirements
### Unit Tests
- `FrameComposer` can be constructed without a bound scene.
- `Hardware` successfully constructs with both `gfx` and `frame_composer`.
- Construction and owned state shape do not encode `16x16` as an implicit world-path invariant.
### Integration Tests
- Shared bank access needed by `FrameComposer` is available through hardware construction.
### Manual Verification
- Inspect the resulting type ownership and confirm scene/sprite state is no longer being newly introduced into `Gfx`.
## Acceptance Criteria
- [ ] `FrameComposer` exists as a dedicated driver-side subsystem.
- [ ] `Hardware` aggregates `FrameComposer` next to `Gfx`.
- [ ] `FrameComposer` has explicit owned placeholders for scene/camera/cache/resolver/sprites.
- [ ] The build remains green with the new ownership structure in place.
## Dependencies
- Source decision: `DEC-0014`
## Risks
- Introducing `FrameComposer` with too much behavior too early can blur later migration steps.
- Introducing too little owned state can leave ownership ambiguous and force rework in later plans.
- Encoding `16x16` into the initial owned-state shape would create a contract violation that later plans would have to unwind.

View File

@ -1,127 +0,0 @@
---
id: PLN-0018
ticket: render-all-scene-cache-and-camera-integration
title: Plan - SpriteController and Frame Emission Model
status: accepted
created: 2026-04-14
completed:
tags: [gfx, runtime, render, sprites, frame-composer]
---
## Objective
Replace the slot-first sprite model with a `FrameComposer`-owned `SpriteController` that emits sprites per frame instead of relying on `Sprite.active` and caller-provided indices.
## Background
`DEC-0014` removes `Sprite.active` from the canonical operational model and locks sprite submission to a frame-emission model owned by `SpriteController`.
## Scope
### Included
- Introduce `SpriteController`.
- Remove the operational dependence on `Sprite.active`.
- Remove caller-owned sprite indices from the canonical submission path.
- Add layer + priority ordering with FIFO tie-breaking.
- Preserve the capacity cap of `512` sprites per frame.
### Excluded
- HUD integration
- scene binding
- cache refresh logic
## Execution Steps
### Step 1 - Redefine the sprite operational model
**What:**
Move canonical sprite submission semantics from slot-first to frame-emission.
**How:**
- Update `Sprite` and adjacent APIs so the canonical path no longer depends on `active`.
- Keep layer numeric and aligned with the scene layer reference type.
- Preserve `priority` as the within-layer ordering field.
**File(s):**
- `crates/console/prometeu-hal/src/sprite.rs`
- any adjacent driver-side sprite helpers
### Step 2 - Implement `SpriteController`
**What:**
Create the owned sprite subsystem under `FrameComposer`.
**How:**
- Add a `SpriteController` type with:
- storage capacity `512`
- frame counter
- per-layer buckets
- stable FIFO semantics for equal priority
- Add `begin_frame()` behavior that clears counters and buckets.
- Add `emit_sprite(...)` behavior that appends to the next internal slot.
**File(s):**
- `crates/console/prometeu-drivers/src/frame_composer.rs`
- optional dedicated `sprite_controller.rs`
### Step 3 - Handle overflow and logging semantics
**What:**
Implement overflow behavior without turning it into a hard runtime failure.
**How:**
- Ignore sprites emitted after capacity is reached.
- Leave explicit room for system logging / telemetry.
- Do not add a special reset API beyond the normal frame lifecycle.
**File(s):**
- `crates/console/prometeu-drivers/src/frame_composer.rs`
- related telemetry/log hooks if needed
### Step 4 - Remove stale slot-first sprite entrypoints
**What:**
Retire the old “set sprite by explicit index” path from the canonical model.
**How:**
- Identify the current caller-facing `Gfx` sprite mutation surface.
- Migrate it toward `FrameComposer`-owned submission.
- Keep transitional shims only if required to preserve buildability for the next plan.
**File(s):**
- `crates/console/prometeu-drivers/src/gfx.rs`
- `crates/console/prometeu-hal/src/gfx_bridge.rs`
- `crates/console/prometeu-drivers/src/frame_composer.rs`
## Test Requirements
### Unit Tests
- `begin_frame()` resets sprite count and buckets.
- `emit_sprite(...)` appends without caller-provided index.
- lower `priority` renders first within a layer.
- equal `priority` resolves FIFO by registration order.
- overflow drops excess sprites without panicking.
### Integration Tests
- `FrameComposer` can emit sprites and provide ordered sprite state for rendering.
### Manual Verification
- Confirm no canonical submission path requires `Sprite.active` or explicit slot index anymore.
## Acceptance Criteria
- [ ] `SpriteController` exists under `FrameComposer`.
- [ ] `Sprite.active` is no longer required by the canonical frame path.
- [ ] Caller-provided sprite indices are retired from the canonical submission path.
- [ ] Layer/priority/FIFO ordering is implemented and tested.
- [ ] Overflow is ignored with space left for logging.
## Dependencies
- Depends on `PLN-0017`
- Source decision: `DEC-0014`
## Risks
- Keeping compatibility shims too long can leave the codebase in a dual sprite model.
- Removing index-based APIs too early may break callsites before `FrameComposer` integration is ready.

View File

@ -1,135 +0,0 @@
---
id: PLN-0019
ticket: render-all-scene-cache-and-camera-integration
title: Plan - Scene Binding, Camera, and Scene Status
status: accepted
created: 2026-04-14
completed:
tags: [gfx, runtime, render, scene, camera, frame-composer]
---
## Objective
Implement the `FrameComposer` scene-binding contract, minimal camera state, and explicit scene-availability status without yet completing the cache-refresh render path.
## Background
`DEC-0014` locks scene activation around `bind_scene(scene_bank_id)` with `SceneBankPoolAccess`, pointer-based access only, and `scene_bank_id + Arc<SceneBank>` retained inside `FrameComposer`.
The same decision also requires `FrameComposer` to remain tile-size agnostic and to preserve canonical per-layer `tile_size`, including `8x8`.
For the scene-layer motion contract, this plan treats `parallax_factor` as the canonical field name for the per-layer camera multiplier.
## Scope
### Included
- scene bind/unbind contract
- active scene identity and shared reference storage
- scene availability status
- minimal camera state (`i32`, top-left viewport)
### Excluded
- applying cache refreshes
- full render-path migration
- HUD behavior
## Execution Steps
### Step 1 - Add scene binding state to `FrameComposer`
**What:**
Implement the canonical bind/unbind surface.
**How:**
- Add `bind_scene(scene_bank_id)` and `unbind_scene()`.
- Resolve scenes from `SceneBankPoolAccess`.
- Store both:
- `scene_bank_id`
- `Arc<SceneBank>`
- Replace prior scene binding completely on a new bind.
**File(s):**
- `crates/console/prometeu-drivers/src/frame_composer.rs`
- `crates/console/prometeu-drivers/src/memory_banks.rs`
### Step 2 - Add explicit scene status
**What:**
Expose scene availability through status, not just implicit option checks.
**How:**
- Define a scene status enum or equivalent status object.
- Distinguish at least:
- no scene bound
- bound and available
- bound but not renderable if such intermediate state is needed
- Ensure no-scene rendering remains valid.
**File(s):**
- `crates/console/prometeu-drivers/src/frame_composer.rs`
- optional HAL-facing status surface if needed later
### Step 3 - Add camera contract
**What:**
Implement the V1 camera ownership inside `FrameComposer`.
**How:**
- Add `set_camera(x, y)`.
- Store camera coordinates as `i32`.
- Treat them as top-left viewport coordinates in world space.
- Keep all advanced camera behavior out of scope.
**File(s):**
- `crates/console/prometeu-drivers/src/frame_composer.rs`
### Step 4 - Tie cache/resolver lifetime to scene binding
**What:**
Align cache/resolver lifetime with the active scene contract.
**How:**
- Cache and resolver remain `None` / absent when no scene is bound.
- On bind:
- create or reinitialize cache/resolver.
- On unbind:
- discard cache/resolver and invalidate the world path.
- Any initialization must derive layer math from the bound scene tile sizes instead of assuming `16x16`.
- Any layer-camera math or related contract references must use `parallax_factor` terminology rather than generic `motion` naming.
**File(s):**
- `crates/console/prometeu-drivers/src/frame_composer.rs`
## Test Requirements
### Unit Tests
- bind stores `scene_bank_id + Arc<SceneBank>`.
- unbind clears active scene and cache.
- scene status reflects no-scene and active-scene states.
- camera coordinates are stored as top-left pixel-space values.
- bind/unbind remains valid for scenes whose layers use `8x8` tiles.
- scene binding and camera-facing contracts preserve `parallax_factor` as the canonical layer field name.
### Integration Tests
- `FrameComposer` can resolve a scene from the pool and survive no-scene operation.
### Manual Verification
- Confirm scene access remains pointer-based and no scene copies are introduced.
## Acceptance Criteria
- [ ] `FrameComposer` binds scenes by bank id through `SceneBankPoolAccess`.
- [ ] Active binding stores both scene id and shared scene reference.
- [ ] Scene status is explicit.
- [ ] Camera contract is implemented as `i32` top-left viewport coordinates.
- [ ] Cache/resolver lifetime follows scene bind/unbind.
- [ ] Scene bind/cache/resolver setup preserves canonical per-layer tile sizes, including `8x8`.
- [ ] Scene-layer camera multiplier naming is aligned on `parallax_factor`.
## Dependencies
- Depends on `PLN-0017`
- Source decision: `DEC-0014`
## Risks
- Weak scene-status semantics can make no-scene behavior ambiguous in later render integration.
- If cache/resolver lifetime is not tied cleanly to binding, stale world state can leak across scene transitions.

View File

@ -1,136 +0,0 @@
---
id: PLN-0020
ticket: render-all-scene-cache-and-camera-integration
title: Plan - Cache Refresh and render_frame Path
status: accepted
created: 2026-04-14
completed:
tags: [gfx, runtime, render, cache, resolver, frame-composer]
---
## Objective
Connect `FrameComposer` to `SceneViewportResolver`, apply cache refreshes inside `FrameComposer`, and establish `render_frame()` as the canonical composition path for world + sprites + fades.
## Background
`DEC-0014` requires that cache refresh policy remain inside `FrameComposer` and that `FrameComposer.render_frame()` become the canonical frame entry while `Gfx` remains only the low-level execution backend.
`DEC-0014` also requires the world path to remain tile-size agnostic, with explicit support for `8x8`, `16x16`, and `32x32` scene-layer tile sizes.
For per-layer camera scaling, this plan treats `parallax_factor` as the canonical scene-layer field name.
## Scope
### Included
- apply `CacheRefreshRequest`s in `FrameComposer`
- connect camera/scene state to resolver updates
- use cache-backed world rendering in the frame path
- keep valid no-scene rendering (`sprites + fades`)
### Excluded
- HUD integration
- final retirement cleanup of legacy callsites
## Execution Steps
### Step 1 - Apply resolver refreshes inside `FrameComposer`
**What:**
Move cache-refresh orchestration fully into `FrameComposer`.
**How:**
- On active-scene frames:
- call resolver update with current camera and scene
- consume returned `CacheRefreshRequest`s
- apply them to `SceneViewportCache`
- Keep `Gfx` unaware of refresh semantics.
- Ensure resolver and refresh math follow the bound layer `tile_size` values rather than any fixed `16x16` default.
- Ensure per-layer camera math is expressed through `parallax_factor` naming in the resolver/cache path.
**File(s):**
- `crates/console/prometeu-drivers/src/frame_composer.rs`
### Step 2 - Define `render_frame()` as the canonical frame path
**What:**
Introduce the new frame service on `FrameComposer`.
**How:**
- Add `render_frame()` to `FrameComposer`.
- If a scene is active and renderable:
- prepare resolver update
- refresh cache
- call the cache-backed world path in `Gfx`
- If no scene is active:
- call the no-scene path for `sprites + fades`
- World rendering must remain valid when the active scene uses `8x8` tiles.
**File(s):**
- `crates/console/prometeu-drivers/src/frame_composer.rs`
- `crates/console/prometeu-drivers/src/gfx.rs`
### Step 3 - Keep `Gfx` as backend only
**What:**
Narrow `Gfx` to backend-oriented composition responsibilities.
**How:**
- Ensure `Gfx` consumes prepared state from `FrameComposer`.
- Do not let `Gfx` regain ownership of cache refresh or scene orchestration.
- Keep low-level helpers for cache-backed copy paths, sprite drawing, and fades in `Gfx`.
**File(s):**
- `crates/console/prometeu-drivers/src/gfx.rs`
### Step 4 - Cover scene and no-scene frame paths
**What:**
Protect the two canonical frame modes.
**How:**
- Add tests for:
- active-scene world composition
- no-scene `sprites + fades`
- scene transition through unbind/rebind
- cache refresh behavior staying inside `FrameComposer`
- active-scene composition with `8x8` tile-size layers
**File(s):**
- `crates/console/prometeu-drivers/src/frame_composer.rs`
- `crates/console/prometeu-drivers/src/gfx.rs`
## Test Requirements
### Unit Tests
- `render_frame()` with no scene produces valid no-scene composition.
- `render_frame()` with a scene applies resolver refreshes before composition.
- cache refresh requests are applied by `FrameComposer`, not `Gfx`.
- `render_frame()` with an `8x8` scene uses resolver/cache math derived from layer tile size rather than a `16x16` assumption.
- Resolver/cache-facing tests use `parallax_factor` terminology for per-layer camera scaling.
### Integration Tests
- scene bind + camera set + sprite emission + `render_frame()` produces the expected composed frame.
- scene bind + camera set + `8x8` scene + `render_frame()` produces the expected composed frame.
### Manual Verification
- Verify that no-scene frames still render sprites/fades without crashes or hidden clears.
## Acceptance Criteria
- [ ] `FrameComposer.render_frame()` exists and is the canonical frame path.
- [ ] Cache refreshes are applied inside `FrameComposer`.
- [ ] World rendering consumes the cache-backed path.
- [ ] No-scene `sprites + fades` behavior remains valid.
- [ ] `Gfx` remains backend-only for this path.
- [ ] The world path is explicitly covered for `8x8` scenes without `16x16`-specific assumptions.
- [ ] Resolver/cache/frame-path terminology is aligned on `parallax_factor` for scene-layer camera scaling.
## Dependencies
- Depends on `PLN-0017`, `PLN-0018`, and `PLN-0019`
- Source decision: `DEC-0014`
## Risks
- If refresh application leaks into `Gfx`, the ownership split from `DEC-0014` collapses.
- If no-scene behavior is not tested explicitly, scene integration can accidentally make scene binding mandatory.
- If tests cover only `16x16`, a latent compositor regression against canonical `8x8` scenes can ship unnoticed.

View File

@ -1,123 +0,0 @@
---
id: PLN-0021
ticket: render-all-scene-cache-and-camera-integration
title: Plan - Service Retirement, Callsite Migration, and Regression Coverage
status: accepted
created: 2026-04-14
completed:
tags: [gfx, runtime, render, migration, regression]
---
## Objective
Retire `Gfx.render_all()` from the canonical flow, migrate callsites to `FrameComposer.render_frame()`, and add the regression coverage needed to lock the new service model.
## Background
`DEC-0014` is explicit that `Gfx.render_all()` must be retired and that `FrameComposer.render_frame()` becomes the canonical frame orchestration entrypoint. This final plan removes the old canonical service shape and validates the migration end-to-end.
The same decision also requires the new canonical path to preserve scene-layer tile sizes such as `8x8`, not just `16x16`.
## Scope
### Included
- retire `Gfx.render_all()` from the canonical path
- migrate frame-loop callsites
- align bridge surfaces as needed
- add regression coverage for the final service model
### Excluded
- HUD integration
- future certification behavior for sprite overflow
## Execution Steps
### Step 1 - Migrate frame-loop callsites
**What:**
Switch runtime frame execution from `Gfx.render_all()` to `FrameComposer.render_frame()`.
**How:**
- Identify all canonical callsites that currently trigger `Gfx.render_all()`.
- Update them to go through `FrameComposer`.
- Preserve present/swap behavior after the render call.
**File(s):**
- `crates/console/prometeu-system/src/virtual_machine_runtime/tick.rs`
- any additional runtime frame-loop callsites
### Step 2 - Retire `Gfx.render_all()` from the canonical service surface
**What:**
Remove the old frame service as the operational entry.
**How:**
- Remove or deprecate `render_all()` from `Gfx` and `GfxBridge` as the canonical render entry.
- Keep only backend-oriented helpers that `FrameComposer` calls.
- Ensure the naming and public path converge to Rust-style `render_frame()`.
**File(s):**
- `crates/console/prometeu-hal/src/gfx_bridge.rs`
- `crates/console/prometeu-drivers/src/gfx.rs`
### Step 3 - Add end-to-end regression coverage
**What:**
Protect the new service model against fallback to the old renderer path.
**How:**
- Add tests that prove:
- frame-loop code calls `FrameComposer.render_frame()`
- no-scene frames remain valid
- active-scene frames render through cache-backed composition
- active-scene frames remain valid for canonical `8x8` scenes
- sprite emission and ordering survive the full path
- Add assertions or test failures for accidental continued reliance on `Gfx.render_all()`.
**File(s):**
- runtime tests
- driver tests
- bridge tests where needed
### Step 4 - Validate full repository behavior
**What:**
Confirm the migration did not break unrelated systems.
**How:**
- Run the repository validation command required by current practice.
- Keep regression evidence attached to the plan execution.
**File(s):**
- repository-wide CI / validation entrypoints
## Test Requirements
### Unit Tests
- `Gfx` no longer exposes `render_all()` as the canonical operational frame path.
### Integration Tests
- runtime tick path renders through `FrameComposer.render_frame()`.
- no-scene and active-scene frame modes both remain valid.
- runtime tick path remains valid when the active scene uses `8x8` tiles.
### Manual Verification
- Run the repository CI path and confirm the final integrated service model is green.
## Acceptance Criteria
- [ ] Frame-loop callsites use `FrameComposer.render_frame()`.
- [ ] `Gfx.render_all()` is retired from the canonical service path.
- [ ] Regression coverage protects against fallback to the old model.
- [ ] Repository validation passes after the migration.
- [ ] Regression coverage includes the canonical `8x8` world-path case.
## Dependencies
- Depends on `PLN-0017`, `PLN-0018`, `PLN-0019`, and `PLN-0020`
- Source decision: `DEC-0014`
## Risks
- Removing `render_all()` too early can strand intermediate callsites.
- Leaving it in place as a canonical path for too long can create a dual-service model that is harder to remove later.
- Migrating callsites without `8x8` regression coverage can falsely validate only the legacy `16x16` path.

View File

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

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

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

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

View File

@ -1,93 +0,0 @@
---
id: PLN-0026
ticket: deferred-overlay-and-primitive-composition
title: Plan - GFX Overlay Contract and Spec Propagation
status: accepted
created: 2026-04-18
completed:
tags: [gfx, runtime, spec, overlay, primitives, hud]
---
## Objective
Propagate `DEC-0016` into the canonical specs and internal contracts so `gfx.*` primitives are defined as deferred final overlay/debug operations outside `FrameComposer`.
## Background
`DEC-0016` locks a new semantic boundary:
- `FrameComposer` remains the owner of canonical game-frame composition;
- `gfx.*` primitives and `draw_text(...)` become deferred final overlay/debug operations;
- that overlay lives outside `FrameComposer` and is drained after `hud_fade`.
Execution must start by updating the normative contract before implementation changes spread through runtime and drivers.
## Scope
### Included
- update canonical runtime/gfx spec text to describe deferred overlay semantics
- update any ABI-facing or developer-facing docs that still imply direct stable writes to `back`
- align local contract comments and module docs where they currently imply immediate-write semantics as the stable model
### Excluded
- implementation of the overlay subsystem
- runtime frame-end integration
- final repository-wide CI
## Execution Steps
### Step 1 - Update canonical graphics/runtime documentation
**What:**
Publish the new semantic contract for `gfx.*` primitives.
**How:**
- Update the canonical runtime/gfx spec so `gfx.draw_text(...)` and peer primitives are described as deferred final overlay/debug operations.
- State explicitly that primitives are not part of canonical scene/sprite/HUD composition.
- State the ordering rule that overlay/debug is drained after `hud_fade`.
- Ensure the no-scene and scene-bound paths are described consistently.
**File(s):**
- canonical runtime/gfx spec files under `docs/specs/runtime/`
### Step 2 - Align implementation-facing contract text
**What:**
Remove stale implementation comments that imply immediate stable writes to the framebuffer.
**How:**
- Inspect module-level comments and trait docs in `hal`, `drivers`, and runtime code for language that now contradicts `DEC-0016`.
- Update only the contract-bearing comments and docs that materially affect maintenance and implementation clarity.
**File(s):**
- `crates/console/prometeu-hal/src/gfx_bridge.rs`
- `crates/console/prometeu-drivers/src/gfx.rs`
- `crates/console/prometeu-drivers/src/frame_composer.rs`
- runtime-adjacent modules where frame ordering is described
## Test Requirements
### Unit Tests
- none required for pure doc propagation
### Integration Tests
- none required for pure doc propagation
### Manual Verification
- inspect the updated spec and local contract comments to confirm they no longer describe primitives as stable direct writes to `back`
## Acceptance Criteria
- [ ] Canonical spec text describes `gfx.*` primitives as deferred final overlay/debug operations.
- [ ] The spec states that overlay/debug is outside `FrameComposer`.
- [ ] The spec states that overlay/debug is drained after `hud_fade`.
- [ ] Local implementation-facing contract comments no longer imply immediate-write semantics as the stable model.
## Dependencies
- Source decision: `DEC-0016`
## Risks
- Missing a normative doc location would leave code and published contract divergent.
- Over-editing local comments could unintentionally restate design choices outside the scope of `DEC-0016`.

View File

@ -1,104 +0,0 @@
---
id: PLN-0027
ticket: deferred-overlay-and-primitive-composition
title: Plan - Deferred GFX Overlay Subsystem
status: accepted
created: 2026-04-18
completed:
tags: [gfx, runtime, overlay, primitives, text, drivers]
---
## Objective
Introduce a dedicated deferred overlay/debug subsystem for `gfx.*` primitives outside `FrameComposer`, with command capture for `draw_text(...)` and the primitive family selected for the first migration.
## Background
`DEC-0016` requires primitive/text overlay ownership to remain outside `FrameComposer` while still allowing shared raster helpers and low-level optimizations internally. The new subsystem must preserve semantic separation from scene/sprite/HUD composition.
## Scope
### Included
- introduce an overlay/debug command queue or equivalent subsystem outside `FrameComposer`
- route `gfx.draw_text(...)` into deferred command capture instead of stable direct framebuffer writes
- route the chosen V1 primitive family into the same deferred overlay/debug path
- keep raster helper reuse allowed without merging semantic ownership
### Excluded
- runtime frame-end sequencing
- no-scene/scene parity tests at the runtime level
- final repository-wide CI
## Execution Steps
### Step 1 - Define overlay/debug state ownership in drivers
**What:**
Create the subsystem that owns deferred `gfx.*` overlay/debug commands.
**How:**
- Add a dedicated owner adjacent to `Gfx`/`Hardware`, but not inside `FrameComposer`.
- Define the minimal command model required for V1 operations.
- Keep the subsystem screen-space and explicitly pipeline-agnostic relative to `composer.*`.
**File(s):**
- `crates/console/prometeu-drivers/src/*`
- `crates/console/prometeu-hal/src/*` if bridge traits need extension
### Step 2 - Route text and selected primitives into deferred capture
**What:**
Stop treating text/primitives as stable direct writes.
**How:**
- Change `gfx.draw_text(...)` to enqueue deferred overlay/debug work.
- Migrate the selected V1 primitive set into the same deferred path.
- Keep any remaining unmigrated primitives either explicitly out of scope or routed consistently if they are already part of the accepted V1 set.
- Preserve internal raster helper reuse where useful.
**File(s):**
- `crates/console/prometeu-drivers/src/gfx.rs`
- runtime dispatch call sites that submit `gfx.*` primitives
### Step 3 - Add local driver-level tests for deferred capture semantics
**What:**
Prove that overlay/debug commands are captured separately from game composition state.
**How:**
- Add tests that assert text/primitives do not need direct stable writes to `back` to survive until overlay drain.
- Add tests that assert the overlay owner is independent from `FrameComposer` state.
**File(s):**
- `crates/console/prometeu-drivers/src/gfx.rs`
- new or existing driver test modules
## Test Requirements
### Unit Tests
- command capture tests for `draw_text(...)`
- tests for each migrated V1 primitive class
- tests proving overlay/debug state is owned outside `FrameComposer`
### Integration Tests
- none in this plan; runtime-level ordering is covered by the next plan
### Manual Verification
- inspect driver ownership boundaries to confirm `FrameComposer` does not gain overlay/debug state
## Acceptance Criteria
- [ ] A dedicated deferred overlay/debug subsystem exists outside `FrameComposer`.
- [ ] `gfx.draw_text(...)` is captured as deferred overlay/debug work.
- [ ] The selected V1 primitive family is captured through the same subsystem.
- [ ] Driver-level tests prove overlay/debug state is operationally separate from canonical game composition state.
## Dependencies
- Source decision: `DEC-0016`
- Prefer to execute after `PLN-0026`
## Risks
- Accidentally reusing `FrameComposer` storage or state would violate the accepted ownership boundary.
- Migrating only part of the primitive family without explicit scoping could create inconsistent semantics across `gfx.*`.

View File

@ -1,106 +0,0 @@
---
id: PLN-0028
ticket: deferred-overlay-and-primitive-composition
title: Plan - Runtime Frame-End Overlay Integration and Parity
status: accepted
created: 2026-04-18
completed:
tags: [runtime, overlay, frame-composer, no-scene, regression, stress]
---
## Objective
Integrate deferred overlay/debug draining into the runtime frame-end sequence so scene-bound and no-scene frames both present the same final `gfx.*` primitive behavior after `hud_fade`.
## Background
After `PLN-0027`, the overlay/debug subsystem will exist but still needs to be drained in the correct place relative to `FrameComposer.render_frame()`, fades, and present/present-adjacent behavior. This plan closes the observable runtime semantics required by `DEC-0016`.
## Scope
### Included
- runtime frame-end ordering changes
- scene-bound and no-scene parity
- regression coverage for overlay visibility above the canonical game frame
- stress-cartridge adjustments if needed to prove text/primitives now survive frame composition
### Excluded
- broad renderer optimization work
- final repository-wide CI
## Execution Steps
### Step 1 - Insert overlay/debug drain into the frame-end path
**What:**
Drain deferred overlay/debug after canonical game composition is complete.
**How:**
- Update the runtime frame-end path so overlay/debug drain occurs after:
- `FrameComposer.render_frame()`
- `scene_fade`
- `hud_fade`
- Ensure the same ordering is respected in the no-scene path.
**File(s):**
- `crates/console/prometeu-system/src/virtual_machine_runtime/tick.rs`
- `crates/console/prometeu-drivers/src/hardware.rs`
- `crates/console/prometeu-drivers/src/gfx.rs`
- any bridge traits needed by the runtime/hardware path
### Step 2 - Add runtime and driver regressions for final visual ordering
**What:**
Lock the new visible behavior.
**How:**
- Add tests proving `gfx.draw_text(...)` remains visible after scene-backed frame composition.
- Add tests proving the same behavior with no scene bound.
- Add tests proving overlay/debug sits above the canonical game frame rather than being erased by it.
**File(s):**
- `crates/console/prometeu-system/src/virtual_machine_runtime/tests.rs`
- driver-level render tests where helpful
### Step 3 - Update stress/integration fixtures if needed
**What:**
Restore or improve stress scenarios that rely on visible text/primitives.
**How:**
- Update `pbxgen-stress` or related stress fixtures so text/primitives are once again a valid visible overlay signal.
- Keep the stress focused on the new model rather than reintroducing obsolete immediate-write assumptions.
**File(s):**
- `crates/tools/pbxgen-stress/src/lib.rs`
- `test-cartridges/stress-console/*`
## Test Requirements
### Unit Tests
- local ordering tests where runtime integration depends on helper sequencing
### Integration Tests
- runtime tests for scene-bound overlay/debug visibility
- runtime tests for no-scene parity
- stress/tooling validation that text or primitives are visible again as final overlay/debug
### Manual Verification
- run the stress path and visually confirm overlay/debug survives on top of scene/sprites after frame composition
## Acceptance Criteria
- [ ] The runtime drains deferred overlay/debug after canonical game composition and after `hud_fade`.
- [ ] Scene-bound and no-scene paths expose the same overlay/debug semantics.
- [ ] Regression tests prove `draw_text(...)` is no longer erased by scene-backed frame composition.
- [ ] Stress/integration fixtures reflect the new final-overlay semantics where applicable.
## Dependencies
- Source decision: `DEC-0016`
- Depends on `PLN-0027`
## Risks
- If fades are still applied after overlay/debug drain, the visible contract will contradict `DEC-0016`.
- Incomplete parity between scene-bound and no-scene paths would leave runtime behavior mode-dependent.

View File

@ -1,82 +0,0 @@
---
id: PLN-0029
ticket: deferred-overlay-and-primitive-composition
title: Plan - Final Overlay CI Validation and Polish
status: accepted
created: 2026-04-18
completed:
tags: [ci, overlay, runtime, gfx, validation]
---
## Objective
Run the final repository validation path for the deferred overlay/debug migration and perform the last compatibility, formatting, lint, and regression fixes required to close the thread cleanly.
## Background
`DEC-0016` changes visible runtime semantics and touches both specs and code paths around frame composition. A dedicated final-validation plan is needed so the implementation family can close on a clean CI signal rather than leaving integration fallout for later.
## Scope
### Included
- full-tree formatting, lint, and test validation
- stress-path smoke validation after overlay integration
- final cleanup fixes required to satisfy CI
### Excluded
- new feature work outside the accepted overlay/debug migration
## Execution Steps
### Step 1 - Run focused validation before full CI
**What:**
Catch local fallout in the touched areas before the full repository pass.
**How:**
- Run targeted tests for drivers, runtime, and `pbxgen-stress`.
- Inspect touched files for stale immediate-write assumptions or missed contract updates.
**File(s):**
- touched files from `PLN-0026` through `PLN-0028`
### Step 2 - Run final repository CI
**What:**
Validate the migration end to end.
**How:**
- Run the repository validation path, including `make ci`.
- Fix any final formatting, lint, test, or generated-fixture fallout caused by the overlay/debug migration.
- Do not widen scope beyond the accepted thread.
**File(s):**
- repository-wide
## Test Requirements
### Unit Tests
- all relevant crate unit tests pass after the migration
### Integration Tests
- runtime and stress/integration tests pass after the migration
- `make ci` passes
### Manual Verification
- inspect the tree for residual direct-write assumptions or incomplete overlay propagation
## Acceptance Criteria
- [ ] Targeted validation passes for the touched drivers/runtime/stress areas.
- [ ] `make ci` passes after the deferred overlay/debug migration family lands.
- [ ] No residual contract mismatch remains between spec text and code behavior in the touched thread.
## Dependencies
- Source decision: `DEC-0016`
- Depends on `PLN-0026`, `PLN-0027`, and `PLN-0028`
## Risks
- Final CI may surface unrelated renderer assumptions that still expect immediate-write semantics.
- Generated cartridge fixtures may drift if regeneration is forgotten during earlier plans.