All checks were successful
Intrepid/Prometeu/Runtime/pipeline/head This commit looks good
Reviewed-on: #12 Co-authored-by: bQUARKz <bquarkz@gmail.com> Co-committed-by: bQUARKz <bquarkz@gmail.com>
337 lines
10 KiB
Markdown
337 lines
10 KiB
Markdown
# Asset Management
|
|
|
|
Domain: asset runtime surface
|
|
Function: normative
|
|
|
|
This chapter defines the runtime-facing asset model of PROMETEU.
|
|
|
|
## 1 Scope
|
|
|
|
PROMETEU asset management is bank-centric.
|
|
|
|
Assets are:
|
|
|
|
- cold bytes stored in the cartridge;
|
|
- described by cartridge metadata;
|
|
- materialized into host-managed banks;
|
|
- separate from VM heap ownership.
|
|
|
|
This chapter describes the runtime contract currently visible in the codebase. It is not a full tooling pipeline specification.
|
|
|
|
## 2 Core Principles
|
|
|
|
1. asset residency is explicit;
|
|
2. asset memory belongs to the machine, not to the VM heap;
|
|
3. banks and slots are hardware/runtime concepts;
|
|
4. loading and activation are explicit operations;
|
|
5. asset memory does not participate in GC.
|
|
|
|
## 3 Cartridge Asset Artifact
|
|
|
|
The runtime currently consumes one primary cartridge asset artifact:
|
|
|
|
- `assets.pa`: autocontained asset artifact.
|
|
|
|
`assets.pa` carries, inside the same binary:
|
|
|
|
- fixed binary prelude;
|
|
- JSON header;
|
|
- payload bytes.
|
|
|
|
The JSON header carries:
|
|
|
|
- `asset_table`: metadata entries describing asset content;
|
|
- `preload`: optional initial residency requests consumed during cartridge initialization.
|
|
|
|
This chapter describes the runtime-facing asset contract. It does not define the Studio packer workflow or the shipper pipeline that publishes the cartridge.
|
|
|
|
### 3.1 `assets.pa` v1 envelope
|
|
|
|
`assets.pa` v1 is structured as:
|
|
|
|
```text
|
|
[fixed binary prelude]
|
|
[json header]
|
|
[binary payload region]
|
|
```
|
|
|
|
The fixed binary prelude contains, at minimum:
|
|
|
|
- `magic`
|
|
- `schema_version`
|
|
- `header_len`
|
|
- `payload_offset`
|
|
|
|
It may additionally include:
|
|
|
|
- `flags`
|
|
- `reserved`
|
|
- `header_checksum`
|
|
|
|
### 3.2 Header and payload contract
|
|
|
|
The runtime loads:
|
|
|
|
- `asset_table` from the JSON header and keeps it live during cartridge execution;
|
|
- `preload` from the JSON header and consumes it only during boot.
|
|
|
|
Payload bytes are addressed from the payload region using offsets relative to `payload_offset`, not relative to the start of the whole file.
|
|
|
|
## 4 Asset Table
|
|
|
|
Current runtime-facing asset metadata includes:
|
|
|
|
```text
|
|
AssetEntry {
|
|
asset_id
|
|
asset_name
|
|
bank_type
|
|
offset
|
|
size
|
|
decoded_size
|
|
codec
|
|
metadata
|
|
}
|
|
```
|
|
|
|
This table describes content identity and storage layout, not live residency.
|
|
|
|
`asset_id` is the stable runtime-facing asset identity and uses 32-bit signed integer semantics compatible with Java `int`.
|
|
|
|
`offset` is relative to the start of the payload region inside `assets.pa`.
|
|
|
|
`size` is the serialized byte count stored in the payload region.
|
|
|
|
`decoded_size` is the byte count of the materialized runtime bank after decode, not necessarily the same as the serialized payload size.
|
|
|
|
`codec` identifies the generic transformation pipeline applied to the serialized payload slice before the asset becomes a resident bank.
|
|
|
|
`codec` does not define the bank-specific serialized layout itself. Specialized banks may still have normative decode rules even when `codec = NONE`.
|
|
|
|
### 4.1 `TILES` asset contract in v1
|
|
|
|
Para `BankType::TILES`, o contrato v1 voltado para o runtime é:
|
|
|
|
- `codec = NONE`
|
|
- pixels serializados usam índices de paleta `u4` empacotados
|
|
- paletas serializadas usam `RGB565` (`u16`, little-endian)
|
|
- `palette_count = 64`
|
|
- a materialização em runtime pode expandir índices de pixel para um `u8` por pixel
|
|
|
|
`NONE` para `TILES` significa que não há camada de codec genérica adicional além do próprio contrato do banco.
|
|
|
|
Para a janela de transição atual:
|
|
|
|
- `RAW` é um alias legado e depreciado de `NONE`
|
|
- novos materiais publicados devem usar `NONE` como valor canônico
|
|
|
|
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.
|
|
|
|
#### 4.1.1 Metadata Normalization
|
|
|
|
Seguindo a `DEC-0004`, o campo `AssetEntry.metadata` deve ser estruturado de forma segmentada para evitar ambiguidades.
|
|
|
|
Campos de metadados obrigatórios (efetivos) para `TILES` no nível raiz:
|
|
|
|
- `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
|
|
|
|
Subárvores opcionais e informativas:
|
|
|
|
- `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).
|
|
|
|
Regras de validação para `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).
|
|
|
|
#### 4.1.2 Payload Layout
|
|
|
|
1. packed indexed pixels for the full sheet, using `ceil(width * height / 2)` bytes;
|
|
2. palette table, using `palette_count * 16 * 2` bytes.
|
|
|
|
The tile-bank payload therefore separates serialized storage form from runtime memory form:
|
|
|
|
- serialized pixel plane: packed `4bpp`
|
|
- decoded pixel plane: expanded `u8` indices, one entry per pixel
|
|
- palette table: `64 * 16` colors in `RGB565`
|
|
|
|
For `TILES` v1:
|
|
|
|
- `size` must match `ceil(width * height / 2) + (palette_count * 16 * 2)`
|
|
- `decoded_size` must match `(width * height) + (palette_count * 16 * 2)`
|
|
|
|
## 5 Banks and Slots
|
|
|
|
The current runtime exposes bank types:
|
|
|
|
- `TILES`
|
|
- `SOUNDS`
|
|
|
|
Assets are loaded into explicit slots identified by slot index at the public ABI boundary.
|
|
|
|
The runtime resolves bank context from `asset_table` using `asset_id`.
|
|
|
|
Internally, the runtime may still use a bank-qualified slot reference such as:
|
|
|
|
```text
|
|
SlotRef { bank_type, index }
|
|
```
|
|
|
|
That internal representation is derived from the resolved `AssetEntry`, not supplied by the caller.
|
|
|
|
## 6 Load Lifecycle
|
|
|
|
The runtime asset manager exposes a staged lifecycle:
|
|
|
|
- `PENDING`
|
|
- `LOADING`
|
|
- `READY`
|
|
- `COMMITTED`
|
|
- `CANCELED`
|
|
- `ERROR`
|
|
|
|
High-level flow:
|
|
|
|
1. request load of an asset into a slot;
|
|
2. resolve the asset entry from live `asset_table`;
|
|
3. open the payload slice in `assets.pa`;
|
|
4. perform read/decode/materialization work;
|
|
5. mark the load `READY`;
|
|
6. explicitly `commit`;
|
|
7. activate the resident asset in the slot.
|
|
|
|
The canonical payload paths are:
|
|
|
|
- `ROM -> open_slice -> CODEX/decode -> Bank`
|
|
- `ROM -> open_slice -> temporary in-memory blob -> CODEX/decode -> Bank`
|
|
|
|
`open_slice` is the runtime-facing concept for opening a limited view over a payload slice. The runtime must not require the whole `assets.pa` payload to remain resident in RAM as its baseline operating mode.
|
|
|
|
`OP_MODE` selects between direct slice consumption and temporary materialization in memory.
|
|
|
|
For v1:
|
|
|
|
- `OP_MODE` is derived from `codec`/CODEX;
|
|
- explicit per-asset hinting is not part of the baseline contract.
|
|
- `TILES` with `codec = NONE` may still stage in memory before bank installation because bank-specific decode expands packed pixel indices into the resident representation.
|
|
- during the migration window, runtime may accept legacy `RAW` as an alias of `NONE`.
|
|
|
|
The runtime does not treat asset installation as implicit side effect.
|
|
|
|
## 7 Residency and Ownership
|
|
|
|
Asset banks are host/runtime-owned memory.
|
|
|
|
Therefore:
|
|
|
|
- VM heap does not own asset residency;
|
|
- GC does not scan asset bank memory;
|
|
- 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
|
|
|
|
The runtime surfaces bank and slot statistics such as:
|
|
|
|
- total bytes;
|
|
- used bytes;
|
|
- free bytes;
|
|
- inflight bytes;
|
|
- slot occupancy;
|
|
- resident asset identity per slot.
|
|
|
|
These metrics support debugging, telemetry, and certification-oriented inspection.
|
|
|
|
## 9 Preload
|
|
|
|
`preload` is stored in the JSON header of `assets.pa`.
|
|
|
|
The normative preload shape is:
|
|
|
|
```text
|
|
PreloadEntry {
|
|
asset_id
|
|
slot
|
|
}
|
|
```
|
|
|
|
These preload entries are consumed during cartridge initialization so the asset manager can establish initial residency before normal execution flow.
|
|
|
|
Validation rules:
|
|
|
|
- `preload` is resolved by `asset_id`, not by `asset_name`;
|
|
- every `preload.asset_id` must exist in the same `asset_table`;
|
|
- no two preload entries may resolve to the same `(bank_type, slot)` pair;
|
|
- legacy preload keyed by `asset_name` is invalid for the current contract.
|
|
|
|
Lifecycle rule:
|
|
|
|
- `preload` is boot-time input only;
|
|
- it does not need to remain live after initialization completes.
|
|
|
|
Bootstrap rule:
|
|
|
|
- invalid preload is a structural cartridge error and must fail cartridge bootstrap before normal execution begins.
|
|
|
|
## 10 Relationship to Other Specs
|
|
|
|
- [`13-cartridge.md`](13-cartridge.md) defines the cartridge package and the requirement that `assets.pa` carries its own asset header.
|
|
- [`16-host-abi-and-syscalls.md`](16-host-abi-and-syscalls.md) defines the syscall boundary used to manipulate assets.
|
|
- [`03-memory-stack-heap-and-allocation.md`](03-memory-stack-heap-and-allocation.md) defines the distinction between VM heap memory and host-owned memory.
|
|
|
|
## 11 Syscall Surface and Status Policy
|
|
|
|
`asset` follows status-first policy.
|
|
|
|
Fault boundary:
|
|
|
|
- `Trap`: structural ABI misuse (type/arity/capability/shape mismatch);
|
|
- `status`: operational failure;
|
|
- `Panic`: internal invariant break only.
|
|
|
|
### 11.1 MVP syscall shape
|
|
|
|
- `asset.load(asset_id, slot) -> (status:int, handle:int)`
|
|
- `asset.status(handle) -> status:int`
|
|
- `asset.commit(handle) -> status:int`
|
|
- `asset.cancel(handle) -> status:int`
|
|
|
|
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.
|
|
- `asset.load` resolves the target bank type from `asset_table` using `asset_id`;
|
|
- public callers must not supply `asset_name` or `bank_type` to `asset.load`;
|
|
- slot validation and residency/lifecycle rejection remain in `asset` status space and are not delegated to `bank`.
|
|
|
|
### 11.2 Minimum status tables
|
|
|
|
`asset.load` request statuses:
|
|
|
|
- `0` = `OK`
|
|
- `3` = `ASSET_NOT_FOUND`
|
|
- `5` = `SLOT_INDEX_INVALID`
|
|
- `6` = `BACKEND_ERROR`
|
|
|
|
`asset.status` lifecycle statuses:
|
|
|
|
- `0` = `PENDING`
|
|
- `1` = `LOADING`
|
|
- `2` = `READY`
|
|
- `3` = `COMMITTED`
|
|
- `4` = `CANCELED`
|
|
- `5` = `ERROR`
|
|
- `6` = `UNKNOWN_HANDLE`
|
|
|
|
`asset.commit` and `asset.cancel` operation statuses:
|
|
|
|
- `0` = `OK`
|
|
- `1` = `UNKNOWN_HANDLE`
|
|
- `2` = `INVALID_STATE`
|