implements PLN-0154
This commit is contained in:
parent
8098dbd7f4
commit
4e05daf280
@ -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,
|
||||
|
||||
@ -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())
|
||||
}
|
||||
}
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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();
|
||||
|
||||
@ -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"}]}
|
||||
|
||||
@ -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]
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user