All checks were successful
Intrepid/Prometeu/Runtime/pipeline/pr-master This commit looks good
146 lines
6.5 KiB
Markdown
146 lines
6.5 KiB
Markdown
---
|
|
id: LSN-0052
|
|
ticket: foreground-stack-game-pause-shell-vm-backed
|
|
title: Foreground Ownership and VM Session Ownership Are Separate
|
|
created: 2026-07-05
|
|
tags: [runtime, os, lifecycle, shell, game, vm, foreground, architecture]
|
|
---
|
|
|
|
# LSN-0052: Foreground Ownership and VM Session Ownership Are Separate
|
|
|
|
## Context
|
|
|
|
DSC-0041 closed the `Game -> Home/Shell -> same Game` lifecycle for the first
|
|
runtime implementation that supports both native Shell apps and VM-backed Shell
|
|
apps. The important architectural shift was not only pausing the Game. The
|
|
runtime also had to stop treating one firmware-owned VM as the place where all
|
|
guest execution state lives.
|
|
|
|
The final model separates two questions:
|
|
|
|
- Who owns the foreground visual/input authority right now?
|
|
- Which VM-backed process owns a mutable VM execution context?
|
|
|
|
Foreground ownership is global SystemOS policy. VM execution state belongs to a
|
|
session associated with a task/process. A suspended resident Game is not a saved
|
|
snapshot and not a special global VM. It is a live VM session that is temporarily
|
|
ineligible for normal foreground ticks, input, frame pacing, and render
|
|
publication.
|
|
|
|
## Key Decisions
|
|
|
|
### Foreground Stack and Game Pause Contract
|
|
|
|
**What:** PROMETEU uses a single foreground owner in v1. Hub/Home is the root
|
|
Shell owner, a Game may remain resident, and one foreground Shell app may run in
|
|
front of the resident Game. Pressing desktop `Esc` is a host/SystemOS Home
|
|
request, not guest input.
|
|
|
|
**Why:** This preserves console-like navigation without turning the runtime into
|
|
a general multitasking scheduler. It lets the system pause and suspend a Game,
|
|
run Hub or Shell, then resume the same Game deterministically.
|
|
|
|
**Trade-offs:** The model intentionally rejects multiple resident Games, direct
|
|
Shell-to-Game return, background execution, and Game-to-Game switching in v1.
|
|
Those features remain future work, but the lifecycle structure now has a place
|
|
to add them.
|
|
|
|
### VM Session Ownership for VM-Backed Processes
|
|
|
|
**What:** VM-backed mutable execution state is owned by VM sessions. A
|
|
VM-backed Game and a VM-backed Shell never share the same VM, stack, heap, PC,
|
|
open handles, cartridge identity, or VM-scoped runtime state.
|
|
|
|
**Why:** A single firmware-owned VM cannot represent a suspended resident Game
|
|
and a foreground VM Shell at the same time. Loading the Shell into that global
|
|
VM would overwrite the Game context that the lifecycle model says is resident.
|
|
|
|
**Trade-offs:** Session ownership is more explicit than one global VM, but it
|
|
keeps the model simpler than snapshot/restore. It also prepares the runtime for
|
|
future background-capable sessions without committing to background scheduling
|
|
yet.
|
|
|
|
## Patterns and Algorithms
|
|
|
|
### Pause Is Cooperative, Suspension Is OS Authority
|
|
|
|
The Game receives lifecycle events such as pause and resume, but the OS owns the
|
|
actual scheduling state. If the Game does not cooperate within the bounded pause
|
|
budget, SystemOS can suspend it anyway. On resume, the Game receives a foreground
|
|
restore event and may still keep its internal pause screen while it
|
|
synchronizes.
|
|
|
|
This distinction prevents userland from owning system navigation. The Game may
|
|
observe and react. It cannot veto Home.
|
|
|
|
### Foreground Owner Is Not the Same as Tick Eligibility
|
|
|
|
Foreground ownership controls input, visual authority, render ownership, and
|
|
normal frame pacing. Tick eligibility controls whether a VM session may execute.
|
|
In v1, only the foreground VM session receives normal ticks, and the resident
|
|
Game does not tick while Shell or Hub is foreground.
|
|
|
|
The important design detail is that the data model does not assume this must be
|
|
true forever. Sessions can later become background-eligible without changing who
|
|
owns render/input foreground.
|
|
|
|
### VM Sessions Are the Unit of Mutable Guest State
|
|
|
|
Each VM-backed task/process maps to a `VmSession`. The session owns the VM,
|
|
runtime state, session-scoped filesystem state, open file handles, next handle
|
|
allocation, cartridge identity, lifecycle delivery state, and debug state.
|
|
|
|
Cartridge loading creates or reuses a VM session through SystemOS session
|
|
services. Firmware orchestrates macro states such as `LoadCartridge`,
|
|
`GameRunning`, `HubHome`, and `ShellRunning`, but it no longer owns a canonical
|
|
guest VM.
|
|
|
|
### Debugger and Host Inspection Must Follow the Active Session
|
|
|
|
Host debugging must inspect and mutate the active session VM, not a transitional
|
|
global VM. PC, operand stack, breakpoints, debug-step execution, cartridge
|
|
identity, and breakpoint-hit events all need to resolve through active session
|
|
state.
|
|
|
|
This keeps debugger behavior aligned with actual execution. A debugger that
|
|
observes a different VM than the scheduler ticks is worse than no debugger: it
|
|
creates false confidence and hides lifecycle bugs.
|
|
|
|
### Operational Failures Should Cross Facades as Typed Errors
|
|
|
|
Session creation and loading are operational boundaries. Missing task, missing
|
|
process, duplicate VM session, missing VM session during initialization, and
|
|
foreground Shell rejection should be typed errors. Firmware can then choose a
|
|
controlled crash report, a launch rejection, or a logged no-transition outcome.
|
|
|
|
Panics are reserved for test/setup wrappers or impossible internal invariants
|
|
that have already been proven by prior checks.
|
|
|
|
## Pitfalls
|
|
|
|
- Do not use a global VM as a compatibility bridge after session ownership is
|
|
introduced. It will eventually become stale or contradictory.
|
|
- Do not let Home/SystemOS be guest input. It changes OS authority, so it must
|
|
bypass guest pad state.
|
|
- Do not present old frames after foreground ownership changes. Render ownership
|
|
and epoch validation are part of lifecycle correctness, not renderer polish.
|
|
- Do not model pause and suspension as the same state. Pause is visible to the
|
|
Game; suspension is the scheduler mechanism.
|
|
- Do not encode v1 limits such as one resident Game or one foreground Shell by
|
|
collapsing storage into one VM. Express those limits as lifecycle/session
|
|
policy.
|
|
- Do not let debugger state drift from scheduler state. The debugger must use
|
|
the same active session as normal execution.
|
|
|
|
## Takeaways
|
|
|
|
- Foreground ownership is global policy; VM execution state is session-owned.
|
|
- A suspended Game is a preserved session, not a serialized VM and not a global
|
|
VM waiting to be reused.
|
|
- Shell apps can be native or VM-backed, but only VM-backed processes need VM
|
|
sessions.
|
|
- Session ownership is the foundation for future background-capable processes,
|
|
even before background execution exists.
|
|
- Typed session/lifecycle errors make launch and recovery behavior explicit at
|
|
firmware boundaries.
|