prometeu-runtime/docs/specs/runtime/15-asset-management.md

11 KiB

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:

[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:

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

For BankType::TILES, the v1 runtime-facing contract is:

  • codec = NONE
  • serialized pixels use packed u4 palette indices
  • serialized palettes use RGB565 (u16, little-endian)
  • palette_count = 64
  • runtime materialization may expand pixel indices to one u8 per pixel

For TILES, NONE means there is no additional generic codec layer beyond the bank contract itself.

For the current transition window:

  • RAW is a legacy deprecated alias of NONE
  • newly published material must use NONE as the canonical value

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

Following DEC-0004, the AssetEntry.metadata field must be structured in segmented form to avoid ambiguity.

Required effective metadata fields for TILES at the root level:

  • 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

Optional informative subtrees:

  • 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).

Validation rules for TILES v1:

  • 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

  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:

  • GLYPH
  • 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:

SlotRef { bank_type, index }

That internal representation is derived from the resolved AssetEntry, not supplied by the caller.

5.1 Canonical Bank Telemetry

The canonical visible bank telemetry contract is exposed by AssetManager.

The per-bank summary is slot-first and uses this shape:

BankTelemetry {
  bank_type
  used_slots
  total_slots
}

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 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

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 and Inspection Boundary

The runtime may maintain bank and slot statistics such as:

  • total bytes;
  • used bytes;
  • free bytes;
  • inflight bytes;
  • slot occupancy;
  • resident asset identity per slot.

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

preload is stored in the JSON header of assets.pa.

The normative preload shape is:

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

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