docs/waves/engine_host_frame_work_items.md
Engine-Host Frame Migration Work Items
Purpose: execution board for migrating Waves runtime/host integration to EngineFrame + EngineInputEvent.
Status keys:
todoin-progressblockeddone
Archive:
docs/waves/ENGINE_HOST_FRAME_WORK_ITEMS_ARCHIVE.md
Program Guardrails
- Keep changes layered:
- engine runtime logic in
engine-wasm/ - host rendering/input wiring in
browser/andengine-wasm/host-sample/ - no WBXML parsing in host TypeScript
- Contract-first policy:
- update contract surfaces before implementation cutover
- keep native and wasm behavior aligned
- Determinism policy:
- preserve deterministic navigation, focus, and frame output ordering
- no host-timing dependent layout logic
- Scope policy:
- no broad refactor bundles; deliver phased, testable slices
Ticket Template
IDStatusDepends OnFilesBuildTestsAcceptNotes(optional)
Phase F0: Contract and API Introduction
F0-01 Define canonical frame/input contract types
Status:doneDepends On: noneFiles:
engine-wasm/engine/src/render/*engine-wasm/contracts/wml-engine.tsbrowser/src-tauri/src/contract_types.rsbrowser/src-tauri/src/bin/generate_contracts.rs
Build:
- Add additive types for:
EnginePresentationFramewith ordered rows/segments, focus/selection, and affordancesEngineInputEvent
- Keep the Tauri-owned
EngineFrameonly as a transitional snapshot/render/presentation envelope. - Defer
EngineCommand; no command queue was required for the stable F0 boundary. - Keep legacy
RenderListcontract available.
Tests:
- contract generation succeeds
- TypeScript compile in
browser/frontend
Accept:
- New frame/input types are exported in Rust and TS contracts without breaking current hosts.
Notes:
- WBP-06 v1 uses engine-owned
EnginePresentationFrameandEngineInputEventDTOs. The host-ownedEngineFrameremains a transitional envelope containing snapshot, legacy render output, and the canonical presentation payload; it does not own presentation semantics. - Logical
primary,task, andbackassociations avoid vendor-specific physical key claims.
F0-02 Add additive engine APIs with compatibility wrappers
Status:doneDepends On:F0-01Files:
engine-wasm/engine/src/lib.rsengine-wasm/contracts/wml-engine.tsbrowser/src-tauri/src/lib.rsbrowser/contracts/generated/engine-host.ts
Build:
- Add:
renderFrame()handleInput(event)
- Keep:
render()handleKey()
- Implement wrapper behavior so outputs stay equivalent for key-only flow.
Tests:
cd engine-wasm/engine && cargo testcd browser/src-tauri && cargo test
Accept:
- Old and new APIs return equivalent behavior for existing fixtures and key sequences.
Notes:
- Native and WASM
renderFrame()/handleInput()share the legacy layout, key, and task execution paths. Action activation is bound to the current frame identity and rejects stale input before mutation.
F0-03 Contract drift guardrails for frame/input interfaces
Status:doneDepends On:F0-01Files:
scripts/(new contract drift check).github/workflows/*docs/waves/CONTRACT_REQUIREMENTS_MAPPING.md
Build:
- Add CI check that generated TS contracts are in sync with Rust contract types.
Tests:
- intentional drift causes CI/check failure
Accept:
- contract changes cannot merge with stale generated outputs.
Notes:
- The existing CI
contracts:checklanes now regenerate the frame/input Rust projections for bothengine-wasm/contracts/generated/runtime-dtos.tsand browser host/command contracts. The Tauri generated schema gate covers the added command allowlist.
Phase F1: Host Rendering Migration
F1-01 WASM host sample frame renderer adoption
Status:doneDepends On:F0-02Files:
engine-wasm/host-sample/renderer.tsengine-wasm/host-sample/main.tsengine-wasm/README.md
Build:
- Consume
renderFrame()and draw from frame contract. - Keep behavior and appearance stable.
Tests:
- host sample manual fixture checks
Accept:
- sample no longer depends on legacy
RenderListcall path.
Notes:
- Implemented by PR
#519; the host sample now consumesrenderFrame()presentation rows while retaining equivalent focus and softkey behavior.
F1-02 Tauri frontend viewport migration to Canvas2D
Status:doneDepends On:F0-02Files:
browser/frontend/src/app/browser-shell-template.tsbrowser/frontend/src/app/browser-presenter.tsbrowser/frontend/src/styles.cssbrowser/frontend/src/app/browser-presenter.test.ts
Build:
- replace HTML line injection viewport path with canvas renderer adapter.
- preserve skeleton, status, and timeline UX.
Tests:
pnpm --dir browser/frontend testpnpm --dir browser/frontend build
Accept:
- viewport rendering no longer uses
innerHTMLfor deck content. - draw output parity remains stable for local fixtures.
Notes:
- Implemented by PR
#520; the Tauri frontend uses the Canvas2D renderer and a synchronized semantic viewport projection for accessibility and deterministic test harnesses. - PR
#527subsequently added the defensive host-output cap and single-pass bounded engine frame construction without reopening this completed migration ticket.
F1-03 Navigation-state integration with frame rendering
Status:doneDepends On:F1-02Files:
browser/frontend/src/app/navigation-state.tsbrowser/frontend/src/app/browser-controller.tsbrowser/frontend/src/app/navigation-state.test.ts
Build:
- keep render/snapshot sequencing deterministic with
engineRenderFrame.
Tests:
- navigation-state tests cover render-after-load and render-after-input ordering.
Accept:
- no regressions in load/fetch/back/external-intent flows.
Notes:
NavigationHooks.onFrameis the single committed-frame publication boundary; snapshot and render projections come from the same acceptedEngineFrame.- Load, input, Back, timer, and clear-intent paths consume the existing atomic frame-returning host APIs. Generation checks suppress cancelled and stale completions before publication.
- Host-history Back stages its deck load and optional card restoration, then publishes only the final restored frame.
- Focused sequencing evidence is in
navigation-state.frame.test.tsandbrowser-controller.timer.test.ts; the existing navigation/controller suites retain local, network, reload, same-deck, Back, cancellation, and external-intent coverage.
Phase F2: Input Event Expansion
F2-01 Add click event path with deterministic hit resolution
Status:doneDepends On:F0-02Files:
engine-wasm/engine/src/lib.rsengine-wasm/engine/src/layout/*browser/frontend/src/app/browser-controller.tsengine-wasm/host-sample/main.ts
Build:
- add host click ->
EngineInputEvent::Clickrouting. - engine resolves click through frame/hit regions, not host-side link lookup.
Tests:
- engine fixture tests for click-target determinism
- host integration tests for click navigation
Accept:
- click activation behavior matches keyboard activation targets.
Notes:
- Frame contract version 2 adds ordered half-open logical hit regions and frame-bound
EngineInputEvent::Click { frameId, x, y }. The engine resolves the advertisedfocus:*action and retains stale-frame rejection before mutation. - Canvas and host-sample adapters convert scaled pointer pixels into the engine column/row grid
without link, control, or WML lookup. Wrapped links, input/select controls, empty space,
boundaries, frame mismatch, native/WASM parity, and keyboard-equivalent outcomes are covered by
focused tests and the
F2-01executable story.
F2-02 Add scroll event path and viewport offset semantics
Status:doneDepends On:F2-01Files:
engine-wasm/engine/src/lib.rsengine-wasm/contracts/wml-engine.tsbrowser/frontend/src/app/browser-controller.ts
Build:
- support
EngineInputEvent::Scroll. - define deterministic scroll clamping and frame offset behavior.
Tests:
- scroll boundary and repeatability tests in engine.
Accept:
- identical event traces produce identical visible frame windows.
Notes:
- Frame contract version 3 adds a neutral 20-row Class C reference window with
offsetRowandcontentRows; presentation rows and hit regions are projected relative to the visible window. EngineInputEvent::Scroll { frameId, deltaRows }is stale-frame protected and clamps signed row deltas to the content bounds. Browser and host-sample wheel adapters normalize each physical wheel event to one row without inspecting deck content.- Native boundary, repeatability, click-after-scroll, browser integration, and the
F2-02executable story cover the acceptance path.
F2-03 Softkey/input abstraction alignment
Status:doneDepends On:F2-01Files:
browser/frontend/src/app/keyboard.tsbrowser/frontend/src/app/browser-controller.tsengine-wasm/contracts/wml-engine.ts
Build:
- map host keyboard/buttons into unified
EngineInputEventpath. - keep legacy key APIs as compatibility layer until cutover.
Tests:
- keyboard and control-button regression tests.
Accept:
- single input abstraction path is used in host application code.
Notes:
- Browser keyboard intents and the Up, Select, and Down controls now construct
EngineInputEvent::Keyand use the same local/networkhandleInputframe path as pointer input. - The native/WASM
handleKeymethods and navigation-state key adapter remain compatibility surfaces until F4; primary browser-controller code no longer calls them. - Browser integration coverage asserts physical keyboard and control-button parity, the absence of
legacy key-command calls, direct committed-frame publication, and existing failure/cancellation
behavior. The
F2-03Waves executable story covers button and keyboard sources.
Phase F3: Engine Internal Boundary Split
F3-01 Separate layout and paint phases
Status:todoDepends On:F0-02Files:
engine-wasm/engine/src/layout/*engine-wasm/engine/src/render/*engine-wasm/engine/src/lib.rs
Build:
- move draw-command emission into paint pass over layout output.
- preserve current command ordering and focus semantics.
Tests:
- existing render snapshot tests
- new tests for layout-output determinism independent from paint
Accept:
- layout and paint responsibilities are explicit and test-covered.
F3-02 Frame snapshot parity harness (native + wasm)
Status:todoDepends On:F3-01Files:
engine-wasm/engine/src/lib.rsengine-wasm/engine/tests/*(new if needed)docs/waves/SPEC_TEST_COVERAGE.md
Build:
- add parity-critical snapshots for
renderFrameand input traces.
Tests:
cd engine-wasm/engine && cargo test
Accept:
- frame and navigation parity is verified across targets for critical flows.
Phase F4: Cutover and Legacy Removal
F4-01 Remove legacy render/input API from host paths
Status:todoDepends On:F1-03,F2-03,F3-02Files:
browser/frontend/src/*engine-wasm/host-sample/*browser/contracts/generated/*engine-wasm/contracts/wml-engine.ts
Build:
- stop calling legacy
render()/handleKey()in host code. - retain compatibility only where needed for transition windows.
Tests:
- browser frontend tests/build
- host-sample smoke checks
Accept:
- all active hosts run on frame/input API path.
F4-02 Legacy contract and wrapper removal (final)
Status:todoDepends On:F4-01Files:
engine-wasm/engine/src/lib.rsengine-wasm/contracts/wml-engine.tsbrowser/src-tauri/src/contract_types.rsbrowser/src-tauri/src/bin/generate_contracts.rs- docs references to legacy API
Build:
- remove legacy
RenderList/DrawCmdwrappers and key-only APIs when no longer used.
Tests:
- engine, browser frontend, and tauri host tests/builds
Accept:
- contract surface is single-path (
EngineFrame+EngineInputEvent) and documented.
Program Tracking
Cross-reference docs:
- migration architecture:
docs/waves/ENGINE_HOST_FRAME_MIGRATION_PLAN.md - waves integration board:
docs/waves/WORK_ITEMS.md - maintenance board:
docs/waves/MAINTENANCE_WORK_ITEMS.md
Completion gate:
- all
F0-F4tickets markeddone - parity gates in
docs/waves/SPEC_TEST_COVERAGE.mdupdated and passing - contract mapping updated in
docs/waves/CONTRACT_REQUIREMENTS_MAPPING.md