Foreground Stack, Game Pause, and VM-Backed Shell Coexistence
This commit is contained in:
parent
a22215392d
commit
3eeda25e97
@ -39,8 +39,8 @@ impl<'a> LifecycleFacade<'a> {
|
||||
|
||||
pub fn set_foreground_task(&mut self, task_id: TaskId) -> Result<(), LifecycleError> {
|
||||
match task_kind_for_task(self.os, task_id)? {
|
||||
TaskKind::Game => return self.set_game_foreground_task(task_id),
|
||||
TaskKind::Shell => return self.set_shell_foreground_task(task_id),
|
||||
TaskKind::Game => self.set_game_foreground_task(task_id),
|
||||
TaskKind::Shell => self.set_shell_foreground_task(task_id),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
{"type":"meta","next_id":{"DSC":44,"AGD":46,"DEC":38,"PLN":145,"LSN":52,"CLSN":1}}
|
||||
{"type":"meta","next_id":{"DSC":44,"AGD":46,"DEC":38,"PLN":148,"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-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-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":"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"]}],"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":"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":"open","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":"open","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":"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-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"}]}
|
||||
|
||||
@ -0,0 +1,149 @@
|
||||
---
|
||||
id: PLN-0145
|
||||
ticket: foreground-stack-game-pause-shell-vm-backed
|
||||
title: Centralize Resident Game Resume Transition
|
||||
status: open
|
||||
created: 2026-07-04
|
||||
ref_decisions: [DEC-0037]
|
||||
tags: [runtime, os, lifecycle, shell, game, vm, foreground, architecture]
|
||||
---
|
||||
|
||||
## Briefing
|
||||
|
||||
`DEC-0037` requires returning to the same resident Game to reactivate the Game
|
||||
VM, restore render ownership, send a resume/foreground lifecycle notification,
|
||||
and clear or barrier pending Game input. That transition currently exists in
|
||||
more than one firmware path: `Firmware::resume_resident_game_from_home` and the
|
||||
Hub library click path that resumes the selected resident Game by `app_id`.
|
||||
|
||||
The behavior is correct, but the duplication is fragile. Any future change to
|
||||
resume ordering, input barriers, render ownership, or lifecycle event delivery
|
||||
could fix one path while leaving the other path stale.
|
||||
|
||||
## Objective
|
||||
|
||||
Create one firmware-owned resident Game resume helper and route every
|
||||
Home/Hub-to-Game resume path through it.
|
||||
|
||||
## Dependencies
|
||||
|
||||
- Source decision: `DEC-0037`.
|
||||
- Depends on the accepted v1 identity rule that `app_id` is unique for all
|
||||
games and may be used to decide whether a Hub game selection refers to the
|
||||
current resident Game.
|
||||
- Should preserve the behavior introduced by `PLN-0142`, `PLN-0143`, and
|
||||
`PLN-0144`.
|
||||
|
||||
## Scope
|
||||
|
||||
Included:
|
||||
|
||||
- Centralize resident Game resume orchestration in `Firmware`.
|
||||
- Preserve resume lifecycle event queuing through `LifecycleFacade::resume_task`.
|
||||
- Preserve render ownership transition back to `AppMode::Game`.
|
||||
- Preserve input barrier behavior across all Home/Hub-to-Game resume paths.
|
||||
- Preserve the Hub rule that selecting the same resident Game resumes it, while
|
||||
selecting a different Game remains blocked by v1 scope.
|
||||
- Keep tests proving same-task resume, lifecycle event delivery, and input
|
||||
barriering.
|
||||
|
||||
Excluded:
|
||||
|
||||
- No Game-to-Game switching.
|
||||
- No multiple resident Games.
|
||||
- No change to `app_id` uniqueness policy.
|
||||
- No direct Shell-to-Game close behavior.
|
||||
|
||||
## Non-Goals
|
||||
|
||||
- Do not move foreground authority from SystemOS into firmware.
|
||||
- Do not change pause budget or suspend behavior.
|
||||
- Do not add UI affordances beyond the existing Hub game row selection.
|
||||
|
||||
## Execution Method
|
||||
|
||||
1. Introduce a single resident Game resume helper.
|
||||
- What changes: create a private firmware method that performs the complete
|
||||
resident Game resume operation and returns the target `TaskId` or a typed
|
||||
failure.
|
||||
- How it changes: move the shared sequence currently duplicated across
|
||||
`resume_resident_game_from_home` and `HubHomeStep`: read resident task,
|
||||
call `LifecycleFacade::resume_task`, transition VM render ownership to
|
||||
`AppMode::Game`, install `GameRunningStep`, clear state initialization,
|
||||
and arm the input barrier.
|
||||
- File(s): `crates/console/prometeu-firmware/src/firmware/firmware.rs`.
|
||||
|
||||
2. Route explicit resume through the helper.
|
||||
- What changes: `Firmware::resume_resident_game_from_home` becomes a thin
|
||||
wrapper around the centralized helper.
|
||||
- How it changes: preserve its public `bool` return contract for existing
|
||||
tests and call sites.
|
||||
- File(s): `crates/console/prometeu-firmware/src/firmware/firmware.rs`.
|
||||
|
||||
3. Route Hub same-game selection through the helper.
|
||||
- What changes: `HubHomeStep` must no longer hand-roll resume task, render
|
||||
ownership, and input clearing.
|
||||
- How it changes: expose a state transition request that lets the firmware
|
||||
perform the centralized helper, or restructure the Hub action handling so
|
||||
the parent `Firmware` owns this transition. Keep `HubHomeStep` responsible
|
||||
only for recognizing that the selected cartridge matches the resident
|
||||
`app_id`.
|
||||
- File(s): `crates/console/prometeu-firmware/src/firmware/firmware.rs`,
|
||||
`crates/console/prometeu-firmware/src/firmware/firmware_step_hub_home.rs`,
|
||||
`crates/console/prometeu-firmware/src/firmware/firmware_state.rs` if a new
|
||||
transition variant is needed.
|
||||
|
||||
4. Keep different-game launch blocked under v1.
|
||||
- What changes: selecting a different `app_id` while a resident Game exists
|
||||
continues to log and remain in Hub.
|
||||
- How it changes: keep the existing warning behavior, but ensure it does not
|
||||
duplicate resume side effects.
|
||||
- File(s): `crates/console/prometeu-firmware/src/firmware/firmware_step_hub_home.rs`.
|
||||
|
||||
5. Update regression tests.
|
||||
- What changes: tests should prove both explicit resume and Hub same-game
|
||||
selection use the same observable transition.
|
||||
- How it changes: assert same `TaskId`, foreground owner restored to Game,
|
||||
pending resume lifecycle event exists before the next Game tick, delivered
|
||||
resume event after the Game tick, and input barrier suppresses held input.
|
||||
- File(s): `crates/console/prometeu-firmware/src/firmware/firmware.rs`.
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
- [ ] There is exactly one implementation of the resident Game resume sequence.
|
||||
- [ ] `Firmware::resume_resident_game_from_home` preserves its external
|
||||
behavior.
|
||||
- [ ] Hub selection of the same resident Game resumes the existing `TaskId`
|
||||
without creating or loading a new Game task.
|
||||
- [ ] The resume path always queues and delivers the Game lifecycle
|
||||
`ResumeForeground` event.
|
||||
- [ ] The resume path always barriers held Game input.
|
||||
- [ ] Selecting a different Game while one Game is resident remains blocked in
|
||||
v1.
|
||||
|
||||
## Tests
|
||||
|
||||
- Unit/integration tests in `prometeu-firmware` for explicit resume from Home.
|
||||
- Unit/integration tests in `prometeu-firmware` for Hub same-game selection
|
||||
after Home suspension.
|
||||
- Regression assertion that held input does not leak into the Game immediately
|
||||
after resume.
|
||||
- Run `cargo test -p prometeu-firmware resident_game_resume`.
|
||||
- Run `cargo test -p prometeu-firmware hub_home_clicking_resident_game`.
|
||||
- Run `cargo test -p prometeu-system`.
|
||||
- Run `discussion validate`.
|
||||
|
||||
## Affected Artifacts
|
||||
|
||||
- `crates/console/prometeu-firmware/src/firmware/firmware.rs`
|
||||
- `crates/console/prometeu-firmware/src/firmware/firmware_step_hub_home.rs`
|
||||
- `crates/console/prometeu-firmware/src/firmware/firmware_state.rs`
|
||||
|
||||
## Risks
|
||||
|
||||
- The current step/state architecture gives `HubHomeStep` a `PrometeuContext`
|
||||
but not direct access to private `Firmware` fields. If a new transition
|
||||
variant is introduced, it must stay narrow and must not turn state steps into
|
||||
owners of lifecycle authority.
|
||||
- Duplicating less logic must not accidentally weaken the input barrier that was
|
||||
added for Hub-to-Game transitions.
|
||||
@ -0,0 +1,119 @@
|
||||
---
|
||||
id: PLN-0146
|
||||
ticket: foreground-stack-game-pause-shell-vm-backed
|
||||
title: Consolidate Lifecycle Process Lookup Helpers
|
||||
status: open
|
||||
created: 2026-07-04
|
||||
ref_decisions: [DEC-0037]
|
||||
tags: [runtime, os, lifecycle, shell, game, vm, foreground, architecture]
|
||||
---
|
||||
|
||||
## Briefing
|
||||
|
||||
`DEC-0037` depends on SystemOS lifecycle authority being internally
|
||||
consistent. The lifecycle facade now exposes both process state and process kind
|
||||
for a task so firmware can distinguish VM-backed Shell tasks from native Shell
|
||||
tasks. Both accessors repeat the same task-to-process lookup pattern.
|
||||
|
||||
The duplication is small, but this facade is now part of the foreground
|
||||
contract surface. Keeping lookup and error mapping in one place reduces the
|
||||
chance that future lifecycle accessors drift in behavior.
|
||||
|
||||
## Objective
|
||||
|
||||
Consolidate task-to-process lookup in `LifecycleFacade` behind one private
|
||||
helper, while preserving the public lifecycle facade behavior and errors.
|
||||
|
||||
## Dependencies
|
||||
|
||||
- Source decision: `DEC-0037`.
|
||||
- Depends on the process/task authority from SystemOS lifecycle work.
|
||||
- Can be implemented independently of `PLN-0145` and `PLN-0147`.
|
||||
|
||||
## Scope
|
||||
|
||||
Included:
|
||||
|
||||
- Add one private helper that resolves a `TaskId` to its backing process.
|
||||
- Route `process_state_for_task` and `process_kind_for_task` through that
|
||||
helper.
|
||||
- Preserve `LifecycleError::TaskNotFound` and
|
||||
`LifecycleError::ProcessNotFound` behavior exactly.
|
||||
- Keep the current process/task manager ownership boundaries intact.
|
||||
- Keep the current non-architectural cleanup in `set_foreground_task` if it is
|
||||
still present in the working tree.
|
||||
|
||||
Excluded:
|
||||
|
||||
- No new public process manager API.
|
||||
- No changes to task or process IDs.
|
||||
- No changes to Shell/Game lifecycle semantics.
|
||||
- No broader facade refactor outside lifecycle lookup.
|
||||
|
||||
## Non-Goals
|
||||
|
||||
- Do not expose raw process manager access through SystemOS.
|
||||
- Do not change `ProcessKind` or `TaskKind` definitions.
|
||||
- Do not alter foreground stack behavior.
|
||||
|
||||
## Execution Method
|
||||
|
||||
1. Add a private lifecycle lookup helper.
|
||||
- What changes: add a private function near `process_id_for_task` that
|
||||
returns a process reference for a `TaskId`.
|
||||
- How it changes: the helper should call `process_id_for_task`, then
|
||||
retrieve the process from `process_manager`, returning
|
||||
`LifecycleError::ProcessNotFound(process_id)` if the process is missing.
|
||||
- File(s): `crates/console/prometeu-system/src/os/facades/lifecycle.rs`.
|
||||
|
||||
2. Route state and kind accessors through the helper.
|
||||
- What changes: `LifecycleFacade::process_state_for_task` and
|
||||
`LifecycleFacade::process_kind_for_task` stop duplicating the process
|
||||
manager lookup.
|
||||
- How it changes: both methods call the helper and map the process reference
|
||||
to `ProcessState` or `ProcessKind`.
|
||||
- File(s): `crates/console/prometeu-system/src/os/facades/lifecycle.rs`.
|
||||
|
||||
3. Preserve existing foreground code cleanup.
|
||||
- What changes: keep `set_foreground_task` as an expression-returning match
|
||||
rather than using redundant `return` statements.
|
||||
- How it changes: ensure formatting and clippy stay clean.
|
||||
- File(s): `crates/console/prometeu-system/src/os/facades/lifecycle.rs`.
|
||||
|
||||
4. Tighten tests around lookup behavior.
|
||||
- What changes: extend or keep tests proving VM Shell and native Shell
|
||||
process kinds are observable through lifecycle.
|
||||
- How it changes: add missing-task and missing-process coverage only if the
|
||||
helper changes the observable path enough to justify it.
|
||||
- File(s): `crates/console/prometeu-system/src/os/system_os.rs`.
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
- [ ] `process_state_for_task` and `process_kind_for_task` share one private
|
||||
task-to-process lookup implementation.
|
||||
- [ ] Missing task and missing process errors remain unchanged.
|
||||
- [ ] Existing lifecycle tests continue to pass.
|
||||
- [ ] Firmware can still distinguish `ProcessKind::VmShell` from
|
||||
`ProcessKind::NativeShell`.
|
||||
- [ ] Clippy reports no warnings for the touched crates.
|
||||
|
||||
## Tests
|
||||
|
||||
- Unit tests in `prometeu-system` for shell process kind lookup.
|
||||
- Existing lifecycle missing task/process tests must continue to pass.
|
||||
- Run `cargo test -p prometeu-system lifecycle process_kind`.
|
||||
- Run `cargo test -p prometeu-firmware shell`.
|
||||
- Run `cargo clippy -p prometeu-system -p prometeu-firmware --all-targets -- -D warnings`.
|
||||
- Run `discussion validate`.
|
||||
|
||||
## Affected Artifacts
|
||||
|
||||
- `crates/console/prometeu-system/src/os/facades/lifecycle.rs`
|
||||
- `crates/console/prometeu-system/src/os/system_os.rs`
|
||||
|
||||
## Risks
|
||||
|
||||
- Over-generalizing the helper could leak process manager concepts outside the
|
||||
lifecycle facade. Keep it private and narrowly typed.
|
||||
- This is intentionally small cleanup. It must not become a broad SystemOS
|
||||
facade redesign.
|
||||
@ -0,0 +1,144 @@
|
||||
---
|
||||
id: PLN-0147
|
||||
ticket: foreground-stack-game-pause-shell-vm-backed
|
||||
title: Move Native Shell Profile Update Into Hub
|
||||
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 Game must not receive normal gameplay ticks while
|
||||
Hub or Shell owns foreground. A recent fix made `ShellRunningStep` branch on
|
||||
`ProcessKind`: VM-backed Shell tasks use the VM-backed shell profile path, while
|
||||
native Shell tasks call `PrometeuHub::gui_update` and `PrometeuHub::render`
|
||||
without ticking the VM.
|
||||
|
||||
That behavior is correct, but the native Shell update sequence now lives in
|
||||
firmware rather than in the Hub profile API. This duplicates part of
|
||||
`PrometeuHub::update_shell_profile` and creates a drift risk if Shell close,
|
||||
render, or input rules change later.
|
||||
|
||||
## Objective
|
||||
|
||||
Move native Shell profile updating into `PrometeuHub` so `ShellRunningStep`
|
||||
chooses the correct profile API without reimplementing Hub behavior.
|
||||
|
||||
## Dependencies
|
||||
|
||||
- Source decision: `DEC-0037`.
|
||||
- Depends on the `ProcessKind::VmShell` vs `ProcessKind::NativeShell`
|
||||
distinction available through `LifecycleFacade::process_kind_for_task`.
|
||||
- May be implemented before or after `PLN-0146`, but should use the consolidated
|
||||
lookup helper if `PLN-0146` has already landed.
|
||||
|
||||
## Scope
|
||||
|
||||
Included:
|
||||
|
||||
- Add a Hub-owned native Shell update API that does not tick the VM.
|
||||
- Keep VM-backed Shell update behavior in the existing VM-backed profile path.
|
||||
- Keep Shell close handling consistent between native and VM-backed Shells.
|
||||
- Keep native Shell rendering in the Hub/Shell UI path.
|
||||
- Keep firmware responsible for choosing which profile applies to the current
|
||||
Shell task.
|
||||
- Preserve regression coverage that a suspended resident Game does not advance
|
||||
while native Shell is foreground.
|
||||
|
||||
Excluded:
|
||||
|
||||
- No change to VM-backed Shell execution semantics.
|
||||
- No change to native Shell UI content.
|
||||
- No direct Shell close to Game.
|
||||
- No multiple foreground Shells.
|
||||
- No background Game ticking.
|
||||
|
||||
## Non-Goals
|
||||
|
||||
- Do not move foreground lifecycle authority into `PrometeuHub`.
|
||||
- Do not make native Shells VM tasks.
|
||||
- Do not introduce a general scheduler abstraction.
|
||||
|
||||
## Execution Method
|
||||
|
||||
1. Add a native Shell profile update method on `PrometeuHub`.
|
||||
- What changes: create `update_native_shell_profile` or an equivalent
|
||||
clearly named method that returns `SystemProfileUpdate`.
|
||||
- How it changes: the method calls `gui_update`, maps Start input to
|
||||
`SystemProfileAction::CloseShell` when a shell window is focused, calls
|
||||
`render`, and always returns `crash: None`.
|
||||
- File(s):
|
||||
`crates/console/prometeu-system/src/programs/prometeu_hub/prometeu_hub.rs`.
|
||||
|
||||
2. Keep the VM-backed Shell profile method explicitly VM-backed.
|
||||
- What changes: either keep `update_shell_profile` and document/name its VM
|
||||
tick behavior, or rename/split it if the codebase convention supports that
|
||||
without churn.
|
||||
- How it changes: ensure the VM-backed path is the only Hub profile update
|
||||
method that calls `os.vm().tick(...)`.
|
||||
- File(s):
|
||||
`crates/console/prometeu-system/src/programs/prometeu_hub/prometeu_hub.rs`.
|
||||
|
||||
3. Simplify `ShellRunningStep`.
|
||||
- What changes: remove manual native Shell `gui_update`, Start handling, and
|
||||
render calls from firmware.
|
||||
- How it changes: branch on `ProcessKind` and call the appropriate Hub
|
||||
profile method; keep crash handling only for the VM-backed method.
|
||||
- File(s):
|
||||
`crates/console/prometeu-firmware/src/firmware/firmware_step_shell_running.rs`.
|
||||
|
||||
4. Add Hub-level native profile tests.
|
||||
- What changes: prove native Shell profile update emits close on the close
|
||||
button and on Start, renders Shell UI, and does not tick the VM.
|
||||
- How it changes: use existing Hub/system test helpers where possible; assert
|
||||
VM tick index remains unchanged for native profile update.
|
||||
- File(s):
|
||||
`crates/console/prometeu-system/src/programs/prometeu_hub/prometeu_hub.rs`
|
||||
and/or `crates/console/prometeu-firmware/src/firmware/firmware.rs`.
|
||||
|
||||
5. Preserve end-to-end regression coverage.
|
||||
- What changes: keep the Game -> Home -> native Shell test asserting that
|
||||
repeated Shell frames do not advance the resident Game VM tick index.
|
||||
- How it changes: rerun the firmware regression added for native Shell
|
||||
foreground.
|
||||
- File(s): `crates/console/prometeu-firmware/src/firmware/firmware.rs`.
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
- [ ] Native Shell update behavior is owned by `PrometeuHub`, not hand-coded in
|
||||
`ShellRunningStep`.
|
||||
- [ ] The native Shell profile update never calls `os.vm().tick(...)`.
|
||||
- [ ] VM-backed Shell update remains the only Shell profile path that ticks the
|
||||
VM runtime.
|
||||
- [ ] Start and close-button Shell close behavior remains unchanged for native
|
||||
Shells.
|
||||
- [ ] A suspended resident Game receives no normal gameplay ticks while native
|
||||
Shell is foreground.
|
||||
|
||||
## Tests
|
||||
|
||||
- Hub-level tests for native Shell profile close behavior.
|
||||
- Hub-level or firmware-level tests proving native Shell profile update does not
|
||||
tick the VM.
|
||||
- Existing firmware regression for Game -> Home -> native Shell repeated frames.
|
||||
- Run `cargo test -p prometeu-system native_shell shell_profile`.
|
||||
- Run `cargo test -p prometeu-firmware game_home_shell_hub_same_game_flow`.
|
||||
- Run `cargo test -p prometeu-firmware`.
|
||||
- Run `cargo test -p prometeu-system`.
|
||||
- Run `discussion validate`.
|
||||
|
||||
## Affected Artifacts
|
||||
|
||||
- `crates/console/prometeu-system/src/programs/prometeu_hub/prometeu_hub.rs`
|
||||
- `crates/console/prometeu-firmware/src/firmware/firmware_step_shell_running.rs`
|
||||
- `crates/console/prometeu-firmware/src/firmware/firmware.rs`
|
||||
|
||||
## Risks
|
||||
|
||||
- Renaming the existing VM-backed shell profile method may create unnecessary
|
||||
churn. Prefer adding the native method and keeping call sites explicit unless
|
||||
the rename is small and clearly improves readability.
|
||||
- Hub APIs must remain UI/profile orchestration only; lifecycle close and task
|
||||
state changes still belong to firmware/SystemOS lifecycle.
|
||||
Loading…
x
Reference in New Issue
Block a user