Foreground Stack, Game Pause, and VM-Backed Shell Coexistence
This commit is contained in:
parent
33f70d1c6e
commit
5ff273f167
@ -1,8 +1,8 @@
|
|||||||
{"type":"meta","next_id":{"DSC":44,"AGD":46,"DEC":38,"PLN":142,"LSN":52,"CLSN":1}}
|
{"type":"meta","next_id":{"DSC":44,"AGD":46,"DEC":38,"PLN":145,"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-03","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"}],"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"}],"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"]}],"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-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"}],"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"}],"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":"open","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":"open","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":"open","created_at":"2026-07-04","updated_at":"2026-07-04","ref_decisions":["DEC-0037"]}],"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"}]}
|
||||||
|
|||||||
@ -0,0 +1,127 @@
|
|||||||
|
---
|
||||||
|
id: PLN-0142
|
||||||
|
ticket: foreground-stack-game-pause-shell-vm-backed
|
||||||
|
title: Deliver Game Lifecycle Events To VM Runtime
|
||||||
|
status: open
|
||||||
|
created: 2026-07-04
|
||||||
|
ref_decisions: [DEC-0037]
|
||||||
|
tags: [runtime, os, lifecycle, shell, game, vm, foreground, architecture]
|
||||||
|
---
|
||||||
|
|
||||||
|
## Briefing
|
||||||
|
|
||||||
|
`DEC-0037` requires pause/resume to be Game-visible lifecycle events. The
|
||||||
|
current implementation records `GameLifecycleEvent` values in SystemOS, but no
|
||||||
|
runtime or VM execution path consumes them. Tests currently prove that the OS
|
||||||
|
queue contains events, not that the Game/runtime can observe them before
|
||||||
|
suspension or after resume.
|
||||||
|
|
||||||
|
## Objective
|
||||||
|
|
||||||
|
Deliver Game lifecycle pause/resume events from SystemOS into the VM runtime
|
||||||
|
boundary in a deterministic, testable way, without exposing Home as guest pad
|
||||||
|
input or a userland syscall.
|
||||||
|
|
||||||
|
## Dependencies
|
||||||
|
|
||||||
|
- Source decision: `DEC-0037`.
|
||||||
|
- Fixes the lifecycle event delivery gap found after `PLN-0140` and
|
||||||
|
`PLN-0141`.
|
||||||
|
- `PLN-0143` depends on this plan if it needs to prove that the pause event is
|
||||||
|
consumed before the pause budget expires.
|
||||||
|
|
||||||
|
## Scope
|
||||||
|
|
||||||
|
Included:
|
||||||
|
|
||||||
|
- Define the runtime-facing lifecycle event delivery API for `Pause` and
|
||||||
|
`ResumeForeground`.
|
||||||
|
- Move events from the SystemOS queue into the VM/runtime tick boundary.
|
||||||
|
- Make delivered events observable in tests without creating a broad app event
|
||||||
|
system.
|
||||||
|
- Preserve the distinction between lifecycle pause and debugger pause.
|
||||||
|
- Ensure events are delivered only to the resident Game task they target.
|
||||||
|
|
||||||
|
Excluded:
|
||||||
|
|
||||||
|
- No guest Home input, pad field, intrinsic, or syscall.
|
||||||
|
- No general userland event bus.
|
||||||
|
- No background execution while suspended.
|
||||||
|
- No new Shell lifecycle event model.
|
||||||
|
|
||||||
|
## Non-Goals
|
||||||
|
|
||||||
|
- Do not implement Game-to-Game switching.
|
||||||
|
- Do not change renderer ownership policy except where tests need to assert
|
||||||
|
lifecycle event ordering.
|
||||||
|
- Do not add wall-clock timers or asynchronous callbacks.
|
||||||
|
|
||||||
|
## Execution Method
|
||||||
|
|
||||||
|
1. Add a narrow VM runtime lifecycle inbox.
|
||||||
|
- What changes: introduce a small data structure for pending/delivered Game
|
||||||
|
lifecycle events in `VirtualMachineRuntime`.
|
||||||
|
- How it changes: add methods such as `queue_game_lifecycle_events`,
|
||||||
|
`take_delivered_game_lifecycle_events`, or a more idiomatic local name
|
||||||
|
that preserves deterministic frame-boundary delivery.
|
||||||
|
- File(s): `crates/console/prometeu-system/src/services/vm_runtime/mod.rs`,
|
||||||
|
`crates/console/prometeu-system/src/services/vm_runtime/tick.rs`, and
|
||||||
|
focused tests under `crates/console/prometeu-system/src/services/vm_runtime/`.
|
||||||
|
|
||||||
|
2. Route SystemOS events into the VM facade before ticking.
|
||||||
|
- What changes: `VmFacade::tick` must drain lifecycle events from SystemOS
|
||||||
|
and pass only events targeted at the currently running resident Game into
|
||||||
|
the VM runtime lifecycle inbox.
|
||||||
|
- How it changes: use the existing `LifecycleFacade::take_game_lifecycle_events`
|
||||||
|
or replace it with an equivalent internal method if borrowing requires a
|
||||||
|
cleaner API. Do not leave events only observable through
|
||||||
|
`pending_game_lifecycle_events`.
|
||||||
|
- File(s): `crates/console/prometeu-system/src/os/facades/vm.rs`,
|
||||||
|
`crates/console/prometeu-system/src/os/facades/lifecycle.rs`.
|
||||||
|
|
||||||
|
3. Expose deterministic test visibility.
|
||||||
|
- What changes: tests must be able to assert that `Pause` and
|
||||||
|
`ResumeForeground` reached the VM runtime boundary.
|
||||||
|
- How it changes: add test-only or public diagnostic accessors on
|
||||||
|
`VmFacade`/`VirtualMachineRuntime` for delivered lifecycle events, scoped
|
||||||
|
to lifecycle validation rather than a guest ABI.
|
||||||
|
- File(s): `crates/console/prometeu-system/src/os/facades/vm.rs`,
|
||||||
|
`crates/console/prometeu-system/src/services/vm_runtime/tests.rs`.
|
||||||
|
|
||||||
|
4. Update firmware tests to assert delivery, not only queue presence.
|
||||||
|
- What changes: existing firmware tests that inspect
|
||||||
|
`pending_game_lifecycle_events` should assert VM-runtime delivery at the
|
||||||
|
tick boundary.
|
||||||
|
- How it changes: after a Game pause/resume flow, verify that the VM/runtime
|
||||||
|
observed the lifecycle event in order.
|
||||||
|
- File(s): `crates/console/prometeu-firmware/src/firmware/firmware.rs`.
|
||||||
|
|
||||||
|
## Acceptance Criteria
|
||||||
|
|
||||||
|
- [ ] `Pause` is moved from SystemOS into the VM runtime boundary before
|
||||||
|
suspension is allowed to complete.
|
||||||
|
- [ ] `ResumeForeground` is moved into the VM runtime boundary before the Game
|
||||||
|
is considered visually restored.
|
||||||
|
- [ ] Tests fail if events remain only in `SystemOS.game_lifecycle_events`.
|
||||||
|
- [ ] Lifecycle event delivery does not mutate `InputSignals`.
|
||||||
|
- [ ] Debugger pause remains separate from lifecycle pause.
|
||||||
|
|
||||||
|
## Tests
|
||||||
|
|
||||||
|
- Unit tests in `prometeu-system` proving VM runtime lifecycle event delivery
|
||||||
|
and drain semantics.
|
||||||
|
- Firmware tests proving Home request delivers `Pause` to the VM/runtime before
|
||||||
|
suspension.
|
||||||
|
- Firmware tests proving resident Game resume delivers `ResumeForeground`
|
||||||
|
before Game foreground restoration.
|
||||||
|
- Run `cargo test -p prometeu-system`.
|
||||||
|
- Run `cargo test -p prometeu-firmware`.
|
||||||
|
- Run `discussion validate`.
|
||||||
|
|
||||||
|
## Affected Artifacts
|
||||||
|
|
||||||
|
- `crates/console/prometeu-system/src/os/facades/vm.rs`
|
||||||
|
- `crates/console/prometeu-system/src/os/facades/lifecycle.rs`
|
||||||
|
- `crates/console/prometeu-system/src/services/vm_runtime/mod.rs`
|
||||||
|
- `crates/console/prometeu-system/src/services/vm_runtime/tick.rs`
|
||||||
|
- `crates/console/prometeu-firmware/src/firmware/firmware.rs`
|
||||||
@ -0,0 +1,122 @@
|
|||||||
|
---
|
||||||
|
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`
|
||||||
@ -0,0 +1,124 @@
|
|||||||
|
---
|
||||||
|
id: PLN-0144
|
||||||
|
ticket: foreground-stack-game-pause-shell-vm-backed
|
||||||
|
title: Suspend Resident Game When Shell Takes Foreground
|
||||||
|
status: open
|
||||||
|
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`
|
||||||
Loading…
x
Reference in New Issue
Block a user