--- id: PLN-0143 ticket: foreground-stack-game-pause-shell-vm-backed title: Guarantee Cooperative Pause Budget Tick Before Suspension status: open created: 2026-07-04 ref_decisions: [DEC-0037] tags: [runtime, os, lifecycle, shell, game, vm, foreground, architecture] --- ## Briefing `DEC-0037` requires a Game-visible `Paused` event followed by a bounded cooperative reaction budget before SystemOS imposes `Suspended`. The current implementation uses a one-tick budget and advances it before `vm.tick` in `GameRunningStep`, so the Game can be suspended without any runtime tick in which it could observe or react to pause. ## Objective Guarantee at least one deterministic VM/runtime delivery point for the Game to observe pause before forced suspension, while preserving SystemOS authority to suspend the Game after the budget. ## Dependencies - Source decision: `DEC-0037`. - Should be executed after or together with `PLN-0142`, because budget tests must prove delivered lifecycle events, not only queued OS events. ## Scope Included: - Fix pause budget ordering so the pause budget cannot expire before the VM runtime has a delivery point for `Pause`. - Define the budget in deterministic machine ticks/frames, not wall-clock time. - Ensure a Game receives no normal gameplay ticks after it reaches `PausedSuspended`. - Preserve the existing forced-suspension authority when the budget expires. - Update tests that currently assert no VM tick occurs immediately after Home. Excluded: - No guest-controlled cancellation of suspension. - No background execution after suspension. - No extension of the pause budget based on host timing. - No direct visual-return behavior; render restore gating remains covered by the existing render boundary work. ## Non-Goals - Do not add a general scheduler. - Do not make pause cooperation mandatory for suspension. - Do not conflate lifecycle pause with debugger pause. ## Execution Method 1. Redefine pause budget state transitions. - What changes: `ResidentGameState::PauseRequested` must represent a state in which one or more delivery ticks remain before `PausedSuspended`. - How it changes: adjust `ForegroundStack::advance_pause_budget` or split it into explicit methods such as `mark_pause_delivered` and `advance_pause_budget_after_delivery`. - File(s): `crates/console/prometeu-system/src/services/foreground.rs`. 2. Move budget advancement after lifecycle delivery. - What changes: `GameRunningStep::on_update` must not suspend before the VM runtime has a chance to receive and process the pause lifecycle event. - How it changes: reorder the GameRunning update so the event delivery path runs first, then the budget is advanced, and only a subsequent eligible boundary can force suspension. - File(s): `crates/console/prometeu-firmware/src/firmware/firmware_step_game_running.rs`, `crates/console/prometeu-system/src/os/facades/vm.rs`. 3. Preserve no-tick-after-suspended behavior. - What changes: once `ResidentGameState::PausedSuspended` and `TaskState::Suspended` are reached, the Game must not receive normal ticks, normal input, or frame pacing. - How it changes: keep the existing early transition to Hub after suspension expires, but ensure it occurs after the cooperative pause window rather than before it. - File(s): `crates/console/prometeu-firmware/src/firmware/firmware_step_game_running.rs`. 4. Update tests to match the corrected semantics. - What changes: tests must stop asserting that the first tick after Home does zero VM work purely because Home was requested. - How it changes: assert that the pause event was delivered during the cooperative window, then assert that a later deterministic tick forces suspension and no further Game ticks occur. - File(s): `crates/console/prometeu-firmware/src/firmware/firmware.rs`, `crates/console/prometeu-system/src/os/system_os.rs`. ## Acceptance Criteria - [ ] A Game receives a deterministic pause delivery point before SystemOS suspends it. - [ ] SystemOS still suspends the Game after the bounded budget even if the Game does not cooperate. - [ ] A suspended Game receives no normal gameplay ticks, normal Game input, or frame pacing. - [ ] Tests prove the order: Home request -> pause delivery -> budget expiry -> suspension. - [ ] Debugger pause behavior is unchanged. ## Tests - Unit tests in `prometeu-system` for pause budget transitions. - Firmware tests for non-cooperative forced suspension after at least one delivered pause boundary. - Regression tests proving suspended Game tick count does not advance. - Run `cargo test -p prometeu-system foreground lifecycle`. - Run `cargo test -p prometeu-firmware pause`. - 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/vm.rs` - `crates/console/prometeu-firmware/src/firmware/firmware_step_game_running.rs` - `crates/console/prometeu-firmware/src/firmware/firmware.rs`