dev/ajustments-asset-entry #12
@ -2,8 +2,8 @@
|
||||
use crate::memory_banks::{SoundBankPoolInstaller, TileBankPoolInstaller};
|
||||
use prometeu_hal::AssetBridge;
|
||||
use prometeu_hal::asset::{
|
||||
AssetEntry, AssetId, AssetLoadError, AssetOpStatus, BankStats, BankType, HandleId, LoadStatus,
|
||||
PreloadEntry, SlotRef, SlotStats,
|
||||
AssetCodec, AssetEntry, AssetId, AssetLoadError, AssetOpStatus, BankStats, BankType, HandleId,
|
||||
LoadStatus, PreloadEntry, SlotRef, SlotStats,
|
||||
};
|
||||
use prometeu_hal::cartridge::AssetsPayloadSource;
|
||||
use prometeu_hal::color::Color;
|
||||
@ -179,10 +179,6 @@ impl AssetBridge for AssetManager {
|
||||
}
|
||||
|
||||
impl AssetManager {
|
||||
fn codec_is_none_or_legacy_raw(codec: &str) -> bool {
|
||||
matches!(codec, "NONE" | "RAW")
|
||||
}
|
||||
|
||||
fn decode_tile_bank_layout(
|
||||
entry: &AssetEntry,
|
||||
) -> Result<(TileSize, usize, usize, usize), String> {
|
||||
@ -242,14 +238,9 @@ impl AssetManager {
|
||||
}
|
||||
|
||||
fn op_mode_for(entry: &AssetEntry) -> Result<AssetOpMode, String> {
|
||||
match entry.bank_type {
|
||||
BankType::TILES if Self::codec_is_none_or_legacy_raw(entry.codec.as_str()) => {
|
||||
Ok(AssetOpMode::StageInMemory)
|
||||
}
|
||||
BankType::SOUNDS if Self::codec_is_none_or_legacy_raw(entry.codec.as_str()) => {
|
||||
Ok(AssetOpMode::DirectFromSlice)
|
||||
}
|
||||
_ => Err(format!("Unsupported codec: {}", entry.codec)),
|
||||
match (entry.bank_type, entry.codec) {
|
||||
(BankType::TILES, AssetCodec::None) => Ok(AssetOpMode::StageInMemory),
|
||||
(BankType::SOUNDS, AssetCodec::None) => Ok(AssetOpMode::DirectFromSlice),
|
||||
}
|
||||
}
|
||||
|
||||
@ -882,6 +873,7 @@ impl AssetManager {
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::memory_banks::{MemoryBanks, SoundBankPoolAccess, TileBankPoolAccess};
|
||||
use prometeu_hal::asset::AssetCodec;
|
||||
|
||||
fn expected_tile_payload_size(width: usize, height: usize) -> usize {
|
||||
(width * height).div_ceil(2) + TILE_BANK_PALETTE_BYTES_V1
|
||||
@ -905,12 +897,13 @@ mod tests {
|
||||
offset: 0,
|
||||
size: expected_tile_payload_size(width, height) as u64,
|
||||
decoded_size: expected_tile_decoded_size(width, height) as u64,
|
||||
codec: "NONE".to_string(),
|
||||
codec: AssetCodec::None,
|
||||
metadata: serde_json::json!({
|
||||
"tile_size": 16,
|
||||
"width": width,
|
||||
"height": height,
|
||||
"palette_count": TILE_BANK_PALETTE_COUNT_V1
|
||||
"palette_count": TILE_BANK_PALETTE_COUNT_V1,
|
||||
"palette_authored": TILE_BANK_PALETTE_COUNT_V1
|
||||
}),
|
||||
}
|
||||
}
|
||||
@ -964,10 +957,8 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_op_mode_for_tiles_raw_is_legacy_alias() {
|
||||
let mut entry = test_tile_asset_entry("tiles", 16, 16);
|
||||
entry.codec = "RAW".to_string();
|
||||
|
||||
fn test_op_mode_for_tiles_none_uses_typed_codec() {
|
||||
let entry = test_tile_asset_entry("tiles", 16, 16);
|
||||
assert_eq!(AssetManager::op_mode_for(&entry), Ok(AssetOpMode::StageInMemory));
|
||||
}
|
||||
|
||||
@ -980,9 +971,10 @@ mod tests {
|
||||
offset: 0,
|
||||
size: 8,
|
||||
decoded_size: 8,
|
||||
codec: "NONE".to_string(),
|
||||
codec: AssetCodec::None,
|
||||
metadata: serde_json::json!({
|
||||
"sample_rate": 44100
|
||||
"sample_rate": 44100,
|
||||
"channels": 1
|
||||
}),
|
||||
};
|
||||
|
||||
@ -1074,9 +1066,10 @@ mod tests {
|
||||
offset: 0,
|
||||
size: data.len() as u64,
|
||||
decoded_size: data.len() as u64,
|
||||
codec: "NONE".to_string(),
|
||||
codec: AssetCodec::None,
|
||||
metadata: serde_json::json!({
|
||||
"sample_rate": 44100
|
||||
"sample_rate": 44100,
|
||||
"channels": 1
|
||||
}),
|
||||
};
|
||||
|
||||
@ -1117,9 +1110,10 @@ mod tests {
|
||||
offset: 0,
|
||||
size: data.len() as u64,
|
||||
decoded_size: data.len() as u64,
|
||||
codec: "NONE".to_string(),
|
||||
codec: AssetCodec::None,
|
||||
metadata: serde_json::json!({
|
||||
"sample_rate": 44100
|
||||
"sample_rate": 44100,
|
||||
"channels": 1
|
||||
}),
|
||||
};
|
||||
|
||||
|
||||
@ -1,12 +1,12 @@
|
||||
use crate::memory_banks::TileBankPoolAccess;
|
||||
use prometeu_hal::GfxBridge;
|
||||
use prometeu_hal::color::Color;
|
||||
use prometeu_hal::glyph::Glyph;
|
||||
use prometeu_hal::sprite::Sprite;
|
||||
use prometeu_hal::tile::Tile;
|
||||
use prometeu_hal::tile_bank::{TileBank, TileSize};
|
||||
use prometeu_hal::tile_layer::{HudTileLayer, ScrollableTileLayer, TileMap};
|
||||
use std::sync::Arc;
|
||||
use prometeu_hal::glyph::Glyph;
|
||||
|
||||
/// Blending modes inspired by classic 16-bit hardware.
|
||||
/// Defines how source pixels are combined with existing pixels in the framebuffer.
|
||||
@ -275,11 +275,7 @@ impl GfxBridge for Gfx {
|
||||
impl Gfx {
|
||||
/// Initializes the graphics system with a specific resolution and shared memory banks.
|
||||
pub fn new(w: usize, h: usize, tile_banks: Arc<dyn TileBankPoolAccess>) -> Self {
|
||||
|
||||
const EMPTY_GLYPH: Glyph = Glyph {
|
||||
glyph_id: 0,
|
||||
palette_id: 0,
|
||||
};
|
||||
const EMPTY_GLYPH: Glyph = Glyph { glyph_id: 0, palette_id: 0 };
|
||||
|
||||
const EMPTY_SPRITE: Sprite = Sprite {
|
||||
glyph: EMPTY_GLYPH,
|
||||
|
||||
@ -12,6 +12,12 @@ pub enum BankType {
|
||||
// BLOBS,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Deserialize, Serialize)]
|
||||
pub enum AssetCodec {
|
||||
#[serde(rename = "NONE")]
|
||||
None,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, Serialize)]
|
||||
pub struct AssetEntry {
|
||||
pub asset_id: AssetId,
|
||||
@ -20,7 +26,7 @@ pub struct AssetEntry {
|
||||
pub offset: u64,
|
||||
pub size: u64,
|
||||
pub decoded_size: u64,
|
||||
pub codec: String, // e.g., "NONE" (legacy alias: "RAW")
|
||||
pub codec: AssetCodec,
|
||||
pub metadata: serde_json::Value,
|
||||
}
|
||||
|
||||
|
||||
@ -198,7 +198,7 @@ fn validate_preload(
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::asset::{AssetEntry, BankType, PreloadEntry};
|
||||
use crate::asset::{AssetCodec, AssetEntry, BankType, PreloadEntry};
|
||||
use crate::cartridge::{ASSETS_PA_MAGIC, ASSETS_PA_SCHEMA_VERSION, AssetsPackPrelude};
|
||||
use crate::tile_bank::TILE_BANK_PALETTE_COUNT_V1;
|
||||
use serde_json::json;
|
||||
@ -367,12 +367,13 @@ mod tests {
|
||||
offset,
|
||||
size,
|
||||
decoded_size: 16 * 16 + (TILE_BANK_PALETTE_COUNT_V1 as u64 * 16 * 2),
|
||||
codec: "NONE".to_string(),
|
||||
codec: AssetCodec::None,
|
||||
metadata: json!({
|
||||
"tile_size": 16,
|
||||
"width": 16,
|
||||
"height": 16,
|
||||
"palette_count": TILE_BANK_PALETTE_COUNT_V1
|
||||
"palette_count": TILE_BANK_PALETTE_COUNT_V1,
|
||||
"palette_authored": TILE_BANK_PALETTE_COUNT_V1
|
||||
}),
|
||||
}
|
||||
}
|
||||
@ -449,12 +450,13 @@ mod tests {
|
||||
offset: 4,
|
||||
size: 4,
|
||||
decoded_size: 16 * 16 + (TILE_BANK_PALETTE_COUNT_V1 as u64 * 16 * 2),
|
||||
codec: "NONE".to_string(),
|
||||
codec: AssetCodec::None,
|
||||
metadata: json!({
|
||||
"tile_size": 16,
|
||||
"width": 16,
|
||||
"height": 16,
|
||||
"palette_count": TILE_BANK_PALETTE_COUNT_V1
|
||||
"palette_count": TILE_BANK_PALETTE_COUNT_V1,
|
||||
"palette_authored": TILE_BANK_PALETTE_COUNT_V1
|
||||
}),
|
||||
},
|
||||
];
|
||||
@ -497,4 +499,88 @@ mod tests {
|
||||
|
||||
assert!(matches!(error, CartridgeError::InvalidFormat));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn load_rejects_unknown_codec_string_in_assets_pa_header() {
|
||||
let dir = TestCartridgeDir::new(manifest_with_capabilities(Some(vec!["asset"])));
|
||||
let header = serde_json::json!({
|
||||
"asset_table": [{
|
||||
"asset_id": 7,
|
||||
"asset_name": "tiles",
|
||||
"bank_type": "TILES",
|
||||
"offset": 0,
|
||||
"size": 4,
|
||||
"decoded_size": 768,
|
||||
"codec": "LZ4",
|
||||
"metadata": {
|
||||
"tile_size": 16,
|
||||
"width": 16,
|
||||
"height": 16,
|
||||
"palette_count": TILE_BANK_PALETTE_COUNT_V1,
|
||||
"palette_authored": TILE_BANK_PALETTE_COUNT_V1
|
||||
}
|
||||
}],
|
||||
"preload": []
|
||||
});
|
||||
let header_bytes = serde_json::to_vec(&header).expect("header must serialize");
|
||||
let prelude = AssetsPackPrelude {
|
||||
magic: ASSETS_PA_MAGIC,
|
||||
schema_version: ASSETS_PA_SCHEMA_VERSION,
|
||||
header_len: header_bytes.len() as u32,
|
||||
payload_offset: (ASSETS_PA_PRELUDE_SIZE + header_bytes.len()) as u64,
|
||||
flags: 0,
|
||||
reserved: 0,
|
||||
header_checksum: 0,
|
||||
};
|
||||
let mut bytes = prelude.to_bytes().to_vec();
|
||||
bytes.extend_from_slice(&header_bytes);
|
||||
bytes.extend_from_slice(&[1_u8, 2, 3, 4]);
|
||||
fs::write(dir.path().join("assets.pa"), bytes).expect("must write assets.pa");
|
||||
|
||||
let error = DirectoryCartridgeLoader::load(dir.path()).unwrap_err();
|
||||
|
||||
assert!(matches!(error, CartridgeError::InvalidFormat));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn load_rejects_legacy_raw_codec_string_in_assets_pa_header() {
|
||||
let dir = TestCartridgeDir::new(manifest_with_capabilities(Some(vec!["asset"])));
|
||||
let header = serde_json::json!({
|
||||
"asset_table": [{
|
||||
"asset_id": 7,
|
||||
"asset_name": "tiles",
|
||||
"bank_type": "TILES",
|
||||
"offset": 0,
|
||||
"size": 4,
|
||||
"decoded_size": 768,
|
||||
"codec": "RAW",
|
||||
"metadata": {
|
||||
"tile_size": 16,
|
||||
"width": 16,
|
||||
"height": 16,
|
||||
"palette_count": TILE_BANK_PALETTE_COUNT_V1,
|
||||
"palette_authored": TILE_BANK_PALETTE_COUNT_V1
|
||||
}
|
||||
}],
|
||||
"preload": []
|
||||
});
|
||||
let header_bytes = serde_json::to_vec(&header).expect("header must serialize");
|
||||
let prelude = AssetsPackPrelude {
|
||||
magic: ASSETS_PA_MAGIC,
|
||||
schema_version: ASSETS_PA_SCHEMA_VERSION,
|
||||
header_len: header_bytes.len() as u32,
|
||||
payload_offset: (ASSETS_PA_PRELUDE_SIZE + header_bytes.len()) as u64,
|
||||
flags: 0,
|
||||
reserved: 0,
|
||||
header_checksum: 0,
|
||||
};
|
||||
let mut bytes = prelude.to_bytes().to_vec();
|
||||
bytes.extend_from_slice(&header_bytes);
|
||||
bytes.extend_from_slice(&[1_u8, 2, 3, 4]);
|
||||
fs::write(dir.path().join("assets.pa"), bytes).expect("must write assets.pa");
|
||||
|
||||
let error = DirectoryCartridgeLoader::load(dir.path()).unwrap_err();
|
||||
|
||||
assert!(matches!(error, CartridgeError::InvalidFormat));
|
||||
}
|
||||
}
|
||||
|
||||
@ -2,4 +2,4 @@
|
||||
pub struct Glyph {
|
||||
pub glyph_id: u16,
|
||||
pub palette_id: u8,
|
||||
}
|
||||
}
|
||||
|
||||
@ -7,6 +7,7 @@ pub mod cartridge_loader;
|
||||
pub mod color;
|
||||
pub mod debugger_protocol;
|
||||
pub mod gfx_bridge;
|
||||
pub mod glyph;
|
||||
pub mod hardware_bridge;
|
||||
pub mod host_context;
|
||||
pub mod host_return;
|
||||
@ -26,7 +27,6 @@ pub mod tile_layer;
|
||||
pub mod touch_bridge;
|
||||
pub mod vm_fault;
|
||||
pub mod window;
|
||||
pub mod glyph;
|
||||
|
||||
pub use asset_bridge::AssetBridge;
|
||||
pub use audio_bridge::{AudioBridge, AudioOpStatus, LoopMode};
|
||||
|
||||
@ -4,6 +4,7 @@ use prometeu_bytecode::{TRAP_INVALID_SYSCALL, TRAP_OOB, TRAP_TYPE, Value};
|
||||
use prometeu_hal::asset::{AssetId, AssetOpStatus, BankType, SlotRef};
|
||||
use prometeu_hal::cartridge::AppMode;
|
||||
use prometeu_hal::color::Color;
|
||||
use prometeu_hal::glyph::Glyph;
|
||||
use prometeu_hal::log::{LogLevel, LogSource};
|
||||
use prometeu_hal::sprite::Sprite;
|
||||
use prometeu_hal::syscalls::Syscall;
|
||||
@ -12,7 +13,6 @@ use prometeu_hal::{
|
||||
AudioOpStatus, GfxOpStatus, HostContext, HostReturn, NativeInterface, SyscallId, expect_bool,
|
||||
expect_int,
|
||||
};
|
||||
use prometeu_hal::glyph::Glyph;
|
||||
|
||||
impl VirtualMachineRuntime {
|
||||
fn syscall_log_write(&mut self, level_val: i64, tag: u16, msg: String) -> Result<(), VmFault> {
|
||||
@ -162,10 +162,7 @@ impl NativeInterface for VirtualMachineRuntime {
|
||||
}
|
||||
|
||||
*hw.gfx_mut().sprite_mut(index) = Sprite {
|
||||
glyph: Glyph {
|
||||
glyph_id,
|
||||
palette_id,
|
||||
},
|
||||
glyph: Glyph { glyph_id, palette_id },
|
||||
x,
|
||||
y,
|
||||
bank_id,
|
||||
|
||||
@ -8,7 +8,9 @@ use prometeu_drivers::hardware::Hardware;
|
||||
use prometeu_hal::AudioOpStatus;
|
||||
use prometeu_hal::GfxOpStatus;
|
||||
use prometeu_hal::InputSignals;
|
||||
use prometeu_hal::asset::{AssetEntry, AssetLoadError, AssetOpStatus, BankType, LoadStatus};
|
||||
use prometeu_hal::asset::{
|
||||
AssetCodec, AssetEntry, AssetLoadError, AssetOpStatus, BankType, LoadStatus,
|
||||
};
|
||||
use prometeu_hal::cartridge::{AssetsPayloadSource, Cartridge};
|
||||
use prometeu_hal::syscalls::caps;
|
||||
use prometeu_hal::tile_bank::TILE_BANK_PALETTE_COUNT_V1;
|
||||
@ -108,12 +110,13 @@ fn test_tile_asset_entry(asset_name: &str, data_len: usize) -> AssetEntry {
|
||||
offset: 0,
|
||||
size: data_len as u64,
|
||||
decoded_size: test_tile_decoded_size(16, 16) as u64,
|
||||
codec: "NONE".to_string(),
|
||||
codec: AssetCodec::None,
|
||||
metadata: serde_json::json!({
|
||||
"tile_size": 16,
|
||||
"width": 16,
|
||||
"height": 16,
|
||||
"palette_count": TILE_BANK_PALETTE_COUNT_V1
|
||||
"palette_count": TILE_BANK_PALETTE_COUNT_V1,
|
||||
"palette_authored": TILE_BANK_PALETTE_COUNT_V1
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{"type":"meta","next_id":{"DSC":21,"AGD":19,"DEC":5,"PLN":3,"LSN":24,"CLSN":1}}
|
||||
... (mantendo as linhas anteriores) ...
|
||||
{"type":"meta","next_id":{"DSC":22,"AGD":20,"DEC":6,"PLN":5,"LSN":24,"CLSN":1}}
|
||||
{"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":"open","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":[{"id":"AGD-0019","file":"AGD-0019-asset-entry-codec-enum-with-metadata.md","status":"accepted","created_at":"2026-04-09","updated_at":"2026-04-09"}],"decisions":[{"id":"DEC-0005","file":"DEC-0005-asset-entry-codec-enum-contract.md","status":"accepted","created_at":"2026-04-09","updated_at":"2026-04-09","ref_agenda":"AGD-0019"}],"plans":[{"id":"PLN-0004","file":"PLN-0004-asset-entry-codec-enum-execution.md","status":"accepted","created_at":"2026-04-09","updated_at":"2026-04-09","ref_decisions":["DEC-0005"]}],"lessons":[]}
|
||||
{"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":[]}
|
||||
|
||||
@ -0,0 +1,183 @@
|
||||
---
|
||||
id: AGD-0019
|
||||
ticket: asset-entry-codec-enum-with-metadata
|
||||
title: Agenda - Asset Entry Codec as Enum with Metadata
|
||||
status: accepted
|
||||
created: 2026-04-09
|
||||
resolved: 2026-04-09
|
||||
decision: DEC-0005
|
||||
tags: [asset, runtime, codec, metadata]
|
||||
---
|
||||
|
||||
# Agenda - Asset Entry Codec as Enum with Metadata
|
||||
|
||||
## Contexto
|
||||
|
||||
A `DSC-0017` consolidou a normalizacao de `AssetEntry.metadata`, separando campos criticos na raiz e empurrando detalhes tecnicos para subarvores como `codec` e `pipeline`.
|
||||
|
||||
Isso resolveu a organizacao do contrato, mas nao fechou a representacao tipada de `codec` dentro do runtime. Hoje o dado ainda e percebido mais como JSON dinamico do que como parte explicita do modelo de dominio.
|
||||
|
||||
O tema desta agenda e decidir se `codec` em `AssetEntry` deve deixar de ser apenas um blob/subarvore e passar a ser um enum tipado, capaz de carregar os metadados pertinentes a cada codec.
|
||||
|
||||
## Problema
|
||||
|
||||
Quando `codec` e tratado como JSON generico ou como informacao frouxa em metadados, o runtime perde:
|
||||
|
||||
- clareza sobre quais codecs existem de fato;
|
||||
- validacao estrutural forte por variante;
|
||||
- ergonomia para loaders e drivers;
|
||||
- separacao nitida entre metadata do banco e metadata do codec.
|
||||
|
||||
Ao mesmo tempo, tipar `codec` cedo demais ou de forma larga demais pode misturar responsabilidades e transformar o enum em um deposito generico de qualquer detalhe tecnico do asset.
|
||||
|
||||
## Pontos Criticos
|
||||
|
||||
1. Limite de responsabilidade.
|
||||
`codec` deve carregar apenas dados necessarios para decodificacao, nao toda a metadata do asset.
|
||||
|
||||
2. Compatibilidade com a normalizacao anterior.
|
||||
A agenda nao deve reabrir a decisao de segmentar metadata; ela deve apenas fechar como o segmento `codec` vira modelo tipado no runtime.
|
||||
|
||||
3. Evolucao de formato.
|
||||
O modelo precisa permitir codecs sem payload adicional e codecs com configuracao especifica, sem cair em campos opcionais demais.
|
||||
|
||||
4. Unknown/forward compatibility.
|
||||
Precisamos decidir se codecs desconhecidos falham no parse, se ficam preservados como raw JSON, ou se existe modo hibrido.
|
||||
|
||||
5. Impacto nos callers.
|
||||
A mudanca afeta serializacao/deserializacao, helpers, validacao de cart e ergonomia dos loaders.
|
||||
|
||||
## Opcoes
|
||||
|
||||
### Opcao A - Manter `codec` como JSON dinamico
|
||||
|
||||
- **Abordagem:** manter `codec` como subarvore em `metadata` ou como `serde_json::Value`, usando helpers tipados apenas nos pontos de consumo.
|
||||
- **Pro:** menor migracao imediata e maior flexibilidade para formatos experimentais.
|
||||
- **Con:** o contrato real continua implicito, com checagens espalhadas e mais risco de drift entre parser e consumidores.
|
||||
- **Tradeoff:** adia a decisao de dominio e preserva a ambiguidade exatamente no ponto onde o runtime precisa de semantica forte.
|
||||
|
||||
### Opcao B - Tornar `codec` um enum tipado com payload por variante
|
||||
|
||||
- **Abordagem:** introduzir algo como `AssetCodec`, com variantes explicitas (`None`, `Png { ... }`, `Jpeg { ... }`, etc.) carregando apenas os metadados do proprio codec.
|
||||
- **Pro:** o runtime ganha exaustividade, parse centralizado e um modelo de dominio mais honesto.
|
||||
- **Con:** exige decidir fronteiras claras entre metadata do codec e metadata do banco/asset; tambem aumenta custo de evolucao quando novos codecs surgem.
|
||||
- **Tradeoff:** troca flexibilidade irrestrita por contrato forte e melhor ergonomia operacional.
|
||||
|
||||
### Opcao C - Separar `codec_kind` de um payload opcional tipado
|
||||
|
||||
- **Abordagem:** usar um enum leve para o tipo de codec e um campo separado para configuracao adicional.
|
||||
- **Pro:** reduz acoplamento do discriminante com o payload e pode simplificar alguns formatos.
|
||||
- **Con:** reintroduz estados invalidos (`kind` e payload divergentes), exigindo validacao cruzada manual.
|
||||
- **Tradeoff:** parece mais flexivel, mas perde a principal vantagem de um tagged enum: coerencia estrutural por construcao.
|
||||
|
||||
## Sugestao / Recomendacao
|
||||
|
||||
Seguir com a **Opcao B**.
|
||||
|
||||
`codec` em `AssetEntry` deveria ser um enum tipado e capaz de carregar os metadados estritamente relativos a ele. Isso fecha melhor o modelo de dominio: o runtime deixa de tratar codec como detalhe textual solto e passa a reconhece-lo como parte semantica do contrato do asset.
|
||||
|
||||
A recomendacao, no entanto, vem com uma fronteira explicita:
|
||||
|
||||
- metadata especifica de decodificacao fica dentro do enum do codec;
|
||||
- metadata do banco/formato de consumo continua fora dele;
|
||||
- metadata editorial ou operacional do asset tambem continua fora dele.
|
||||
|
||||
Em outras palavras, a discussao nao e "colocar toda metadata dentro de `codec`", e sim "dar ao segmento `codec` uma representacao tipada, exaustiva e com payload por variante quando necessario".
|
||||
|
||||
Com as respostas atuais, a recomendacao fica mais concreta:
|
||||
|
||||
- o JSON serializado pelo Studio dentro de `asset.pa` pode manter `codec` como string opaca;
|
||||
- o runtime Rust deve desserializar essa string diretamente para um enum em `AssetEntry`;
|
||||
- o nome canonico de cada codec no JSON deve seguir o contrato definido pelo runtime, e o Studio/paker deve se conformar exatamente a ele;
|
||||
- a variante inicial canonica e apenas `None`;
|
||||
- `Raw` deve ser considerada removida do modelo;
|
||||
- codec desconhecido no runtime e erro fatal de carregamento e deve impedir a execucao do cartucho;
|
||||
- `pipeline` nao deve sobreviver no runtime e pode ser descartado completamente desse lado.
|
||||
|
||||
## Perguntas em Aberto
|
||||
|
||||
- Como o modelo evolui quando surgir o primeiro codec real com payload adicional sem perder a separacao entre o discriminante string no JSON e a interpretacao tipada no runtime?
|
||||
|
||||
## Discussao
|
||||
|
||||
### Direcao fechada ate aqui
|
||||
|
||||
1. **Serializacao no Studio**
|
||||
O JSON serializado pelo Studio dentro de `asset.pa` deve expor `codec` como string opaca.
|
||||
|
||||
2. **Desserializacao no runtime**
|
||||
O runtime Rust deve carregar essa string diretamente em um enum no proprio `AssetEntry`. O wire format continua string, mas o modelo carregado no runtime passa a ser tipado.
|
||||
|
||||
3. **Canon do nome**
|
||||
O nome textual do codec no JSON nao e arbitrario por produtor. Ele deve seguir exatamente o canon definido pelo contrato. O canon fechado para este tema e `SCREAMING_SNAKE_CASE`, alinhado a `BankType`, e o packer deve seguir esse formato sem aliases livres.
|
||||
|
||||
4. **Variante inicial**
|
||||
O unico codec canonico agora e `None`.
|
||||
|
||||
5. **Fim de `Raw`**
|
||||
`Raw` nao deve mais existir como conceito no modelo.
|
||||
|
||||
6. **Codecs desconhecidos**
|
||||
Nao devem ser empacotados. Se mesmo assim chegarem ao runtime, isso e erro de validacao do `AssetEntry` e o cartucho deve ser fechado antes de seguir.
|
||||
|
||||
7. **Escopo atual de codecs**
|
||||
Como ainda nao existe codec real implementado, a primeira versao do enum pode ser minima e conter apenas `None`.
|
||||
|
||||
8. **Destino de `pipeline`**
|
||||
`pipeline` nao tem valor operacional no runtime atual e pode ser descartado completamente desse lado.
|
||||
|
||||
### Leitura arquitetural dessas respostas
|
||||
|
||||
As respostas empurram a agenda para um contrato bem mais estrito do que o texto inicial sugeria:
|
||||
|
||||
- `codec` existe como conceito de dominio mesmo antes de haver codecs concretos alem de `None`;
|
||||
- o JSON de `asset.pa` pode manter um discriminante simples e opaco, enquanto o runtime desserializa isso diretamente para enum e usa esse valor para escolher a interpretacao tipada de `metadata.codec`;
|
||||
- a autoridade sobre o spelling do codec pertence ao contrato compartilhado, nao ao Studio isoladamente;
|
||||
- o runtime nao deve carregar extensibilidade aberta para codecs desconhecidos;
|
||||
- a compatibilidade futura deve ser dirigida pelo Studio e pelo empacotamento, nao por tolerancia dinamica no runtime;
|
||||
- `pipeline` deixa de disputar espaco conceitual com `codec` no runtime.
|
||||
|
||||
Isso favorece um modelo de enum fechado, validado cedo e com semantica fail-fast.
|
||||
|
||||
## Criterio para Encerrar
|
||||
|
||||
Esta agenda pode ser encerrada quando houver consenso escrito sobre:
|
||||
|
||||
- o papel exato de `codec` no modelo de dominio do `AssetEntry`;
|
||||
- a fronteira entre payload do codec e restante da metadata;
|
||||
- a estrategia para codecs sem metadata adicional e para codecs desconhecidos;
|
||||
- o shape string de `codec` no JSON e sua relacao com o enum carregado no runtime e com `metadata.codec`;
|
||||
- o proximo passo normativo para transformar isso em decisao sem reabrir `DSC-0017`.
|
||||
|
||||
## Resolucao Provisoria
|
||||
|
||||
Ha consenso provisoriamente estabelecido sobre os seguintes pontos:
|
||||
|
||||
- `codec` deve existir como enum tipado no modelo do runtime;
|
||||
- a variante inicial unica e `None`;
|
||||
- `Raw` sai do contrato;
|
||||
- codecs desconhecidos sao invalidos e devem falhar de forma fatal no carregamento do cartucho;
|
||||
- `pipeline` pode ser descartado do runtime;
|
||||
- o JSON de `asset.pa` deve serializar `codec` como string opaca;
|
||||
- o runtime Rust deve desserializar essa string diretamente para enum no `AssetEntry`;
|
||||
- o nome textual do codec no JSON deve seguir `SCREAMING_SNAKE_CASE`, e o Studio deve se conformar exatamente a ele;
|
||||
- codec desconhecido deve falhar na validacao do `AssetEntry`, antes de qualquer carga efetiva.
|
||||
|
||||
O unico ponto em aberto passa a ser a politica de evolucao para o primeiro codec real com payload, preservando a distincao entre:
|
||||
|
||||
- discriminante string no JSON do asset; e
|
||||
- shape tipado de `metadata.codec` no runtime.
|
||||
|
||||
## Resolucao
|
||||
|
||||
A agenda fica encerrada com a seguinte orientacao:
|
||||
|
||||
- `codec` permanece `string` no JSON de `asset.pa`;
|
||||
- o runtime Rust deve desserializar essa string diretamente para enum no `AssetEntry`;
|
||||
- o nome textual do codec segue `SCREAMING_SNAKE_CASE`, alinhado a `BankType`;
|
||||
- `None` e a unica variante inicial;
|
||||
- `Raw` sai do contrato;
|
||||
- codec desconhecido falha na validacao do `AssetEntry` e fecha o cartucho;
|
||||
- `pipeline` e descartado do runtime.
|
||||
|
||||
A evolucao para codecs com payload adicional fica explicitamente adiada para uma decisao futura motivada por um codec real.
|
||||
@ -0,0 +1,91 @@
|
||||
---
|
||||
id: DEC-0005
|
||||
ticket: asset-entry-codec-enum-with-metadata
|
||||
title: Asset Entry Codec Enum Contract
|
||||
status: accepted
|
||||
created: 2026-04-09
|
||||
accepted: 2026-04-09
|
||||
agenda: AGD-0019
|
||||
plans: [PLN-0004]
|
||||
tags: [asset, runtime, codec, metadata]
|
||||
---
|
||||
|
||||
## Status
|
||||
|
||||
Accepted on 2026-04-09.
|
||||
|
||||
## Contexto
|
||||
|
||||
A discussao `AGD-0019` fechou que o campo `codec` de `AssetEntry` faz parte do contrato de dominio do runtime e nao deve permanecer como texto frouxo consumido ad hoc por loaders.
|
||||
|
||||
Hoje o empacotamento e produzido no Studio em Java/Jackson e o runtime consome o header JSON de `asset.pa` em Rust. Portanto, o contrato precisa distinguir claramente:
|
||||
|
||||
- o wire format serializado pelo Studio;
|
||||
- o modelo tipado carregado pelo runtime;
|
||||
- a relacao entre o discriminante do codec e qualquer metadata especifica de codec.
|
||||
|
||||
A decisao tambem precisa consolidar o fim do alias legado `RAW` e a politica de falha para codecs desconhecidos.
|
||||
|
||||
## Decisao
|
||||
|
||||
1. `AssetEntry.codec` no runtime MUST ser representado por um enum tipado, e MUST NOT permanecer como `String` no modelo carregado.
|
||||
2. O JSON serializado em `asset.pa` MUST continuar representando `codec` como uma `string`.
|
||||
3. O runtime Rust MUST desserializar essa `string` diretamente para o enum de codec no proprio `AssetEntry`.
|
||||
4. O spelling textual do codec no JSON MUST seguir exatamente o canon definido por este contrato. O canon inicial MUST ser `SCREAMING_SNAKE_CASE`, alinhado ao padrao ja usado por `BankType`. O Studio/paker MUST emitir exatamente esse spelling e MUST NOT introduzir aliases livres.
|
||||
5. A variante inicial unica do enum MUST ser `None`.
|
||||
6. O alias/conceito `Raw` MUST be removed from the contract and MUST NOT be emitted pelo Studio nem aceito como shape valido futuro.
|
||||
7. Se o runtime encontrar um codec desconhecido para aquele binario, a validacao de `AssetEntry` MUST falhar antes de qualquer carga efetiva do asset, e o cartucho MUST ser rejeitado.
|
||||
8. `pipeline` MUST NOT fazer parte do modelo operacional do runtime para esse contrato e MAY ser descartado completamente no lado do runtime.
|
||||
9. Metadados especificos de codec, quando existirem, MUST ser interpretados a partir do codec resolvido e MUST permanecer separados da metadata editorial ou da metadata propria do banco consumidor.
|
||||
10. A estrategia para o primeiro codec com payload adicional is deferred. Esta decisao fecha apenas o contrato atual e o ponto de extensao, sem antecipar um shape normativo para codecs futuros com payload.
|
||||
|
||||
## Rationale
|
||||
|
||||
- O wire format em `string` preserva simplicidade e compatibilidade com o Studio em Java/Jackson.
|
||||
- O enum no runtime torna o contrato exaustivo, evita parsing textual espalhado e reduz drift entre loader, validacao e consumidores.
|
||||
- Rejeitar codec desconhecido cedo mantem o sistema fail-fast e evita estados parcialmente carregados.
|
||||
- Remover `Raw` evita manter semantica historica ambigua em paralelo ao contrato novo.
|
||||
- Expulsar `pipeline` do runtime reduz ruido conceitual e impede sobreposicao de responsabilidade com `codec`.
|
||||
- Adiar o desenho de codecs com payload evita overdesign antes de existir um caso concreto.
|
||||
|
||||
## Invariantes / Contrato
|
||||
|
||||
- O valor de `codec` no JSON de `asset.pa` e um discriminante textual canonico.
|
||||
- O discriminante textual canonico de `codec` no JSON usa `SCREAMING_SNAKE_CASE`.
|
||||
- O valor de `codec` carregado em Rust e um enum fechado para o conjunto de codecs suportados por aquele runtime.
|
||||
- O Studio e o runtime compartilham o mesmo spelling canonico para cada variante.
|
||||
- O runtime nao oferece modo tolerante para codecs desconhecidos.
|
||||
- O contrato inicial possui uma unica variante valida: `None`.
|
||||
- `Raw` nao pertence mais ao contrato canonico.
|
||||
- `pipeline` nao participa do contrato operacional do runtime.
|
||||
- Quando `metadata.codec` existir para algum codec futuro, sua interpretacao dependera do discriminante ja validado.
|
||||
|
||||
## Impactos
|
||||
|
||||
- `prometeu-hal` deve trocar `AssetEntry.codec: String` por um enum serializavel/desserializavel com canon textual explicito.
|
||||
- `prometeu-drivers` deve remover a aceitacao de `RAW` como alias legado e passar a operar sobre enum, nao sobre comparacao textual solta.
|
||||
- O loader/validacao do cart deve falhar cedo se a desserializacao ou validacao do codec falhar.
|
||||
- O Studio/paker deve emitir exatamente o nome canonico definido para o codec.
|
||||
- O nome canonico inicial de `None` no JSON deve ser `NONE`.
|
||||
- Nao ha necessidade de definir agora um DTO separado apenas para codec; o proprio `AssetEntry` continua sendo o contrato serializado e desserializado.
|
||||
|
||||
## Referencias
|
||||
|
||||
- AGD-0019: Asset Entry Codec as Enum with Metadata
|
||||
- DSC-0017: Asset Entry Metadata Normalization Contract
|
||||
- LSN-0023: Typed Helpers for Asset Metadata
|
||||
- `crates/console/prometeu-hal/src/asset.rs`
|
||||
- `crates/console/prometeu-hal/src/cartridge_loader.rs`
|
||||
- `crates/console/prometeu-drivers/src/asset.rs`
|
||||
|
||||
## Propagacao Necessaria
|
||||
|
||||
- Atualizar o modelo Rust de `AssetEntry` para usar enum de codec.
|
||||
- Atualizar a validacao/desserializacao do header de `asset.pa`.
|
||||
- Atualizar drivers para abandonar `RAW` e comparacoes por `String`.
|
||||
- Ajustar o Studio/paker para emitir o spelling canonico escolhido pelo contrato.
|
||||
- Escrever um plano de execucao antes de alterar spec/codigo.
|
||||
|
||||
## Revision Log
|
||||
|
||||
- 2026-04-09: Initial accepted decision from AGD-0019.
|
||||
@ -0,0 +1,141 @@
|
||||
---
|
||||
id: PLN-0004
|
||||
ticket: asset-entry-codec-enum-with-metadata
|
||||
title: Asset Entry Codec Enum Execution
|
||||
status: accepted
|
||||
created: 2026-04-09
|
||||
completed:
|
||||
tags: [asset, runtime, codec, metadata]
|
||||
---
|
||||
|
||||
## Briefing
|
||||
|
||||
Implement DEC-0005 by replacing `AssetEntry.codec: String` with a typed Rust enum while keeping the `assets.pa` JSON wire format as a canonical `SCREAMING_SNAKE_CASE` string. The initial supported codec set contains only `None`, serialized as `NONE`. Unknown codecs must fail during `AssetEntry` validation, `RAW` must be removed from the accepted contract, and runtime code must stop relying on free-form string comparisons.
|
||||
|
||||
## Decisions de Origem
|
||||
|
||||
- DEC-0005: Asset Entry Codec Enum Contract
|
||||
|
||||
## Alvo
|
||||
|
||||
Land a runtime-side implementation that:
|
||||
|
||||
- introduces a serializable/deserializable `AssetCodec` enum in `prometeu-hal`;
|
||||
- migrates `AssetEntry` to use the enum directly;
|
||||
- rejects unknown codec strings during `assets.pa` parsing/validation;
|
||||
- removes legacy `RAW` handling from runtime consumers and tests;
|
||||
- preserves the current JSON transport contract for the Studio packer: `codec` remains a `SCREAMING_SNAKE_CASE` string in `assets.pa`.
|
||||
|
||||
## Escopo
|
||||
|
||||
- Runtime contract changes in `prometeu-hal` for `AssetEntry` and codec serialization.
|
||||
- Cartridge loading and `assets.pa` validation behavior.
|
||||
- Asset driver logic and tests that currently assume `codec` is a `String`.
|
||||
- Runtime test fixtures that construct `AssetEntry` instances directly.
|
||||
|
||||
## Fora de Escopo
|
||||
|
||||
- Studio/Java packer implementation work.
|
||||
- Introduction of any real codec beyond `None`.
|
||||
- Design or implementation of `metadata.codec` payload shapes for future codecs.
|
||||
- Discussion or implementation of a separate DTO just for `AssetEntry`.
|
||||
|
||||
## Plano de Execucao
|
||||
|
||||
### Step 1 - Introduce `AssetCodec` in `prometeu-hal`
|
||||
|
||||
**What:**
|
||||
Define the runtime enum for asset codecs and migrate `AssetEntry.codec` from `String` to that enum.
|
||||
|
||||
**How:**
|
||||
Add `AssetCodec` to `crates/console/prometeu-hal/src/asset.rs` with idiomatic Rust variant naming and explicit serde mapping to `SCREAMING_SNAKE_CASE`. The initial enum must contain only `None`, serialized as `NONE`. Update `AssetEntry` to use `AssetCodec` and remove the legacy comment about `RAW`.
|
||||
|
||||
**File(s):**
|
||||
- `crates/console/prometeu-hal/src/asset.rs`
|
||||
|
||||
### Step 2 - Make `assets.pa` parsing fail on unknown codecs
|
||||
|
||||
**What:**
|
||||
Ensure unknown codec strings are rejected before any asset load path proceeds.
|
||||
|
||||
**How:**
|
||||
Rely on enum deserialization failure or an explicit validation hook during `assets.pa` header parsing so that invalid codec values produce `CartridgeError::InvalidFormat`. Keep the failure at `AssetEntry` validation time inside cartridge loading, not delayed to driver execution.
|
||||
|
||||
**File(s):**
|
||||
- `crates/console/prometeu-hal/src/cartridge_loader.rs`
|
||||
- Any supporting type definitions in `crates/console/prometeu-hal/src/cartridge.rs` if required by parsing flow
|
||||
|
||||
### Step 3 - Remove runtime string-based codec branching
|
||||
|
||||
**What:**
|
||||
Update asset runtime behavior to consume the enum directly and remove legacy `RAW` acceptance.
|
||||
|
||||
**How:**
|
||||
Replace `codec_is_none_or_legacy_raw` and string matches in `crates/console/prometeu-drivers/src/asset.rs` with enum-based matching on `AssetCodec`. Ensure unsupported codecs remain an error path, but `RAW` is no longer recognized anywhere in runtime logic.
|
||||
|
||||
**File(s):**
|
||||
- `crates/console/prometeu-drivers/src/asset.rs`
|
||||
|
||||
### Step 4 - Update test fixtures and regression coverage
|
||||
|
||||
**What:**
|
||||
Bring existing tests and fixtures in line with the new typed contract and add regression tests for rejection behavior.
|
||||
|
||||
**How:**
|
||||
Replace direct string fixture values such as `"NONE"` and `"RAW"` with enum construction where tests instantiate `AssetEntry` directly. Add or update loader tests to cover:
|
||||
|
||||
- successful parse of `codec: "NONE"`;
|
||||
- failure on unknown codec strings;
|
||||
- failure on legacy `RAW` if it still appears in serialized input.
|
||||
|
||||
Update driver tests to assert enum-based behavior for the supported codec set.
|
||||
|
||||
**File(s):**
|
||||
- `crates/console/prometeu-hal/src/cartridge_loader.rs`
|
||||
- `crates/console/prometeu-drivers/src/asset.rs`
|
||||
- `crates/console/prometeu-system/src/virtual_machine_runtime/tests.rs`
|
||||
|
||||
### Step 5 - Align downstream packer work item
|
||||
|
||||
**What:**
|
||||
Capture the non-runtime propagation requirement for the Studio packer.
|
||||
|
||||
**How:**
|
||||
Record in implementation notes, issue tracking, or follow-up execution context that the Studio/Java packer must emit canonical `SCREAMING_SNAKE_CASE` codec strings and must stop producing `RAW`. No runtime code should add compatibility shims for packer drift.
|
||||
|
||||
**File(s):**
|
||||
- No runtime file changes required in this repository for this step
|
||||
|
||||
## Criterios de Aceite
|
||||
|
||||
- `AssetEntry.codec` is an enum in Rust, not a `String`.
|
||||
- `assets.pa` still serializes/deserializes codec as a JSON string.
|
||||
- The canonical wire spelling for the initial codec is `NONE`.
|
||||
- Unknown codec strings cause cartridge loading to fail before asset loading proceeds.
|
||||
- `RAW` is no longer accepted by runtime code or runtime tests.
|
||||
- Asset driver code branches on `AssetCodec`, not string literals.
|
||||
- Existing runtime tests pass after fixture migration, and regression tests cover the new failure behavior.
|
||||
|
||||
## Tests / Validacao
|
||||
|
||||
### Unit Tests
|
||||
|
||||
- Serialization/deserialization tests for `AssetCodec` proving `AssetCodec::None <-> "NONE"`.
|
||||
- Asset driver tests that match on enum variants instead of strings.
|
||||
|
||||
### Integration Tests
|
||||
|
||||
- Cartridge loader test that accepts `assets.pa` headers containing `codec: "NONE"`.
|
||||
- Cartridge loader test that rejects an unknown codec string.
|
||||
- Cartridge loader test that rejects legacy `RAW`.
|
||||
|
||||
### Manual Verification
|
||||
|
||||
- Inspect generated `assets.pa` header JSON from a known-good sample and verify `codec` remains a string field with `SCREAMING_SNAKE_CASE`.
|
||||
- Run the relevant Rust test suites for `prometeu-hal`, `prometeu-drivers`, and any affected runtime tests.
|
||||
|
||||
## Riscos
|
||||
|
||||
- Existing tests and fixtures may be numerous because `AssetEntry` is widely constructed directly.
|
||||
- If deserialization failure maps too generically, debugging bad packer output may become opaque unless tests assert the intended failure path clearly.
|
||||
- Studio work is out of scope for this repository, so rollout coordination is required to avoid runtime/packer contract skew.
|
||||
Loading…
x
Reference in New Issue
Block a user