Merge pull request 'dev/perf-runtime-introspection-syscalls' (#17) from dev/perf-runtime-introspection-syscalls into master
All checks were successful
Intrepid/Prometeu/Runtime/pipeline/head This commit looks good

Reviewed-on: #17
This commit is contained in:
bquarkz 2026-04-19 08:20:09 +00:00
commit 88eaf16045
22 changed files with 499 additions and 222 deletions

View File

@ -68,6 +68,8 @@ pub enum DebugEvent {
glyph_slots_total: u32,
sound_slots_used: u32,
sound_slots_total: u32,
scene_slots_used: u32,
scene_slots_total: u32,
},
#[serde(rename = "fault")]
Fault {
@ -99,6 +101,8 @@ mod tests {
glyph_slots_total: 16,
sound_slots_used: 2,
sound_slots_total: 16,
scene_slots_used: 3,
scene_slots_total: 16,
};
let json = serde_json::to_string(&event).unwrap();

View File

@ -64,7 +64,6 @@ pub enum Syscall {
AssetCommit = 0x6003,
AssetCancel = 0x6004,
BankInfo = 0x6101,
BankSlotInfo = 0x6102,
}
/// Canonical metadata describing a syscall using the unified slot-based ABI.

View File

@ -1,12 +1,7 @@
use crate::syscalls::{Syscall, SyscallRegistryEntry, caps};
pub(crate) const ENTRIES: &[SyscallRegistryEntry] = &[
SyscallRegistryEntry::builder(Syscall::BankInfo, "bank", "info")
pub(crate) const ENTRIES: &[SyscallRegistryEntry] =
&[SyscallRegistryEntry::builder(Syscall::BankInfo, "bank", "info")
.args(1)
.rets(1)
.caps(caps::BANK),
SyscallRegistryEntry::builder(Syscall::BankSlotInfo, "bank", "slot_info")
.args(2)
.rets(1)
.caps(caps::BANK),
];
.rets(2)
.caps(caps::BANK)];

View File

@ -48,7 +48,6 @@ impl Syscall {
0x6003 => Some(Self::AssetCommit),
0x6004 => Some(Self::AssetCancel),
0x6101 => Some(Self::BankInfo),
0x6102 => Some(Self::BankSlotInfo),
_ => None,
}
}
@ -99,7 +98,6 @@ impl Syscall {
Self::AssetCommit => "AssetCommit",
Self::AssetCancel => "AssetCancel",
Self::BankInfo => "BankInfo",
Self::BankSlotInfo => "BankSlotInfo",
}
}
}

View File

@ -249,6 +249,22 @@ fn status_first_syscall_signatures_are_pinned() {
let asset_cancel = meta_for(Syscall::AssetCancel);
assert_eq!(asset_cancel.arg_slots, 1);
assert_eq!(asset_cancel.ret_slots, 1);
let bank_info = meta_for(Syscall::BankInfo);
assert_eq!(bank_info.arg_slots, 1);
assert_eq!(bank_info.ret_slots, 2);
}
#[test]
fn resolver_rejects_removed_bank_slot_info_identity() {
assert!(resolve_syscall("bank", "slot_info", 1).is_none());
let requested = [SyscallIdentity { module: "bank", name: "slot_info", version: 1 }];
let err = resolve_program_syscalls(&requested, caps::ALL).unwrap_err();
assert_eq!(
err,
LoadError::UnknownSyscall { module: "bank".into(), name: "slot_info".into(), version: 1 }
);
}
#[test]

View File

@ -18,6 +18,8 @@ pub struct TelemetryFrame {
pub glyph_slots_total: u32,
pub sound_slots_used: u32,
pub sound_slots_total: u32,
pub scene_slots_used: u32,
pub scene_slots_total: u32,
// RAM (Heap)
pub heap_used_bytes: usize,
@ -45,6 +47,8 @@ pub struct AtomicTelemetry {
pub glyph_slots_total: AtomicU32,
pub sound_slots_used: AtomicU32,
pub sound_slots_total: AtomicU32,
pub scene_slots_used: AtomicU32,
pub scene_slots_total: AtomicU32,
// RAM (Heap)
pub heap_used_bytes: AtomicUsize,
@ -75,6 +79,8 @@ impl AtomicTelemetry {
glyph_slots_total: self.glyph_slots_total.load(Ordering::Relaxed),
sound_slots_used: self.sound_slots_used.load(Ordering::Relaxed),
sound_slots_total: self.sound_slots_total.load(Ordering::Relaxed),
scene_slots_used: self.scene_slots_used.load(Ordering::Relaxed),
scene_slots_total: self.scene_slots_total.load(Ordering::Relaxed),
heap_used_bytes: self.heap_used_bytes.load(Ordering::Relaxed),
heap_max_bytes: self.heap_max_bytes.load(Ordering::Relaxed),
logs_count: self.logs_count.load(Ordering::Relaxed),
@ -93,6 +99,8 @@ impl AtomicTelemetry {
self.glyph_slots_total.store(0, Ordering::Relaxed);
self.sound_slots_used.store(0, Ordering::Relaxed);
self.sound_slots_total.store(0, Ordering::Relaxed);
self.scene_slots_used.store(0, Ordering::Relaxed);
self.scene_slots_total.store(0, Ordering::Relaxed);
self.heap_used_bytes.store(0, Ordering::Relaxed);
self.vm_steps.store(0, Ordering::Relaxed);
self.logs_count.store(0, Ordering::Relaxed);

View File

@ -567,19 +567,8 @@ impl NativeInterface for VirtualMachineRuntime {
used_slots: 0,
total_slots: 0,
});
let json = serde_json::to_string(&telemetry).unwrap_or_default();
ret.push_string(json);
Ok(())
}
Syscall::BankSlotInfo => {
let asset_type = match expect_int(args, 0)? as u32 {
0 => BankType::GLYPH,
1 => BankType::SOUNDS,
_ => return Err(VmFault::Trap(TRAP_TYPE, "Invalid asset type".to_string())),
};
let slot = SlotRef { asset_type, index: expect_int(args, 1)? as usize };
let json = serde_json::to_string(&hw.assets().slot_info(slot)).unwrap_or_default();
ret.push_string(json);
ret.push_int(telemetry.used_slots as i64);
ret.push_int(telemetry.total_slots as i64);
Ok(())
}
}

View File

@ -937,6 +937,60 @@ fn tick_asset_status_unknown_handle_returns_status_not_crash() {
assert_eq!(vm.operand_stack_top(1), vec![Value::Int64(LoadStatus::UnknownHandle as i64)]);
}
#[test]
fn tick_bank_info_returns_slot_summary_not_json() {
let mut runtime = VirtualMachineRuntime::new(None);
let mut vm = VirtualMachine::default();
let mut hardware = Hardware::new();
let signals = InputSignals::default();
let asset_data = test_glyph_asset_data();
hardware.assets.initialize_for_cartridge(
vec![test_glyph_asset_entry("tile_asset", asset_data.len())],
vec![prometeu_hal::asset::PreloadEntry { asset_id: 7, slot: 0 }],
AssetsPayloadSource::from_bytes(asset_data),
);
let code = assemble("PUSH_I32 0\nHOSTCALL 0\nHALT").expect("assemble");
let program = serialized_single_function_module(
code,
vec![SyscallDecl {
module: "bank".into(),
name: "info".into(),
version: 1,
arg_slots: 1,
ret_slots: 2,
}],
);
let cartridge = cartridge_with_program(program, caps::BANK);
runtime.initialize_vm(&mut vm, &cartridge).expect("runtime must initialize");
let report = runtime.tick(&mut vm, &signals, &mut hardware);
assert!(report.is_none(), "bank summary must not crash");
assert!(vm.is_halted());
assert_eq!(vm.operand_stack_top(2), vec![Value::Int64(16), Value::Int64(1)]);
}
#[test]
fn initialize_vm_rejects_removed_bank_slot_info_syscall_identity() {
let mut runtime = VirtualMachineRuntime::new(None);
let mut vm = VirtualMachine::default();
let code = assemble("PUSH_I32 0\nPUSH_I32 0\nHOSTCALL 0\nHALT").expect("assemble");
let program = serialized_single_function_module(
code,
vec![SyscallDecl {
module: "bank".into(),
name: "slot_info".into(),
version: 1,
arg_slots: 2,
ret_slots: 1,
}],
);
let cartridge = cartridge_with_program(program, caps::BANK);
let res = runtime.initialize_vm(&mut vm, &cartridge);
assert!(matches!(res, Err(CrashReport::VmInit { error: VmInitError::LoaderPatchFailed(_) })));
}
#[test]
fn tick_asset_commit_invalid_transition_returns_status_not_crash() {
let mut runtime = VirtualMachineRuntime::new(None);

View File

@ -7,7 +7,9 @@ use prometeu_vm::LogicalFrameEndingReason;
use std::sync::atomic::Ordering;
impl VirtualMachineRuntime {
fn bank_telemetry_summary(hw: &dyn HardwareBridge) -> (BankTelemetry, BankTelemetry) {
fn bank_telemetry_summary(
hw: &dyn HardwareBridge,
) -> (BankTelemetry, BankTelemetry, BankTelemetry) {
let telemetry = hw.assets().bank_telemetry();
let glyph =
telemetry.iter().find(|entry| entry.bank_type == BankType::GLYPH).cloned().unwrap_or(
@ -17,8 +19,12 @@ impl VirtualMachineRuntime {
telemetry.iter().find(|entry| entry.bank_type == BankType::SOUNDS).cloned().unwrap_or(
BankTelemetry { bank_type: BankType::SOUNDS, used_slots: 0, total_slots: 0 },
);
let scenes =
telemetry.iter().find(|entry| entry.bank_type == BankType::SCENE).cloned().unwrap_or(
BankTelemetry { bank_type: BankType::SCENE, used_slots: 0, total_slots: 0 },
);
(glyph, sounds)
(glyph, sounds, scenes)
}
pub fn debug_step_instruction(
@ -148,7 +154,7 @@ impl VirtualMachineRuntime {
hw.render_frame();
// 1. Snapshot full telemetry at logical frame end
let (glyph_bank, sound_bank) = Self::bank_telemetry_summary(hw);
let (glyph_bank, sound_bank, scene_bank) = Self::bank_telemetry_summary(hw);
self.atomic_telemetry
.glyph_slots_used
.store(glyph_bank.used_slots as u32, Ordering::Relaxed);
@ -161,6 +167,12 @@ impl VirtualMachineRuntime {
self.atomic_telemetry
.sound_slots_total
.store(sound_bank.total_slots as u32, Ordering::Relaxed);
self.atomic_telemetry
.scene_slots_used
.store(scene_bank.used_slots as u32, Ordering::Relaxed);
self.atomic_telemetry
.scene_slots_total
.store(scene_bank.total_slots as u32, Ordering::Relaxed);
self.atomic_telemetry
.heap_used_bytes
@ -218,7 +230,7 @@ impl VirtualMachineRuntime {
// 2. High-frequency telemetry update (only if inspection is active)
if self.inspection_active {
let (glyph_bank, sound_bank) = Self::bank_telemetry_summary(hw);
let (glyph_bank, sound_bank, scene_bank) = Self::bank_telemetry_summary(hw);
self.atomic_telemetry
.glyph_slots_used
.store(glyph_bank.used_slots as u32, Ordering::Relaxed);
@ -231,6 +243,12 @@ impl VirtualMachineRuntime {
self.atomic_telemetry
.sound_slots_total
.store(sound_bank.total_slots as u32, Ordering::Relaxed);
self.atomic_telemetry
.scene_slots_used
.store(scene_bank.used_slots as u32, Ordering::Relaxed);
self.atomic_telemetry
.scene_slots_total
.store(scene_bank.total_slots as u32, Ordering::Relaxed);
self.atomic_telemetry
.heap_used_bytes

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,72 @@ 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,
scene_slots_used: telemetry.scene_slots_used,
scene_slots_total: telemetry.scene_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 +320,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 +342,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

@ -94,6 +94,7 @@ pub(crate) fn capture_snapshot(stats: &HostStats, firmware: &Firmware) -> Overla
let heap_ratio = ratio(tel.heap_used_bytes as u64, heap_total_bytes as u64);
let glyph_ratio = ratio(tel.glyph_slots_used as u64, tel.glyph_slots_total as u64);
let sound_ratio = ratio(tel.sound_slots_used as u64, tel.sound_slots_total as u64);
let scene_ratio = ratio(tel.scene_slots_used as u64, tel.scene_slots_total as u64);
OverlaySnapshot {
rows: vec![
@ -163,6 +164,12 @@ pub(crate) fn capture_snapshot(stats: &HostStats, firmware: &Firmware) -> Overla
ratio: sound_ratio,
warn: tel.sound_slots_total > 0 && tel.sound_slots_used >= tel.sound_slots_total,
},
OverlayBar {
label: "SCENE",
value: format!("{} / {} slots", tel.scene_slots_used, tel.scene_slots_total),
ratio: scene_ratio,
warn: tel.scene_slots_total > 0 && tel.scene_slots_used >= tel.scene_slots_total,
},
],
footer,
}

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,123 @@ 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,
scene_slots_used: 2,
scene_slots_total: 16,
..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,
scene_slots_used,
scene_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);
assert_eq!(scene_slots_used, 2);
assert_eq!(scene_slots_total, 16);
}
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

@ -0,0 +1,29 @@
{"type":"meta","next_id":{"DSC":29,"AGD":29,"DEC":18,"PLN":33,"LSN":34,"CLSN":1}}
{"type":"discussion","id":"DSC-0023","status":"done","ticket":"perf-full-migration-to-atomic-telemetry","title":"Agenda - [PERF] Full Migration to Atomic Telemetry","created_at":"2026-04-10","updated_at":"2026-04-10","tags":["perf","runtime","telemetry"],"agendas":[{"id":"AGD-0021","file":"workflow/agendas/AGD-0021-full-migration-to-atomic-telemetry.md","status":"done","created_at":"2026-04-10","updated_at":"2026-04-10"}],"decisions":[{"id":"DEC-0008","file":"workflow/decisions/DEC-0008-full-migration-to-atomic-telemetry.md","status":"accepted","created_at":"2026-04-10","updated_at":"2026-04-10"}],"plans":[{"id":"PLN-0007","file":"workflow/plans/PLN-0007-full-migration-to-atomic-telemetry.md","status":"done","created_at":"2026-04-10","updated_at":"2026-04-10"}],"lessons":[{"id":"LSN-0028","file":"lessons/DSC-0023-perf-full-migration-to-atomic-telemetry/LSN-0028-converging-to-single-atomic-telemetry-source.md","status":"done","created_at":"2026-04-10","updated_at":"2026-04-10"}]}
{"type":"discussion","id":"DSC-0020","status":"done","ticket":"jenkins-gitea-integration","title":"Jenkins Gitea Integration and Relocation","created_at":"2026-04-07","updated_at":"2026-04-07","tags":["ci","jenkins","gitea"],"agendas":[{"id":"AGD-0018","file":"workflow/agendas/AGD-0018-jenkins-gitea-integration-and-relocation.md","status":"done","created_at":"2026-04-07","updated_at":"2026-04-07"}],"decisions":[{"id":"DEC-0003","file":"workflow/decisions/DEC-0003-jenkins-gitea-strategy.md","status":"accepted","created_at":"2026-04-07","updated_at":"2026-04-07"}],"plans":[{"id":"PLN-0003","file":"workflow/plans/PLN-0003-jenkins-gitea-execution.md","status":"done","created_at":"2026-04-07","updated_at":"2026-04-07"}],"lessons":[{"id":"LSN-0021","file":"lessons/DSC-0020-jenkins-gitea-integration/LSN-0021-jenkins-gitea-integration.md","status":"done","created_at":"2026-04-07","updated_at":"2026-04-07"}]}
{"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-03-27","tags":[],"agendas":[{"id":"AGD-0001","file":"workflow/agendas/AGD-0001-runtime-edge-test-plan.md","status":"open","created_at":"2026-03-27","updated_at":"2026-03-27"}],"decisions":[],"plans":[],"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":[]}
{"type":"discussion","id":"DSC-0006","status":"open","ticket":"vm-owned-random-service","title":"Agenda - VM-Owned Random Service","created_at":"2026-03-27","updated_at":"2026-03-27","tags":[],"agendas":[{"id":"AGD-0005","file":"workflow/agendas/AGD-0005-vm-owned-random-service.md","status":"open","created_at":"2026-03-27","updated_at":"2026-03-27"}],"decisions":[],"plans":[],"lessons":[]}
{"type":"discussion","id":"DSC-0007","status":"open","ticket":"app-home-filesystem-surface-and-semantics","title":"Agenda - App Home Filesystem Surface and Semantics","created_at":"2026-03-27","updated_at":"2026-03-27","tags":[],"agendas":[{"id":"AGD-0006","file":"workflow/agendas/AGD-0006-app-home-filesystem-surface-and-semantics.md","status":"open","created_at":"2026-03-27","updated_at":"2026-03-27"}],"decisions":[],"plans":[],"lessons":[]}
{"type":"discussion","id":"DSC-0008","status":"done","ticket":"perf-runtime-telemetry-hot-path","title":"Agenda - [PERF] Runtime Telemetry Hot Path","created_at":"2026-03-27","updated_at":"2026-04-10","tags":[],"agendas":[{"id":"AGD-0007","file":"workflow/agendas/AGD-0007-perf-runtime-telemetry-hot-path.md","status":"done","created_at":"2026-03-27","updated_at":"2026-04-10"}],"decisions":[{"id":"DEC-0005","file":"workflow/decisions/DEC-0005-perf-push-based-telemetry-model.md","status":"accepted","created_at":"2026-04-10","updated_at":"2026-04-10"}],"plans":[{"id":"PLN-0005","file":"workflow/plans/PLN-0005-perf-push-based-telemetry-implementation.md","status":"done","created_at":"2026-04-10","updated_at":"2026-04-10"}],"lessons":[{"id":"LSN-0026","file":"lessons/DSC-0008-perf-runtime-telemetry-hot-path/LSN-0026-push-based-telemetry-model.md","status":"done","created_at":"2026-04-10","updated_at":"2026-04-10"}]}
{"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":"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"}]}
{"type":"discussion","id":"DSC-0026","status":"done","ticket":"render-all-scene-cache-and-camera-integration","title":"Integrate render_all with Scene Cache and Camera","created_at":"2026-04-14","updated_at":"2026-04-18","tags":["gfx","runtime","render","camera","scene"],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0031","file":"lessons/DSC-0026-render-all-scene-cache-and-camera-integration/LSN-0031-frame-composition-belongs-above-the-render-backend.md","status":"done","created_at":"2026-04-18","updated_at":"2026-04-18"}]}
{"type":"discussion","id":"DSC-0027","status":"done","ticket":"frame-composer-public-syscall-surface","title":"Agenda - FrameComposer Public Syscall Surface","created_at":"2026-04-17","updated_at":"2026-04-18","tags":["gfx","runtime","syscall","abi","frame-composer","scene","camera","sprites"],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0032","file":"lessons/DSC-0027-frame-composer-public-syscall-surface/LSN-0032-public-abi-must-follow-the-canonical-service-boundary.md","status":"done","created_at":"2026-04-18","updated_at":"2026-04-18"}]}
{"type":"discussion","id":"DSC-0028","status":"done","ticket":"deferred-overlay-and-primitive-composition","title":"Deferred Overlay and Primitive Composition over FrameComposer","created_at":"2026-04-18","updated_at":"2026-04-18","tags":["gfx","runtime","render","frame-composer","overlay","primitives","hud"],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0033","file":"lessons/DSC-0028-deferred-overlay-and-primitive-composition/LSN-0033-debug-primitives-should-be-a-final-overlay-not-part-of-game-composition.md","status":"done","created_at":"2026-04-18","updated_at":"2026-04-18"}]}
{"type":"discussion","id":"DSC-0014","status":"open","ticket":"perf-vm-allocation-and-copy-pressure","title":"Agenda - [PERF] VM Allocation and Copy Pressure","created_at":"2026-03-27","updated_at":"2026-03-27","tags":[],"agendas":[{"id":"AGD-0013","file":"workflow/agendas/AGD-0013-perf-vm-allocation-and-copy-pressure.md","status":"open","created_at":"2026-03-27","updated_at":"2026-03-27"}],"decisions":[],"plans":[],"lessons":[]}
{"type":"discussion","id":"DSC-0015","status":"open","ticket":"perf-cartridge-boot-and-program-ownership","title":"Agenda - [PERF] Cartridge Boot and Program Ownership","created_at":"2026-03-27","updated_at":"2026-03-27","tags":[],"agendas":[{"id":"AGD-0014","file":"workflow/agendas/AGD-0014-perf-cartridge-boot-and-program-ownership.md","status":"open","created_at":"2026-03-27","updated_at":"2026-03-27"}],"decisions":[],"plans":[],"lessons":[]}
{"type":"discussion","id":"DSC-0016","status":"done","ticket":"tilemap-empty-cell-vs-tile-id-zero","title":"Tilemap Empty Cell vs Tile ID Zero","created_at":"2026-03-27","updated_at":"2026-04-09","tags":[],"agendas":[{"id":"AGD-0015","file":"workflow/agendas/AGD-0015-tilemap-empty-cell-vs-tile-id-zero.md","status":"done","created_at":"2026-03-27","updated_at":"2026-04-09"}],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0022","file":"lessons/DSC-0016-tilemap-empty-cell-semantics/LSN-0022-tilemap-empty-cell-convergence.md","status":"done","created_at":"2026-04-09","updated_at":"2026-04-09"}]}
{"type":"discussion","id":"DSC-0017","status":"done","ticket":"asset-entry-metadata-normalization-contract","title":"Asset Entry Metadata Normalization Contract","created_at":"2026-03-27","updated_at":"2026-04-09","tags":[],"agendas":[{"id":"AGD-0016","file":"workflow/agendas/AGD-0016-asset-entry-metadata-normalization-contract.md","status":"done","created_at":"2026-03-27","updated_at":"2026-04-09"}],"decisions":[{"id":"DEC-0004","file":"workflow/decisions/DEC-0004-asset-entry-metadata-normalization-contract.md","status":"accepted","created_at":"2026-04-09","updated_at":"2026-04-09"}],"plans":[],"lessons":[{"id":"LSN-0023","file":"lessons/DSC-0017-asset-metadata-normalization/LSN-0023-typed-asset-metadata-helpers.md","status":"done","created_at":"2026-04-09","updated_at":"2026-04-09"}]}
{"type":"discussion","id":"DSC-0018","status":"done","ticket":"asset-load-asset-id-int-contract","title":"Asset Load Asset ID Int Contract","created_at":"2026-03-27","updated_at":"2026-03-27","tags":["asset","runtime","abi"],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0019","file":"lessons/DSC-0018-asset-load-asset-id-int-contract/LSN-0019-asset-load-id-abi-convergence.md","status":"done","created_at":"2026-03-27","updated_at":"2026-03-27"}]}
{"type":"discussion","id":"DSC-0019","status":"done","ticket":"jenkinsfile-correction","title":"Jenkinsfile Correction and Relocation","created_at":"2026-04-07","updated_at":"2026-04-07","tags":["ci","jenkins"],"agendas":[{"id":"AGD-0017","file":"workflow/agendas/AGD-0017-jenkinsfile-correction.md","status":"done","created_at":"2026-04-07","updated_at":"2026-04-07"}],"decisions":[{"id":"DEC-0002","file":"workflow/decisions/DEC-0002-jenkinsfile-strategy.md","status":"accepted","created_at":"2026-04-07","updated_at":"2026-04-07"}],"plans":[{"id":"PLN-0002","file":"workflow/plans/PLN-0002-jenkinsfile-execution.md","status":"done","created_at":"2026-04-07","updated_at":"2026-04-07"}],"lessons":[{"id":"LSN-0020","file":"lessons/DSC-0019-jenkins-ci-standardization/LSN-0020-jenkins-standard-relocation.md","status":"done","created_at":"2026-04-07","updated_at":"2026-04-07"}]}

View File

@ -1,4 +1,4 @@
{"type":"meta","next_id":{"DSC":29,"AGD":29,"DEC":17,"PLN":30,"LSN":34,"CLSN":1}}
{"type":"meta","next_id":{"DSC":29,"AGD":29,"DEC":18,"PLN":33,"LSN":35,"CLSN":1}}
{"type":"discussion","id":"DSC-0023","status":"done","ticket":"perf-full-migration-to-atomic-telemetry","title":"Agenda - [PERF] Full Migration to Atomic Telemetry","created_at":"2026-04-10","updated_at":"2026-04-10","tags":["perf","runtime","telemetry"],"agendas":[{"id":"AGD-0021","file":"workflow/agendas/AGD-0021-full-migration-to-atomic-telemetry.md","status":"done","created_at":"2026-04-10","updated_at":"2026-04-10"}],"decisions":[{"id":"DEC-0008","file":"workflow/decisions/DEC-0008-full-migration-to-atomic-telemetry.md","status":"accepted","created_at":"2026-04-10","updated_at":"2026-04-10"}],"plans":[{"id":"PLN-0007","file":"workflow/plans/PLN-0007-full-migration-to-atomic-telemetry.md","status":"done","created_at":"2026-04-10","updated_at":"2026-04-10"}],"lessons":[{"id":"LSN-0028","file":"lessons/DSC-0023-perf-full-migration-to-atomic-telemetry/LSN-0028-converging-to-single-atomic-telemetry-source.md","status":"done","created_at":"2026-04-10","updated_at":"2026-04-10"}]}
{"type":"discussion","id":"DSC-0020","status":"done","ticket":"jenkins-gitea-integration","title":"Jenkins Gitea Integration and Relocation","created_at":"2026-04-07","updated_at":"2026-04-07","tags":["ci","jenkins","gitea"],"agendas":[{"id":"AGD-0018","file":"workflow/agendas/AGD-0018-jenkins-gitea-integration-and-relocation.md","status":"done","created_at":"2026-04-07","updated_at":"2026-04-07"}],"decisions":[{"id":"DEC-0003","file":"workflow/decisions/DEC-0003-jenkins-gitea-strategy.md","status":"accepted","created_at":"2026-04-07","updated_at":"2026-04-07"}],"plans":[{"id":"PLN-0003","file":"workflow/plans/PLN-0003-jenkins-gitea-execution.md","status":"done","created_at":"2026-04-07","updated_at":"2026-04-07"}],"lessons":[{"id":"LSN-0021","file":"lessons/DSC-0020-jenkins-gitea-integration/LSN-0021-jenkins-gitea-integration.md","status":"done","created_at":"2026-04-07","updated_at":"2026-04-07"}]}
{"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"}]}
@ -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":"open","ticket":"perf-runtime-introspection-syscalls","title":"Agenda - [PERF] Runtime Introspection Syscalls","created_at":"2026-03-27","updated_at":"2026-03-27","tags":[],"agendas":[{"id":"AGD-0011","file":"workflow/agendas/AGD-0011-perf-runtime-introspection-syscalls.md","status":"open","created_at":"2026-03-27","updated_at":"2026-03-27"}],"decisions":[],"plans":[],"lessons":[]}
{"type":"discussion","id":"DSC-0012","status":"done","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":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0034","file":"lessons/DSC-0012-perf-runtime-introspection-syscalls/LSN-0034-host-owned-debug-boundaries.md","status":"done","created_at":"2026-04-19","updated_at":"2026-04-19"}]}
{"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

@ -0,0 +1,55 @@
---
id: LSN-0034
ticket: perf-runtime-introspection-syscalls
title: Host-Owned Debug Boundaries and Cheap Machine Diagnostics
created: 2026-04-19
tags: [runtime, host, debug, certification, telemetry, abi]
---
## Context
`DSC-0012` resolved a recurring ambiguity in PROMETEU: whether development diagnostics should be treated as part of the guest/runtime contract or as host tooling concerns. The codebase already had host overlay rendering, atomic telemetry snapshots, and slot-first bank telemetry, but the runtime still exposed JSON-formatted bank inspection syscalls.
The completed work converged specs, runtime ABI, and host debugger behavior around a single boundary: rich diagnostics belong to the host, while the runtime exports only bounded machine-facing summaries.
## Key Decisions
### Host-Owned Debug and Certification (`DEC-0009`)
**What:**
Debug tooling and certification are host-owned concerns. Guest-visible debug convenience APIs are not part of the long-term runtime ABI.
**Why:**
Development inspection, profiling, and certification analysis happen on desktop host environments, not on production handheld/runtime targets. Keeping those concerns in the guest ABI forces production execution to carry tooling-oriented surface area and cost.
**Trade-offs:**
The runtime gives up general introspection syscalls, so host tooling must consume telemetry and internal host/runtime integration points directly. In exchange, the public ABI becomes cheaper, narrower, and easier to reason about.
## Patterns and Algorithms
- Treat diagnostics as a layered boundary:
The runtime owns deterministic counters, bounded summaries, and machine-facing operational signals.
The host owns rendering, protocol projection, certification output, and rich inspection UX.
- Prefer cheap structured values over textual debug payloads:
If a machine-facing diagnostic survives, it should return small canonical stack values such as `(used_slots, total_slots)`, not JSON blobs.
- Use one telemetry source for all host consumers:
Atomic telemetry snapshots should feed debugger streaming, overlays, and certification evaluation so the platform does not fork multiple diagnostic pipelines.
- Keep telemetry slot-first when the real machine contract is slot-first:
Bank occupancy was correctly modeled as slot usage, so the surviving public summary stayed aligned with that semantic model instead of byte-oriented totals or slot-detail dumps.
## Pitfalls
- Do not let host-only needs backdoor themselves into the guest ABI as "temporary" debug syscalls. They tend to linger and become accidental contract.
- Do not use JSON-on-the-wire as a fallback ABI for runtime inspection. It is easy to add, but it creates unbounded cost and weakens the canonical machine model.
- Do not update only specs or only code. This boundary needed spec propagation, runtime ABI cleanup, and host debugger alignment together to avoid split-brain behavior.
## Takeaways
- Debug and certification pipelines should be modeled as host products that consume runtime telemetry, not as guest features.
- Surviving machine diagnostics must be justified by operational need and expressed as bounded structured values.
- The clean boundary is: runtime produces telemetry, host interprets and presents it.

View File

@ -1,72 +0,0 @@
---
id: AGD-0011
ticket: perf-runtime-introspection-syscalls
title: Agenda - [PERF] Runtime Introspection Syscalls
status: open
created: 2026-03-27
resolved:
decision:
tags: []
---
# Agenda - [PERF] Runtime Introspection Syscalls
## Problema
As syscalls de introspecao ainda carregam custo de serializacao e agregacao demais para algo que deveria ser observabilidade sob demanda.
Hoje `BankInfo` e `BankSlotInfo` montam JSON por chamada e puxam dados potencialmente caros do asset manager.
## Dor
- tooling de debug pode contaminar custo percebido da runtime surface.
- serializacao de string/JSON vira alocacao no meio do dispatch.
- sem fronteira clara, apps podem abusar de syscalls de introspecao como se fossem baratas.
## Hotspots Atuais
- [dispatch.rs](/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/crates/console/prometeu-system/src/virtual_machine_runtime/dispatch.rs#L481)
- [asset.rs](/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/crates/console/prometeu-drivers/src/asset.rs#L618)
## Alvo da Discussao
Separar claramente custo de introspecao/debug do custo da superficie operacional normal.
## O Que Precisa Ser Definido
1. Papel dessas syscalls.
Decidir se `BankInfo`/`BankSlotInfo` sao:
- superficie publica normal;
- superficie de debug;
- superficie host/devtools apenas.
2. Shape de retorno.
Definir se JSON continua existindo ou se v1 exige shape mais barato/canonico.
3. Caching.
Delimitar se snapshots de introspecao podem ser cacheados por frame.
4. Limites de uso.
Decidir se o runtime deve impor throttling, budget ou feature gate de debug.
## Open Questions de Arquitetura
1. Vale manter JSON na ABI do guest ou isso deveria ficar restrito ao host/debugger?
2. Existe um subconjunto de dados numericos suficiente para carts sem tooling externo?
3. O certifier deve observar essas chamadas como custo anormal de debug?
## Dependencias
- `../specs/10-debug-inspection-and-profiling.md`
- `../specs/15-asset-management.md`
- `../specs/16-host-abi-and-syscalls.md`
- `../specs/16a-syscall-policies.md`
## Criterio de Saida Desta Agenda
Pode virar PR quando houver decisao escrita sobre:
- papel normativo de `BankInfo`/`BankSlotInfo`;
- permanencia ou remocao de JSON como shape de retorno;
- politica de cache/throttling;
- custo aceitavel de introspecao no dispatch.

View File

@ -98,7 +98,7 @@ Important properties:
- events are processed at known points;
- no execution occurs outside the frame loop;
- frame structure remains observable for tooling and certification.
- frame structure remains observable for host tooling and host-owned certification.
## 7 Determinism and Best Practices

View File

@ -7,19 +7,18 @@ Didactic companion: [`../learn/mental-model-observability-and-debugging.md`](../
## 1 Scope
This chapter defines the machine-visible debugging, inspection, and profiling surface of PROMETEU.
This chapter defines the machine-visible diagnostics and profiling surface of PROMETEU after `DEC-0009`.
`DEC-0009` locks debug tooling and certification output as host-owned concerns. The runtime machine contract therefore exposes only bounded operational diagnostics and deterministic telemetry production, not a general-purpose guest-visible debug surface.
It covers:
- execution modes;
- pause and stepping;
- state inspection;
- graphics inspection;
- runtime-visible execution control used by host tooling;
- bounded operational telemetry;
- profiling;
- breakpoints and watchpoints;
- event and fault visibility;
- certification-facing diagnostics;
- Host-side debug overlay (HUD) isolation.
- certification input data;
- host-side debug overlay (HUD) isolation.
## 2 Execution Modes
@ -34,18 +33,18 @@ PROMETEU operates in three main modes:
### 2.2 Debug Mode
- controlled execution
- access to internal state
- host-mediated access to internal state
- pauses and stepping
### 2.3 Certification Mode
- deterministic execution
- collected metrics
- report generation
- host-generated report output
No mode alters the logical result of the program.
## 3 Execution Debug
## 3 Execution Control
### 3.1 Pause and Resume
@ -64,24 +63,26 @@ During pause:
### 3.2 Step-by-Step
PROMETEU allows stepping at different levels:
PROMETEU allows host tooling to step execution at different levels:
- **by frame**
- **by function**
- **by VM instruction**
Stepping by instruction reveals:
When the host activates instruction-level inspection, it may observe:
- Program Counter (PC)
- current instruction
- operand stack
- call stack
## 4 State Inspection
## 4 State Inspection Boundary
Detailed state inspection is a host-owned concern. The runtime may expose deterministic machine state to host tooling, but this chapter does not define a general guest ABI for introspection convenience.
### 4.1 Stacks
PROMETEU allows inspecting:
Host tooling may inspect:
- **Operand Stack**
- **Call Stack**
@ -94,7 +95,7 @@ For each frame:
### 4.2 Heap
The heap can be inspected in real time:
The host may inspect heap state in real time:
- total size
- current usage
@ -109,22 +110,22 @@ The programmer can observe:
### 4.3 Global Space
Global variables:
Host-owned inspection may observe global variables, including:
- current values
- references
- initialization
## 5 Graphics Debug
## 5 Graphics Inspection Boundary
PROMETEU allows inspecting the graphics system:
Host tooling may inspect the graphics system:
- front buffer
- back buffer
- palette state
- active sprites
It is possible to:
The host may:
- freeze the image
- observe buffers separately
@ -153,7 +154,7 @@ SYSTEM:612
### 6.2 Per-Function Profiling
PROMETEU can associate cycles with:
Host tooling may associate cycles with:
- functions
- methods
@ -161,7 +162,7 @@ PROMETEU can associate cycles with:
### 6.3 Per-Instruction Profiling
At the lowest level, the system can display:
At the lowest level, host tooling can display:
- executed instructions
- individual cost
@ -185,13 +186,13 @@ Peak:34KB❌
Limit:32KB
```
These data directly feed the certification.
These data feed host-owned certification.
### 7.1 Bank Occupancy Profiling
Bank occupancy diagnostics are slot-first.
The visible per-bank telemetry used by host inspection surfaces and certification is:
The visible per-bank telemetry used by host inspection surfaces and host-owned certification is:
- `bank_type`
- `used_slots`
@ -206,9 +207,11 @@ Byte-oriented bank occupancy is not the canonical visible profiling contract.
## 8 Breakpoints and Watchpoints
Breakpoints and watchpoints are host-mediated tooling controls. They are not part of the gameplay-facing cartridge contract.
### 8.1 Breakpoints
PROMETEU supports breakpoints in:
The platform supports host-owned breakpoints in:
- specific frames
- functions
@ -222,7 +225,7 @@ Breakpoints:
### 8.2 Watchpoints
Watchpoints monitor:
Host tooling may monitor watchpoints over:
- variables
- heap addresses
@ -233,10 +236,14 @@ Execution can pause when:
- a value changes
- a limit is exceeded
## 9 Event and Fault Debugging
## 9 Event and Fault Diagnostics
## 10 Certification Diagnostics
Certification diagnostics are produced by the host from deterministic runtime telemetry.
The runtime does not generate the final certification artifact. It only maintains the machine-facing counters and summaries required for host-owned certification.
Certification diagnostics may enforce bank occupancy ceilings.
For bank residency, certification uses slot-based limits, such as:
@ -246,7 +253,7 @@ For bank residency, certification uses slot-based limits, such as:
Bank certification MUST NOT depend on `max_gfx_bytes` or `max_audio_bytes`.
PROMETEU allows observing:
Host tooling may observe:
- event queue
- active timers
@ -259,7 +266,7 @@ Each event has:
- cost
- consequence
## 10 Host-Side Debug Overlay (HUD) Isolation
## 11 Host-Side Debug Overlay (HUD) Isolation
The visual Debug Overlay (HUD) for technical inspection is not part of the emulated machine pipeline.
@ -270,7 +277,7 @@ The visual Debug Overlay (HUD) for technical inspection is not part of the emula
3. **Host overlay module:** The Desktop Host owns a dedicated overlay module that performs host-side text, panel, and simple bar composition.
4. **Composition boundary:** The overlay is composed on the Host presentation surface after the emulated frame is ready. Overlay pixels must not be written back into the emulated framebuffer.
5. **Host control:** Overlay visibility and presentation policy remain under Host control.
2. **Host (Desktop):** Responsible for collecting telemetry from the runtime and rendering the HUD as a native, transparent layer.
6. **Host (Desktop):** Responsible for collecting telemetry from the runtime and rendering the HUD as a native, transparent layer.
### 10.2 Principles
@ -287,11 +294,11 @@ To ensure zero-impact synchronization between the VM and the Host Debug Overlay,
3. **Single Source of Truth:** This model is the exclusive source of truth for both real-time inspection and frame-end certification, replacing legacy per-frame buffered fields.
4. **Frame-Closed Log Metric:** `logs_count` in the snapshot represents the number of logs emitted in the last completed logical frame, not a transient in-flight counter.
## 11 Integration with CAP and Certification
## 12 Integration with CAP and Certification
All debug and profiling data:
All machine diagnostics and profiling data:
- feed the certification report
- are collected deterministically
- do not depend on external tools
- feed the host-owned certification report;
- are collected deterministically;
- do not require a guest-visible debug ABI;
- are consistent regardless of whether the Host HUD is active or not.

View File

@ -162,7 +162,7 @@ Without changing semantics.
## 11 Certification and Portability
The **PROMETEU Certification** is valid for all platforms.
The host-owned **PROMETEU Certification** is valid for all platforms.
If a cartridge:

View File

@ -110,44 +110,44 @@ This table describes content identity and storage layout, not live residency.
### 4.1 `TILES` asset contract in v1
Para `BankType::TILES`, o contrato v1 voltado para o runtime é:
For `BankType::TILES`, the v1 runtime-facing contract is:
- `codec = NONE`
- pixels serializados usam índices de paleta `u4` empacotados
- paletas serializadas usam `RGB565` (`u16`, little-endian)
- serialized pixels use packed `u4` palette indices
- serialized palettes use `RGB565` (`u16`, little-endian)
- `palette_count = 64`
- a materialização em runtime pode expandir índices de pixel para um `u8` por pixel
- runtime materialization may expand pixel indices to one `u8` per pixel
`NONE` para `TILES` significa que não há camada de codec genérica adicional além do próprio contrato do banco.
For `TILES`, `NONE` means there is no additional generic codec layer beyond the bank contract itself.
Para a janela de transição atual:
For the current transition window:
- `RAW` é um alias legado e depreciado de `NONE`
- novos materiais publicados devem usar `NONE` como valor canônico
- `RAW` is a legacy deprecated alias of `NONE`
- newly published material must use `NONE` as the canonical value
Mesmo com `codec = NONE`, `TILES` ainda requer decode específico de banco a partir de seu payload serializado. O layout de bytes serializados não precisa, portanto, ser idêntico ao layout em memória.
Even with `codec = NONE`, `TILES` still requires bank-specific decode from its serialized payload. The serialized byte layout therefore does not need to match the in-memory layout.
#### 4.1.1 Metadata Normalization
Seguindo a `DEC-0004`, o campo `AssetEntry.metadata` deve ser estruturado de forma segmentada para evitar ambiguidades.
Following `DEC-0004`, the `AssetEntry.metadata` field must be structured in segmented form to avoid ambiguity.
Campos de metadados obrigatórios (efetivos) para `TILES` no nível raiz:
Required effective metadata fields for `TILES` at the root level:
- `tile_size`: aresta do tile em pixels; valores válidos são `8`, `16`, ou `32`
- `width`: largura total da folha do banco em pixels
- `height`: altura total da folha do banco em pixels
- `palette_count`: número de paletas serializadas para o banco
- `tile_size`: tile edge in pixels; valid values are `8`, `16`, or `32`
- `width`: total sheet width in pixels
- `height`: total sheet height in pixels
- `palette_count`: number of serialized palettes for the bank
Subárvores opcionais e informativas:
Optional informative subtrees:
- `metadata.codec`: Configuração específica do codec/compressor (ex: dicionários, flags de compressão).
- `metadata.pipeline`: Metadados informativos do processo de build do Studio (ex: source hashes, timestamps, tool versions).
- `metadata.codec`: codec/compressor-specific configuration (for example dictionaries or compression flags).
- `metadata.pipeline`: informative metadata from the Studio build process (for example source hashes, timestamps, or tool versions).
Regras de validação para `TILES` v1:
Validation rules for `TILES` v1:
- `palette_count` deve ser `64`
- `width * height` define o número de pixels indexados lógicos na folha decodificada
- metadados adicionais podem existir, mas o contrato do runtime não deve depender deles para reconstruir o banco em memória (exceto se definidos na raiz como campos efetivos).
- `palette_count` must be `64`
- `width * height` defines the number of logical indexed pixels in the decoded sheet
- extra metadata may exist, but the runtime contract must not depend on it to reconstruct the in-memory bank unless that data is defined at the root as an effective field.
#### 4.1.2 Payload Layout
@ -202,7 +202,8 @@ Rules:
- the visible contract MUST NOT expose byte-oriented bank occupancy as the canonical summary;
- canonical bank names are `GLYPH` and `SOUNDS`;
- detailed occupancy inspection remains slot-based through slot references, not bank byte totals;
- detailed occupancy inspection remains host-owned and slot-based through slot references, not bank byte totals;
- public runtime specs MUST NOT treat `bank.slot_info` or JSON bank inspection payloads as the long-term guest ABI after `DEC-0009`;
- any residual byte accounting MAY exist internally, but it is not part of the visible bank telemetry contract.
## 6 Load Lifecycle
@ -255,9 +256,9 @@ Therefore:
- shutting down a cartridge can release bank residency independently of VM heap behavior.
- the runtime must not keep the full `assets.pa` payload resident in RAM as a baseline requirement.
## 8 Bank Telemetry
## 8 Bank Telemetry and Inspection Boundary
The runtime surfaces bank and slot statistics such as:
The runtime may maintain bank and slot statistics such as:
- total bytes;
- used bytes;
@ -266,7 +267,11 @@ The runtime surfaces bank and slot statistics such as:
- slot occupancy;
- resident asset identity per slot.
These metrics support debugging, telemetry, and certification-oriented inspection.
These metrics support host-owned debugging, telemetry, and certification-oriented inspection.
Only bounded operational summaries belong to the public runtime contract.
Detailed per-slot inspection is valid for host tooling and runtime internals, but it must not be treated as a general guest-visible debug convenience API.
## 9 Preload

View File

@ -15,6 +15,8 @@ It focuses on:
Operational policies such as capabilities, fault classes, determinism, GC interaction, budgeting, and blocking are split into a companion chapter.
Per `DEC-0009`, debug tooling and certification are host-owned concerns. This chapter therefore excludes general-purpose guest-visible debug syscalls from the canonical public ABI.
## 1 Design Principles
The syscall ABI follows these rules:
@ -199,6 +201,16 @@ For `asset.load`:
- `slot` is the target slot index;
- bank kind is resolved from `asset_table` by `asset_id`, not supplied by the caller.
### Bank diagnostics surface (`bank`, v1)
`DEC-0009` narrows the public bank contract:
- `bank.info(bank_type) -> (used_slots, total_slots)` is the only surviving public bank diagnostic shape in v1;
- `bank.info` exists only as a cheap deterministic operational summary aligned with the slot-first bank telemetry contract from [`15-asset-management.md`](15-asset-management.md);
- `bank.slot_info` is host/debug tooling surface and is not part of the canonical public guest ABI;
- JSON-on-the-wire bank inspection payloads are not valid public ABI;
- `bank.info` returns stack values, not textual structured payloads.
### Composition surface (`composer`, v1)
The canonical frame-orchestration public ABI uses module `composer`.

View File

@ -9,6 +9,8 @@ It complements [`16-host-abi-and-syscalls.md`](16-host-abi-and-syscalls.md), whi
Unless a domain chapter explicitly narrows behavior further, this chapter is the transversal policy for all syscalls in v1.
Per `DEC-0009`, guest-visible syscalls must not exist merely for debug convenience or certification plumbing. Those concerns belong to host-owned tooling.
## 1 Error Model: Faults vs Status Returns
Syscalls use a status-first hybrid model.
@ -61,6 +63,7 @@ Practical rule:
- `void` is allowed only for operations whose non-fault path is effectively unconditional success;
- any operation with a meaningful operational non-success outcome must surface that outcome through `status`, not through absence of return values.
- debug-only or certification-only convenience calls are not justified public ABI even if they could be given a valid return shape.
### No-op policy
@ -77,6 +80,14 @@ This means operational problems must not be reclassified as:
- `Trap`, when the failure is not structural;
- `Panic`, when the failure is not an internal invariant break.
### Diagnostics boundary
These policy constraints also apply to observability surfaces:
- host-owned inspection and certification consumers may use runtime telemetry and internal host/runtime integration paths;
- guest-visible syscalls must be justified by machine-facing operational needs, not by tooling convenience;
- textual JSON diagnostics are not valid long-term public syscall ABI.
## 2 Capability System
Each syscall requires a declared capability.
@ -141,7 +152,7 @@ The system may account for:
- cycles spent in syscalls;
- allocations triggered by syscalls.
This keeps host interaction visible in certification, telemetry, and profiling.
This keeps host interaction visible in host-owned certification, telemetry, and profiling.
## 6 Blocking and Long Operations