diff --git a/crates/console/prometeu-firmware/src/firmware/firmware_step_game_running.rs b/crates/console/prometeu-firmware/src/firmware/firmware_step_game_running.rs index a3c37323..677ea2ef 100644 --- a/crates/console/prometeu-firmware/src/firmware/firmware_step_game_running.rs +++ b/crates/console/prometeu-firmware/src/firmware/firmware_step_game_running.rs @@ -37,13 +37,11 @@ impl GameRunningStep { return Some(FirmwareState::AppCrashes(AppCrashesStep { report })); } - ctx.os.vm().deliver_pending_game_lifecycle_events(); - let pause_requested = matches!( ctx.os.lifecycle().resident_game().map(|game| game.state), Some(ResidentGameState::PauseRequested { .. }) ); - let result = ctx.os.vm().tick(ctx.vm, ctx.signals, ctx.platform); + let result = ctx.os.vm().tick_session(self.task_id, ctx.signals, ctx.platform); if let Some(report) = result { let _ = ctx.os.lifecycle().crash_task(self.task_id, Some(&report)); diff --git a/crates/console/prometeu-firmware/src/firmware/firmware_step_shell_running.rs b/crates/console/prometeu-firmware/src/firmware/firmware_step_shell_running.rs index 856bdd3f..d23244d5 100644 --- a/crates/console/prometeu-firmware/src/firmware/firmware_step_shell_running.rs +++ b/crates/console/prometeu-firmware/src/firmware/firmware_step_shell_running.rs @@ -76,7 +76,7 @@ impl ShellRunningStep { let outcome = match process_kind { ProcessKind::VmShell => { - ctx.hub.update_shell_profile(ctx.os, ctx.vm, ctx.signals, ctx.platform) + ctx.hub.update_vm_shell_profile(ctx.os, self.task_id, ctx.signals, ctx.platform) } ProcessKind::NativeShell => ctx.hub.update_native_shell_profile(ctx.os, ctx.platform), ProcessKind::VmGame => { diff --git a/crates/console/prometeu-system/src/os/facades/vm.rs b/crates/console/prometeu-system/src/os/facades/vm.rs index 971b20cc..994c79af 100644 --- a/crates/console/prometeu-system/src/os/facades/vm.rs +++ b/crates/console/prometeu-system/src/os/facades/vm.rs @@ -1,5 +1,7 @@ use crate::CrashReport; use crate::os::{GameLifecycleEvent, SystemOS}; +use crate::task::TaskId; +use crate::vm_session::VmSession; use crate::{RenderWorkerConfig, RenderWorkerController}; use prometeu_hal::app_mode::AppMode; use prometeu_hal::cartridge::Cartridge; @@ -46,6 +48,34 @@ impl<'a> VmFacade<'a> { ) } + pub fn tick_session( + &mut self, + task_id: TaskId, + signals: &InputSignals, + platform: &mut dyn RuntimePlatform, + ) -> Option { + self.deliver_pending_game_lifecycle_events_to_session(task_id); + + let Some(session) = self.os.vm_sessions.for_task_mut(task_id) else { + return Some(CrashReport::VmPanic { + message: format!("task {:?} has no VM session", task_id), + pc: None, + }); + }; + + session.runtime.tick( + &mut self.os.log_service, + &mut self.os.fs, + &mut session.fs_state, + &mut self.os.memcard, + &mut session.open_files, + &mut session.next_handle, + &mut session.vm, + signals, + platform, + ) + } + pub fn deliver_pending_game_lifecycle_events(&mut self) { if self.os.vm_runtime.current_cartridge_app_mode == AppMode::Game { let resident_game_task = self.os.foreground_stack.resident_game_task(); @@ -65,6 +95,32 @@ impl<'a> VmFacade<'a> { } } + fn deliver_pending_game_lifecycle_events_to_session(&mut self, task_id: TaskId) { + let Some(session) = self.os.vm_sessions.for_task(task_id) else { + return; + }; + + if session.runtime.current_cartridge_app_mode != AppMode::Game { + return; + } + + let mut retained = Vec::new(); + let mut delivered = Vec::new(); + + for event in self.os.game_lifecycle_events.drain(..) { + if event.task_id == task_id { + delivered.push(event); + } else { + retained.push(event); + } + } + + self.os.game_lifecycle_events = retained; + if let Some(session) = self.os.vm_sessions.for_task_mut(task_id) { + session.runtime.deliver_game_lifecycle_events(delivered); + } + } + pub fn reset(&mut self, vm: &mut VirtualMachine) { self.os.vm_runtime.reset(vm); } @@ -78,55 +134,106 @@ impl<'a> VmFacade<'a> { } pub fn paused(&self) -> bool { - self.os.vm_runtime.paused + self.active_session() + .map(|session| session.runtime.paused) + .unwrap_or(self.os.vm_runtime.paused) } pub fn set_paused(&mut self, paused: bool) { + if let Some(session) = self.active_session_mut() { + session.runtime.paused = paused; + return; + } + self.os.vm_runtime.paused = paused; } pub fn set_inspection_active(&mut self, active: bool) { + if let Some(session) = self.active_session_mut() { + session.runtime.inspection_active = active; + return; + } + self.os.vm_runtime.inspection_active = active; } pub fn request_debug_step(&mut self) { + if let Some(session) = self.active_session_mut() { + session.runtime.debug_step_request = true; + return; + } + self.os.vm_runtime.debug_step_request = true; } pub fn debug_step_requested(&self) -> bool { - self.os.vm_runtime.debug_step_request + self.active_session() + .map(|session| session.runtime.debug_step_request) + .unwrap_or(self.os.vm_runtime.debug_step_request) } pub fn logical_frame_active(&self) -> bool { - self.os.vm_runtime.logical_frame_active + self.active_session() + .map(|session| session.runtime.logical_frame_active) + .unwrap_or(self.os.vm_runtime.logical_frame_active) } pub fn delivered_game_lifecycle_events(&self) -> &[GameLifecycleEvent] { - self.os.vm_runtime.delivered_game_lifecycle_events() + self.active_session() + .map(|session| session.runtime.delivered_game_lifecycle_events()) + .unwrap_or_else(|| self.os.vm_runtime.delivered_game_lifecycle_events()) } pub fn take_delivered_game_lifecycle_events(&mut self) -> Vec { + if let Some(session) = self.active_session_mut() { + return session.runtime.take_delivered_game_lifecycle_events(); + } + self.os.vm_runtime.take_delivered_game_lifecycle_events() } pub fn tick_index(&self) -> u64 { - self.os.vm_runtime.tick_index + self.active_session() + .map(|session| session.runtime.tick_index) + .unwrap_or(self.os.vm_runtime.tick_index) } pub fn logical_frame_index(&self) -> u64 { - self.os.vm_runtime.logical_frame_index + self.active_session() + .map(|session| session.runtime.logical_frame_index) + .unwrap_or(self.os.vm_runtime.logical_frame_index) } pub fn last_frame_cpu_time_us(&self) -> u64 { - self.os.vm_runtime.last_frame_cpu_time_us + self.active_session() + .map(|session| session.runtime.last_frame_cpu_time_us) + .unwrap_or(self.os.vm_runtime.last_frame_cpu_time_us) } pub fn completed_logical_frames(&self) -> u64 { - self.os.vm_runtime.atomic_telemetry.completed_logical_frames.load(Ordering::Relaxed).into() + self.active_session() + .map(|session| { + session + .runtime + .atomic_telemetry + .completed_logical_frames + .load(Ordering::Relaxed) + .into() + }) + .unwrap_or_else(|| { + self.os + .vm_runtime + .atomic_telemetry + .completed_logical_frames + .load(Ordering::Relaxed) + .into() + }) } pub fn telemetry_snapshot(&self) -> TelemetryFrame { - self.os.vm_runtime.atomic_telemetry.snapshot() + self.active_session() + .map(|session| session.runtime.atomic_telemetry.snapshot()) + .unwrap_or_else(|| self.os.vm_runtime.atomic_telemetry.snapshot()) } pub fn start_render_worker(&mut self, config: RenderWorkerConfig, backend: B, sink: S) @@ -164,22 +271,54 @@ impl<'a> VmFacade<'a> { } pub fn last_crash_report(&self) -> Option<&CrashReport> { - self.os.vm_runtime.last_crash_report.as_ref() + self.active_session() + .and_then(|session| session.runtime.last_crash_report.as_ref()) + .or(self.os.vm_runtime.last_crash_report.as_ref()) } pub fn current_app_id(&self) -> u32 { - self.os.vm_runtime.current_app_id + self.active_session() + .map(|session| session.runtime.current_app_id) + .unwrap_or(self.os.vm_runtime.current_app_id) } pub fn current_cartridge_title(&self) -> String { - self.os.vm_runtime.current_cartridge_title.clone() + self.active_session() + .map(|session| session.runtime.current_cartridge_title.clone()) + .unwrap_or_else(|| self.os.vm_runtime.current_cartridge_title.clone()) } pub fn current_cartridge_app_version(&self) -> String { - self.os.vm_runtime.current_cartridge_app_version.clone() + self.active_session() + .map(|session| session.runtime.current_cartridge_app_version.clone()) + .unwrap_or_else(|| self.os.vm_runtime.current_cartridge_app_version.clone()) } pub fn current_cartridge_app_mode(&self) -> AppMode { - self.os.vm_runtime.current_cartridge_app_mode + self.active_session() + .map(|session| session.runtime.current_cartridge_app_mode) + .unwrap_or(self.os.vm_runtime.current_cartridge_app_mode) + } + + fn active_session(&self) -> Option<&VmSession> { + self.os + .task_manager + .foreground_task() + .and_then(|task_id| self.os.vm_sessions.for_task(task_id)) + .or_else(|| { + self.os + .foreground_stack + .resident_game_task() + .and_then(|task_id| self.os.vm_sessions.for_task(task_id)) + }) + } + + fn active_session_mut(&mut self) -> Option<&mut VmSession> { + let task_id = self + .os + .task_manager + .foreground_task() + .or_else(|| self.os.foreground_stack.resident_game_task())?; + self.os.vm_sessions.for_task_mut(task_id) } } diff --git a/crates/console/prometeu-system/src/programs/prometeu_hub/prometeu_hub.rs b/crates/console/prometeu-system/src/programs/prometeu_hub/prometeu_hub.rs index 9496fb58..d55546b1 100644 --- a/crates/console/prometeu-system/src/programs/prometeu_hub/prometeu_hub.rs +++ b/crates/console/prometeu-system/src/programs/prometeu_hub/prometeu_hub.rs @@ -1,3 +1,4 @@ +use crate::task::TaskId; use crate::{CrashReport, GameLibrary, SystemOS}; use prometeu_hal::color::Color; use prometeu_hal::primitives::Rect; @@ -194,6 +195,29 @@ impl PrometeuHub { SystemProfileUpdate { crash, action } } + pub fn update_vm_shell_profile( + &mut self, + os: &mut SystemOS, + task_id: TaskId, + signals: &InputSignals, + platform: &mut dyn RuntimePlatform, + ) -> SystemProfileUpdate { + let mut crash = None; + let mut action = self.gui_update(os, platform); + + if os.windows().focused_window().is_some() { + if platform.input().pad().start().down { + action = Some(SystemProfileAction::CloseShell); + } else if action != Some(SystemProfileAction::CloseShell) { + crash = os.vm().tick_session(task_id, signals, platform); + } + } + + self.render(os, platform); + + SystemProfileUpdate { crash, action } + } + pub fn update_native_shell_profile( &mut self, os: &mut SystemOS, diff --git a/discussion/index.ndjson b/discussion/index.ndjson index 1047ae9a..323d279f 100644 --- a/discussion/index.ndjson +++ b/discussion/index.ndjson @@ -2,7 +2,7 @@ {"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"},{"id":"AGD-0046","file":"AGD-0046-vm-context-ownership-for-resident-game-and-vm-backed-shell.md","status":"accepted","created_at":"2026-07-04","updated_at":"2026-07-04"}],"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"},{"id":"DEC-0038","file":"DEC-0038-vm-session-ownership-for-vm-backed-processes.md","status":"accepted","created_at":"2026-07-04","updated_at":"2026-07-04","ref_agenda":"AGD-0046"}],"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":"done","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":"done","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":"done","created_at":"2026-07-04","updated_at":"2026-07-04","ref_decisions":["DEC-0037"]},{"id":"PLN-0148","file":"PLN-0148-introduce-vm-session-registry-and-identity.md","status":"done","created_at":"2026-07-04","updated_at":"2026-07-04","ref_decisions":["DEC-0038"]},{"id":"PLN-0149","file":"PLN-0149-move-vm-runtime-state-into-vm-sessions.md","status":"done","created_at":"2026-07-04","updated_at":"2026-07-04","ref_decisions":["DEC-0038"]},{"id":"PLN-0150","file":"PLN-0150-route-cartridge-loading-through-vm-sessions.md","status":"done","created_at":"2026-07-04","updated_at":"2026-07-04","ref_decisions":["DEC-0038"]},{"id":"PLN-0151","file":"PLN-0151-schedule-foreground-vm-session-ticks.md","status":"open","created_at":"2026-07-04","updated_at":"2026-07-04","ref_decisions":["DEC-0038"]},{"id":"PLN-0152","file":"PLN-0152-validate-game-and-vm-shell-session-coexistence.md","status":"open","created_at":"2026-07-04","updated_at":"2026-07-04","ref_decisions":["DEC-0038"]},{"id":"PLN-0153","file":"PLN-0153-specify-vm-session-ownership-and-background-ready-scheduling.md","status":"open","created_at":"2026-07-04","updated_at":"2026-07-04","ref_decisions":["DEC-0038"]}],"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"},{"id":"AGD-0046","file":"AGD-0046-vm-context-ownership-for-resident-game-and-vm-backed-shell.md","status":"accepted","created_at":"2026-07-04","updated_at":"2026-07-04"}],"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"},{"id":"DEC-0038","file":"DEC-0038-vm-session-ownership-for-vm-backed-processes.md","status":"accepted","created_at":"2026-07-04","updated_at":"2026-07-04","ref_agenda":"AGD-0046"}],"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":"done","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":"done","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":"done","created_at":"2026-07-04","updated_at":"2026-07-04","ref_decisions":["DEC-0037"]},{"id":"PLN-0148","file":"PLN-0148-introduce-vm-session-registry-and-identity.md","status":"done","created_at":"2026-07-04","updated_at":"2026-07-04","ref_decisions":["DEC-0038"]},{"id":"PLN-0149","file":"PLN-0149-move-vm-runtime-state-into-vm-sessions.md","status":"done","created_at":"2026-07-04","updated_at":"2026-07-04","ref_decisions":["DEC-0038"]},{"id":"PLN-0150","file":"PLN-0150-route-cartridge-loading-through-vm-sessions.md","status":"done","created_at":"2026-07-04","updated_at":"2026-07-04","ref_decisions":["DEC-0038"]},{"id":"PLN-0151","file":"PLN-0151-schedule-foreground-vm-session-ticks.md","status":"done","created_at":"2026-07-04","updated_at":"2026-07-04","ref_decisions":["DEC-0038"]},{"id":"PLN-0152","file":"PLN-0152-validate-game-and-vm-shell-session-coexistence.md","status":"open","created_at":"2026-07-04","updated_at":"2026-07-04","ref_decisions":["DEC-0038"]},{"id":"PLN-0153","file":"PLN-0153-specify-vm-session-ownership-and-background-ready-scheduling.md","status":"open","created_at":"2026-07-04","updated_at":"2026-07-04","ref_decisions":["DEC-0038"]}],"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"}]} diff --git a/discussion/workflow/plans/PLN-0151-schedule-foreground-vm-session-ticks.md b/discussion/workflow/plans/PLN-0151-schedule-foreground-vm-session-ticks.md index b07684c9..873f2796 100644 --- a/discussion/workflow/plans/PLN-0151-schedule-foreground-vm-session-ticks.md +++ b/discussion/workflow/plans/PLN-0151-schedule-foreground-vm-session-ticks.md @@ -2,7 +2,7 @@ id: PLN-0151 ticket: foreground-stack-game-pause-shell-vm-backed title: Schedule Foreground VM Session Ticks -status: open +status: done created: 2026-07-04 ref_decisions: [DEC-0038] tags: [runtime, os, lifecycle, shell, game, vm, foreground, architecture]