diff --git a/crates/console/prometeu-hal/src/debugger_protocol.rs b/crates/console/prometeu-hal/src/debugger_protocol.rs index e6428be7..d718a149 100644 --- a/crates/console/prometeu-hal/src/debugger_protocol.rs +++ b/crates/console/prometeu-hal/src/debugger_protocol.rs @@ -40,7 +40,7 @@ pub enum DebugResponse { Breakpoints { pcs: Vec }, } -#[derive(Debug, Serialize, Deserialize)] +#[derive(Debug, Clone, Serialize, Deserialize)] pub struct HandshakeCartridge { pub app_id: u32, pub title: String, diff --git a/crates/console/prometeu-system/src/os/facades/vm.rs b/crates/console/prometeu-system/src/os/facades/vm.rs index 994c79af..87ba5cb8 100644 --- a/crates/console/prometeu-system/src/os/facades/vm.rs +++ b/crates/console/prometeu-system/src/os/facades/vm.rs @@ -3,6 +3,7 @@ use crate::os::{GameLifecycleEvent, SystemOS}; use crate::task::TaskId; use crate::vm_session::VmSession; use crate::{RenderWorkerConfig, RenderWorkerController}; +use prometeu_bytecode::Value; use prometeu_hal::app_mode::AppMode; use prometeu_hal::cartridge::Cartridge; use prometeu_hal::telemetry::{CertificationConfig, TelemetryFrame}; @@ -133,6 +134,56 @@ impl<'a> VmFacade<'a> { self.os.vm_runtime.debug_step_instruction(&mut self.os.log_service, vm, platform) } + pub fn debug_step_active_session( + &mut self, + platform: &mut dyn RuntimePlatform, + ) -> Option { + let Some(task_id) = self.active_session_task_id() else { + return Some(CrashReport::VmPanic { + message: "debug step requested without an active VM session".to_string(), + pc: None, + }); + }; + let Some(session) = self.os.vm_sessions.for_task_mut(task_id) else { + return Some(CrashReport::VmPanic { + message: format!("active debug task {:?} has no VM session", task_id), + pc: None, + }); + }; + + session.runtime.debug_step_instruction(&mut self.os.log_service, &mut session.vm, platform) + } + + pub fn active_pc(&self) -> Option { + self.active_session().map(|session| session.vm.pc()) + } + + pub fn active_operand_stack_top(&self, n: usize) -> Vec { + self.active_session().map(|session| session.vm.operand_stack_top(n)).unwrap_or_default() + } + + pub fn insert_active_breakpoint(&mut self, pc: usize) -> bool { + if let Some(session) = self.active_session_mut() { + session.vm.insert_breakpoint(pc); + return true; + } + + false + } + + pub fn remove_active_breakpoint(&mut self, pc: usize) -> bool { + if let Some(session) = self.active_session_mut() { + session.vm.remove_breakpoint(pc); + return true; + } + + false + } + + pub fn active_breakpoints_list(&self) -> Vec { + self.active_session().map(|session| session.vm.breakpoints_list()).unwrap_or_default() + } + pub fn paused(&self) -> bool { self.active_session() .map(|session| session.runtime.paused) @@ -314,11 +365,14 @@ impl<'a> VmFacade<'a> { } 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())?; + let task_id = self.active_session_task_id()?; self.os.vm_sessions.for_task_mut(task_id) } + + fn active_session_task_id(&self) -> Option { + self.os + .task_manager + .foreground_task() + .or_else(|| self.os.foreground_stack.resident_game_task()) + } } diff --git a/crates/console/prometeu-system/src/os/system_os.rs b/crates/console/prometeu-system/src/os/system_os.rs index 09bb980c..35fb4ca4 100644 --- a/crates/console/prometeu-system/src/os/system_os.rs +++ b/crates/console/prometeu-system/src/os/system_os.rs @@ -295,6 +295,43 @@ mod tests { assert_eq!(shell_session.open_files.get(&1).map(String::as_str), Some("/shell.dat")); } + #[test] + fn vm_debug_operations_target_foreground_shell_before_resident_game() { + let mut os = SystemOS::new(None); + let game = os.sessions().create_vm_game_task(42, "Sector Crawl"); + os.lifecycle().request_home_from_game(game).expect("home request should succeed"); + os.lifecycle().advance_game_pause_budget(game).expect("budget should expire"); + let shell = os.sessions().create_vm_shell_task(7, "Settings"); + + { + let mut sessions = os.sessions(); + let game_session = + sessions.vm_session_for_task_mut(game).expect("game VM session should exist"); + game_session.vm.insert_breakpoint(10); + } + + assert!(os.vm().insert_active_breakpoint(20)); + assert_eq!(os.vm().active_breakpoints_list(), vec![20]); + + let sessions = os.sessions(); + assert_eq!( + sessions + .vm_session_for_task(game) + .expect("game VM session should exist") + .vm + .breakpoints_list(), + vec![10] + ); + assert_eq!( + sessions + .vm_session_for_task(shell) + .expect("shell VM session should exist") + .vm + .breakpoints_list(), + vec![20] + ); + } + #[test] fn home_request_notifies_game_before_budget_suspends_it() { let mut os = SystemOS::new(None); diff --git a/crates/host/prometeu-host-desktop-winit/src/debugger.rs b/crates/host/prometeu-host-desktop-winit/src/debugger.rs index 9bb1ea92..c14df166 100644 --- a/crates/host/prometeu-host-desktop-winit/src/debugger.rs +++ b/crates/host/prometeu-host-desktop-winit/src/debugger.rs @@ -28,6 +28,8 @@ pub struct HostDebugger { last_telemetry_frame: u64, /// Last fault summary sent to the debugger client. last_fault_summary: Option, + /// Debug cartridge metadata captured before the VM session exists. + debug_cartridge: Option, } impl Default for HostDebugger { @@ -46,19 +48,25 @@ impl HostDebugger { last_log_seq: 0, last_telemetry_frame: 0, last_fault_summary: None, + debug_cartridge: None, } } /// Configures the debugger based on the boot target. /// If debug mode is enabled, it binds to the specified TCP port. - pub fn setup_boot_target(&mut self, boot_target: &BootTarget, firmware: &mut Firmware) { + pub fn setup_boot_target(&mut self, boot_target: &BootTarget, _firmware: &mut Firmware) { if let BootTarget::Cartridge { path, debug: true, debug_port } = boot_target { self.waiting_for_start = true; // Pre-load cartridge metadata so the Handshake message can contain - // valid information about the App being debugged. + // valid information before the VM session is created. if let Ok(cartridge) = CartridgeLoader::load(path) { - let _ = firmware.os.vm().initialize(&mut firmware.vm, &cartridge); + self.debug_cartridge = Some(HandshakeCartridge { + app_id: cartridge.app_id, + title: cartridge.title, + app_version: cartridge.app_version, + app_mode: cartridge.app_mode, + }); } match TcpListener::bind(format!("127.0.0.1:{}", debug_port)) { @@ -116,12 +124,7 @@ impl HostDebugger { let handshake = DebugResponse::Handshake { protocol_version: DEVTOOLS_PROTOCOL_VERSION, runtime_version: "0.1".to_string(), - cartridge: HandshakeCartridge { - app_id: firmware.os.vm().current_app_id(), - title: firmware.os.vm().current_cartridge_title(), - app_version: firmware.os.vm().current_cartridge_app_version(), - app_mode: firmware.os.vm().current_cartridge_app_mode(), - }, + cartridge: self.handshake_cartridge(firmware), }; self.send_response(handshake); } else { @@ -201,7 +204,7 @@ impl HostDebugger { DebugCommand::Step => { // Execute exactly one instruction and keep paused. firmware.os.vm().set_paused(true); - let _ = firmware.os.vm().debug_step_instruction(&mut firmware.vm, platform); + let _ = firmware.os.vm().debug_step_active_session(platform); } DebugCommand::StepFrame => { // Execute until the end of the current logical frame. @@ -210,10 +213,10 @@ impl HostDebugger { } DebugCommand::GetState => { // Return detailed VM register and stack state. - let stack_top = firmware.vm.operand_stack_top(10); + let stack_top = firmware.os.vm().active_operand_stack_top(10); let resp = DebugResponse::GetState { - pc: firmware.vm.pc(), + pc: firmware.os.vm().active_pc().unwrap_or(0), stack_top, frame_index: firmware.os.vm().logical_frame_index(), app_id: firmware.os.vm().current_app_id(), @@ -221,18 +224,37 @@ impl HostDebugger { self.send_response(resp); } DebugCommand::SetBreakpoint { pc } => { - firmware.vm.insert_breakpoint(pc); + let _ = firmware.os.vm().insert_active_breakpoint(pc); } DebugCommand::ListBreakpoints => { - let pcs = firmware.vm.breakpoints_list(); + let pcs = firmware.os.vm().active_breakpoints_list(); self.send_response(DebugResponse::Breakpoints { pcs }); } DebugCommand::ClearBreakpoint { pc } => { - firmware.vm.remove_breakpoint(pc); + let _ = firmware.os.vm().remove_active_breakpoint(pc); } } } + fn handshake_cartridge(&self, firmware: &mut Firmware) -> HandshakeCartridge { + let app_id = firmware.os.vm().current_app_id(); + if app_id != 0 { + return HandshakeCartridge { + app_id, + title: firmware.os.vm().current_cartridge_title(), + app_version: firmware.os.vm().current_cartridge_app_version(), + app_mode: firmware.os.vm().current_cartridge_app_mode(), + }; + } + + self.debug_cartridge.clone().unwrap_or_else(|| HandshakeCartridge { + app_id, + title: firmware.os.vm().current_cartridge_title(), + app_version: firmware.os.vm().current_cartridge_app_version(), + app_mode: firmware.os.vm().current_cartridge_app_mode(), + }) + } + pub(crate) fn cert_event_from_snapshot( tag: u16, telemetry: TelemetryFrame, @@ -315,7 +337,7 @@ impl HostDebugger { // Map specific internal log tags to protocol events. if event.tag == 0xDEB1 { self.send_event(DebugEvent::BreakpointHit { - pc: firmware.vm.pc(), + pc: firmware.os.vm().active_pc().unwrap_or(0), frame_index: firmware.os.vm().logical_frame_index(), }); } @@ -409,6 +431,51 @@ mod tests { assert!(firmware.os.vm().debug_step_requested()); } + #[test] + fn breakpoint_commands_mutate_active_vm_session_not_legacy_vm() { + let mut debugger = HostDebugger::new(); + let mut firmware = Firmware::new(None); + let mut platform = TestPlatform::new(); + let task_id = firmware.os.sessions().create_vm_game_task(42, "Sector Crawl"); + firmware.vm.insert_breakpoint(9); + + debugger.handle_command( + DebugCommand::SetBreakpoint { pc: 123 }, + &mut firmware, + &mut platform, + ); + + assert_eq!(firmware.vm.breakpoints_list(), vec![9]); + assert_eq!( + firmware + .os + .sessions() + .vm_session_for_task(task_id) + .expect("game VM session should exist") + .vm + .breakpoints_list(), + vec![123] + ); + + debugger.handle_command( + DebugCommand::ClearBreakpoint { pc: 123 }, + &mut firmware, + &mut platform, + ); + + assert_eq!(firmware.vm.breakpoints_list(), vec![9]); + assert!( + firmware + .os + .sessions() + .vm_session_for_task(task_id) + .expect("game VM session should exist") + .vm + .breakpoints_list() + .is_empty() + ); + } + #[test] fn handle_command_start_leaves_waiting_for_start_mode() { let mut debugger = HostDebugger::new(); diff --git a/discussion/index.ndjson b/discussion/index.ndjson index 230d8da5..d1685785 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-05","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":"done","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":"done","created_at":"2026-07-04","updated_at":"2026-07-04","ref_decisions":["DEC-0038"]},{"id":"PLN-0154","file":"PLN-0154-route-debugger-operations-through-vm-sessions.md","status":"open","created_at":"2026-07-05","updated_at":"2026-07-05","ref_decisions":["DEC-0038"]},{"id":"PLN-0155","file":"PLN-0155-retire-legacy-firmware-vm-runtime-bridge.md","status":"open","created_at":"2026-07-05","updated_at":"2026-07-05","ref_decisions":["DEC-0038"]},{"id":"PLN-0156","file":"PLN-0156-harden-vm-session-lifecycle-error-boundaries.md","status":"open","created_at":"2026-07-05","updated_at":"2026-07-05","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-05","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":"done","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":"done","created_at":"2026-07-04","updated_at":"2026-07-04","ref_decisions":["DEC-0038"]},{"id":"PLN-0154","file":"PLN-0154-route-debugger-operations-through-vm-sessions.md","status":"done","created_at":"2026-07-05","updated_at":"2026-07-05","ref_decisions":["DEC-0038"]},{"id":"PLN-0155","file":"PLN-0155-retire-legacy-firmware-vm-runtime-bridge.md","status":"open","created_at":"2026-07-05","updated_at":"2026-07-05","ref_decisions":["DEC-0038"]},{"id":"PLN-0156","file":"PLN-0156-harden-vm-session-lifecycle-error-boundaries.md","status":"open","created_at":"2026-07-05","updated_at":"2026-07-05","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-0154-route-debugger-operations-through-vm-sessions.md b/discussion/workflow/plans/PLN-0154-route-debugger-operations-through-vm-sessions.md index 3e125b3f..45bfaac8 100644 --- a/discussion/workflow/plans/PLN-0154-route-debugger-operations-through-vm-sessions.md +++ b/discussion/workflow/plans/PLN-0154-route-debugger-operations-through-vm-sessions.md @@ -2,7 +2,7 @@ id: PLN-0154 ticket: foreground-stack-game-pause-shell-vm-backed title: Route Debugger Operations Through VM Sessions -status: open +status: done created: 2026-07-05 ref_decisions: [DEC-0038] tags: [runtime, os, lifecycle, shell, game, vm, foreground, architecture]