implements PLN-0154

This commit is contained in:
bQUARKz 2026-07-05 00:21:10 +01:00
parent 8098dbd7f4
commit 4e05daf280
Signed by: bquarkz
SSH Key Fingerprint: SHA256:Z7dgqoglWwoK6j6u4QC87OveEq74WOhFN+gitsxtkf8
6 changed files with 182 additions and 24 deletions

View File

@ -40,7 +40,7 @@ pub enum DebugResponse {
Breakpoints { pcs: Vec<usize> },
}
#[derive(Debug, Serialize, Deserialize)]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct HandshakeCartridge {
pub app_id: u32,
pub title: String,

View File

@ -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<CrashReport> {
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<usize> {
self.active_session().map(|session| session.vm.pc())
}
pub fn active_operand_stack_top(&self, n: usize) -> Vec<Value> {
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<usize> {
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<TaskId> {
self.os
.task_manager
.foreground_task()
.or_else(|| self.os.foreground_stack.resident_game_task())
}
}

View File

@ -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);

View File

@ -28,6 +28,8 @@ pub struct HostDebugger {
last_telemetry_frame: u64,
/// Last fault summary sent to the debugger client.
last_fault_summary: Option<String>,
/// Debug cartridge metadata captured before the VM session exists.
debug_cartridge: Option<HandshakeCartridge>,
}
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();

View File

@ -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"}]}

View File

@ -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]