--- id: PLN-0144 ticket: foreground-stack-game-pause-shell-vm-backed title: Suspend Resident Game When Shell Takes Foreground status: done created: 2026-07-04 ref_decisions: [DEC-0037] tags: [runtime, os, lifecycle, shell, game, vm, foreground, architecture] --- ## Briefing `DEC-0037` says a suspended resident Game must not receive normal gameplay ticks, normal Game input, or frame pacing while Hub/Shell owns foreground. The current `set_shell_foreground` path can mark the resident Game as `PausedSuspended` in the foreground stack while `TaskManager::set_foreground` only demotes the previous foreground Game task to `Background`. This creates a state mismatch if a Shell is opened while the Game has not already gone through the Home suspension path. ## Objective Make Shell foreground acquisition either require an already suspended resident Game or perform the necessary OS-owned suspension consistently across foreground stack, task manager, and process manager. ## Dependencies - Source decision: `DEC-0037`. - Can be implemented independently of `PLN-0142` and `PLN-0143`, but tests should be rerun with those fixes if they are executed first. ## Scope Included: - Close the mismatch between `ResidentGameState::PausedSuspended` and `TaskState::Background`. - Ensure Shell foreground cannot leave a resident Game running or backgrounded. - Cover both `create_vm_shell_task` and `create_native_shell_task` paths. - Preserve the rule that only one foreground Shell may exist. - Keep the normal Home -> Shell flow working. Excluded: - No direct Shell -> Game return behavior; v1 still returns Shell close to Hub. - No background Game execution. - No multiple resident Games. - No Shell persistence policy changes. ## Non-Goals - Do not broaden Shell lifecycle semantics. - Do not implement Game-to-Game switching. - Do not add UI controls for resume. ## Execution Method 1. Define the legal Shell foreground precondition. - What changes: decide in code whether Shell foreground requires the resident Game to already be `PausedSuspended`, or whether `set_shell_foreground_task` is responsible for suspending it. - How it changes: prefer centralizing the invariant in `LifecycleFacade::set_shell_foreground_task`, because it owns task/process transitions. - File(s): `crates/console/prometeu-system/src/os/facades/lifecycle.rs`, `crates/console/prometeu-system/src/services/foreground.rs`. 2. Synchronize task/process state when Shell takes foreground. - What changes: if a resident Game exists and is not already suspended, mark the Game task and process `Suspended` before or during Shell foreground transition. - How it changes: use `process_id_for_task` for the resident Game and call `task_manager.mark_suspended` and `process_manager.mark_suspended` in the same lifecycle operation that sets Shell foreground. - File(s): `crates/console/prometeu-system/src/os/facades/lifecycle.rs`. 3. Tighten foreground stack behavior. - What changes: `ForegroundStack::set_shell_foreground` must not silently hide invalid state transitions. - How it changes: either reject Shell foreground when the resident Game is still `Foreground`/`PauseRequested`, or return enough information for the lifecycle facade to suspend the resident Game explicitly. - File(s): `crates/console/prometeu-system/src/services/foreground.rs`. 4. Add regression tests for reachable session paths. - What changes: create tests that call `create_vm_shell_task` and `create_native_shell_task` while a Game task is foreground. - How it changes: assert foreground owner is Shell, resident Game remains recorded, Game task state is `Suspended`, and Game process state is `Suspended`. - File(s): `crates/console/prometeu-system/src/os/system_os.rs`, `crates/console/prometeu-firmware/src/firmware/firmware.rs` if the firmware Home/Shell path needs coverage. ## Acceptance Criteria - [ ] A Shell foreground transition cannot leave the resident Game in `TaskState::Background`. - [ ] Foreground stack state, task state, and process state agree that the resident Game is suspended while Shell is foreground. - [ ] `create_vm_shell_task` and `create_native_shell_task` both preserve the invariant. - [ ] Opening a second foreground Shell remains rejected. - [ ] Closing Shell still returns to Hub/Home, not directly to Game. ## Tests - Unit tests in `prometeu-system` for `set_shell_foreground_task` with a resident foreground Game. - Session facade tests for VM Shell and native Shell creation while a Game is resident. - Existing firmware Shell close tests must continue to pass. - Run `cargo test -p prometeu-system foreground lifecycle shell`. - Run `cargo test -p prometeu-firmware shell`. - Run `discussion validate`. ## Affected Artifacts - `crates/console/prometeu-system/src/services/foreground.rs` - `crates/console/prometeu-system/src/os/facades/lifecycle.rs` - `crates/console/prometeu-system/src/os/facades/sessions.rs` - `crates/console/prometeu-system/src/os/system_os.rs` - `crates/console/prometeu-firmware/src/firmware/firmware.rs`