From c89116b6f82c1d39aed6eb3e0765565ff75fa56a Mon Sep 17 00:00:00 2001 From: bQUARKz Date: Tue, 14 Jul 2026 15:42:11 +0100 Subject: [PATCH] implements PLN-0167 variable glyph palette specs --- discussion/index.ndjson | 2 +- ...ract-update-for-variable-glyph-palettes.md | 3 ++- docs/specs/runtime/04-gfx-peripheral.md | 15 +++++++++---- docs/specs/runtime/15-asset-management.md | 22 +++++++++++++++---- 4 files changed, 32 insertions(+), 10 deletions(-) diff --git a/discussion/index.ndjson b/discussion/index.ndjson index 7d1cafa1..3c90ca1c 100644 --- a/discussion/index.ndjson +++ b/discussion/index.ndjson @@ -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-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-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":[]} diff --git a/discussion/workflow/plans/PLN-0167-spec-contract-update-for-variable-glyph-palettes.md b/discussion/workflow/plans/PLN-0167-spec-contract-update-for-variable-glyph-palettes.md index 36126eeb..c048cf2b 100644 --- a/discussion/workflow/plans/PLN-0167-spec-contract-update-for-variable-glyph-palettes.md +++ b/discussion/workflow/plans/PLN-0167-spec-contract-update-for-variable-glyph-palettes.md @@ -2,7 +2,8 @@ id: PLN-0167 ticket: runtime-owned-variable-glyph-bank-palette-protocol title: Spec Contract Update for Variable Glyph Palettes -status: open +status: done +completed: 2026-07-14 created: 2026-07-14 ref_decisions: [DEC-0041] tags: [runtime, gfx, assets, glyph-bank, palette-serialization, protocol, specs] diff --git a/docs/specs/runtime/04-gfx-peripheral.md b/docs/specs/runtime/04-gfx-peripheral.md index d6801caa..b6f8105f 100644 --- a/docs/specs/runtime/04-gfx-peripheral.md +++ b/docs/specs/runtime/04-gfx-peripheral.md @@ -625,7 +625,8 @@ Each tilemap cell contains: 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 @@ -640,7 +641,8 @@ Each sprite draw contains: 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: 1. Read indexed pixel from tile (value 0..15) -2. Resolve: +2. Validate and resolve: - real_color = palette[palette_id][index] 3. Apply: - flip @@ -667,6 +669,9 @@ else: 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 @@ -766,6 +771,7 @@ Rules: - 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; +- 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. ### 20.2 `composer.emit_sprite` @@ -774,7 +780,7 @@ Rules: ABI: 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 4. `y: int` — y coordinate 5. `layer: int` — composition layer reference @@ -797,4 +803,5 @@ Operational notes: - the canonical public sprite contract is frame-emission based; - no caller-provided sprite index 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. diff --git a/docs/specs/runtime/15-asset-management.md b/docs/specs/runtime/15-asset-management.md index 699c499d..43e6982d 100644 --- a/docs/specs/runtime/15-asset-management.md +++ b/docs/specs/runtime/15-asset-management.md @@ -115,7 +115,7 @@ For `BankType::GLYPH`, the v1 runtime-facing contract is: - `codec = NONE` - serialized pixels use packed `u4` palette indices - 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 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` - `width`: total sheet width 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: @@ -145,7 +145,7 @@ Optional informative subtrees: 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 - 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` - 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: @@ -172,6 +181,11 @@ before they are loaded by the runtime. Palette indices are ordinary indices. Transparency is represented by the alpha 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 For `BankType::SCENE`, the v1 runtime-facing contract is: