implements PLN-0038

This commit is contained in:
bQUARKz 2026-04-20 18:04:52 +01:00
parent 6bd4c13d24
commit 77351a8813
Signed by: bquarkz
SSH Key Fingerprint: SHA256:Z7dgqoglWwoK6j6u4QC87OveEq74WOhFN+gitsxtkf8
5 changed files with 150 additions and 4 deletions

View File

@ -175,6 +175,24 @@ mod tests {
use prometeu_hal::syscalls::caps;
use prometeu_system::CrashReport;
fn halting_program() -> Vec<u8> {
let code = assemble("HALT").expect("assemble");
BytecodeModule {
version: 0,
const_pool: vec![],
functions: vec![FunctionMeta {
code_offset: 0,
code_len: code.len() as u32,
..Default::default()
}],
code,
debug_info: None,
exports: vec![],
syscalls: vec![],
}
.serialize()
}
fn invalid_game_cartridge() -> Cartridge {
Cartridge {
app_id: 7,
@ -225,6 +243,20 @@ mod tests {
}
}
fn valid_cartridge(app_mode: AppMode) -> Cartridge {
Cartridge {
app_id: 9,
title: "Valid Cart".into(),
app_version: "1.0.0".into(),
app_mode,
capabilities: caps::NONE,
program: halting_program(),
assets: AssetsPayloadSource::empty(),
asset_table: vec![],
preload: vec![],
}
}
#[test]
fn load_cartridge_transitions_to_app_crashes_when_vm_init_fails() {
let mut firmware = Firmware::new(None);
@ -268,4 +300,56 @@ mod tests {
other => panic!("expected AppCrashes state, got {:?}", other),
}
}
#[test]
fn reset_routes_hub_boot_target_to_splash_screen() {
let mut firmware = Firmware::new(None);
let mut hardware = Hardware::new();
let signals = InputSignals::default();
firmware.boot_target = BootTarget::Hub;
firmware.tick(&signals, &mut hardware);
assert!(matches!(firmware.state, FirmwareState::SplashScreen(_)));
}
#[test]
fn reset_routes_cartridge_boot_target_to_launch_hub() {
let mut firmware = Firmware::new(None);
let mut hardware = Hardware::new();
let signals = InputSignals::default();
firmware.boot_target = BootTarget::Cartridge {
path: "missing-cart".into(),
debug: false,
debug_port: 7777,
};
firmware.tick(&signals, &mut hardware);
assert!(matches!(firmware.state, FirmwareState::LaunchHub(_)));
}
#[test]
fn load_cartridge_routes_system_apps_back_to_hub_home() {
let mut firmware = Firmware::new(None);
let mut hardware = Hardware::new();
let signals = InputSignals::default();
firmware.load_cartridge(valid_cartridge(AppMode::System));
firmware.tick(&signals, &mut hardware);
assert!(matches!(firmware.state, FirmwareState::HubHome(_)));
}
#[test]
fn load_cartridge_routes_game_apps_to_game_running() {
let mut firmware = Firmware::new(None);
let mut hardware = Hardware::new();
let signals = InputSignals::default();
firmware.load_cartridge(valid_cartridge(AppMode::Game));
firmware.tick(&signals, &mut hardware);
assert!(matches!(firmware.state, FirmwareState::GameRunning(_)));
}
}

View File

@ -368,3 +368,63 @@ impl HostDebugger {
self.last_fault_summary = Some(summary);
}
}
#[cfg(test)]
mod tests {
use super::*;
use prometeu_drivers::hardware::Hardware;
use prometeu_hal::debugger_protocol::DebugCommand;
#[test]
fn setup_boot_target_ignores_hub_and_non_debug_cartridges() {
let mut debugger = HostDebugger::new();
let mut firmware = Firmware::new(None);
debugger.setup_boot_target(&BootTarget::Hub, &mut firmware);
assert!(!debugger.waiting_for_start);
assert!(debugger.listener.is_none());
debugger.setup_boot_target(
&BootTarget::Cartridge {
path: "dummy".into(),
debug: false,
debug_port: 7777,
},
&mut firmware,
);
assert!(!debugger.waiting_for_start);
assert!(debugger.listener.is_none());
}
#[test]
fn handle_command_updates_pause_and_step_flags_without_host_io() {
let mut debugger = HostDebugger::new();
let mut firmware = Firmware::new(None);
let mut hardware = Hardware::new();
debugger.handle_command(DebugCommand::Pause, &mut firmware, &mut hardware);
assert!(firmware.os.paused);
debugger.handle_command(DebugCommand::Resume, &mut firmware, &mut hardware);
assert!(!firmware.os.paused);
debugger.handle_command(DebugCommand::StepFrame, &mut firmware, &mut hardware);
assert!(!firmware.os.paused);
assert!(firmware.os.debug_step_request);
}
#[test]
fn handle_command_start_leaves_waiting_for_start_mode() {
let mut debugger = HostDebugger::new();
let mut firmware = Firmware::new(None);
let mut hardware = Hardware::new();
debugger.waiting_for_start = true;
firmware.os.paused = true;
debugger.handle_command(DebugCommand::Start, &mut firmware, &mut hardware);
assert!(!debugger.waiting_for_start);
assert!(!firmware.os.paused);
}
}

View File

@ -604,6 +604,9 @@ mod tests {
}
}
// These ignored tests intentionally cover host-dependent behavior that requires
// real socket bind/connect coordination. Deterministic debugger state changes
// are covered below the host layer in `debugger.rs`.
#[test]
#[ignore = "requires localhost TCP bind/connect; run via `cargo test -p prometeu-host-desktop-winit --lib -- --ignored`"]
fn test_debug_port_opens() {

View File

@ -4,7 +4,7 @@
{"type":"discussion","id":"DSC-0021","status":"done","ticket":"asset-entry-codec-enum-with-metadata","title":"Asset Entry Codec Enum Contract","created_at":"2026-04-09","updated_at":"2026-04-09","tags":["asset","runtime","codec","metadata"],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0024","file":"lessons/DSC-0021-asset-entry-codec-enum-contract/LSN-0024-string-on-the-wire-enum-in-runtime.md","status":"done","created_at":"2026-04-09","updated_at":"2026-04-09"}]}
{"type":"discussion","id":"DSC-0022","status":"done","ticket":"tile-bank-vs-glyph-bank-domain-naming","title":"Glyph Bank Domain Naming Contract","created_at":"2026-04-09","updated_at":"2026-04-10","tags":["gfx","runtime","naming","domain-model"],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0025","file":"lessons/DSC-0022-glyph-bank-domain-naming/LSN-0025-rename-artifact-by-meaning-not-by-token.md","status":"done","created_at":"2026-04-10","updated_at":"2026-04-10"}]}
{"type":"discussion","id":"DSC-0001","status":"done","ticket":"legacy-runtime-learn-import","title":"Import legacy runtime learn into discussion lessons","created_at":"2026-03-27","updated_at":"2026-03-27","tags":["migration","tech-debt"],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0001","file":"lessons/DSC-0001-runtime-learn-legacy-import/LSN-0001-prometeu-learn-index.md","status":"done","created_at":"2026-03-27","updated_at":"2026-03-27"},{"id":"LSN-0002","file":"lessons/DSC-0001-runtime-learn-legacy-import/LSN-0002-historical-asset-status-first-fault-and-return-contract.md","status":"done","created_at":"2026-03-27","updated_at":"2026-03-27"},{"id":"LSN-0003","file":"lessons/DSC-0001-runtime-learn-legacy-import/LSN-0003-historical-audio-status-first-fault-and-return-contract.md","status":"done","created_at":"2026-03-27","updated_at":"2026-03-27"},{"id":"LSN-0004","file":"lessons/DSC-0001-runtime-learn-legacy-import/LSN-0004-historical-cartridge-boot-protocol-and-manifest-authority.md","status":"done","created_at":"2026-03-27","updated_at":"2026-03-27"},{"id":"LSN-0005","file":"lessons/DSC-0001-runtime-learn-legacy-import/LSN-0005-historical-game-memcard-slots-surface-and-semantics.md","status":"done","created_at":"2026-03-27","updated_at":"2026-03-27"},{"id":"LSN-0006","file":"lessons/DSC-0001-runtime-learn-legacy-import/LSN-0006-historical-gfx-status-first-fault-and-return-contract.md","status":"done","created_at":"2026-03-27","updated_at":"2026-03-27"},{"id":"LSN-0007","file":"lessons/DSC-0001-runtime-learn-legacy-import/LSN-0007-historical-retired-fault-and-input-decisions.md","status":"done","created_at":"2026-03-27","updated_at":"2026-03-27"},{"id":"LSN-0008","file":"lessons/DSC-0001-runtime-learn-legacy-import/LSN-0008-historical-vm-core-and-assets.md","status":"done","created_at":"2026-03-27","updated_at":"2026-03-27"},{"id":"LSN-0009","file":"lessons/DSC-0001-runtime-learn-legacy-import/LSN-0009-mental-model-asset-management.md","status":"done","created_at":"2026-03-27","updated_at":"2026-03-27"},{"id":"LSN-0010","file":"lessons/DSC-0001-runtime-learn-legacy-import/LSN-0010-mental-model-audio.md","status":"done","created_at":"2026-03-27","updated_at":"2026-03-27"},{"id":"LSN-0011","file":"lessons/DSC-0001-runtime-learn-legacy-import/LSN-0011-mental-model-gfx.md","status":"done","created_at":"2026-03-27","updated_at":"2026-03-27"},{"id":"LSN-0012","file":"lessons/DSC-0001-runtime-learn-legacy-import/LSN-0012-mental-model-input.md","status":"done","created_at":"2026-03-27","updated_at":"2026-03-27"},{"id":"LSN-0013","file":"lessons/DSC-0001-runtime-learn-legacy-import/LSN-0013-mental-model-observability-and-debugging.md","status":"done","created_at":"2026-03-27","updated_at":"2026-03-27"},{"id":"LSN-0014","file":"lessons/DSC-0001-runtime-learn-legacy-import/LSN-0014-mental-model-portability-and-cross-platform.md","status":"done","created_at":"2026-03-27","updated_at":"2026-03-27"},{"id":"LSN-0015","file":"lessons/DSC-0001-runtime-learn-legacy-import/LSN-0015-mental-model-save-memory-and-memcard.md","status":"done","created_at":"2026-03-27","updated_at":"2026-03-27"},{"id":"LSN-0016","file":"lessons/DSC-0001-runtime-learn-legacy-import/LSN-0016-mental-model-status-first-and-fault-thinking.md","status":"done","created_at":"2026-03-27","updated_at":"2026-03-27"},{"id":"LSN-0017","file":"lessons/DSC-0001-runtime-learn-legacy-import/LSN-0017-mental-model-time-and-cycles.md","status":"done","created_at":"2026-03-27","updated_at":"2026-03-27"},{"id":"LSN-0018","file":"lessons/DSC-0001-runtime-learn-legacy-import/LSN-0018-mental-model-touch.md","status":"done","created_at":"2026-03-27","updated_at":"2026-03-27"}]}
{"type":"discussion","id":"DSC-0002","status":"open","ticket":"runtime-edge-test-plan","title":"Agenda - Runtime Edge Test Plan","created_at":"2026-03-27","updated_at":"2026-04-20","tags":[],"agendas":[{"id":"AGD-0001","file":"workflow/agendas/AGD-0001-runtime-edge-test-plan.md","status":"done","created_at":"2026-03-27","updated_at":"2026-04-20"}],"decisions":[{"id":"DEC-0020","file":"workflow/decisions/DEC-0020-runtime-edge-coverage-governance-by-domain.md","status":"in_progress","created_at":"2026-04-20","updated_at":"2026-04-20","ref_agenda":"AGD-0001"}],"plans":[{"id":"PLN-0037","file":"workflow/plans/PLN-0037-runtime-edge-coverage-governance-foundation.md","status":"done","created_at":"2026-04-20","updated_at":"2026-04-20","ref_decisions":["DEC-0020"]},{"id":"PLN-0038","file":"workflow/plans/PLN-0038-firmware-and-host-dependent-domain-coverage-expansion.md","status":"open","created_at":"2026-04-20","updated_at":"2026-04-20","ref_decisions":["DEC-0020"]},{"id":"PLN-0039","file":"workflow/plans/PLN-0039-incremental-runtime-domain-suite-split-and-baselines.md","status":"open","created_at":"2026-04-20","updated_at":"2026-04-20","ref_decisions":["DEC-0020"]}],"lessons":[]}
{"type":"discussion","id":"DSC-0002","status":"open","ticket":"runtime-edge-test-plan","title":"Agenda - Runtime Edge Test Plan","created_at":"2026-03-27","updated_at":"2026-04-20","tags":[],"agendas":[{"id":"AGD-0001","file":"workflow/agendas/AGD-0001-runtime-edge-test-plan.md","status":"done","created_at":"2026-03-27","updated_at":"2026-04-20"}],"decisions":[{"id":"DEC-0020","file":"workflow/decisions/DEC-0020-runtime-edge-coverage-governance-by-domain.md","status":"in_progress","created_at":"2026-04-20","updated_at":"2026-04-20","ref_agenda":"AGD-0001"}],"plans":[{"id":"PLN-0037","file":"workflow/plans/PLN-0037-runtime-edge-coverage-governance-foundation.md","status":"done","created_at":"2026-04-20","updated_at":"2026-04-20","ref_decisions":["DEC-0020"]},{"id":"PLN-0038","file":"workflow/plans/PLN-0038-firmware-and-host-dependent-domain-coverage-expansion.md","status":"done","created_at":"2026-04-20","updated_at":"2026-04-20","ref_decisions":["DEC-0020"]},{"id":"PLN-0039","file":"workflow/plans/PLN-0039-incremental-runtime-domain-suite-split-and-baselines.md","status":"open","created_at":"2026-04-20","updated_at":"2026-04-20","ref_decisions":["DEC-0020"]}],"lessons":[]}
{"type":"discussion","id":"DSC-0003","status":"open","ticket":"packed-cartridge-loader-pmc","title":"Agenda - Packed Cartridge Loader PMC","created_at":"2026-03-27","updated_at":"2026-03-27","tags":[],"agendas":[{"id":"AGD-0002","file":"workflow/agendas/AGD-0002-packed-cartridge-loader-pmc.md","status":"open","created_at":"2026-03-27","updated_at":"2026-03-27"}],"decisions":[],"plans":[],"lessons":[]}
{"type":"discussion","id":"DSC-0004","status":"open","ticket":"system-run-cart","title":"Agenda - System Run Cart","created_at":"2026-03-27","updated_at":"2026-03-27","tags":[],"agendas":[{"id":"AGD-0003","file":"workflow/agendas/AGD-0003-system-run-cart.md","status":"open","created_at":"2026-03-27","updated_at":"2026-03-27"}],"decisions":[],"plans":[],"lessons":[]}
{"type":"discussion","id":"DSC-0005","status":"open","ticket":"system-fault-semantics-and-control-surface","title":"Agenda - System Fault Semantics and Control Surface","created_at":"2026-03-27","updated_at":"2026-03-27","tags":[],"agendas":[{"id":"AGD-0004","file":"workflow/agendas/AGD-0004-system-fault-semantics-and-control-surface.md","status":"open","created_at":"2026-03-27","updated_at":"2026-03-27"}],"decisions":[],"plans":[],"lessons":[]}

View File

@ -2,9 +2,9 @@
id: PLN-0038
ticket: runtime-edge-test-plan
title: Plan - Firmware and Host-Dependent Domain Coverage Expansion
status: open
status: done
created: 2026-04-20
completed:
completed: 2026-04-20
tags: [tests, firmware, host, coverage]
---
@ -133,4 +133,3 @@ Use the governance helpers from `PLN-0037` if available, or temporary documented
- Adding host-only tests for behavior that belongs below the host boundary.
- Expanding firmware tests without aligning them to the state machine contract in the specs.
- Overfitting ignored integration tests to desktop timing details.