diff --git a/crates/console/prometeu-hal/src/syscalls.rs b/crates/console/prometeu-hal/src/syscalls.rs index 3e9b269a..d63173a1 100644 --- a/crates/console/prometeu-hal/src/syscalls.rs +++ b/crates/console/prometeu-hal/src/syscalls.rs @@ -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. diff --git a/crates/console/prometeu-hal/src/syscalls/domains/bank.rs b/crates/console/prometeu-hal/src/syscalls/domains/bank.rs index 87a7ef1b..265b399d 100644 --- a/crates/console/prometeu-hal/src/syscalls/domains/bank.rs +++ b/crates/console/prometeu-hal/src/syscalls/domains/bank.rs @@ -3,10 +3,6 @@ use crate::syscalls::{Syscall, SyscallRegistryEntry, caps}; 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) + .rets(2) .caps(caps::BANK), ]; diff --git a/crates/console/prometeu-hal/src/syscalls/registry.rs b/crates/console/prometeu-hal/src/syscalls/registry.rs index b8007c71..7b353b1a 100644 --- a/crates/console/prometeu-hal/src/syscalls/registry.rs +++ b/crates/console/prometeu-hal/src/syscalls/registry.rs @@ -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", } } } diff --git a/crates/console/prometeu-hal/src/syscalls/tests.rs b/crates/console/prometeu-hal/src/syscalls/tests.rs index 3129d813..362a6687 100644 --- a/crates/console/prometeu-hal/src/syscalls/tests.rs +++ b/crates/console/prometeu-hal/src/syscalls/tests.rs @@ -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] diff --git a/crates/console/prometeu-system/src/virtual_machine_runtime/dispatch.rs b/crates/console/prometeu-system/src/virtual_machine_runtime/dispatch.rs index 2a0fb39b..fdf0c963 100644 --- a/crates/console/prometeu-system/src/virtual_machine_runtime/dispatch.rs +++ b/crates/console/prometeu-system/src/virtual_machine_runtime/dispatch.rs @@ -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(()) } } diff --git a/crates/console/prometeu-system/src/virtual_machine_runtime/tests.rs b/crates/console/prometeu-system/src/virtual_machine_runtime/tests.rs index 6ca08d2b..df491343 100644 --- a/crates/console/prometeu-system/src/virtual_machine_runtime/tests.rs +++ b/crates/console/prometeu-system/src/virtual_machine_runtime/tests.rs @@ -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); diff --git a/discussion/index.ndjson b/discussion/index.ndjson index ff3c5058..a4d12840 100644 --- a/discussion/index.ndjson +++ b/discussion/index.ndjson @@ -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":"review","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":"review","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"}]} diff --git a/discussion/workflow/plans/PLN-0031-dec9-runtime-bank-abi-cleanup.md b/discussion/workflow/plans/PLN-0031-dec9-runtime-bank-abi-cleanup.md index 101254fd..c24a8aeb 100644 --- a/discussion/workflow/plans/PLN-0031-dec9-runtime-bank-abi-cleanup.md +++ b/discussion/workflow/plans/PLN-0031-dec9-runtime-bank-abi-cleanup.md @@ -2,9 +2,9 @@ id: PLN-0031 ticket: perf-runtime-introspection-syscalls title: DEC-0009 Runtime Bank ABI Cleanup -status: review +status: done created: 2026-04-19 -completed: +completed: 2026-04-19 tags: [runtime, syscall, abi, bank, telemetry, debug] --- diff --git a/docs/specs/runtime/16-host-abi-and-syscalls.md b/docs/specs/runtime/16-host-abi-and-syscalls.md index 85467369..77d66115 100644 --- a/docs/specs/runtime/16-host-abi-and-syscalls.md +++ b/docs/specs/runtime/16-host-abi-and-syscalls.md @@ -205,10 +205,11 @@ For `asset.load`: `DEC-0009` narrows the public bank contract: -- `bank.slot_info` is host/debug tooling surface and is not part of the canonical long-term guest ABI; +- `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; -- if a public `bank.info` surface survives implementation cleanup, it must be reduced to a cheap deterministic operational summary aligned with the slot-first bank telemetry contract from [`15-asset-management.md`](15-asset-management.md); -- if no machine-facing operational need remains, `bank.info` should also be removed from the public guest ABI. +- `bank.info` returns stack values, not textual structured payloads. ### Composition surface (`composer`, v1)