implements PLN-0032

This commit is contained in:
bQUARKz 2026-04-19 08:44:09 +01:00
parent 52785b5a8c
commit 33dd6d008b
Signed by: bquarkz
SSH Key Fingerprint: SHA256:Z7dgqoglWwoK6j6u4QC87OveEq74WOhFN+gitsxtkf8
4 changed files with 192 additions and 58 deletions

View File

@ -2,6 +2,7 @@ use prometeu_drivers::hardware::Hardware;
use prometeu_firmware::{BootTarget, Firmware};
use prometeu_hal::cartridge_loader::CartridgeLoader;
use prometeu_hal::debugger_protocol::*;
use prometeu_hal::telemetry::{CertificationConfig, TelemetryFrame};
use prometeu_system::CrashReport;
use std::io::{Read, Write};
use std::net::{TcpListener, TcpStream};
@ -12,6 +13,8 @@ use std::net::{TcpListener, TcpStream};
/// Prometeu Debugger) to observe and control the execution of the virtual machine.
///
/// Communication is based on JSONL (JSON lines) over TCP.
/// Detailed inspection and certification events are synthesized in the host
/// from telemetry snapshots and host/runtime integration state.
pub struct HostDebugger {
/// If true, the VM will not start execution until a 'start' command is received.
pub waiting_for_start: bool,
@ -230,6 +233,70 @@ impl HostDebugger {
}
}
pub(crate) fn cert_event_from_snapshot(
tag: u16,
telemetry: TelemetryFrame,
cert_config: &CertificationConfig,
frame_index: u64,
) -> Option<DebugEvent> {
let (rule, used, limit) = match tag {
0xCA01 => (
"cycles_budget".to_string(),
telemetry.cycles_used,
cert_config.cycles_budget_per_frame.unwrap_or(0),
),
0xCA02 => (
"max_syscalls".to_string(),
telemetry.syscalls as u64,
cert_config.max_syscalls_per_frame.unwrap_or(0) as u64,
),
0xCA03 => (
"max_host_cpu_us".to_string(),
telemetry.host_cpu_time_us,
cert_config.max_host_cpu_us_per_frame.unwrap_or(0),
),
0xCA04 => (
"max_glyph_slots_used".to_string(),
telemetry.glyph_slots_used as u64,
cert_config.max_glyph_slots_used.unwrap_or(0) as u64,
),
0xCA05 => (
"max_sound_slots_used".to_string(),
telemetry.sound_slots_used as u64,
cert_config.max_sound_slots_used.unwrap_or(0) as u64,
),
0xCA06 => (
"max_heap_bytes".to_string(),
telemetry.heap_used_bytes as u64,
cert_config.max_heap_bytes.unwrap_or(0) as u64,
),
0xCA07 => (
"max_logs_per_frame".to_string(),
telemetry.logs_count as u64,
cert_config.max_logs_per_frame.unwrap_or(0) as u64,
),
_ => return None,
};
Some(DebugEvent::Cert { rule, used, limit, frame_index })
}
pub(crate) fn telemetry_event_from_snapshot(telemetry: TelemetryFrame) -> DebugEvent {
DebugEvent::Telemetry {
frame_index: telemetry.frame_index,
vm_steps: telemetry.vm_steps,
syscalls: telemetry.syscalls,
cycles: telemetry.cycles_used,
cycles_budget: telemetry.cycles_budget,
host_cpu_time_us: telemetry.host_cpu_time_us,
violations: telemetry.violations,
glyph_slots_used: telemetry.glyph_slots_used,
glyph_slots_total: telemetry.glyph_slots_total,
sound_slots_used: telemetry.sound_slots_used,
sound_slots_total: telemetry.sound_slots_total,
}
}
/// Scans the system for new information to push to the debugger client.
fn stream_events(&mut self, firmware: &mut Firmware) {
if let Some(report) = firmware.os.last_crash_report.as_ref() {
@ -251,46 +318,15 @@ impl HostDebugger {
});
}
// Map Certification tags (0xCA01-0xCA03) to 'Cert' protocol events.
if event.tag >= 0xCA01 && event.tag <= 0xCA03 {
let tel = firmware.os.atomic_telemetry.snapshot();
let cert_config = &firmware.os.certifier.config;
let (rule, used, limit) = match event.tag {
0xCA01 => (
"cycles_budget".to_string(),
tel.cycles_used,
cert_config.cycles_budget_per_frame.unwrap_or(0),
),
0xCA02 => (
"max_syscalls".to_string(),
tel.syscalls as u64,
cert_config.max_syscalls_per_frame.unwrap_or(0) as u64,
),
0xCA03 => (
"max_host_cpu_us".to_string(),
tel.host_cpu_time_us,
cert_config.max_host_cpu_us_per_frame.unwrap_or(0),
),
0xCA04 => (
"max_glyph_slots_used".to_string(),
tel.glyph_slots_used as u64,
cert_config.max_glyph_slots_used.unwrap_or(0) as u64,
),
0xCA05 => (
"max_sound_slots_used".to_string(),
tel.sound_slots_used as u64,
cert_config.max_sound_slots_used.unwrap_or(0) as u64,
),
_ => ("unknown".to_string(), 0, 0),
};
self.send_event(DebugEvent::Cert {
rule,
used,
limit,
frame_index: firmware.os.logical_frame_index,
});
if (0xCA01..=0xCA07).contains(&event.tag)
&& let Some(cert_event) = Self::cert_event_from_snapshot(
event.tag,
firmware.os.atomic_telemetry.snapshot(),
&firmware.os.certifier.config,
firmware.os.logical_frame_index,
)
{
self.send_event(cert_event);
}
self.send_event(DebugEvent::Log {
@ -304,19 +340,7 @@ impl HostDebugger {
let current_frame = firmware.os.logical_frame_index;
if current_frame > self.last_telemetry_frame {
let tel = firmware.os.atomic_telemetry.snapshot();
self.send_event(DebugEvent::Telemetry {
frame_index: tel.frame_index,
vm_steps: tel.vm_steps,
syscalls: tel.syscalls,
cycles: tel.cycles_used,
cycles_budget: tel.cycles_budget,
host_cpu_time_us: tel.host_cpu_time_us,
violations: tel.violations,
glyph_slots_used: tel.glyph_slots_used,
glyph_slots_total: tel.glyph_slots_total,
sound_slots_used: tel.sound_slots_used,
sound_slots_total: tel.sound_slots_total,
});
self.send_event(Self::telemetry_event_from_snapshot(tel));
self.last_telemetry_frame = current_frame;
}
}

View File

@ -58,7 +58,8 @@ pub struct HostRunner {
/// Performance metrics collector.
stats: HostStats,
/// Remote debugger interface.
/// Remote debugger interface. It consumes host-owned telemetry and runtime state
/// directly instead of depending on guest-visible inspection syscalls.
debugger: HostDebugger,
/// Flag to enable/disable the technical telemetry display.
@ -225,7 +226,8 @@ impl ApplicationHandler for HostRunner {
// 1. Process pending debug commands from the network.
self.debugger.check_commands(&mut self.firmware, &mut self.hardware);
// Sync inspection mode state.
// Sync inspection mode state. This is host-owned overlay/debugger control,
// not a guest-visible debug ABI switch.
self.firmware.os.inspection_active = self.overlay_enabled || self.debugger.stream.is_some();
// 2. Maintain filesystem connection if it was lost (e.g., directory removed).
@ -307,9 +309,117 @@ mod tests {
use super::*;
use prometeu_firmware::BootTarget;
use prometeu_hal::debugger_protocol::DEVTOOLS_PROTOCOL_VERSION;
use prometeu_hal::telemetry::{CertificationConfig, TelemetryFrame};
use std::io::{Read, Write};
use std::net::TcpStream;
#[test]
fn host_debugger_maps_cert_events_from_host_owned_sources() {
let telemetry = TelemetryFrame {
glyph_slots_used: 3,
heap_used_bytes: 4096,
logs_count: 7,
..Default::default()
};
let config = CertificationConfig {
enabled: true,
max_glyph_slots_used: Some(2),
max_heap_bytes: Some(2048),
max_logs_per_frame: Some(5),
..Default::default()
};
match HostDebugger::cert_event_from_snapshot(0xCA04, telemetry, &config, 12) {
Some(prometeu_hal::debugger_protocol::DebugEvent::Cert {
rule,
used,
limit,
frame_index,
}) => {
assert_eq!(rule, "max_glyph_slots_used");
assert_eq!(used, 3);
assert_eq!(limit, 2);
assert_eq!(frame_index, 12);
}
other => panic!("unexpected glyph cert event: {:?}", other),
}
match HostDebugger::cert_event_from_snapshot(0xCA06, telemetry, &config, 12) {
Some(prometeu_hal::debugger_protocol::DebugEvent::Cert {
rule,
used,
limit,
frame_index,
}) => {
assert_eq!(rule, "max_heap_bytes");
assert_eq!(used, 4096);
assert_eq!(limit, 2048);
assert_eq!(frame_index, 12);
}
other => panic!("unexpected heap cert event: {:?}", other),
}
match HostDebugger::cert_event_from_snapshot(0xCA07, telemetry, &config, 12) {
Some(prometeu_hal::debugger_protocol::DebugEvent::Cert {
rule,
used,
limit,
frame_index,
}) => {
assert_eq!(rule, "max_logs_per_frame");
assert_eq!(used, 7);
assert_eq!(limit, 5);
assert_eq!(frame_index, 12);
}
other => panic!("unexpected logs cert event: {:?}", other),
}
}
#[test]
fn host_debugger_maps_telemetry_from_atomic_snapshot_fields() {
let telemetry = TelemetryFrame {
frame_index: 8,
vm_steps: 123,
syscalls: 9,
cycles_used: 456,
cycles_budget: 789,
host_cpu_time_us: 321,
violations: 2,
glyph_slots_used: 1,
glyph_slots_total: 16,
sound_slots_used: 0,
sound_slots_total: 8,
..Default::default()
};
match HostDebugger::telemetry_event_from_snapshot(telemetry) {
prometeu_hal::debugger_protocol::DebugEvent::Telemetry {
frame_index,
vm_steps,
syscalls,
cycles,
cycles_budget,
host_cpu_time_us,
violations,
glyph_slots_used,
glyph_slots_total,
sound_slots_used,
sound_slots_total,
} => {
assert_eq!(frame_index, 8);
assert_eq!(vm_steps, 123);
assert_eq!(syscalls, 9);
assert_eq!(cycles, 456);
assert_eq!(cycles_budget, 789);
assert_eq!(host_cpu_time_us, 321);
assert_eq!(violations, 2);
assert_eq!(glyph_slots_used, 1);
assert_eq!(glyph_slots_total, 16);
assert_eq!(sound_slots_used, 0);
assert_eq!(sound_slots_total, 8);
}
other => panic!("unexpected telemetry event: {:?}", other),
}
}
#[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

@ -14,7 +14,7 @@
{"type":"discussion","id":"DSC-0009","status":"open","ticket":"perf-async-background-work-lanes-for-assets-and-fs","title":"Agenda - [PERF] Async Background Work Lanes for Assets and FS","created_at":"2026-03-27","updated_at":"2026-03-27","tags":[],"agendas":[{"id":"AGD-0008","file":"workflow/agendas/AGD-0008-perf-async-background-work-lanes-for-assets-and-fs.md","status":"open","created_at":"2026-03-27","updated_at":"2026-03-27"}],"decisions":[],"plans":[],"lessons":[]}
{"type":"discussion","id":"DSC-0010","status":"open","ticket":"perf-host-desktop-frame-pacing-and-presentation","title":"Agenda - [PERF] Host Desktop Frame Pacing and Presentation","created_at":"2026-03-27","updated_at":"2026-03-27","tags":[],"agendas":[{"id":"AGD-0009","file":"workflow/agendas/AGD-0009-perf-host-desktop-frame-pacing-and-presentation.md","status":"open","created_at":"2026-03-27","updated_at":"2026-03-27"}],"decisions":[],"plans":[],"lessons":[]}
{"type":"discussion","id":"DSC-0011","status":"open","ticket":"perf-gfx-render-pipeline-and-dirty-regions","title":"Agenda - [PERF] GFX Render Pipeline and Dirty Regions","created_at":"2026-03-27","updated_at":"2026-03-27","tags":[],"agendas":[{"id":"AGD-0010","file":"workflow/agendas/AGD-0010-perf-gfx-render-pipeline-and-dirty-regions.md","status":"open","created_at":"2026-03-27","updated_at":"2026-03-27"}],"decisions":[],"plans":[],"lessons":[]}
{"type":"discussion","id":"DSC-0012","status":"review","ticket":"perf-runtime-introspection-syscalls","title":"Agenda - [PERF] Runtime Introspection Syscalls","created_at":"2026-03-27","updated_at":"2026-04-19","tags":["perf","runtime","syscall","telemetry","debug","asset"],"agendas":[{"id":"AGD-0011","file":"workflow/agendas/AGD-0011-perf-runtime-introspection-syscalls.md","status":"accepted","created_at":"2026-03-27","updated_at":"2026-04-18"}],"decisions":[{"id":"DEC-0009","file":"workflow/decisions/DEC-0009-host-owned-debug-and-certification.md","status":"accepted","created_at":"2026-04-18","updated_at":"2026-04-19","ref_agenda":"AGD-0011"}],"plans":[{"id":"PLN-0030","file":"workflow/plans/PLN-0030-dec9-spec-boundary-propagation.md","status":"done","created_at":"2026-04-19","updated_at":"2026-04-19","ref_decisions":["DEC-0009"]},{"id":"PLN-0031","file":"workflow/plans/PLN-0031-dec9-runtime-bank-abi-cleanup.md","status":"done","created_at":"2026-04-19","updated_at":"2026-04-19","ref_decisions":["DEC-0009"]},{"id":"PLN-0032","file":"workflow/plans/PLN-0032-dec9-host-debugger-and-certification-alignment.md","status":"review","created_at":"2026-04-19","updated_at":"2026-04-19","ref_decisions":["DEC-0009"]}],"lessons":[]}
{"type":"discussion","id":"DSC-0012","status":"review","ticket":"perf-runtime-introspection-syscalls","title":"Agenda - [PERF] Runtime Introspection Syscalls","created_at":"2026-03-27","updated_at":"2026-04-19","tags":["perf","runtime","syscall","telemetry","debug","asset"],"agendas":[{"id":"AGD-0011","file":"workflow/agendas/AGD-0011-perf-runtime-introspection-syscalls.md","status":"accepted","created_at":"2026-03-27","updated_at":"2026-04-18"}],"decisions":[{"id":"DEC-0009","file":"workflow/decisions/DEC-0009-host-owned-debug-and-certification.md","status":"accepted","created_at":"2026-04-18","updated_at":"2026-04-19","ref_agenda":"AGD-0011"}],"plans":[{"id":"PLN-0030","file":"workflow/plans/PLN-0030-dec9-spec-boundary-propagation.md","status":"done","created_at":"2026-04-19","updated_at":"2026-04-19","ref_decisions":["DEC-0009"]},{"id":"PLN-0031","file":"workflow/plans/PLN-0031-dec9-runtime-bank-abi-cleanup.md","status":"done","created_at":"2026-04-19","updated_at":"2026-04-19","ref_decisions":["DEC-0009"]},{"id":"PLN-0032","file":"workflow/plans/PLN-0032-dec9-host-debugger-and-certification-alignment.md","status":"done","created_at":"2026-04-19","updated_at":"2026-04-19","ref_decisions":["DEC-0009"]}],"lessons":[]}
{"type":"discussion","id":"DSC-0013","status":"done","ticket":"perf-host-debug-overlay-isolation","title":"Agenda - [PERF] Host Debug Overlay Isolation","created_at":"2026-03-27","updated_at":"2026-04-10","tags":[],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0027","file":"lessons/DSC-0013-perf-host-debug-overlay-isolation/LSN-0027-host-debug-overlay-isolation.md","status":"done","created_at":"2026-04-10","updated_at":"2026-04-10"}]}
{"type":"discussion","id":"DSC-0024","status":"done","ticket":"generic-memory-bank-slot-contract","title":"Agenda - Generic Memory Bank Slot Contract","created_at":"2026-04-10","updated_at":"2026-04-10","tags":["runtime","asset","memory-bank","slots","host"],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0029","file":"lessons/DSC-0024-generic-memory-bank-slot-contract/LSN-0029-slot-first-bank-telemetry-belongs-in-asset-manager.md","status":"done","created_at":"2026-04-10","updated_at":"2026-04-10"}]}
{"type":"discussion","id":"DSC-0025","status":"done","ticket":"scene-bank-and-viewport-cache-refactor","title":"Scene Bank and Viewport Cache Refactor","created_at":"2026-04-11","updated_at":"2026-04-14","tags":["gfx","tilemap","runtime","render"],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0030","file":"lessons/DSC-0025-scene-bank-and-viewport-cache-refactor/LSN-0030-canonical-scene-cache-and-resolver-split.md","status":"done","created_at":"2026-04-14","updated_at":"2026-04-14"}]}

View File

@ -2,9 +2,9 @@
id: PLN-0032
ticket: perf-runtime-introspection-syscalls
title: DEC-0009 Host Debugger and Certification Alignment
status: review
status: done
created: 2026-04-19
completed:
completed: 2026-04-19
tags: [host, debug, certification, telemetry, desktop]
---