implements PLN-0167 variable glyph palette specs

This commit is contained in:
bQUARKz 2026-07-14 15:42:11 +01:00
parent dc279fe72b
commit c89116b6f8
Signed by: bquarkz
SSH Key Fingerprint: SHA256:Z7dgqoglWwoK6j6u4QC87OveEq74WOhFN+gitsxtkf8
4 changed files with 32 additions and 10 deletions

View File

@ -44,4 +44,4 @@
{"type":"discussion","id":"DSC-0033","status":"done","ticket":"system-os-service-ownership-and-module-layout","title":"Agenda - SystemOS Service Ownership and Module Layout","created_at":"2026-05-14","updated_at":"2026-05-15","tags":["runtime","os","services","module-layout","vm","window-manager","logging"],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0042","file":"discussion/lessons/DSC-0033-system-os-service-ownership-and-module-layout/LSN-0042-systemos-service-ownership-boundary.md","status":"done","created_at":"2026-05-15","updated_at":"2026-05-15"}]} {"type":"discussion","id":"DSC-0033","status":"done","ticket":"system-os-service-ownership-and-module-layout","title":"Agenda - SystemOS Service Ownership and Module Layout","created_at":"2026-05-14","updated_at":"2026-05-15","tags":["runtime","os","services","module-layout","vm","window-manager","logging"],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0042","file":"discussion/lessons/DSC-0033-system-os-service-ownership-and-module-layout/LSN-0042-systemos-service-ownership-boundary.md","status":"done","created_at":"2026-05-15","updated_at":"2026-05-15"}]}
{"type":"discussion","id":"DSC-0036","status":"done","ticket":"prometeu-hub-ui-direction","title":"Agenda - Prometeu Hub UI Direction","created_at":"2026-05-15","updated_at":"2026-05-22","tags":["hub","ui","shell","system-apps","lifecycle","design-system"],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0045","file":"discussion/lessons/DSC-0036-prometeu-hub-ui-direction/LSN-0045-hub-ui-slices-should-prove-os-boundaries.md","status":"done","created_at":"2026-05-22","updated_at":"2026-05-22"}]} {"type":"discussion","id":"DSC-0036","status":"done","ticket":"prometeu-hub-ui-direction","title":"Agenda - Prometeu Hub UI Direction","created_at":"2026-05-15","updated_at":"2026-05-22","tags":["hub","ui","shell","system-apps","lifecycle","design-system"],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0045","file":"discussion/lessons/DSC-0036-prometeu-hub-ui-direction/LSN-0045-hub-ui-slices-should-prove-os-boundaries.md","status":"done","created_at":"2026-05-22","updated_at":"2026-05-22"}]}
{"type":"discussion","id":"DSC-0037","status":"done","ticket":"rgba8888-framebuffer-and-pixel-format-direction","title":"Agenda - RGBA8888 Framebuffer and Pixel Format Direction","created_at":"2026-05-22","updated_at":"2026-05-23","tags":["gfx","framebuffer","rgb565","rgba8888","renderer","assets","host","backend"],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0046","file":"discussion/lessons/DSC-0037-rgba8888-framebuffer-and-pixel-format-direction/LSN-0046-pixel-format-contracts-must-move-as-one-surface.md","status":"done","created_at":"2026-05-23","updated_at":"2026-05-23"}]} {"type":"discussion","id":"DSC-0037","status":"done","ticket":"rgba8888-framebuffer-and-pixel-format-direction","title":"Agenda - RGBA8888 Framebuffer and Pixel Format Direction","created_at":"2026-05-22","updated_at":"2026-05-23","tags":["gfx","framebuffer","rgb565","rgba8888","renderer","assets","host","backend"],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0046","file":"discussion/lessons/DSC-0037-rgba8888-framebuffer-and-pixel-format-direction/LSN-0046-pixel-format-contracts-must-move-as-one-surface.md","status":"done","created_at":"2026-05-23","updated_at":"2026-05-23"}]}
{"type":"discussion","id":"DSC-0046","status":"in_progress","ticket":"runtime-owned-variable-glyph-bank-palette-protocol","title":"Runtime-Owned Variable Glyph Bank Palette Protocol","created_at":"2026-07-14","updated_at":"2026-07-14","tags":["runtime","gfx","assets","glyph-bank","palette-serialization","protocol"],"agendas":[{"id":"AGD-0049","file":"AGD-0049-runtime-owned-variable-glyph-bank-palette-protocol.md","status":"accepted","created_at":"2026-07-14","updated_at":"2026-07-14"}],"decisions":[{"id":"DEC-0041","file":"DEC-0041-variable-glyph-bank-palette-protocol.md","status":"accepted","created_at":"2026-07-14","updated_at":"2026-07-14","ref_agenda":"AGD-0049"}],"plans":[{"id":"PLN-0167","file":"PLN-0167-spec-contract-update-for-variable-glyph-palettes.md","status":"open","created_at":"2026-07-14","updated_at":"2026-07-14","ref_decisions":["DEC-0041"]},{"id":"PLN-0168","file":"PLN-0168-glyphbank-variable-palette-resident-model.md","status":"open","created_at":"2026-07-14","updated_at":"2026-07-14","ref_decisions":["DEC-0041"]},{"id":"PLN-0169","file":"PLN-0169-asset-decode-validation-for-variable-glyph-palettes.md","status":"open","created_at":"2026-07-14","updated_at":"2026-07-14","ref_decisions":["DEC-0041"]},{"id":"PLN-0170","file":"PLN-0170-composer-palette-reference-failure-semantics.md","status":"open","created_at":"2026-07-14","updated_at":"2026-07-14","ref_decisions":["DEC-0041"]},{"id":"PLN-0171","file":"PLN-0171-variable-glyph-palette-tests-fixtures-and-residue-scan.md","status":"open","created_at":"2026-07-14","updated_at":"2026-07-14","ref_decisions":["DEC-0041"]},{"id":"PLN-0172","file":"PLN-0172-runtime-spec-handoff-to-packer-and-studio.md","status":"open","created_at":"2026-07-14","updated_at":"2026-07-14","ref_decisions":["DEC-0041"]}],"lessons":[]} {"type":"discussion","id":"DSC-0046","status":"in_progress","ticket":"runtime-owned-variable-glyph-bank-palette-protocol","title":"Runtime-Owned Variable Glyph Bank Palette Protocol","created_at":"2026-07-14","updated_at":"2026-07-14","tags":["runtime","gfx","assets","glyph-bank","palette-serialization","protocol"],"agendas":[{"id":"AGD-0049","file":"AGD-0049-runtime-owned-variable-glyph-bank-palette-protocol.md","status":"accepted","created_at":"2026-07-14","updated_at":"2026-07-14"}],"decisions":[{"id":"DEC-0041","file":"DEC-0041-variable-glyph-bank-palette-protocol.md","status":"accepted","created_at":"2026-07-14","updated_at":"2026-07-14","ref_agenda":"AGD-0049"}],"plans":[{"id":"PLN-0167","file":"PLN-0167-spec-contract-update-for-variable-glyph-palettes.md","status":"done","created_at":"2026-07-14","updated_at":"2026-07-14","ref_decisions":["DEC-0041"]},{"id":"PLN-0168","file":"PLN-0168-glyphbank-variable-palette-resident-model.md","status":"open","created_at":"2026-07-14","updated_at":"2026-07-14","ref_decisions":["DEC-0041"]},{"id":"PLN-0169","file":"PLN-0169-asset-decode-validation-for-variable-glyph-palettes.md","status":"open","created_at":"2026-07-14","updated_at":"2026-07-14","ref_decisions":["DEC-0041"]},{"id":"PLN-0170","file":"PLN-0170-composer-palette-reference-failure-semantics.md","status":"open","created_at":"2026-07-14","updated_at":"2026-07-14","ref_decisions":["DEC-0041"]},{"id":"PLN-0171","file":"PLN-0171-variable-glyph-palette-tests-fixtures-and-residue-scan.md","status":"open","created_at":"2026-07-14","updated_at":"2026-07-14","ref_decisions":["DEC-0041"]},{"id":"PLN-0172","file":"PLN-0172-runtime-spec-handoff-to-packer-and-studio.md","status":"open","created_at":"2026-07-14","updated_at":"2026-07-14","ref_decisions":["DEC-0041"]}],"lessons":[]}

View File

@ -2,7 +2,8 @@
id: PLN-0167 id: PLN-0167
ticket: runtime-owned-variable-glyph-bank-palette-protocol ticket: runtime-owned-variable-glyph-bank-palette-protocol
title: Spec Contract Update for Variable Glyph Palettes title: Spec Contract Update for Variable Glyph Palettes
status: open status: done
completed: 2026-07-14
created: 2026-07-14 created: 2026-07-14
ref_decisions: [DEC-0041] ref_decisions: [DEC-0041]
tags: [runtime, gfx, assets, glyph-bank, palette-serialization, protocol, specs] tags: [runtime, gfx, assets, glyph-bank, palette-serialization, protocol, specs]

View File

@ -625,7 +625,8 @@ Each tilemap cell contains:
Runtime-facing validity rule for v1: Runtime-facing validity rule for v1:
- `palette_id` values are valid only in the range `0..63` - `palette_id` values are valid only when `palette_id < palette_count` for the
resolved resident glyph bank
#### Sprite #### Sprite
@ -640,7 +641,8 @@ Each sprite draw contains:
Runtime-facing validity rule for v1: Runtime-facing validity rule for v1:
- `palette_id` values are valid only in the range `0..63` - `palette_id` values are valid only when `palette_id < palette_count` for the
referenced resident glyph bank
--- ---
@ -649,7 +651,7 @@ Runtime-facing validity rule for v1:
The pipeline works like this: The pipeline works like this:
1. Read indexed pixel from tile (value 0..15) 1. Read indexed pixel from tile (value 0..15)
2. Resolve: 2. Validate and resolve:
- real_color = palette[palette_id][index] - real_color = palette[palette_id][index]
3. Apply: 3. Apply:
- flip - flip
@ -667,6 +669,9 @@ else:
draw_or_blend(color) draw_or_blend(color)
``` ```
The `palette_id` lookup above is valid only after the runtime has established
that the referenced resident glyph bank contains that palette.
--- ---
### 19.7. Organization of Tile Banks ### 19.7. Organization of Tile Banks
@ -766,6 +771,7 @@ Rules:
- missing glyph dependencies referenced by a resident scene are not a passive `status:int` case; - 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 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; - if scene composition later discovers that a layer dependency can no longer be resolved, the machine MUST fail fatally and emit a clear log;
- if scene activation or composition discovers that a tile references `palette_id >= palette_count` for its resolved glyph bank, the machine MUST fail explicitly and MUST NOT substitute transparent, black, or default color;
- runtime MUST NOT continue canonical scene composition after such a dependency failure. - runtime MUST NOT continue canonical scene composition after such a dependency failure.
### 20.2 `composer.emit_sprite` ### 20.2 `composer.emit_sprite`
@ -774,7 +780,7 @@ Rules:
ABI: ABI:
1. `glyph_id: int` — glyph index within the bank 1. `glyph_id: int` — glyph index within the bank
2. `palette_id: int` — palette index 2. `palette_id: int` — palette index within the referenced bank; valid only when `palette_id < palette_count` for that resident glyph bank
3. `x: int` — x coordinate 3. `x: int` — x coordinate
4. `y: int` — y coordinate 4. `y: int` — y coordinate
5. `layer: int` — composition layer reference 5. `layer: int` — composition layer reference
@ -797,4 +803,5 @@ Operational notes:
- the canonical public sprite contract is frame-emission based; - the canonical public sprite contract is frame-emission based;
- no caller-provided sprite index exists in the v1 canonical ABI; - no caller-provided sprite index exists in the v1 canonical ABI;
- no `active` flag exists in the v1 canonical ABI; - no `active` flag exists in the v1 canonical ABI;
- `palette_id >= palette_count` for the referenced glyph bank is an explicit invalid palette reference and MUST NOT be rendered through transparent, black, or default color substitution;
- overflow remains non-fatal and must not escalate to trap in v1. - overflow remains non-fatal and must not escalate to trap in v1.

View File

@ -115,7 +115,7 @@ For `BankType::GLYPH`, the v1 runtime-facing contract is:
- `codec = NONE` - `codec = NONE`
- serialized pixels use packed `u4` palette indices - serialized pixels use packed `u4` palette indices
- serialized palettes use `RGBA8888` with canonical RGBA channel order - serialized palettes use `RGBA8888` with canonical RGBA channel order
- `palette_count = 64` - `palette_count` is the number of serialized and resident palettes and must be in `1..=64`
- runtime materialization may expand pixel indices to one `u8` per pixel - runtime materialization may expand pixel indices to one `u8` per pixel
For `GLYPH`, `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.
@ -136,7 +136,7 @@ Required effective metadata fields for `GLYPH` at the root level:
- `tile_size`: tile edge in pixels; valid values are `8`, `16`, or `32` - `tile_size`: tile edge in pixels; valid values are `8`, `16`, or `32`
- `width`: total sheet width in pixels - `width`: total sheet width in pixels
- `height`: total sheet height in pixels - `height`: total sheet height in pixels
- `palette_count`: number of serialized palettes for the bank - `palette_count`: number of serialized palettes and resident runtime palettes for the bank
Optional informative subtrees: Optional informative subtrees:
@ -145,7 +145,7 @@ Optional informative subtrees:
Validation rules for `GLYPH` v1: Validation rules for `GLYPH` v1:
- `palette_count` must be `64` - `palette_count` must be in the inclusive range `1..=64`
- `width * height` defines the number of logical indexed pixels in the decoded sheet - `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. - 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.
@ -158,7 +158,16 @@ The tile-bank payload therefore separates serialized storage form from runtime m
- serialized pixel plane: packed `4bpp` - serialized pixel plane: packed `4bpp`
- decoded pixel plane: expanded `u8` indices, one entry per pixel - decoded pixel plane: expanded `u8` indices, one entry per pixel
- palette table: `64 * 16` colors in RGBA8888 channel order - palette table: `palette_count * 16` colors in RGBA8888 channel order
For `GLYPH` v1:
```text
serialized_pixel_bytes = ceil(width * height / 2)
palette_bytes = palette_count * 16 * 4
size = serialized_pixel_bytes + palette_bytes
decoded_size = (width * height) + palette_bytes
```
For `GLYPH` v1: For `GLYPH` v1:
@ -172,6 +181,11 @@ before they are loaded by the runtime.
Palette indices are ordinary indices. Transparency is represented by the alpha Palette indices are ordinary indices. Transparency is represented by the alpha
channel of the resolved RGBA8888 palette entry, not by reserving index `0`. channel of the resolved RGBA8888 palette entry, not by reserving index `0`.
`palette_id` is valid only when it is lower than the referenced resident glyph
bank's `palette_count`. Canonical runtime composition MUST NOT substitute
transparent, black, or any other default color for `palette_id >=
palette_count`.
### 4.2 `SCENE` asset contract in v1 ### 4.2 `SCENE` asset contract in v1
For `BankType::SCENE`, the v1 runtime-facing contract is: For `BankType::SCENE`, the v1 runtime-facing contract is: