From cafbc420189ebf89806ad2955ad4fbeaa2485acc Mon Sep 17 00:00:00 2001 From: bQUARKz Date: Mon, 15 Jun 2026 12:31:01 +0100 Subject: [PATCH] accept real render worker decision --- discussion/index.ndjson | 4 +- ...D-0043-real-render-worker-establishment.md | 2 +- .../DEC-0033-real-render-worker-contract.md | 296 ++++++++++++++++++ 3 files changed, 299 insertions(+), 3 deletions(-) create mode 100644 discussion/workflow/decisions/DEC-0033-real-render-worker-contract.md diff --git a/discussion/index.ndjson b/discussion/index.ndjson index 8e7174a2..9794dfd3 100644 --- a/discussion/index.ndjson +++ b/discussion/index.ndjson @@ -1,8 +1,8 @@ -{"type":"meta","next_id":{"DSC":43,"AGD":44,"DEC":33,"PLN":110,"LSN":49,"CLSN":1}} +{"type":"meta","next_id":{"DSC":43,"AGD":44,"DEC":34,"PLN":110,"LSN":49,"CLSN":1}} {"type":"discussion","id":"DSC-0039","status":"abandoned","ticket":"render-pipeline-family-and-future-3d","title":"Render Pipeline Family and Future 3D","created_at":"2026-06-04","updated_at":"2026-06-04","tags":["gfx","renderer","runtime","architecture","pipeline"],"agendas":[{"id":"AGD-0039","file":"AGD-0039-render-pipeline-family-and-future-3d.md","status":"abandoned","created_at":"2026-06-04","updated_at":"2026-06-04","_override_reason":"User explicitly chose to close this agenda without a new decision because DSC-0038 already established enough architecture for future extension, and 3D is intentionally deferred."}],"decisions":[],"plans":[],"lessons":[],"_override_reason":"User explicitly chose to close this agenda without a new decision because DSC-0038 already established enough architecture for future extension, and 3D is intentionally deferred."} {"type":"discussion","id":"DSC-0040","status":"done","ticket":"vm-render-parallel-execution-boundary","title":"VM and Render Parallel Execution Boundary","created_at":"2026-06-04","updated_at":"2026-06-06","tags":["runtime","renderer","vm","concurrency","architecture","perf"],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0048","file":"discussion/lessons/DSC-0040-vm-render-parallel-execution-boundary/LSN-0048-render-workers-need-a-closed-packet-contract.md","status":"done","created_at":"2026-06-06","updated_at":"2026-06-06"}]} {"type":"discussion","id":"DSC-0041","status":"open","ticket":"foreground-stack-game-pause-shell-vm-backed","title":"Foreground Stack, Game Pause, and VM-Backed Shell Coexistence","created_at":"2026-06-05","updated_at":"2026-06-05","tags":["runtime","os","lifecycle","shell","game","vm","foreground","architecture"],"agendas":[{"id":"AGD-0041","file":"AGD-0041-foreground-stack-game-pause-shell-vm-backed.md","status":"open","created_at":"2026-06-05","updated_at":"2026-06-05"}],"decisions":[],"plans":[],"lessons":[]} -{"type":"discussion","id":"DSC-0042","status":"in_progress","ticket":"real-render-worker-establishment","title":"Real Render Worker Establishment","created_at":"2026-06-06","updated_at":"2026-06-15","tags":["runtime","renderer","worker","concurrency","host","hal","architecture"],"agendas":[{"id":"AGD-0042","file":"AGD-0042-host-hardware-render-boundary-preparation.md","status":"accepted","created_at":"2026-06-06","updated_at":"2026-06-06"},{"id":"AGD-0043","file":"AGD-0043-real-render-worker-establishment.md","status":"open","created_at":"2026-06-06","updated_at":"2026-06-06"}],"decisions":[{"id":"DEC-0032","file":"DEC-0032-platform-layer-and-hardwarebridge-elimination.md","status":"accepted","created_at":"2026-06-06","updated_at":"2026-06-06","ref_agenda":"AGD-0042"}],"plans":[{"id":"PLN-0098","file":"PLN-0098-define-platform-facade-contracts.md","status":"done","created_at":"2026-06-06","updated_at":"2026-06-15","ref_decisions":["DEC-0032"]},{"id":"PLN-0099","file":"PLN-0099-introduce-owned-render-submission-sink.md","status":"done","created_at":"2026-06-06","updated_at":"2026-06-15","ref_decisions":["DEC-0032"]},{"id":"PLN-0100","file":"PLN-0100-migrate-local-render-publication-to-sink.md","status":"done","created_at":"2026-06-06","updated_at":"2026-06-15","ref_decisions":["DEC-0032"]},{"id":"PLN-0101","file":"PLN-0101-remove-immediate-gfx-syscall-rendering.md","status":"done","created_at":"2026-06-06","updated_at":"2026-06-15","ref_decisions":["DEC-0032"]},{"id":"PLN-0102","file":"PLN-0102-introduce-game2d-frame-composer-service.md","status":"done","created_at":"2026-06-06","updated_at":"2026-06-15","ref_decisions":["DEC-0032"]},{"id":"PLN-0103","file":"PLN-0103-introduce-runtime-platform-and-testplatform.md","status":"done","created_at":"2026-06-06","updated_at":"2026-06-15","ref_decisions":["DEC-0032"]},{"id":"PLN-0104","file":"PLN-0104-migrate-vm-runtime-hostcontext-to-platform.md","status":"done","created_at":"2026-06-06","updated_at":"2026-06-15","ref_decisions":["DEC-0032"]},{"id":"PLN-0105","file":"PLN-0105-migrate-firmware-and-hub-to-platform-services.md","status":"done","created_at":"2026-06-06","updated_at":"2026-06-15","ref_decisions":["DEC-0032"]},{"id":"PLN-0106","file":"PLN-0106-migrate-desktop-host-to-platform-services.md","status":"done","created_at":"2026-06-06","updated_at":"2026-06-15","ref_decisions":["DEC-0032"]},{"id":"PLN-0107","file":"PLN-0107-migrate-remaining-platform-domains.md","status":"done","created_at":"2026-06-06","updated_at":"2026-06-15","ref_decisions":["DEC-0032"]},{"id":"PLN-0108","file":"PLN-0108-migrate-tests-to-testplatform.md","status":"done","created_at":"2026-06-06","updated_at":"2026-06-15","ref_decisions":["DEC-0032"]},{"id":"PLN-0109","file":"PLN-0109-remove-hardwarebridge-and-update-specs.md","status":"done","created_at":"2026-06-06","updated_at":"2026-06-15","ref_decisions":["DEC-0032"]}],"lessons":[]} +{"type":"discussion","id":"DSC-0042","status":"in_progress","ticket":"real-render-worker-establishment","title":"Real Render Worker Establishment","created_at":"2026-06-06","updated_at":"2026-06-15","tags":["runtime","renderer","worker","concurrency","host","hal","architecture"],"agendas":[{"id":"AGD-0042","file":"AGD-0042-host-hardware-render-boundary-preparation.md","status":"accepted","created_at":"2026-06-06","updated_at":"2026-06-06"},{"id":"AGD-0043","file":"AGD-0043-real-render-worker-establishment.md","status":"accepted","created_at":"2026-06-06","updated_at":"2026-06-15"}],"decisions":[{"id":"DEC-0032","file":"DEC-0032-platform-layer-and-hardwarebridge-elimination.md","status":"accepted","created_at":"2026-06-06","updated_at":"2026-06-06","ref_agenda":"AGD-0042"},{"id":"DEC-0033","file":"DEC-0033-real-render-worker-contract.md","status":"accepted","created_at":"2026-06-15","updated_at":"2026-06-15","ref_agenda":"AGD-0043"}],"plans":[{"id":"PLN-0098","file":"PLN-0098-define-platform-facade-contracts.md","status":"done","created_at":"2026-06-06","updated_at":"2026-06-15","ref_decisions":["DEC-0032"]},{"id":"PLN-0099","file":"PLN-0099-introduce-owned-render-submission-sink.md","status":"done","created_at":"2026-06-06","updated_at":"2026-06-15","ref_decisions":["DEC-0032"]},{"id":"PLN-0100","file":"PLN-0100-migrate-local-render-publication-to-sink.md","status":"done","created_at":"2026-06-06","updated_at":"2026-06-15","ref_decisions":["DEC-0032"]},{"id":"PLN-0101","file":"PLN-0101-remove-immediate-gfx-syscall-rendering.md","status":"done","created_at":"2026-06-06","updated_at":"2026-06-15","ref_decisions":["DEC-0032"]},{"id":"PLN-0102","file":"PLN-0102-introduce-game2d-frame-composer-service.md","status":"done","created_at":"2026-06-06","updated_at":"2026-06-15","ref_decisions":["DEC-0032"]},{"id":"PLN-0103","file":"PLN-0103-introduce-runtime-platform-and-testplatform.md","status":"done","created_at":"2026-06-06","updated_at":"2026-06-15","ref_decisions":["DEC-0032"]},{"id":"PLN-0104","file":"PLN-0104-migrate-vm-runtime-hostcontext-to-platform.md","status":"done","created_at":"2026-06-06","updated_at":"2026-06-15","ref_decisions":["DEC-0032"]},{"id":"PLN-0105","file":"PLN-0105-migrate-firmware-and-hub-to-platform-services.md","status":"done","created_at":"2026-06-06","updated_at":"2026-06-15","ref_decisions":["DEC-0032"]},{"id":"PLN-0106","file":"PLN-0106-migrate-desktop-host-to-platform-services.md","status":"done","created_at":"2026-06-06","updated_at":"2026-06-15","ref_decisions":["DEC-0032"]},{"id":"PLN-0107","file":"PLN-0107-migrate-remaining-platform-domains.md","status":"done","created_at":"2026-06-06","updated_at":"2026-06-15","ref_decisions":["DEC-0032"]},{"id":"PLN-0108","file":"PLN-0108-migrate-tests-to-testplatform.md","status":"done","created_at":"2026-06-06","updated_at":"2026-06-15","ref_decisions":["DEC-0032"]},{"id":"PLN-0109","file":"PLN-0109-remove-hardwarebridge-and-update-specs.md","status":"done","created_at":"2026-06-06","updated_at":"2026-06-15","ref_decisions":["DEC-0032"]}],"lessons":[]} {"type":"discussion","id":"DSC-0038","status":"done","ticket":"render-frame-packet-boundary","title":"Logical Render Pipelines and Command Packets","created_at":"2026-05-25","updated_at":"2026-06-04","tags":["gfx","renderer","runtime","frame-composer","architecture","ui","pipeline"],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0047","file":"discussion/lessons/DSC-0038-render-frame-packet-boundary/LSN-0047-typed-render-submissions-preserve-domain-boundaries.md","status":"done","created_at":"2026-06-04","updated_at":"2026-06-04"}]} {"type":"discussion","id":"DSC-0035","status":"done","ticket":"task-owned-shell-windows","title":"Agenda - Task-Owned Shell Windows","created_at":"2026-05-15","updated_at":"2026-05-15","tags":["runtime","os","task","window-manager","shell","lifecycle"],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0044","file":"discussion/lessons/DSC-0035-task-owned-shell-windows/LSN-0044-task-window-liveness-belongs-to-the-task.md","status":"done","created_at":"2026-05-15","updated_at":"2026-05-15"}]} {"type":"discussion","id":"DSC-0034","status":"done","ticket":"system-os-domain-facades","title":"Agenda - SystemOS Domain Facades","created_at":"2026-05-15","updated_at":"2026-05-15","tags":["runtime","os","services","api-surface","lifecycle","fs"],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0043","file":"discussion/lessons/DSC-0034-system-os-domain-facades/LSN-0043-systemos-domain-facades.md","status":"done","created_at":"2026-05-15","updated_at":"2026-05-15"}]} diff --git a/discussion/workflow/agendas/AGD-0043-real-render-worker-establishment.md b/discussion/workflow/agendas/AGD-0043-real-render-worker-establishment.md index 122fc8eb..dd671366 100644 --- a/discussion/workflow/agendas/AGD-0043-real-render-worker-establishment.md +++ b/discussion/workflow/agendas/AGD-0043-real-render-worker-establishment.md @@ -2,7 +2,7 @@ id: AGD-0043 ticket: real-render-worker-establishment title: Real Render Worker Establishment -status: open +status: accepted created: 2026-06-06 resolved: decision: diff --git a/discussion/workflow/decisions/DEC-0033-real-render-worker-contract.md b/discussion/workflow/decisions/DEC-0033-real-render-worker-contract.md new file mode 100644 index 00000000..59cbe397 --- /dev/null +++ b/discussion/workflow/decisions/DEC-0033-real-render-worker-contract.md @@ -0,0 +1,296 @@ +--- +id: DEC-0033 +ticket: real-render-worker-establishment +title: Real Render Worker Contract +status: accepted +created: 2026-06-15 +accepted: +agenda: AGD-0043 +plans: [] +tags: [runtime, renderer, worker, concurrency, host, hal, architecture] +--- + +## Status + +Decision accepted from agenda `AGD-0043`. + +This is the normative contract for implementation plans that establish the real render worker for Prometeu. + +## Contexto + +`DEC-0031` established the VM/render boundary around closed render submissions, single-slot handoff, frame pacing, AppMode policy, ownership epoch, and render telemetry. + +`DEC-0032` and plans `PLN-0098` through `PLN-0109` prepared the platform boundary required for a real worker: + +- `HardwareBridge` was removed from production/runtime contracts; +- `RuntimePlatform` became the runtime-facing platform service boundary; +- `RenderSubmissionSink` accepts owned render submissions; +- `Game2DFrameComposer` separates logical Game 2D frame closure from backend rendering; +- `gfx2d.*` and `gfxui.*` syscalls buffer commands instead of mutating `Gfx` immediately; +- firmware, Hub, runtime, host desktop, and tests moved to platform services; +- specs now state that worker/render consumers must not depend on `&mut Hardware`, `&mut Gfx`, live `FrameComposer`, or mutable VM state. + +The remaining work is to replace the cooperative/local `LocalRenderWorker` proof with a real worker that drains render submissions without blocking VM progress and publishes complete RGBA8888 frames for host presentation. + +## Decisao + +Prometeu SHALL implement the real render worker as a runtime-owned worker controller with host-provided backend integration. + +The worker controller SHALL live in `prometeu-system`, near `RenderManager`, because `RenderManager` owns AppMode policy, ownership/epoch, latest-wins handoff semantics, and render telemetry. + +Shared contract types and traits SHALL live in `prometeu-hal` when they cross runtime/host/driver boundaries. Local/default and test implementations SHALL live in `prometeu-drivers` or host crates as appropriate. + +The worker SHALL consume owned `RenderSubmission` values through a thread-safe single-slot latest-wins handoff. The VM producer MUST NOT block on rasterization, publication, presentation, or worker completion. + +The worker SHALL publish owned RGBA8888 frames, not native window/swapchain objects. The initial shared frame type SHALL be `OwnedRgba8888Frame` in `prometeu-hal`. + +The host event loop SHALL remain responsible for native window upload/present. The worker MUST NOT depend on winit, pixels, SDL, swapchain handles, native textures, or host window APIs. + +The agenda may be implemented through multiple plans, but `AGD-0043` is complete only when the worker functions on the real host path, not merely in fake/local tests. + +## Rationale + +The real worker must prove the architecture promised by `DEC-0031`: VM execution and render consumption can proceed independently without crossing mutable runtime state into the renderer. + +Putting the controller in `prometeu-system` keeps render policy in the same layer that already owns frame lifecycle, ownership epochs, latest-wins behavior, and telemetry. Putting it only in the host would make the contract desktop-specific and harder to test without a window. + +Publishing an owned RGBA8888 frame keeps the worker host-agnostic. The host can upload that frame to any native presentation backend while the worker stays testable through ordinary memory comparisons. + +Using a single explicit pending slot directly models the accepted backpressure rule. Channels or queues can accidentally preserve history or block producers. The runtime contract is not "render every produced frame"; it is "the latest complete submission wins and the VM does not wait for the consumer." + +Read-only bank access by id preserves the no-copy resource boundary. Banks are render resources, not payloads to duplicate into each submission. The worker should resolve resource ids through a compact read-only interface without taking `&mut Hardware`, `&mut Gfx`, a live `FrameComposer`, or VM state. + +## Invariantes / Contrato + +### 1. Runtime controller ownership + +The worker controller MUST live in `prometeu-system`. + +`RenderManager` SHALL remain the authority for: + +- AppMode render policy; +- ownership/epoch; +- latest-wins handoff semantics; +- render telemetry; +- stale submission discard; +- shutdown/request-stop coordination visible to runtime policy. + +Host crates MAY instantiate or wire the controller, but they MUST NOT redefine worker semantics. + +### 2. Shared HAL contracts + +`prometeu-hal` SHALL define shared types/traits that cross the runtime/host/driver boundary. + +At minimum, the worker work SHALL introduce: + +- `OwnedRgba8888Frame`; +- compact read-only render resource access contracts for bank lookup by id; +- typed worker/backend error contracts where they are shared across crates. + +### 3. Owned RGBA8888 frame publication + +`OwnedRgba8888Frame` SHALL represent a completed logical frame ready for host upload/present. + +It MUST include: + +- `FrameId`; +- render ownership/epoch metadata; +- width; +- height; +- `stride_pixels`; +- owned RGBA8888 pixel data as `Vec`. + +The pixel data MUST use the canonical RGBA8888 raw value contract already used by the runtime specs. It MUST NOT be described as native-endian host pixels, native texture data, or backend-specific surface memory. + +Repeating the last valid frame SHALL mean reusing the last published `OwnedRgba8888Frame`, not recomposing from VM state or live composer state. + +### 4. Thread-safe latest-wins handoff + +The real handoff SHALL be a thread-safe single-slot latest-wins structure. + +The initial implementation SHOULD use an explicit slot based on `Mutex> + Condvar`. + +Producer behavior: + +- publish replaces the pending submission if one already exists; +- replacement increments drop/replacement telemetry; +- publish MUST NOT wait for rasterization or present; +- publish MUST wake the consumer when needed. + +Consumer behavior: + +- wait for pending submission or shutdown; +- take ownership of the latest pending submission; +- leave the pending slot empty while work is in flight; +- discard stale work before publication if ownership/epoch no longer matches. + +### 5. Pending and in-flight are separate + +The worker MUST distinguish pending submissions from in-flight work. + +Once the worker takes a submission, that submission is in flight. New producer submissions may replace the pending slot while the worker is still rasterizing the previous in-flight submission. + +Before publishing an in-flight frame, the worker MUST check: + +- stop/shutdown state; +- render owner; +- render epoch/generation. + +If the frame is stale, the worker MUST discard it and update telemetry. It MUST NOT publish stale pixels. + +### 6. Shutdown is bounded + +Worker shutdown MUST be bounded and observable. + +The shutdown timeout MUST be configurable. The initial default SHOULD be `250ms`. + +On shutdown: + +- stop state MUST be signaled; +- the worker MUST be woken if it is waiting; +- join MUST complete within the configured bound or return/report a `ShutdownTimeout` failure; +- in-flight work MAY finish rasterization, but MUST NOT publish after stop/epoch invalidation says it is stale. + +### 7. Read-only bank access by id + +The render backend SHALL resolve render resources through a compact read-only interface by stable ids. + +Banks are read-only by definition during render consumption. The worker MUST NOT copy entire banks into submissions. The worker MUST NOT require bank snapshots. The worker MUST NOT require `Arc` as part of the public contract. + +Implementation may use any internal storage strategy that satisfies the public contract, but the render worker contract is ids plus read-only access. + +Resource installation, mutation, and residency changes remain outside in-flight render consumption. + +### 8. Backend and host presentation split + +The worker backend SHALL consume `RenderSubmission` plus read-only resource access and produce `OwnedRgba8888Frame`. + +The host event loop SHALL upload/present the latest published frame through its native API. + +The worker MUST NOT call native window present directly unless a future decision revises the host presentation model. + +### 9. Typed error model + +The worker work SHALL introduce a minimal typed error model, such as `RenderWorkerError`. + +The error model MUST cover at least: + +- backend unavailable; +- render failed; +- publish/present handoff failed; +- shutdown timeout; +- stale submission discarded; +- worker panic captured as internal failure. + +Panic containment MAY remain as a safety net. Ordinary worker/backend failure MUST NOT rely on panic as the normal reporting path. + +### 10. Telemetry + +Worker telemetry SHALL preserve and extend the existing render telemetry model. + +At minimum, telemetry SHOULD include: + +- submissions produced; +- pending submissions replaced/dropped; +- submissions consumed; +- frames published/presented; +- stale submissions discarded; +- render failures; +- repeated-frame count; +- shutdown timeout count. + +Telemetry MUST NOT change VM semantics. + +### 11. Test contract + +The worker contract MUST be proven without a native window. + +Tests SHALL use deterministic synchronization primitives such as barriers and condvars, not timing sleeps as the primary proof mechanism. + +The test matrix MUST prove: + +- VM producer does not block when worker rasterization is held; +- latest-wins replacement occurs while a frame is in flight; +- stale owner/epoch prevents publication; +- shutdown is bounded; +- typed errors and telemetry are emitted; +- repeat uses the last published `OwnedRgba8888Frame`; +- fake/local backend behavior matches the contract before desktop integration. + +### 12. Final scope + +The implementation MAY be split into multiple plans. + +However, the agenda is not complete until the real host path uses the worker. A fake/local backend is required for contract tests, but it is not sufficient as the final state of `AGD-0043`. + +## Impactos + +### Spec + +Runtime specs must document: + +- `OwnedRgba8888Frame`; +- the thread-safe single-slot latest-wins worker handoff; +- the worker/host presentation split; +- read-only bank access by id; +- shutdown and typed error behavior; +- telemetry expectations. + +### Runtime + +`prometeu-system` must add the worker controller and integrate it with `RenderManager`. + +The VM tick path must submit render work without blocking on worker consumption. + +### HAL + +`prometeu-hal` must expose shared worker contracts: + +- owned RGBA8888 frame type; +- render resource read-only access traits; +- worker/backend error types as needed. + +### Drivers + +`prometeu-drivers` must provide fake/local implementations suitable for deterministic tests and non-window integration. + +Concrete local rendering may continue to use existing GFX machinery internally, but must expose the worker-facing contract without leaking `&mut Hardware`, `&mut Gfx`, or live `FrameComposer`. + +### Host + +The desktop host must integrate the real worker path and upload/present the latest published `OwnedRgba8888Frame` through its native window backend. + +The host owns native presentation; the worker owns render consumption and frame publication. + +### Tests + +Tests must cover concurrency behavior deterministically and must include final host-path integration evidence. + +## Referencias + +- `AGD-0043`: Real Render Worker Establishment. +- `AGD-0042`: Host Hardware and Render Boundary Preparation. +- `DEC-0031`: VM and Render Parallel Execution Boundary. +- `DEC-0032`: Platform Layer and HardwareBridge Elimination. +- `LSN-0048`: Render Workers Need a Closed Packet Contract. +- `docs/specs/runtime/04-gfx-peripheral.md`. +- `docs/specs/runtime/11-portability-and-cross-platform-execution.md`. + +## Propagacao Necessaria + +Create implementation plans before editing specs or code. + +Recommended plan sequence: + +1. define `OwnedRgba8888Frame`, read-only bank access contracts, and worker error types in HAL; +2. introduce the thread-safe latest-wins handoff and deterministic fake/local worker tests; +3. implement worker controller lifecycle, stop token, bounded shutdown, pending/in-flight separation, and telemetry in `prometeu-system`; +4. implement fake/local backend that consumes `RenderSubmission` and produces `OwnedRgba8888Frame`; +5. integrate runtime render submission path with the worker without blocking VM ticks; +6. add stale owner/epoch discard and repeat-last-published-frame behavior; +7. integrate desktop host upload/present from the latest published `OwnedRgba8888Frame`; +8. update specs and final validation tests. + +## Revision Log + +- 2026-06-15: Initial decision draft generated from accepted `AGD-0043`.