Asset Status-First Surface and Lifecycle
This commit is contained in:
parent
9cb0e77b01
commit
0c32457a10
@ -786,29 +786,37 @@ mod tests {
|
||||
use super::*;
|
||||
use crate::memory_banks::{MemoryBanks, SoundBankPoolAccess, TileBankPoolAccess};
|
||||
|
||||
#[test]
|
||||
fn test_asset_loading_flow() {
|
||||
let banks = Arc::new(MemoryBanks::new());
|
||||
let gfx_installer = Arc::clone(&banks) as Arc<dyn TileBankPoolInstaller>;
|
||||
let sound_installer = Arc::clone(&banks) as Arc<dyn SoundBankPoolInstaller>;
|
||||
|
||||
fn test_tile_asset_data() -> Vec<u8> {
|
||||
let mut data = vec![1u8; 256];
|
||||
data.extend_from_slice(&[0u8; 2048]);
|
||||
data
|
||||
}
|
||||
|
||||
let asset_entry = AssetEntry {
|
||||
fn test_tile_asset_entry(asset_name: &str, data_len: usize) -> AssetEntry {
|
||||
AssetEntry {
|
||||
asset_id: 0,
|
||||
asset_name: "test_tiles".to_string(),
|
||||
asset_name: asset_name.to_string(),
|
||||
bank_type: BankType::TILES,
|
||||
offset: 0,
|
||||
size: data.len() as u64,
|
||||
decoded_size: data.len() as u64,
|
||||
size: data_len as u64,
|
||||
decoded_size: data_len as u64,
|
||||
codec: "RAW".to_string(),
|
||||
metadata: serde_json::json!({
|
||||
"tile_size": 16,
|
||||
"width": 16,
|
||||
"height": 16
|
||||
}),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_asset_loading_flow() {
|
||||
let banks = Arc::new(MemoryBanks::new());
|
||||
let gfx_installer = Arc::clone(&banks) as Arc<dyn TileBankPoolInstaller>;
|
||||
let sound_installer = Arc::clone(&banks) as Arc<dyn SoundBankPoolInstaller>;
|
||||
|
||||
let data = test_tile_asset_data();
|
||||
let asset_entry = test_tile_asset_entry("test_tiles", data.len());
|
||||
|
||||
let am = AssetManager::new(vec![asset_entry], data, gfx_installer, sound_installer);
|
||||
let slot = SlotRef::gfx(0);
|
||||
@ -842,23 +850,8 @@ mod tests {
|
||||
let gfx_installer = Arc::clone(&banks) as Arc<dyn TileBankPoolInstaller>;
|
||||
let sound_installer = Arc::clone(&banks) as Arc<dyn SoundBankPoolInstaller>;
|
||||
|
||||
let mut data = vec![1u8; 256];
|
||||
data.extend_from_slice(&[0u8; 2048]);
|
||||
|
||||
let asset_entry = AssetEntry {
|
||||
asset_id: 0,
|
||||
asset_name: "test_tiles".to_string(),
|
||||
bank_type: BankType::TILES,
|
||||
offset: 0,
|
||||
size: data.len() as u64,
|
||||
decoded_size: data.len() as u64,
|
||||
codec: "RAW".to_string(),
|
||||
metadata: serde_json::json!({
|
||||
"tile_size": 16,
|
||||
"width": 16,
|
||||
"height": 16
|
||||
}),
|
||||
};
|
||||
let data = test_tile_asset_data();
|
||||
let asset_entry = test_tile_asset_entry("test_tiles", data.len());
|
||||
|
||||
let am = AssetManager::new(vec![asset_entry], data, gfx_installer, sound_installer);
|
||||
|
||||
@ -959,19 +952,9 @@ mod tests {
|
||||
let gfx_installer = Arc::clone(&banks) as Arc<dyn TileBankPoolInstaller>;
|
||||
let sound_installer = Arc::clone(&banks) as Arc<dyn SoundBankPoolInstaller>;
|
||||
|
||||
let mut data = vec![0u8; 256]; // pixels
|
||||
data.extend_from_slice(&[0u8; 2048]); // palette
|
||||
|
||||
let asset_entry = AssetEntry {
|
||||
asset_id: 10,
|
||||
asset_name: "my_tiles".to_string(),
|
||||
bank_type: BankType::TILES,
|
||||
offset: 0,
|
||||
size: data.len() as u64,
|
||||
decoded_size: data.len() as u64,
|
||||
codec: "RAW".to_string(),
|
||||
metadata: serde_json::json!({ "tile_size": 16, "width": 16, "height": 16 }),
|
||||
};
|
||||
let data = test_tile_asset_data();
|
||||
let mut asset_entry = test_tile_asset_entry("my_tiles", data.len());
|
||||
asset_entry.asset_id = 10;
|
||||
|
||||
let preload = vec![PreloadEntry { asset_name: "my_tiles".to_string(), slot: 3 }];
|
||||
|
||||
@ -982,4 +965,89 @@ mod tests {
|
||||
assert_eq!(am.find_slot_by_name("unknown", BankType::TILES), None);
|
||||
assert_eq!(am.find_slot_by_name("my_tiles", BankType::SOUNDS), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_load_returns_asset_not_found() {
|
||||
let banks = Arc::new(MemoryBanks::new());
|
||||
let gfx_installer = Arc::clone(&banks) as Arc<dyn TileBankPoolInstaller>;
|
||||
let sound_installer = Arc::clone(&banks) as Arc<dyn SoundBankPoolInstaller>;
|
||||
let am = AssetManager::new(vec![], vec![], gfx_installer, sound_installer);
|
||||
|
||||
let result = am.load("missing", SlotRef::gfx(0));
|
||||
|
||||
assert_eq!(result, Err(AssetLoadError::AssetNotFound));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_load_returns_slot_index_invalid() {
|
||||
let banks = Arc::new(MemoryBanks::new());
|
||||
let gfx_installer = Arc::clone(&banks) as Arc<dyn TileBankPoolInstaller>;
|
||||
let sound_installer = Arc::clone(&banks) as Arc<dyn SoundBankPoolInstaller>;
|
||||
let data = test_tile_asset_data();
|
||||
let am = AssetManager::new(
|
||||
vec![test_tile_asset_entry("test_tiles", data.len())],
|
||||
data,
|
||||
gfx_installer,
|
||||
sound_installer,
|
||||
);
|
||||
|
||||
let result = am.load("test_tiles", SlotRef::gfx(16));
|
||||
|
||||
assert_eq!(result, Err(AssetLoadError::SlotIndexInvalid));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_load_returns_slot_kind_mismatch() {
|
||||
let banks = Arc::new(MemoryBanks::new());
|
||||
let gfx_installer = Arc::clone(&banks) as Arc<dyn TileBankPoolInstaller>;
|
||||
let sound_installer = Arc::clone(&banks) as Arc<dyn SoundBankPoolInstaller>;
|
||||
let data = test_tile_asset_data();
|
||||
let am = AssetManager::new(
|
||||
vec![test_tile_asset_entry("test_tiles", data.len())],
|
||||
data,
|
||||
gfx_installer,
|
||||
sound_installer,
|
||||
);
|
||||
|
||||
let result = am.load("test_tiles", SlotRef::audio(0));
|
||||
|
||||
assert_eq!(result, Err(AssetLoadError::SlotKindMismatch));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_status_returns_unknown_handle() {
|
||||
let banks = Arc::new(MemoryBanks::new());
|
||||
let gfx_installer = Arc::clone(&banks) as Arc<dyn TileBankPoolInstaller>;
|
||||
let sound_installer = Arc::clone(&banks) as Arc<dyn SoundBankPoolInstaller>;
|
||||
let am = AssetManager::new(vec![], vec![], gfx_installer, sound_installer);
|
||||
|
||||
assert_eq!(am.status(999), LoadStatus::UnknownHandle);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_commit_and_cancel_return_explicit_statuses() {
|
||||
let banks = Arc::new(MemoryBanks::new());
|
||||
let gfx_installer = Arc::clone(&banks) as Arc<dyn TileBankPoolInstaller>;
|
||||
let sound_installer = Arc::clone(&banks) as Arc<dyn SoundBankPoolInstaller>;
|
||||
let data = test_tile_asset_data();
|
||||
let am = AssetManager::new(
|
||||
vec![test_tile_asset_entry("test_tiles", data.len())],
|
||||
data,
|
||||
gfx_installer,
|
||||
sound_installer,
|
||||
);
|
||||
|
||||
assert_eq!(am.commit(999), AssetOpStatus::UnknownHandle);
|
||||
assert_eq!(am.cancel(999), AssetOpStatus::UnknownHandle);
|
||||
|
||||
let handle = am.load("test_tiles", SlotRef::gfx(0)).expect("load must allocate handle");
|
||||
let start = Instant::now();
|
||||
while am.status(handle) != LoadStatus::READY && start.elapsed().as_secs() < 5 {
|
||||
thread::sleep(std::time::Duration::from_millis(10));
|
||||
}
|
||||
|
||||
assert_eq!(am.cancel(handle), AssetOpStatus::Ok);
|
||||
assert_eq!(am.status(handle), LoadStatus::CANCELED);
|
||||
assert_eq!(am.commit(handle), AssetOpStatus::InvalidState);
|
||||
}
|
||||
}
|
||||
|
||||
@ -30,23 +30,24 @@ pub struct PreloadEntry {
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
|
||||
#[repr(i32)]
|
||||
pub enum LoadStatus {
|
||||
PENDING,
|
||||
LOADING,
|
||||
READY,
|
||||
COMMITTED,
|
||||
CANCELED,
|
||||
ERROR,
|
||||
UnknownHandle,
|
||||
PENDING = 0,
|
||||
LOADING = 1,
|
||||
READY = 2,
|
||||
COMMITTED = 3,
|
||||
CANCELED = 4,
|
||||
ERROR = 5,
|
||||
UnknownHandle = 6,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
#[repr(i32)]
|
||||
pub enum AssetLoadError {
|
||||
AssetNotFound = 1,
|
||||
SlotKindMismatch = 2,
|
||||
SlotIndexInvalid = 3,
|
||||
BackendError = 4,
|
||||
AssetNotFound = 3,
|
||||
SlotKindMismatch = 4,
|
||||
SlotIndexInvalid = 5,
|
||||
BackendError = 6,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
use super::*;
|
||||
use prometeu_bytecode::{TRAP_INVALID_SYSCALL, TRAP_OOB, TRAP_TYPE, Value};
|
||||
use crate::services::memcard::{MemcardSlotState, MemcardStatus};
|
||||
use prometeu_hal::asset::{AssetLoadError, AssetOpStatus, BankType, LoadStatus, SlotRef};
|
||||
use prometeu_hal::asset::{AssetOpStatus, BankType, SlotRef};
|
||||
use prometeu_hal::cartridge::AppMode;
|
||||
use prometeu_hal::color::Color;
|
||||
use prometeu_hal::log::{LogLevel, LogSource};
|
||||
@ -458,29 +458,14 @@ impl NativeInterface for VirtualMachineRuntime {
|
||||
Ok(())
|
||||
}
|
||||
Err(status) => {
|
||||
let status_val = match status {
|
||||
AssetLoadError::AssetNotFound => 3,
|
||||
AssetLoadError::SlotKindMismatch => 4,
|
||||
AssetLoadError::SlotIndexInvalid => 5,
|
||||
AssetLoadError::BackendError => 6,
|
||||
};
|
||||
ret.push_int(status_val);
|
||||
ret.push_int(status as i64);
|
||||
ret.push_int(0);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
Syscall::AssetStatus => {
|
||||
let status_val = match hw.assets().status(expect_int(args, 0)? as u32) {
|
||||
LoadStatus::PENDING => 0,
|
||||
LoadStatus::LOADING => 1,
|
||||
LoadStatus::READY => 2,
|
||||
LoadStatus::COMMITTED => 3,
|
||||
LoadStatus::CANCELED => 4,
|
||||
LoadStatus::ERROR => 5,
|
||||
LoadStatus::UnknownHandle => 6,
|
||||
};
|
||||
ret.push_int(status_val);
|
||||
ret.push_int(hw.assets().status(expect_int(args, 0)? as u32) as i64);
|
||||
Ok(())
|
||||
}
|
||||
Syscall::AssetCommit => {
|
||||
|
||||
@ -6,7 +6,7 @@ use prometeu_bytecode::model::{BytecodeModule, ConstantPoolEntry, FunctionMeta,
|
||||
use prometeu_drivers::hardware::Hardware;
|
||||
use crate::fs::{FsBackend, FsEntry, FsError};
|
||||
use prometeu_hal::AudioOpStatus;
|
||||
use prometeu_hal::asset::AssetOpStatus;
|
||||
use prometeu_hal::asset::{AssetEntry, AssetLoadError, AssetOpStatus, BankType, LoadStatus};
|
||||
use prometeu_hal::GfxOpStatus;
|
||||
use prometeu_hal::InputSignals;
|
||||
use prometeu_hal::cartridge::Cartridge;
|
||||
@ -92,6 +92,29 @@ fn serialized_single_function_module_with_consts(
|
||||
.serialize()
|
||||
}
|
||||
|
||||
fn test_tile_asset_entry(asset_name: &str, data_len: usize) -> AssetEntry {
|
||||
AssetEntry {
|
||||
asset_id: 7,
|
||||
asset_name: asset_name.to_string(),
|
||||
bank_type: BankType::TILES,
|
||||
offset: 0,
|
||||
size: data_len as u64,
|
||||
decoded_size: data_len as u64,
|
||||
codec: "RAW".to_string(),
|
||||
metadata: serde_json::json!({
|
||||
"tile_size": 16,
|
||||
"width": 16,
|
||||
"height": 16
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
fn test_tile_asset_data() -> Vec<u8> {
|
||||
let mut data = vec![1u8; 256];
|
||||
data.extend_from_slice(&[0u8; 2048]);
|
||||
data
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn initialize_vm_applies_cartridge_capabilities_before_loader_resolution() {
|
||||
let mut runtime = VirtualMachineRuntime::new(None);
|
||||
@ -569,6 +592,184 @@ fn tick_asset_commit_operational_error_returns_status_not_crash() {
|
||||
assert_eq!(vm.operand_stack_top(1), vec![Value::Int64(AssetOpStatus::UnknownHandle as i64)]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn tick_asset_load_missing_asset_returns_status_and_zero_handle() {
|
||||
let mut runtime = VirtualMachineRuntime::new(None);
|
||||
let mut vm = VirtualMachine::default();
|
||||
let mut hardware = Hardware::new();
|
||||
let signals = InputSignals::default();
|
||||
let code = assemble("PUSH_CONST 0\nPUSH_I32 0\nPUSH_I32 0\nHOSTCALL 0\nHALT").expect("assemble");
|
||||
let program = serialized_single_function_module_with_consts(
|
||||
code,
|
||||
vec![ConstantPoolEntry::String("missing_asset".into())],
|
||||
vec![SyscallDecl {
|
||||
module: "asset".into(),
|
||||
name: "load".into(),
|
||||
version: 1,
|
||||
arg_slots: 3,
|
||||
ret_slots: 2,
|
||||
}],
|
||||
);
|
||||
let cartridge = cartridge_with_program(program, caps::ASSET);
|
||||
|
||||
runtime.initialize_vm(&mut vm, &cartridge).expect("runtime must initialize");
|
||||
let report = runtime.tick(&mut vm, &signals, &mut hardware);
|
||||
assert!(report.is_none(), "missing asset must not crash");
|
||||
assert!(vm.is_halted());
|
||||
assert_eq!(
|
||||
vm.operand_stack_top(2),
|
||||
vec![Value::Int64(0), Value::Int64(AssetLoadError::AssetNotFound as i64)]
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn tick_asset_load_invalid_slot_returns_status_and_zero_handle() {
|
||||
let mut runtime = VirtualMachineRuntime::new(None);
|
||||
let mut vm = VirtualMachine::default();
|
||||
let mut hardware = Hardware::new();
|
||||
let signals = InputSignals::default();
|
||||
let asset_data = test_tile_asset_data();
|
||||
hardware.assets.initialize_for_cartridge(
|
||||
vec![test_tile_asset_entry("tile_asset", asset_data.len())],
|
||||
vec![],
|
||||
asset_data,
|
||||
);
|
||||
let code = assemble("PUSH_CONST 0\nPUSH_I32 0\nPUSH_I32 16\nHOSTCALL 0\nHALT").expect("assemble");
|
||||
let program = serialized_single_function_module_with_consts(
|
||||
code,
|
||||
vec![ConstantPoolEntry::String("tile_asset".into())],
|
||||
vec![SyscallDecl {
|
||||
module: "asset".into(),
|
||||
name: "load".into(),
|
||||
version: 1,
|
||||
arg_slots: 3,
|
||||
ret_slots: 2,
|
||||
}],
|
||||
);
|
||||
let cartridge = cartridge_with_program(program, caps::ASSET);
|
||||
|
||||
runtime.initialize_vm(&mut vm, &cartridge).expect("runtime must initialize");
|
||||
let report = runtime.tick(&mut vm, &signals, &mut hardware);
|
||||
assert!(report.is_none(), "invalid slot must not crash");
|
||||
assert!(vm.is_halted());
|
||||
assert_eq!(
|
||||
vm.operand_stack_top(2),
|
||||
vec![Value::Int64(0), Value::Int64(AssetLoadError::SlotIndexInvalid as i64)]
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn tick_asset_load_kind_mismatch_returns_status_and_zero_handle() {
|
||||
let mut runtime = VirtualMachineRuntime::new(None);
|
||||
let mut vm = VirtualMachine::default();
|
||||
let mut hardware = Hardware::new();
|
||||
let signals = InputSignals::default();
|
||||
let asset_data = test_tile_asset_data();
|
||||
hardware.assets.initialize_for_cartridge(
|
||||
vec![test_tile_asset_entry("tile_asset", asset_data.len())],
|
||||
vec![],
|
||||
asset_data,
|
||||
);
|
||||
let code = assemble("PUSH_CONST 0\nPUSH_I32 1\nPUSH_I32 0\nHOSTCALL 0\nHALT").expect("assemble");
|
||||
let program = serialized_single_function_module_with_consts(
|
||||
code,
|
||||
vec![ConstantPoolEntry::String("tile_asset".into())],
|
||||
vec![SyscallDecl {
|
||||
module: "asset".into(),
|
||||
name: "load".into(),
|
||||
version: 1,
|
||||
arg_slots: 3,
|
||||
ret_slots: 2,
|
||||
}],
|
||||
);
|
||||
let cartridge = cartridge_with_program(program, caps::ASSET);
|
||||
|
||||
runtime.initialize_vm(&mut vm, &cartridge).expect("runtime must initialize");
|
||||
let report = runtime.tick(&mut vm, &signals, &mut hardware);
|
||||
assert!(report.is_none(), "slot kind mismatch must not crash");
|
||||
assert!(vm.is_halted());
|
||||
assert_eq!(
|
||||
vm.operand_stack_top(2),
|
||||
vec![Value::Int64(0), Value::Int64(AssetLoadError::SlotKindMismatch as i64)]
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn tick_asset_status_unknown_handle_returns_status_not_crash() {
|
||||
let mut runtime = VirtualMachineRuntime::new(None);
|
||||
let mut vm = VirtualMachine::default();
|
||||
let mut hardware = Hardware::new();
|
||||
let signals = InputSignals::default();
|
||||
let code = assemble("PUSH_I32 999\nHOSTCALL 0\nHALT").expect("assemble");
|
||||
let program = serialized_single_function_module(
|
||||
code,
|
||||
vec![SyscallDecl {
|
||||
module: "asset".into(),
|
||||
name: "status".into(),
|
||||
version: 1,
|
||||
arg_slots: 1,
|
||||
ret_slots: 1,
|
||||
}],
|
||||
);
|
||||
let cartridge = cartridge_with_program(program, caps::ASSET);
|
||||
|
||||
runtime.initialize_vm(&mut vm, &cartridge).expect("runtime must initialize");
|
||||
let report = runtime.tick(&mut vm, &signals, &mut hardware);
|
||||
assert!(report.is_none(), "unknown asset handle must not crash");
|
||||
assert!(vm.is_halted());
|
||||
assert_eq!(vm.operand_stack_top(1), vec![Value::Int64(LoadStatus::UnknownHandle as i64)]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn tick_asset_commit_invalid_transition_returns_status_not_crash() {
|
||||
let mut runtime = VirtualMachineRuntime::new(None);
|
||||
let mut vm = VirtualMachine::default();
|
||||
let mut hardware = Hardware::new();
|
||||
let signals = InputSignals::default();
|
||||
let code = assemble(
|
||||
"PUSH_I32 1\nHOSTCALL 0\nPOP_N 1\nPUSH_I32 1\nHOSTCALL 1\nHALT",
|
||||
)
|
||||
.expect("assemble");
|
||||
let program = serialized_single_function_module(
|
||||
code,
|
||||
vec![
|
||||
SyscallDecl {
|
||||
module: "asset".into(),
|
||||
name: "cancel".into(),
|
||||
version: 1,
|
||||
arg_slots: 1,
|
||||
ret_slots: 1,
|
||||
},
|
||||
SyscallDecl {
|
||||
module: "asset".into(),
|
||||
name: "commit".into(),
|
||||
version: 1,
|
||||
arg_slots: 1,
|
||||
ret_slots: 1,
|
||||
},
|
||||
],
|
||||
);
|
||||
let cartridge = cartridge_with_program(program, caps::ASSET);
|
||||
|
||||
let asset_data = test_tile_asset_data();
|
||||
hardware.assets.initialize_for_cartridge(
|
||||
vec![test_tile_asset_entry("tile_asset", asset_data.len())],
|
||||
vec![],
|
||||
asset_data,
|
||||
);
|
||||
let handle = hardware
|
||||
.assets
|
||||
.load("tile_asset", prometeu_hal::asset::SlotRef::gfx(0))
|
||||
.expect("asset handle must be allocated");
|
||||
|
||||
runtime.initialize_vm(&mut vm, &cartridge).expect("runtime must initialize");
|
||||
let report = runtime.tick(&mut vm, &signals, &mut hardware);
|
||||
assert!(report.is_none(), "invalid transition must not crash");
|
||||
assert!(vm.is_halted());
|
||||
assert_eq!(handle, 1);
|
||||
assert_eq!(vm.operand_stack_top(1), vec![Value::Int64(AssetOpStatus::InvalidState as i64)]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn tick_gfx_set_sprite_type_mismatch_surfaces_trap_not_panic() {
|
||||
let mut runtime = VirtualMachineRuntime::new(None);
|
||||
|
||||
@ -1,54 +0,0 @@
|
||||
# PR004 - Asset Status-First Surface and Lifecycle
|
||||
|
||||
## Briefing
|
||||
|
||||
A decision `010` fechou a superficie final de `asset`:
|
||||
|
||||
- `asset.load(name, kind, slot) -> (status, handle)`
|
||||
- `asset.status(handle) -> status`
|
||||
- `asset.commit(handle) -> status`
|
||||
- `asset.cancel(handle) -> status`
|
||||
|
||||
Sem no-op silencioso e sem `Panic` operacional.
|
||||
|
||||
## Alvo
|
||||
|
||||
Implementar o contrato de `asset` em spec, registry e runtime.
|
||||
|
||||
Arquivos principais:
|
||||
|
||||
- `docs/runtime/specs/15-asset-management.md`
|
||||
- `crates/console/prometeu-hal/src/syscalls/domains/asset.rs`
|
||||
- `crates/console/prometeu-system/src/virtual_machine_runtime/dispatch.rs`
|
||||
- `crates/console/prometeu-drivers/src/asset.rs`
|
||||
- `crates/console/prometeu-hal/src/asset_bridge.rs` (se necessario)
|
||||
|
||||
## Escopo Funcional
|
||||
|
||||
- substituir `Err -> Panic` de `asset.load` por status operacional;
|
||||
- tornar `asset.commit` e `asset.cancel` retornos explicitos de status;
|
||||
- explicitar `UNKNOWN_HANDLE` em `asset.status`;
|
||||
- validar slot index/kind no request path de `load`;
|
||||
- manter erros de residency/slot no dominio `asset` (nao migrar para `bank`).
|
||||
|
||||
## Fora de Escopo
|
||||
|
||||
- redesign da politica interna de residencia;
|
||||
- novos dominios de asset alem de `TILES` e `SOUNDS`.
|
||||
|
||||
## Critérios de Aceite
|
||||
|
||||
- assinaturas de syscall `asset` alinhadas com decision `010`;
|
||||
- `asset.load` nao produz `Panic` para falha operacional;
|
||||
- `commit`/`cancel` nao ficam em no-op silencioso;
|
||||
- tabela de status por operacao documentada e testada.
|
||||
|
||||
## Tests
|
||||
|
||||
- `cargo test -p prometeu-system`
|
||||
- `cargo test -p prometeu-drivers`
|
||||
- cenarios de:
|
||||
- handle desconhecido;
|
||||
- transicao invalida;
|
||||
- asset nao encontrado;
|
||||
- slot invalido/kind mismatch.
|
||||
@ -149,6 +149,7 @@ Rules:
|
||||
- `handle` is valid only when `load` status is `OK`;
|
||||
- failed `load` returns `handle = 0`;
|
||||
- `commit` and `cancel` must not be silent no-op for unknown/invalid handle state.
|
||||
- slot validation, kind mismatch, and residency/lifecycle rejection remain in `asset` status space and are not delegated to `bank`.
|
||||
|
||||
### 11.2 Minimum status tables
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user