dev/scene-bank-glyph-runtime-binding-leak #21
@ -53,7 +53,11 @@ pub const SCENE_PAYLOAD_MAGIC_V1: [u8; 4] = *b"SCNE";
|
||||
pub const SCENE_PAYLOAD_VERSION_V1: u16 = 1;
|
||||
pub const SCENE_LAYER_COUNT_V1: usize = 4;
|
||||
pub const SCENE_HEADER_BYTES_V1: usize = 12;
|
||||
pub const SCENE_LAYER_HEADER_BYTES_V1: usize = 28;
|
||||
// Per-layer header:
|
||||
// flags:u8 + glyph_asset_id:i32 + tile_size:u8 + reserved:u16
|
||||
// + parallax_x:f32 + parallax_y:f32 + width:u32 + height:u32
|
||||
// + tile_count:u32 + reserved:u32
|
||||
pub const SCENE_LAYER_HEADER_BYTES_V1: usize = 32;
|
||||
pub const SCENE_TILE_RECORD_BYTES_V1: usize = 4;
|
||||
pub const SCENE_DECODED_LAYER_OVERHEAD_BYTES_V1: usize = 16;
|
||||
|
||||
|
||||
@ -21,7 +21,7 @@
|
||||
{"type":"discussion","id":"DSC-0026","status":"done","ticket":"render-all-scene-cache-and-camera-integration","title":"Integrate render_all with Scene Cache and Camera","created_at":"2026-04-14","updated_at":"2026-04-18","tags":["gfx","runtime","render","camera","scene"],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0031","file":"lessons/DSC-0026-render-all-scene-cache-and-camera-integration/LSN-0031-frame-composition-belongs-above-the-render-backend.md","status":"done","created_at":"2026-04-18","updated_at":"2026-04-18"}]}
|
||||
{"type":"discussion","id":"DSC-0027","status":"done","ticket":"frame-composer-public-syscall-surface","title":"Agenda - FrameComposer Public Syscall Surface","created_at":"2026-04-17","updated_at":"2026-04-18","tags":["gfx","runtime","syscall","abi","frame-composer","scene","camera","sprites"],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0032","file":"lessons/DSC-0027-frame-composer-public-syscall-surface/LSN-0032-public-abi-must-follow-the-canonical-service-boundary.md","status":"done","created_at":"2026-04-18","updated_at":"2026-04-18"}]}
|
||||
{"type":"discussion","id":"DSC-0028","status":"done","ticket":"deferred-overlay-and-primitive-composition","title":"Deferred Overlay and Primitive Composition over FrameComposer","created_at":"2026-04-18","updated_at":"2026-04-18","tags":["gfx","runtime","render","frame-composer","overlay","primitives","hud"],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0033","file":"lessons/DSC-0028-deferred-overlay-and-primitive-composition/LSN-0033-debug-primitives-should-be-a-final-overlay-not-part-of-game-composition.md","status":"done","created_at":"2026-04-18","updated_at":"2026-04-18"}]}
|
||||
{"type":"discussion","id":"DSC-0029","status":"open","ticket":"scene-bank-glyph-runtime-binding-leak","title":"Scene Bank Glyph Runtime Binding Leak","created_at":"2026-04-24","updated_at":"2026-04-24","tags":["gfx","runtime","asset","scene","glyph","format","architecture"],"agendas":[{"id":"AGD-0029","file":"AGD-0029-scene-bank-glyph-runtime-binding-leak.md","status":"accepted","created_at":"2026-04-24","updated_at":"2026-04-24"}],"decisions":[{"id":"DEC-0021","file":"DEC-0021-scene-bank-glyph-dependencies-must-bind-by-asset-id.md","status":"in_progress","created_at":"2026-04-24","updated_at":"2026-04-24","ref_agenda":"AGD-0029"}],"plans":[{"id":"PLN-0040","file":"PLN-0040-scene-glyph-dependency-spec-and-wire-layout.md","status":"review","created_at":"2026-04-24","updated_at":"2026-04-24","ref_decisions":["DEC-0021"]},{"id":"PLN-0041","file":"PLN-0041-scene-glyph-runtime-resolution-and-fatal-paths.md","status":"review","created_at":"2026-04-24","updated_at":"2026-04-24","ref_decisions":["DEC-0021"]},{"id":"PLN-0042","file":"PLN-0042-scene-glyph-tooling-and-fixture-migration.md","status":"review","created_at":"2026-04-24","updated_at":"2026-04-24","ref_decisions":["DEC-0021"]}],"lessons":[]}
|
||||
{"type":"discussion","id":"DSC-0029","status":"open","ticket":"scene-bank-glyph-runtime-binding-leak","title":"Scene Bank Glyph Runtime Binding Leak","created_at":"2026-04-24","updated_at":"2026-04-24","tags":["gfx","runtime","asset","scene","glyph","format","architecture"],"agendas":[{"id":"AGD-0029","file":"AGD-0029-scene-bank-glyph-runtime-binding-leak.md","status":"accepted","created_at":"2026-04-24","updated_at":"2026-04-24"}],"decisions":[{"id":"DEC-0021","file":"DEC-0021-scene-bank-glyph-dependencies-must-bind-by-asset-id.md","status":"in_progress","created_at":"2026-04-24","updated_at":"2026-04-24","ref_agenda":"AGD-0029"}],"plans":[{"id":"PLN-0040","file":"PLN-0040-scene-glyph-dependency-spec-and-wire-layout.md","status":"done","created_at":"2026-04-24","updated_at":"2026-04-24","ref_decisions":["DEC-0021"]},{"id":"PLN-0041","file":"PLN-0041-scene-glyph-runtime-resolution-and-fatal-paths.md","status":"review","created_at":"2026-04-24","updated_at":"2026-04-24","ref_decisions":["DEC-0021"]},{"id":"PLN-0042","file":"PLN-0042-scene-glyph-tooling-and-fixture-migration.md","status":"review","created_at":"2026-04-24","updated_at":"2026-04-24","ref_decisions":["DEC-0021"]}],"lessons":[]}
|
||||
{"type":"discussion","id":"DSC-0014","status":"done","ticket":"perf-vm-allocation-and-copy-pressure","title":"Agenda - [PERF] VM Allocation and Copy Pressure","created_at":"2026-03-27","updated_at":"2026-04-20","tags":[],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0035","file":"lessons/DSC-0014-perf-vm-allocation-and-copy-pressure/LSN-0035-first-materialization-is-not-the-same-as-hot-path-copy-pressure.md","status":"done","created_at":"2026-04-20","updated_at":"2026-04-20"}]}
|
||||
{"type":"discussion","id":"DSC-0015","status":"abandoned","ticket":"perf-cartridge-boot-and-program-ownership","title":"Agenda - [PERF] Cartridge Boot and Program Ownership","created_at":"2026-03-27","updated_at":"2026-04-20","tags":[],"agendas":[{"id":"AGD-0014","file":"workflow/agendas/AGD-0014-perf-cartridge-boot-and-program-ownership.md","status":"abandoned","created_at":"2026-03-27","updated_at":"2026-04-20","_override_reason":"User explicitly chose to close the discussion without decision because FS->memory copy for the program is already acceptable."}],"decisions":[],"plans":[],"lessons":[],"_override_reason":"User explicitly chose to abandon the discussion without creating a decision because FS->memory copy for the program is already acceptable."}
|
||||
{"type":"discussion","id":"DSC-0016","status":"done","ticket":"tilemap-empty-cell-vs-tile-id-zero","title":"Tilemap Empty Cell vs Tile ID Zero","created_at":"2026-03-27","updated_at":"2026-04-09","tags":[],"agendas":[{"id":"AGD-0015","file":"workflow/agendas/AGD-0015-tilemap-empty-cell-vs-tile-id-zero.md","status":"done","created_at":"2026-03-27","updated_at":"2026-04-09"}],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0022","file":"lessons/DSC-0016-tilemap-empty-cell-semantics/LSN-0022-tilemap-empty-cell-convergence.md","status":"done","created_at":"2026-04-09","updated_at":"2026-04-09"}]}
|
||||
|
||||
@ -2,9 +2,9 @@
|
||||
id: PLN-0040
|
||||
ticket: scene-bank-glyph-runtime-binding-leak
|
||||
title: Scene glyph dependency spec and wire layout migration
|
||||
status: review
|
||||
status: done
|
||||
created: 2026-04-24
|
||||
completed:
|
||||
completed: 2026-04-24
|
||||
tags: [gfx, runtime, asset, scene, glyph, format, spec]
|
||||
---
|
||||
|
||||
@ -102,4 +102,3 @@ Remove proposed/legacy wording that frames missing dependencies as recoverable s
|
||||
- Spec-only edits can drift from the runtime implementation if later plans are not executed promptly.
|
||||
- Scene payload layout changes may require touching multiple docs; missing one will leave contradictory contract text.
|
||||
- If HAL constants are updated here before runtime code, temporary compile or test fallout may appear in later plans and must be handled intentionally.
|
||||
|
||||
|
||||
@ -579,7 +579,7 @@ Fault boundary:
|
||||
| `gfx.draw_square` | `void` | no real operational failure path in v1 |
|
||||
| `gfx.draw_text` | `void` | no real operational failure path in v1 |
|
||||
| `gfx.clear_565` | `void` | no real operational failure path in v1 |
|
||||
| `composer.bind_scene` | `status:int` | explicit orchestration-domain operational result |
|
||||
| `composer.bind_scene` | `status:int` | status-returning API, but missing scene glyph dependencies are fatal runtime errors |
|
||||
| `composer.unbind_scene` | `status:int` | explicit orchestration-domain operational result |
|
||||
| `composer.set_camera` | `void` | no real operational failure path in v1 |
|
||||
| `composer.emit_sprite` | `status:int` | explicit orchestration-domain operational rejection |
|
||||
@ -596,6 +596,18 @@ The public `gfx.*` primitive family remains valid in v1, but its stable operatio
|
||||
|
||||
This means callers MUST NOT rely on stable immediate writes to the working back buffer as the public contract for `gfx.draw_text(...)` or sibling primitives.
|
||||
|
||||
### 19.1.b Scene dependency fatal boundary
|
||||
|
||||
`composer.bind_scene` remains a status-returning syscall in the public ABI, but scene glyph dependency absence is outside the accepted passive operational-error model.
|
||||
|
||||
Rules:
|
||||
|
||||
- the target scene slot may still be rejected through ordinary status-returning behavior when the scene itself is unavailable;
|
||||
- missing glyph dependencies referenced by a resident scene are not a passive `status:int` case;
|
||||
- if scene activation discovers that a layer dependency cannot be resolved to a committed glyph asset, the machine MUST fail fatally and emit a clear log;
|
||||
- if scene composition later discovers that a layer dependency can no longer be resolved, the machine MUST fail fatally and emit a clear log;
|
||||
- runtime MUST NOT continue canonical scene composition after such a dependency failure.
|
||||
|
||||
### 19.2 `composer.emit_sprite`
|
||||
|
||||
`composer.emit_sprite` returns `status:int`.
|
||||
|
||||
@ -108,9 +108,9 @@ This table describes content identity and storage layout, not live residency.
|
||||
|
||||
`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
|
||||
### 4.1 `GLYPH` asset contract in v1
|
||||
|
||||
For `BankType::TILES`, the v1 runtime-facing contract is:
|
||||
For `BankType::GLYPH`, the v1 runtime-facing contract is:
|
||||
|
||||
- `codec = NONE`
|
||||
- serialized pixels use packed `u4` palette indices
|
||||
@ -118,20 +118,20 @@ For `BankType::TILES`, the v1 runtime-facing contract is:
|
||||
- `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 `GLYPH`, `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.
|
||||
Even with `codec = NONE`, `GLYPH` 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:
|
||||
Required effective metadata fields for `GLYPH` at the root level:
|
||||
|
||||
- `tile_size`: tile edge in pixels; valid values are `8`, `16`, or `32`
|
||||
- `width`: total sheet width in pixels
|
||||
@ -143,7 +143,7 @@ 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:
|
||||
Validation rules for `GLYPH` v1:
|
||||
|
||||
- `palette_count` must be `64`
|
||||
- `width * height` defines the number of logical indexed pixels in the decoded sheet
|
||||
@ -160,17 +160,74 @@ The tile-bank payload therefore separates serialized storage form from runtime m
|
||||
- decoded pixel plane: expanded `u8` indices, one entry per pixel
|
||||
- palette table: `64 * 16` colors in `RGB565`
|
||||
|
||||
For `TILES` v1:
|
||||
For `GLYPH` v1:
|
||||
|
||||
- `size` must match `ceil(width * height / 2) + (palette_count * 16 * 2)`
|
||||
- `decoded_size` must match `(width * height) + (palette_count * 16 * 2)`
|
||||
|
||||
### 4.2 `SCENE` asset contract in v1
|
||||
|
||||
For `BankType::SCENE`, the v1 runtime-facing contract is:
|
||||
|
||||
- `codec = NONE`
|
||||
- payload magic is `SCNE`
|
||||
- payload version is `1`
|
||||
- layer count is fixed at `4`
|
||||
- each layer carries its own glyph dependency
|
||||
- the glyph dependency is serialized as canonical `AssetId` using signed 32-bit little-endian width
|
||||
- the payload MUST describe cold asset dependencies only and MUST NOT encode runtime glyph slot topology
|
||||
|
||||
Even with `codec = NONE`, `SCENE` still has a bank-specific binary contract. The serialized layout is normative and distinct from any transient runtime residency state.
|
||||
|
||||
#### 4.2.1 Layer Header Layout
|
||||
|
||||
Each scene layer header is:
|
||||
|
||||
1. `flags: u8`
|
||||
2. `glyph_asset_id: i32` (little-endian)
|
||||
3. `tile_size: u8`
|
||||
4. `reserved: u16`
|
||||
5. `parallax_x: f32`
|
||||
6. `parallax_y: f32`
|
||||
7. `width: u32`
|
||||
8. `height: u32`
|
||||
9. `tile_count: u32`
|
||||
10. `reserved: u32`
|
||||
|
||||
This makes the canonical per-layer header size `32` bytes.
|
||||
|
||||
Normative rules:
|
||||
|
||||
- `glyph_asset_id` MUST be interpreted as the cold identity of the glyph dependency for that layer;
|
||||
- `glyph_asset_id` MUST NOT be interpreted as a runtime slot id;
|
||||
- each layer MUST own exactly one glyph dependency reference;
|
||||
- no shared dependency table exists in this contract;
|
||||
- `tile_count` MUST equal `width * height`.
|
||||
|
||||
#### 4.2.2 Runtime Binding Semantics
|
||||
|
||||
`SCENE` assets do not own runtime residency.
|
||||
|
||||
Therefore:
|
||||
|
||||
- the runtime MUST resolve scene glyph dependencies through runtime-owned residency state;
|
||||
- the runtime MUST maintain a runtime-owned mapping from committed glyph `AssetId` to glyph slot;
|
||||
- scene bind and scene draw MUST consult runtime residency, not serialized slot topology;
|
||||
- a missing scene glyph dependency is not a passive asset-status condition.
|
||||
|
||||
If a scene glyph dependency cannot be resolved:
|
||||
|
||||
- `bind_scene` MUST fail as a fatal machine error with clear logging;
|
||||
- draw/composition MUST fail as a fatal machine error with clear logging;
|
||||
- runtime MUST NOT continue scene composition after the missing dependency is detected.
|
||||
|
||||
## 5 Banks and Slots
|
||||
|
||||
The current runtime exposes bank types:
|
||||
|
||||
- `GLYPH`
|
||||
- `SOUNDS`
|
||||
- `SCENE`
|
||||
|
||||
Assets are loaded into explicit slots identified by slot index at the public ABI boundary.
|
||||
|
||||
|
||||
@ -229,6 +229,12 @@ For mutating composer operations:
|
||||
- `set_camera` remains `void` in v1;
|
||||
- no caller-provided sprite index or `active` flag is part of the canonical contract.
|
||||
|
||||
Fatal boundary clarification for `bind_scene`:
|
||||
|
||||
- `bind_scene` remains status-returning for ordinary orchestration-domain rejection such as unresolved target scene slot;
|
||||
- missing glyph dependencies inside a resident scene are not accepted as passive `ComposerOpStatus` outcomes;
|
||||
- if scene activation or later composition detects an unresolved scene glyph dependency, runtime MUST escalate that condition as a fatal machine error with clear logging.
|
||||
|
||||
## 7 Syscalls as Callable Entities (Not First-Class)
|
||||
|
||||
Syscalls behave like call sites, not like first-class guest values.
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user