prometeu-runtime/discussion/workflow/plans/PLN-0122-unify-render-worker-publication-store.md
bQUARKz 506eb36786
All checks were successful
Intrepid/Prometeu/Runtime/pipeline/pr-master This commit looks good
Real Render Worker Establishment
2026-06-20 09:16:38 +01:00

129 lines
7.3 KiB
Markdown

---
id: PLN-0122
ticket: real-render-worker-establishment
title: Unify Render Worker Publication Store
status: done
created: 2026-06-20
completed: 2026-06-20
ref_decisions: [DEC-0033]
tags: [runtime, renderer, worker, host, publication]
---
## Objective
Make worker frame publication have one observable authority by moving latest published frame storage behind the `RenderWorkerFrameSink` implementation used by the desktop host.
## Background
`DEC-0033` requires the worker to publish owned `OwnedRgba8888Frame` values while the host event loop remains responsible for native upload and present. The current desktop integration starts the worker with a host sink that accepts frames but discards them, while host presentation reads the latest frame from `RenderWorkerController`.
That works mechanically, but it weakens the publication model: the sink is not the observable publication boundary, and the controller becomes both lifecycle owner and frame store. This plan tightens the implementation without changing the DEC-0033 architecture.
## Scope
### Included
- Introduce an explicit latest-frame publication store that implements `RenderWorkerFrameSink`.
- Make the desktop host pass that store to the worker and read frames from the same store for upload/present.
- Keep native upload and present in the host event loop.
- Keep `RenderWorkerController` responsible for worker lifecycle, handoff, shutdown, typed errors, and telemetry.
- Preserve repeat-latest-frame semantics using the stored `OwnedRgba8888Frame`.
- Add tests proving the sink/store is the observable publication authority.
### Excluded
- No change to worker scheduling, latest-wins handoff, or AppMode render policy.
- No change to `OwnedRgba8888Frame` layout or pixel format.
- No native window, pixels, winit, SDL, swapchain, or texture dependency inside worker/runtime crates.
- No move of native present into the worker thread.
## Execution Steps
### Step 1 - Add latest-frame store contract
**What:** Add a small thread-safe store for the latest published `OwnedRgba8888Frame`.
**How:** Implement a `RenderWorkerFrameSink` storage type using a lock-protected `Option<OwnedRgba8888Frame>`. It must provide read APIs for `latest_frame()` and `repeat_latest_frame()` or equivalent names that make host presentation read from the same publication authority used by `publish()`.
**File(s):** `crates/console/prometeu-hal/src/render_worker.rs` or `crates/console/prometeu-system/src/services/vm_runtime/render_worker.rs`, depending on whether the store is shared as a HAL utility or kept runtime/host integration-local.
### Step 2 - Remove controller-owned latest frame storage
**What:** Stop treating `RenderWorkerController` as the frame publication store.
**How:** Remove or narrow `latest_published_frame` from controller state. `record_published` should update telemetry and rely on the sink/store for frame retention. Controller APIs that expose latest frames should either be removed or delegated explicitly to the publication store so there is not a second authoritative copy.
**File(s):** `crates/console/prometeu-system/src/services/vm_runtime/render_worker.rs`, `crates/console/prometeu-system/src/services/vm_runtime/lifecycle.rs`, `crates/console/prometeu-system/src/os/facades/vm.rs`.
### Step 3 - Wire desktop host to the publication store
**What:** Replace the no-op desktop sink with a real store-backed sink.
**How:** Add the store as host runner state, pass a clone to `start_render_worker`, and update redraw/presentation logic to read latest/repeated frames from that store. Delete the sink implementation that discards frames.
**File(s):** `crates/host/prometeu-host-desktop-winit/src/runner.rs`.
### Step 4 - Preserve host presentation split
**What:** Keep upload/present in the winit event loop while publication remains worker-owned.
**How:** Continue copying RGBA8888 pixels into the existing `pixels` frame only from `WindowEvent::RedrawRequested`. The store must contain owned memory only and must not expose native host resources to worker/runtime code.
**File(s):** `crates/host/prometeu-host-desktop-winit/src/runner.rs`, `crates/host/prometeu-host-desktop-winit/src/utilities.rs` if helper changes are needed.
### Step 5 - Add focused tests
**What:** Prove one-publication-authority behavior.
**How:** Add tests that publish through the sink and read the same frame through the store, prove repeat uses the stored frame without rendering again, and prove desktop presentation state observes store publication rather than controller-private storage.
**File(s):** `crates/console/prometeu-system/src/services/vm_runtime/render_worker.rs`, `crates/host/prometeu-host-desktop-winit/src/runner.rs`, and any new store module tests.
## Test Requirements
### Unit Tests
- Store publishes and returns the latest `OwnedRgba8888Frame`.
- Multiple publishes keep only the newest frame observable.
- Repeat returns the stored frame and records repeat telemetry through the existing runtime path.
- Controller publication telemetry remains correct after frame retention moves to the sink/store.
### Integration Tests
- `cargo test -p prometeu-system`
- `cargo test -p prometeu-host-desktop-winit`
- `cargo test -p prometeu-hal` if the store lives in HAL.
### Manual Verification
- Run the desktop host with a simple game cartridge and verify the host presents worker-produced frames.
## Acceptance Criteria
- [x] Desktop host no longer uses a no-op `RenderWorkerFrameSink` that discards frames.
- [x] The same sink/store that receives `publish(frame)` is the source used by host presentation.
- [x] `RenderWorkerController` no longer owns an independent authoritative latest-frame store.
- [x] Worker/runtime crates remain free of native window and presentation APIs.
- [x] Existing worker lifecycle, shutdown, stale epoch, repeat, and telemetry tests pass.
- [x] Focused host tests prove the real publication store drives redraw/presentation.
## Dependencies
- `DEC-0033` remains the governing decision.
- `PLN-0118` repeat/stale behavior and `PLN-0119` desktop presentation integration are the implementation context being tightened.
## Risks
- Moving frame retention out of the controller can accidentally split repeat telemetry from host presentation; keep repeat accounting in one explicit runtime path.
- Placing the store in HAL may overexpose a host convenience type; placing it in system may require a narrower host-facing API. Choose the smallest layer that avoids circular dependencies and keeps DEC-0033 boundaries intact.
- Holding a mutex while copying pixels into the host frame would increase present latency; clone or take the owned frame before doing host upload work.
## Validation Evidence
- `cargo fmt --check`: passed.
- `cargo test -p prometeu-system -p prometeu-host-desktop-winit`: passed.
- `cargo test --workspace`: passed.
- Publication residue scan: no `HostWorkerFrameSink`, `latest_render_worker_frame`, `repeat_latest_render_worker_frame`, controller `latest_published_frame` storage API, or `repeat_latest_frame` API remains in production crates.
- Native presentation dependency scan: worker/runtime console code remains free of native window/presentation APIs; matches containing `pixels` are HAL pixel field names, not `pixels`/winit host APIs.
- Manual desktop window run was not performed in this environment; `host_presentation_observes_worker_publication_store` covers the host publication/redraw boundary without native window setup.