VM Context Ownership for Resident Game and VM-Backed Shell

This commit is contained in:
bQUARKz 2026-07-05 00:16:50 +01:00
parent e01b463e1f
commit 8098dbd7f4
Signed by: bquarkz
SSH Key Fingerprint: SHA256:Z7dgqoglWwoK6j6u4QC87OveEq74WOhFN+gitsxtkf8
4 changed files with 282 additions and 2 deletions

View File

@ -1,8 +1,8 @@
{"type":"meta","next_id":{"DSC":44,"AGD":47,"DEC":39,"PLN":154,"LSN":52,"CLSN":1}} {"type":"meta","next_id":{"DSC":44,"AGD":47,"DEC":39,"PLN":157,"LSN":52,"CLSN":1}}
{"type":"discussion","id":"DSC-0043","status":"open","ticket":"system-os-cartridge-switch-orchestrator","title":"SystemOS Cartridge Switch Orchestrator","created_at":"2026-07-03","updated_at":"2026-07-03","tags":["runtime","os","lifecycle","game","cartridge","architecture"],"agendas":[{"id":"AGD-0044","file":"AGD-0044-systemos-cartridge-switch-orchestrator.md","status":"open","created_at":"2026-07-03","updated_at":"2026-07-03"}],"decisions":[],"plans":[],"lessons":[]} {"type":"discussion","id":"DSC-0043","status":"open","ticket":"system-os-cartridge-switch-orchestrator","title":"SystemOS Cartridge Switch Orchestrator","created_at":"2026-07-03","updated_at":"2026-07-03","tags":["runtime","os","lifecycle","game","cartridge","architecture"],"agendas":[{"id":"AGD-0044","file":"AGD-0044-systemos-cartridge-switch-orchestrator.md","status":"open","created_at":"2026-07-03","updated_at":"2026-07-03"}],"decisions":[],"plans":[],"lessons":[]}
{"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-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-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":"in_progress","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-07-04","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":"accepted","created_at":"2026-06-05","updated_at":"2026-07-03"},{"id":"AGD-0046","file":"AGD-0046-vm-context-ownership-for-resident-game-and-vm-backed-shell.md","status":"accepted","created_at":"2026-07-04","updated_at":"2026-07-04"}],"decisions":[{"id":"DEC-0037","file":"DEC-0037-foreground-stack-and-game-pause-contract.md","status":"accepted","created_at":"2026-07-03","updated_at":"2026-07-03","ref_agenda":"AGD-0041"},{"id":"DEC-0038","file":"DEC-0038-vm-session-ownership-for-vm-backed-processes.md","status":"accepted","created_at":"2026-07-04","updated_at":"2026-07-04","ref_agenda":"AGD-0046"}],"plans":[{"id":"PLN-0136","file":"PLN-0136-route-desktop-home-key-outside-guest-input.md","status":"done","created_at":"2026-07-03","updated_at":"2026-07-03","ref_decisions":["DEC-0037"]},{"id":"PLN-0137","file":"PLN-0137-implement-systemos-foreground-stack-state.md","status":"done","created_at":"2026-07-03","updated_at":"2026-07-03","ref_decisions":["DEC-0037"]},{"id":"PLN-0138","file":"PLN-0138-specify-foreground-pause-and-home-contract.md","status":"done","created_at":"2026-07-03","updated_at":"2026-07-03","ref_decisions":["DEC-0037"]},{"id":"PLN-0139","file":"PLN-0139-validate-game-home-shell-game-end-to-end.md","status":"done","created_at":"2026-07-03","updated_at":"2026-07-03","ref_decisions":["DEC-0037"]},{"id":"PLN-0140","file":"PLN-0140-deliver-game-pause-resume-and-suspension.md","status":"done","created_at":"2026-07-03","updated_at":"2026-07-03","ref_decisions":["DEC-0037"]},{"id":"PLN-0141","file":"PLN-0141-integrate-render-audio-and-input-pause-boundaries.md","status":"done","created_at":"2026-07-03","updated_at":"2026-07-03","ref_decisions":["DEC-0037"]},{"id":"PLN-0142","file":"PLN-0142-deliver-game-lifecycle-events-to-vm-runtime.md","status":"done","created_at":"2026-07-04","updated_at":"2026-07-04","ref_decisions":["DEC-0037"]},{"id":"PLN-0143","file":"PLN-0143-guarantee-cooperative-pause-budget-tick-before-suspension.md","status":"done","created_at":"2026-07-04","updated_at":"2026-07-04","ref_decisions":["DEC-0037"]},{"id":"PLN-0144","file":"PLN-0144-suspend-resident-game-when-shell-takes-foreground.md","status":"done","created_at":"2026-07-04","updated_at":"2026-07-04","ref_decisions":["DEC-0037"]},{"id":"PLN-0145","file":"PLN-0145-centralize-resident-game-resume-transition.md","status":"done","created_at":"2026-07-04","updated_at":"2026-07-04","ref_decisions":["DEC-0037"]},{"id":"PLN-0146","file":"PLN-0146-consolidate-lifecycle-process-lookup-helpers.md","status":"done","created_at":"2026-07-04","updated_at":"2026-07-04","ref_decisions":["DEC-0037"]},{"id":"PLN-0147","file":"PLN-0147-move-native-shell-profile-update-into-hub.md","status":"done","created_at":"2026-07-04","updated_at":"2026-07-04","ref_decisions":["DEC-0037"]},{"id":"PLN-0148","file":"PLN-0148-introduce-vm-session-registry-and-identity.md","status":"done","created_at":"2026-07-04","updated_at":"2026-07-04","ref_decisions":["DEC-0038"]},{"id":"PLN-0149","file":"PLN-0149-move-vm-runtime-state-into-vm-sessions.md","status":"done","created_at":"2026-07-04","updated_at":"2026-07-04","ref_decisions":["DEC-0038"]},{"id":"PLN-0150","file":"PLN-0150-route-cartridge-loading-through-vm-sessions.md","status":"done","created_at":"2026-07-04","updated_at":"2026-07-04","ref_decisions":["DEC-0038"]},{"id":"PLN-0151","file":"PLN-0151-schedule-foreground-vm-session-ticks.md","status":"done","created_at":"2026-07-04","updated_at":"2026-07-04","ref_decisions":["DEC-0038"]},{"id":"PLN-0152","file":"PLN-0152-validate-game-and-vm-shell-session-coexistence.md","status":"done","created_at":"2026-07-04","updated_at":"2026-07-04","ref_decisions":["DEC-0038"]},{"id":"PLN-0153","file":"PLN-0153-specify-vm-session-ownership-and-background-ready-scheduling.md","status":"done","created_at":"2026-07-04","updated_at":"2026-07-04","ref_decisions":["DEC-0038"]}],"lessons":[]} {"type":"discussion","id":"DSC-0041","status":"in_progress","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-07-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":"accepted","created_at":"2026-06-05","updated_at":"2026-07-03"},{"id":"AGD-0046","file":"AGD-0046-vm-context-ownership-for-resident-game-and-vm-backed-shell.md","status":"accepted","created_at":"2026-07-04","updated_at":"2026-07-04"}],"decisions":[{"id":"DEC-0037","file":"DEC-0037-foreground-stack-and-game-pause-contract.md","status":"accepted","created_at":"2026-07-03","updated_at":"2026-07-03","ref_agenda":"AGD-0041"},{"id":"DEC-0038","file":"DEC-0038-vm-session-ownership-for-vm-backed-processes.md","status":"accepted","created_at":"2026-07-04","updated_at":"2026-07-04","ref_agenda":"AGD-0046"}],"plans":[{"id":"PLN-0136","file":"PLN-0136-route-desktop-home-key-outside-guest-input.md","status":"done","created_at":"2026-07-03","updated_at":"2026-07-03","ref_decisions":["DEC-0037"]},{"id":"PLN-0137","file":"PLN-0137-implement-systemos-foreground-stack-state.md","status":"done","created_at":"2026-07-03","updated_at":"2026-07-03","ref_decisions":["DEC-0037"]},{"id":"PLN-0138","file":"PLN-0138-specify-foreground-pause-and-home-contract.md","status":"done","created_at":"2026-07-03","updated_at":"2026-07-03","ref_decisions":["DEC-0037"]},{"id":"PLN-0139","file":"PLN-0139-validate-game-home-shell-game-end-to-end.md","status":"done","created_at":"2026-07-03","updated_at":"2026-07-03","ref_decisions":["DEC-0037"]},{"id":"PLN-0140","file":"PLN-0140-deliver-game-pause-resume-and-suspension.md","status":"done","created_at":"2026-07-03","updated_at":"2026-07-03","ref_decisions":["DEC-0037"]},{"id":"PLN-0141","file":"PLN-0141-integrate-render-audio-and-input-pause-boundaries.md","status":"done","created_at":"2026-07-03","updated_at":"2026-07-03","ref_decisions":["DEC-0037"]},{"id":"PLN-0142","file":"PLN-0142-deliver-game-lifecycle-events-to-vm-runtime.md","status":"done","created_at":"2026-07-04","updated_at":"2026-07-04","ref_decisions":["DEC-0037"]},{"id":"PLN-0143","file":"PLN-0143-guarantee-cooperative-pause-budget-tick-before-suspension.md","status":"done","created_at":"2026-07-04","updated_at":"2026-07-04","ref_decisions":["DEC-0037"]},{"id":"PLN-0144","file":"PLN-0144-suspend-resident-game-when-shell-takes-foreground.md","status":"done","created_at":"2026-07-04","updated_at":"2026-07-04","ref_decisions":["DEC-0037"]},{"id":"PLN-0145","file":"PLN-0145-centralize-resident-game-resume-transition.md","status":"done","created_at":"2026-07-04","updated_at":"2026-07-04","ref_decisions":["DEC-0037"]},{"id":"PLN-0146","file":"PLN-0146-consolidate-lifecycle-process-lookup-helpers.md","status":"done","created_at":"2026-07-04","updated_at":"2026-07-04","ref_decisions":["DEC-0037"]},{"id":"PLN-0147","file":"PLN-0147-move-native-shell-profile-update-into-hub.md","status":"done","created_at":"2026-07-04","updated_at":"2026-07-04","ref_decisions":["DEC-0037"]},{"id":"PLN-0148","file":"PLN-0148-introduce-vm-session-registry-and-identity.md","status":"done","created_at":"2026-07-04","updated_at":"2026-07-04","ref_decisions":["DEC-0038"]},{"id":"PLN-0149","file":"PLN-0149-move-vm-runtime-state-into-vm-sessions.md","status":"done","created_at":"2026-07-04","updated_at":"2026-07-04","ref_decisions":["DEC-0038"]},{"id":"PLN-0150","file":"PLN-0150-route-cartridge-loading-through-vm-sessions.md","status":"done","created_at":"2026-07-04","updated_at":"2026-07-04","ref_decisions":["DEC-0038"]},{"id":"PLN-0151","file":"PLN-0151-schedule-foreground-vm-session-ticks.md","status":"done","created_at":"2026-07-04","updated_at":"2026-07-04","ref_decisions":["DEC-0038"]},{"id":"PLN-0152","file":"PLN-0152-validate-game-and-vm-shell-session-coexistence.md","status":"done","created_at":"2026-07-04","updated_at":"2026-07-04","ref_decisions":["DEC-0038"]},{"id":"PLN-0153","file":"PLN-0153-specify-vm-session-ownership-and-background-ready-scheduling.md","status":"done","created_at":"2026-07-04","updated_at":"2026-07-04","ref_decisions":["DEC-0038"]},{"id":"PLN-0154","file":"PLN-0154-route-debugger-operations-through-vm-sessions.md","status":"open","created_at":"2026-07-05","updated_at":"2026-07-05","ref_decisions":["DEC-0038"]},{"id":"PLN-0155","file":"PLN-0155-retire-legacy-firmware-vm-runtime-bridge.md","status":"open","created_at":"2026-07-05","updated_at":"2026-07-05","ref_decisions":["DEC-0038"]},{"id":"PLN-0156","file":"PLN-0156-harden-vm-session-lifecycle-error-boundaries.md","status":"open","created_at":"2026-07-05","updated_at":"2026-07-05","ref_decisions":["DEC-0038"]}],"lessons":[]}
{"type":"discussion","id":"DSC-0042","status":"done","ticket":"real-render-worker-establishment","title":"Real Render Worker Establishment","created_at":"2026-06-06","updated_at":"2026-06-20","tags":["runtime","renderer","worker","concurrency","host","hal","architecture"],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0049","file":"discussion/lessons/DSC-0042-real-render-worker-establishment/LSN-0049-render-worker-publication-boundary.md","status":"done","created_at":"2026-06-20","updated_at":"2026-06-20"}]} {"type":"discussion","id":"DSC-0042","status":"done","ticket":"real-render-worker-establishment","title":"Real Render Worker Establishment","created_at":"2026-06-06","updated_at":"2026-06-20","tags":["runtime","renderer","worker","concurrency","host","hal","architecture"],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0049","file":"discussion/lessons/DSC-0042-real-render-worker-establishment/LSN-0049-render-worker-publication-boundary.md","status":"done","created_at":"2026-06-20","updated_at":"2026-06-20"}]}
{"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-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-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"}]}

View File

@ -0,0 +1,95 @@
---
id: PLN-0154
ticket: foreground-stack-game-pause-shell-vm-backed
title: Route Debugger Operations Through VM Sessions
status: open
created: 2026-07-05
ref_decisions: [DEC-0038]
tags: [runtime, os, lifecycle, shell, game, vm, foreground, architecture]
---
## Briefing
DEC-0038 requires VM-backed mutable execution state to be owned by VM sessions. Normal execution now ticks session-owned VMs, but desktop debugger commands still inspect and mutate `firmware.vm`, the transitional legacy VM. This leaves debugger state, breakpoints, single-step execution, PC snapshots, and stack snapshots inconsistent with the active VM session.
## Objective
Route host debugger operations through the active VM session rather than the legacy firmware VM. Debugger pause/resume/step/state/breakpoint operations must target the same VM context that foreground execution ticks.
## Dependencies
- Source decision: DEC-0038.
- Builds on PLN-0148 through PLN-0152.
- Should be implemented before PLN-0155 removes the legacy firmware VM bridge.
## Scope
- Add session-aware debugger accessors to `SystemOS`/`VmFacade`.
- Expose active VM session inspection and mutation operations needed by the debugger:
- PC;
- operand stack preview;
- insert breakpoint;
- remove breakpoint;
- list breakpoints;
- single-instruction debug step;
- active cartridge identity for handshake and state responses.
- Update `crates/host/prometeu-host-desktop-winit/src/debugger.rs` so it no longer reads or mutates `firmware.vm` for active VM state.
- Ensure debugger setup for direct debug boot initializes through normal cartridge/session loading or an explicit session-aware metadata path, not `os.vm().initialize(&mut firmware.vm, ...)`.
- Keep pause/resume/step-frame control mapped to active VM session runtime state.
- Add tests that would fail if debugger state came from the legacy VM while the session VM is active.
## Non-Goals
- Do not remove `Firmware.vm`; that is PLN-0155.
- Do not redesign the debugger protocol.
- Do not add multi-client debugging.
- Do not add background-session debugging beyond active/resident session semantics already supported by DEC-0038.
## Execution Method
1. Add focused `VmFacade` methods for active-session VM inspection:
- `active_pc`;
- `active_operand_stack_top`;
- `insert_active_breakpoint`;
- `remove_active_breakpoint`;
- `active_breakpoints_list`;
- `debug_step_active_session`.
2. Define active-session resolution explicitly:
- foreground VM session first;
- resident Game session when Hub has foreground but a resident Game is the active debug target;
- no legacy fallback for debugger mutation once a session exists.
3. Update `HostDebugger::setup_boot_target` so debug cartridge metadata is loaded without initializing `firmware.vm` as canonical state.
4. Update `HostDebugger::handle_command` for `Step`, `GetState`, `SetBreakpoint`, `ListBreakpoints`, and `ClearBreakpoint`.
5. Update `HostDebugger::stream_events` breakpoint-hit PC reporting to read from the active session.
6. Add tests under `crates/host/prometeu-host-desktop-winit/src/debugger.rs` proving debugger commands observe and mutate the session VM.
7. Run the host, firmware, and system test suites.
## Acceptance Criteria
- Debugger handshake reports cartridge identity from session/runtime state or preloaded metadata, not from a global VM initialized only for debugger setup.
- `GetState` returns PC and stack data from the active VM session.
- `Step` advances the active VM session, not `firmware.vm`.
- Breakpoint commands mutate the active VM session.
- Breakpoint-hit events report the active session PC.
- No debugger command path directly reads or mutates `firmware.vm` for active VM execution state.
- Existing debugger protocol tests pass.
## Tests
- `cargo test -p prometeu-host-desktop-winit`
- `cargo test -p prometeu-firmware`
- `cargo test -p prometeu-system`
- `cargo clippy -p prometeu-host-desktop-winit -p prometeu-firmware -p prometeu-system --all-targets -- -D warnings`
- Add tests for:
- `GetState` reads session VM PC;
- `Step` affects session VM;
- breakpoint insert/list/remove uses session VM;
- debugger setup does not initialize `firmware.vm` as the canonical app context.
## Affected Artifacts
- `crates/host/prometeu-host-desktop-winit/src/debugger.rs`
- `crates/console/prometeu-system/src/os/facades/vm.rs`
- `crates/console/prometeu-system/src/services/vm_session.rs`
- `crates/console/prometeu-firmware/src/firmware/firmware.rs`
- Debugger-related tests in host and firmware crates

View File

@ -0,0 +1,89 @@
---
id: PLN-0155
ticket: foreground-stack-game-pause-shell-vm-backed
title: Retire Legacy Firmware VM Runtime Bridge
status: open
created: 2026-07-05
ref_decisions: [DEC-0038]
tags: [runtime, os, lifecycle, shell, game, vm, foreground, architecture]
---
## Briefing
DEC-0038 states that `Firmware.vm` must not remain the canonical owner of VM-backed app context. PLN-0148 through PLN-0152 moved normal cartridge loading and ticking toward VM sessions, but a transitional legacy bridge still initializes and exposes the old global VM/runtime path for compatibility.
## Objective
Remove the legacy firmware VM/runtime bridge from normal runtime architecture. After this plan, VM-backed app execution, initialization, active runtime queries, and host-facing inspection must resolve through VM sessions or explicitly global render/runtime services.
## Dependencies
- Source decision: DEC-0038.
- Requires PLN-0154 so debugger operations no longer depend on `firmware.vm`.
- Builds on PLN-0148 through PLN-0153.
## Scope
- Remove `Firmware.vm` from `crates/console/prometeu-firmware/src/firmware/firmware.rs` if all callsites have migrated.
- Remove `PrometeuContext.vm` from `crates/console/prometeu-firmware/src/firmware/prometeu_context.rs`.
- Remove `legacy_vm` from `SessionsFacade::load_vm_cartridge`.
- Remove `initialize_legacy_active_vm`.
- Remove or narrow global `VmFacade::initialize`, `tick`, `reset`, and `debug_step_instruction` methods that operate on caller-supplied `VirtualMachine`.
- Keep global render ownership, render worker lifecycle, telemetry publication, and log service where they are global SystemOS responsibilities.
- Preserve Hub/Home rendering behavior while avoiding any guest VM state stored in firmware.
- Update direct boot, debug boot, reset, and load-cartridge tests to prove session ownership is the only app VM path.
## Non-Goals
- Do not remove `VirtualMachineRuntime` itself.
- Do not redesign render worker ownership.
- Do not add background execution.
- Do not change debugger protocol shape beyond the PLN-0154 migration.
## Execution Method
1. Use `rg` to list every remaining `firmware.vm`, `ctx.vm`, `legacy_vm`, and `os.vm().initialize/tick/reset/debug_step_instruction` callsite.
2. Replace firmware context construction so state steps receive `SystemOS`, Hub, signals, platform, and boot target only.
3. Replace reset behavior with session registry/runtime reset semantics:
- clear VM sessions on firmware reset when booting fresh;
- preserve only explicitly resident sessions during lifecycle flows, not reset.
4. Update cartridge loading to initialize only the selected VM session.
5. Split `VmFacade` into:
- session-targeted VM execution/inspection methods;
- global render/runtime authority methods.
6. Delete compatibility methods that accept `&mut VirtualMachine` when no remaining production callsite exists.
7. Add tests or assertions proving no production code path initializes or ticks a global firmware VM.
8. Run full affected test suites and clippy.
## Acceptance Criteria
- `Firmware` no longer owns `pub vm: VirtualMachine`.
- `PrometeuContext` no longer carries a VM reference.
- `LoadCartridgeStep` initializes only session-owned VM context.
- `GameRunningStep` and VM-backed `ShellRunningStep` tick only sessions.
- Debugger, stats, and host runner access active session state or global render services explicitly.
- `rg "firmware\\.vm|ctx\\.vm|legacy_vm|os\\.vm\\(\\)\\.initialize\\(|os\\.vm\\(\\)\\.tick\\("` finds no production runtime dependency on the legacy global VM path.
- Tests continue to prove Game resident + VM Shell coexistence.
## Tests
- `cargo test -p prometeu-system`
- `cargo test -p prometeu-firmware`
- `cargo test -p prometeu-host-desktop-winit`
- `cargo clippy -p prometeu-system -p prometeu-firmware -p prometeu-host-desktop-winit --all-targets -- -D warnings`
- Add or update tests for:
- reset clears session-owned VM contexts appropriately;
- direct boot creates session-owned VM context;
- debug boot uses session-owned VM context;
- no global VM tick path remains.
## Affected Artifacts
- `crates/console/prometeu-firmware/src/firmware/firmware.rs`
- `crates/console/prometeu-firmware/src/firmware/prometeu_context.rs`
- `crates/console/prometeu-firmware/src/firmware/firmware_step_*.rs`
- `crates/console/prometeu-system/src/os/facades/sessions.rs`
- `crates/console/prometeu-system/src/os/facades/vm.rs`
- `crates/host/prometeu-host-desktop-winit/src/debugger.rs`
- `crates/host/prometeu-host-desktop-winit/src/runner.rs`
- `crates/host/prometeu-host-desktop-winit/src/stats.rs`

View File

@ -0,0 +1,96 @@
---
id: PLN-0156
ticket: foreground-stack-game-pause-shell-vm-backed
title: Harden VM Session Lifecycle Error Boundaries
status: open
created: 2026-07-05
ref_decisions: [DEC-0038]
tags: [runtime, os, lifecycle, shell, game, vm, foreground, architecture]
---
## Briefing
DEC-0038 makes VM session services part of the runtime ownership boundary. Some current session creation paths still use `expect` for lifecycle failures and missing task/process/session invariants. That is acceptable for short-term scaffolding, but session services should expose typed errors at operational boundaries so callers can choose controlled crash, rejection, or recovery behavior.
## Objective
Replace operational `expect`/panic paths in VM session creation/loading with typed errors and controlled firmware outcomes. Keep internal invariant assertions only where impossible states have already been proven by prior checks.
## Dependencies
- Source decision: DEC-0038.
- Builds on PLN-0148 through PLN-0152.
- Can be implemented before or after PLN-0154.
- Should be implemented before broadening VM session scheduling or adding background-capable processes.
## Scope
- Add or extend typed errors for session/lifecycle operations:
- lifecycle rejection while creating Game/Shell task;
- missing task for session creation;
- missing process for session creation;
- duplicate session;
- VM-backed session missing during cartridge initialization;
- foreground Shell already exists.
- Convert `SessionsFacade::create_vm_shell_task` to a fallible equivalent and keep an infallible wrapper only for test/setup code if needed.
- Convert `create_vm_session_for_task` to avoid `expect` for task/process lookup.
- Convert `initialize_session_cartridge` to return typed missing-session errors instead of panicking.
- Map session/lifecycle errors into controlled `CrashReport` or launch rejection behavior in firmware.
- Preserve existing V1 policy:
- one resident Game;
- one foreground Shell;
- no Game-to-Game switching;
- native Shell creates no VM session.
## Non-Goals
- Do not change DEC-0038 ownership semantics.
- Do not add background execution.
- Do not redesign the foreground stack.
- Do not hide programmer invariants behind overly broad error swallowing.
## Execution Method
1. Introduce a `SessionError` or extend `VmSessionError` with operational cases that cross facade boundaries.
2. Update `SessionsFacade` methods:
- `try_create_vm_game_task`;
- new `try_create_vm_shell_task`;
- `load_vm_cartridge`;
- `create_vm_session_for_task`;
- `initialize_session_cartridge`.
3. Update firmware loading paths to map typed session errors into:
- controlled `CrashReport::VmPanic` for unrecoverable internal failures;
- logged rejection and no state transition for unsupported lifecycle transitions where appropriate.
4. Update tests that currently rely on panics or infallible creation.
5. Add focused tests for:
- duplicate foreground Shell rejection during VM Shell load;
- missing task/process session creation errors;
- missing VM session during initialization;
- native Shell still creates no VM session.
6. Run system, firmware, host tests and clippy.
## Acceptance Criteria
- VM session facade operational failures are represented by typed errors.
- `create_vm_shell_task` has a fallible path used by production cartridge loading.
- VM Shell load does not panic when lifecycle rejects the Shell; it returns a controlled error/outcome.
- Missing task/process/session conditions in session services return typed errors.
- Existing tests for resident Game, native Shell, VM Shell, and Game/Shell coexistence still pass.
- No new broad `unwrap`/`expect` appears in production session/lifecycle paths.
## Tests
- `cargo test -p prometeu-system`
- `cargo test -p prometeu-firmware`
- `cargo test -p prometeu-host-desktop-winit`
- `cargo clippy -p prometeu-system -p prometeu-firmware -p prometeu-host-desktop-winit --all-targets -- -D warnings`
- Add tests for controlled errors from session creation/loading edge cases.
## Affected Artifacts
- `crates/console/prometeu-system/src/os/facades/sessions.rs`
- `crates/console/prometeu-system/src/services/vm_session.rs`
- `crates/console/prometeu-system/src/os/lifecycle.rs`
- `crates/console/prometeu-firmware/src/firmware/firmware_step_load_cartridge.rs`
- `crates/console/prometeu-firmware/src/firmware/firmware_step_hub_home.rs`
- Related system and firmware tests