dev/render-all-scene-cache-and-camera-integration #16
29
discussion/.backups/index.ndjson.20260418-162736.bak
Normal file
29
discussion/.backups/index.ndjson.20260418-162736.bak
Normal 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"}]}
|
||||||
29
discussion/.backups/index.ndjson.20260418-162925.bak
Normal file
29
discussion/.backups/index.ndjson.20260418-162925.bak
Normal 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"}]}
|
||||||
@ -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-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-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-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-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-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-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-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-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":"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-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-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-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-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"}]}
|
||||||
|
|||||||
@ -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.
|
||||||
@ -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.
|
||||||
@ -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.
|
||||||
@ -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.
|
|
||||||
@ -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.
|
|
||||||
@ -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.
|
|
||||||
@ -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`.
|
|
||||||
@ -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`.
|
|
||||||
@ -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`.
|
|
||||||
@ -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.
|
|
||||||
@ -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.
|
|
||||||
@ -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.
|
|
||||||
@ -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.
|
|
||||||
@ -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.
|
|
||||||
@ -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.
|
|
||||||
@ -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.
|
|
||||||
@ -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.
|
|
||||||
@ -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 repository’s 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.
|
|
||||||
@ -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`.
|
|
||||||
@ -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.*`.
|
|
||||||
@ -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.
|
|
||||||
@ -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.
|
|
||||||
Loading…
x
Reference in New Issue
Block a user