Variable Glyph Bank Palette Serialization
All checks were successful
JaCoCo Coverage #### Project Overview No changes detected, that affect the code coverage. * Line Coverage: 61.08% (17147/28073) * Branch Coverage: 51.93% (6599/12707) * Lines of Code: 28073 * Cyclomatic Complexity: 11234 #### Quality Gates Summary Output truncated.
Test / Build skipped: 15, passed: 583
Intrepid/Prometeu/Studio/pipeline/head This commit looks good

This commit is contained in:
bQUARKz 2026-07-14 16:53:20 +01:00
parent fa089c5cd0
commit ad2ae00f39
Signed by: bquarkz
SSH Key Fingerprint: SHA256:Z7dgqoglWwoK6j6u4QC87OveEq74WOhFN+gitsxtkf8
9 changed files with 128 additions and 1121 deletions

View File

@ -1,4 +1,4 @@
{"type":"meta","next_id":{"DSC":39,"AGD":42,"DEC":39,"PLN":92,"LSN":54,"CLSN":1}} {"type":"meta","next_id":{"DSC":39,"AGD":42,"DEC":39,"PLN":92,"LSN":55,"CLSN":1}}
{"type":"discussion","id":"DSC-0038","status":"done","ticket":"studio-packer-rgba8888-asset-pipeline","title":"Studio and Packer RGBA8888 Asset Pipeline Alignment","created_at":"2026-05-23","updated_at":"2026-07-14","tags":["studio","packer","assets","glyph-bank","palette","rgba8888","runtime-alignment"],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0053","file":"discussion/lessons/DSC-0038-studio-packer-rgba8888-asset-pipeline/LSN-0053-rgba8888-is-the-canonical-studio-packer-palette-contract.md","status":"done","created_at":"2026-07-14","updated_at":"2026-07-14"}]} {"type":"discussion","id":"DSC-0038","status":"done","ticket":"studio-packer-rgba8888-asset-pipeline","title":"Studio and Packer RGBA8888 Asset Pipeline Alignment","created_at":"2026-05-23","updated_at":"2026-07-14","tags":["studio","packer","assets","glyph-bank","palette","rgba8888","runtime-alignment"],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0053","file":"discussion/lessons/DSC-0038-studio-packer-rgba8888-asset-pipeline/LSN-0053-rgba8888-is-the-canonical-studio-packer-palette-contract.md","status":"done","created_at":"2026-07-14","updated_at":"2026-07-14"}]}
{"type":"discussion","id":"DSC-0037","status":"done","ticket":"pbs-autocomplete-parameter-names","title":"PBS autocomplete parameter names for stdlib and method calls","created_at":"2026-05-08","updated_at":"2026-05-14","tags":["compiler-pbs","studio","lsp","autocomplete","signature-help","stdlib"],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0052","file":"discussion/lessons/DSC-0037-pbs-autocomplete-parameter-names/LSN-0052-canonical-callable-parameter-names-through-pbs-editor-assistance.md","status":"done","created_at":"2026-05-14","updated_at":"2026-05-14"}]} {"type":"discussion","id":"DSC-0037","status":"done","ticket":"pbs-autocomplete-parameter-names","title":"PBS autocomplete parameter names for stdlib and method calls","created_at":"2026-05-08","updated_at":"2026-05-14","tags":["compiler-pbs","studio","lsp","autocomplete","signature-help","stdlib"],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0052","file":"discussion/lessons/DSC-0037-pbs-autocomplete-parameter-names/LSN-0052-canonical-callable-parameter-names-through-pbs-editor-assistance.md","status":"done","created_at":"2026-05-14","updated_at":"2026-05-14"}]}
{"type":"discussion","id":"DSC-0036","status":"open","ticket":"pbs-symbol-documentation-and-hover-markdown","title":"Modelo de documentacao de simbolos em PBS e consumo markdown no hover","created_at":"2026-05-08","updated_at":"2026-05-08","tags":["compiler","compiler-pbs","studio","lsp","vscode","editor","hover","documentation","markdown"],"agendas":[{"id":"AGD-0039","file":"AGD-0039-pbs-symbol-documentation-and-hover-markdown.md","status":"open","created_at":"2026-05-08","updated_at":"2026-05-08"}],"decisions":[],"plans":[],"lessons":[]} {"type":"discussion","id":"DSC-0036","status":"open","ticket":"pbs-symbol-documentation-and-hover-markdown","title":"Modelo de documentacao de simbolos em PBS e consumo markdown no hover","created_at":"2026-05-08","updated_at":"2026-05-08","tags":["compiler","compiler-pbs","studio","lsp","vscode","editor","hover","documentation","markdown"],"agendas":[{"id":"AGD-0039","file":"AGD-0039-pbs-symbol-documentation-and-hover-markdown.md","status":"open","created_at":"2026-05-08","updated_at":"2026-05-08"}],"decisions":[],"plans":[],"lessons":[]}
@ -18,7 +18,7 @@
{"type":"discussion","id":"DSC-0002","status":"done","ticket":"palette-management-in-studio","title":"Palette Management in Studio","created_at":"2026-03-26","updated_at":"2026-04-23","tags":["studio","legacy-import","palette-management","tile-bank","packer-boundary"],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0042","file":"discussion/lessons/DSC-0002-palette-management-in-studio/LSN-0042-schema-driven-palette-authoring-and-local-metadata-events.md","status":"done","created_at":"2026-04-23","updated_at":"2026-04-23"}]} {"type":"discussion","id":"DSC-0002","status":"done","ticket":"palette-management-in-studio","title":"Palette Management in Studio","created_at":"2026-03-26","updated_at":"2026-04-23","tags":["studio","legacy-import","palette-management","tile-bank","packer-boundary"],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0042","file":"discussion/lessons/DSC-0002-palette-management-in-studio/LSN-0042-schema-driven-palette-authoring-and-local-metadata-events.md","status":"done","created_at":"2026-04-23","updated_at":"2026-04-23"}]}
{"type":"discussion","id":"DSC-0003","status":"done","ticket":"packer-docs-import","title":"Import docs/packer into discussion-framework artifacts","created_at":"2026-03-26","updated_at":"2026-03-26","tags":["packer","migration","discussion-framework","docs-import"],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0009","file":"discussion/lessons/DSC-0003-packer-docs-import/LSN-0009-mental-model-packer-legacy.md","status":"done","created_at":"2026-03-26","updated_at":"2026-03-26"},{"id":"LSN-0010","file":"discussion/lessons/DSC-0003-packer-docs-import/LSN-0010-asset-identity-and-runtime-contract-legacy.md","status":"done","created_at":"2026-03-26","updated_at":"2026-03-26"},{"id":"LSN-0011","file":"discussion/lessons/DSC-0003-packer-docs-import/LSN-0011-foundations-workspace-runtime-and-build-legacy.md","status":"done","created_at":"2026-03-26","updated_at":"2026-03-26"},{"id":"LSN-0012","file":"discussion/lessons/DSC-0003-packer-docs-import/LSN-0012-runtime-ownership-and-studio-boundary-legacy.md","status":"done","created_at":"2026-03-26","updated_at":"2026-03-26"},{"id":"LSN-0013","file":"discussion/lessons/DSC-0003-packer-docs-import/LSN-0013-metadata-convergence-and-runtime-sink-legacy.md","status":"done","created_at":"2026-03-26","updated_at":"2026-03-26"},{"id":"LSN-0014","file":"discussion/lessons/DSC-0003-packer-docs-import/LSN-0014-pack-wizard-summary-validation-and-pack-execution-legacy.md","status":"done","created_at":"2026-03-26","updated_at":"2026-03-26"},{"id":"LSN-0015","file":"discussion/lessons/DSC-0003-packer-docs-import/LSN-0015-tile-bank-packing-contract-legacy.md","status":"done","created_at":"2026-03-26","updated_at":"2026-03-26"},{"id":"LSN-0017","file":"discussion/lessons/DSC-0003-packer-docs-import/LSN-0017-packer-docs-import-pattern.md","status":"done","created_at":"2026-03-26","updated_at":"2026-03-26"}]} {"type":"discussion","id":"DSC-0003","status":"done","ticket":"packer-docs-import","title":"Import docs/packer into discussion-framework artifacts","created_at":"2026-03-26","updated_at":"2026-03-26","tags":["packer","migration","discussion-framework","docs-import"],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0009","file":"discussion/lessons/DSC-0003-packer-docs-import/LSN-0009-mental-model-packer-legacy.md","status":"done","created_at":"2026-03-26","updated_at":"2026-03-26"},{"id":"LSN-0010","file":"discussion/lessons/DSC-0003-packer-docs-import/LSN-0010-asset-identity-and-runtime-contract-legacy.md","status":"done","created_at":"2026-03-26","updated_at":"2026-03-26"},{"id":"LSN-0011","file":"discussion/lessons/DSC-0003-packer-docs-import/LSN-0011-foundations-workspace-runtime-and-build-legacy.md","status":"done","created_at":"2026-03-26","updated_at":"2026-03-26"},{"id":"LSN-0012","file":"discussion/lessons/DSC-0003-packer-docs-import/LSN-0012-runtime-ownership-and-studio-boundary-legacy.md","status":"done","created_at":"2026-03-26","updated_at":"2026-03-26"},{"id":"LSN-0013","file":"discussion/lessons/DSC-0003-packer-docs-import/LSN-0013-metadata-convergence-and-runtime-sink-legacy.md","status":"done","created_at":"2026-03-26","updated_at":"2026-03-26"},{"id":"LSN-0014","file":"discussion/lessons/DSC-0003-packer-docs-import/LSN-0014-pack-wizard-summary-validation-and-pack-execution-legacy.md","status":"done","created_at":"2026-03-26","updated_at":"2026-03-26"},{"id":"LSN-0015","file":"discussion/lessons/DSC-0003-packer-docs-import/LSN-0015-tile-bank-packing-contract-legacy.md","status":"done","created_at":"2026-03-26","updated_at":"2026-03-26"},{"id":"LSN-0017","file":"discussion/lessons/DSC-0003-packer-docs-import/LSN-0017-packer-docs-import-pattern.md","status":"done","created_at":"2026-03-26","updated_at":"2026-03-26"}]}
{"type":"discussion","id":"DSC-0004","status":"abandoned","ticket":"tilemap-and-metatile-runtime-binary-layout","title":"Tilemap and Metatile Runtime Binary Layout","created_at":"2026-03-26","updated_at":"2026-04-24","tags":["packer","legacy-import","tilemap","metatile","runtime-layout"],"agendas":[{"id":"AGD-0004","file":"AGD-0004-tilemap-and-metatile-runtime-binary-layout.md","status":"abandoned","created_at":"2026-03-26","updated_at":"2026-04-24","_override_reason":"Explicit user request on 2026-04-24 to abandon AGD-0004 because the agenda is no longer valid."}],"decisions":[],"plans":[],"lessons":[]} {"type":"discussion","id":"DSC-0004","status":"abandoned","ticket":"tilemap-and-metatile-runtime-binary-layout","title":"Tilemap and Metatile Runtime Binary Layout","created_at":"2026-03-26","updated_at":"2026-04-24","tags":["packer","legacy-import","tilemap","metatile","runtime-layout"],"agendas":[{"id":"AGD-0004","file":"AGD-0004-tilemap-and-metatile-runtime-binary-layout.md","status":"abandoned","created_at":"2026-03-26","updated_at":"2026-04-24","_override_reason":"Explicit user request on 2026-04-24 to abandon AGD-0004 because the agenda is no longer valid."}],"decisions":[],"plans":[],"lessons":[]}
{"type":"discussion","id":"DSC-0005","status":"open","ticket":"variable-tile-bank-palette-serialization","title":"Variable Glyph Bank Palette Serialization","created_at":"2026-03-26","updated_at":"2026-07-14","tags":["packer","legacy-import","glyph-bank","palette-serialization","rgba8888","runtime-alignment"],"agendas":[{"id":"AGD-0005","file":"AGD-0005-variable-tile-bank-palette-serialization.md","status":"accepted","created_at":"2026-03-26","updated_at":"2026-07-14"}],"decisions":[{"id":"DEC-0038","file":"DEC-0038-variable-glyph-bank-palette-serialization.md","status":"accepted","created_at":"2026-07-14","updated_at":"2026-07-14","ref_agenda":"AGD-0005"}],"plans":[{"id":"PLN-0087","file":"PLN-0087-variable-glyph-palette-spec-propagation.md","status":"done","created_at":"2026-07-14","updated_at":"2026-07-14","ref_decisions":["DEC-0038"]},{"id":"PLN-0088","file":"PLN-0088-variable-glyph-palette-metadata-and-count-model.md","status":"done","created_at":"2026-07-14","updated_at":"2026-07-14","ref_decisions":["DEC-0038"]},{"id":"PLN-0089","file":"PLN-0089-variable-glyph-palette-payload-emission-and-size-accounting.md","status":"done","created_at":"2026-07-14","updated_at":"2026-07-14","ref_decisions":["DEC-0038"]},{"id":"PLN-0090","file":"PLN-0090-studio-and-packer-projections-for-variable-glyph-palettes.md","status":"done","created_at":"2026-07-14","updated_at":"2026-07-14","ref_decisions":["DEC-0038"]},{"id":"PLN-0091","file":"PLN-0091-variable-glyph-palette-tests-fixtures-and-final-validation.md","status":"done","created_at":"2026-07-14","updated_at":"2026-07-14","ref_decisions":["DEC-0038"]}],"lessons":[]} {"type":"discussion","id":"DSC-0005","status":"done","ticket":"variable-tile-bank-palette-serialization","title":"Variable Glyph Bank Palette Serialization","created_at":"2026-03-26","updated_at":"2026-07-14","tags":["packer","legacy-import","glyph-bank","palette-serialization","rgba8888","runtime-alignment"],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0054","file":"discussion/lessons/DSC-0005-variable-glyph-bank-palette-serialization/LSN-0054-runtime-owned-variable-glyph-palette-counts.md","status":"done","created_at":"2026-07-14","updated_at":"2026-07-14"}]}
{"type":"discussion","id":"DSC-0006","status":"done","ticket":"pbs-game-facing-asset-refs-and-call-result-discard","title":"PBS Game-Facing Asset References and Ignored Call Result Lowering","created_at":"2026-03-27","updated_at":"2026-03-30","tags":["compiler","pbs","ergonomics","lowering","runtime","asset-identity","expression-statements"],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0024","file":"discussion/lessons/DSC-0006-pbs-game-facing-asset-refs-and-call-result-discard/LSN-0024-addressable-surface-host-metadata-and-ignored-value-discipline.md","status":"done","created_at":"2026-03-30","updated_at":"2026-03-30"}]} {"type":"discussion","id":"DSC-0006","status":"done","ticket":"pbs-game-facing-asset-refs-and-call-result-discard","title":"PBS Game-Facing Asset References and Ignored Call Result Lowering","created_at":"2026-03-27","updated_at":"2026-03-30","tags":["compiler","pbs","ergonomics","lowering","runtime","asset-identity","expression-statements"],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0024","file":"discussion/lessons/DSC-0006-pbs-game-facing-asset-refs-and-call-result-discard/LSN-0024-addressable-surface-host-metadata-and-ignored-value-discipline.md","status":"done","created_at":"2026-03-30","updated_at":"2026-03-30"}]}
{"type":"discussion","id":"DSC-0007","status":"done","ticket":"pbs-learn-to-discussion-lessons-migration","title":"Migrate PBS Learn Documents into Discussion Lessons","created_at":"2026-03-27","updated_at":"2026-03-27","tags":["compiler","pbs","migration","discussion-framework","lessons","learn-prune"],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0018","file":"discussion/lessons/DSC-0007-pbs-learn-to-discussion-lessons-migration/LSN-0018-pbs-ast-and-parser-contract-legacy.md","status":"done","created_at":"2026-03-27","updated_at":"2026-03-27"},{"id":"LSN-0019","file":"discussion/lessons/DSC-0007-pbs-learn-to-discussion-lessons-migration/LSN-0019-pbs-name-resolution-and-linking-legacy.md","status":"done","created_at":"2026-03-27","updated_at":"2026-03-27"},{"id":"LSN-0020","file":"discussion/lessons/DSC-0007-pbs-learn-to-discussion-lessons-migration/LSN-0020-pbs-runtime-values-identity-memory-boundaries-legacy.md","status":"done","created_at":"2026-03-27","updated_at":"2026-03-27"},{"id":"LSN-0021","file":"discussion/lessons/DSC-0007-pbs-learn-to-discussion-lessons-migration/LSN-0021-pbs-diagnostics-and-conformance-governance-legacy.md","status":"done","created_at":"2026-03-27","updated_at":"2026-03-27"},{"id":"LSN-0022","file":"discussion/lessons/DSC-0007-pbs-learn-to-discussion-lessons-migration/LSN-0022-pbs-globals-lifecycle-and-published-entrypoint-legacy.md","status":"done","created_at":"2026-03-27","updated_at":"2026-03-27"}]} {"type":"discussion","id":"DSC-0007","status":"done","ticket":"pbs-learn-to-discussion-lessons-migration","title":"Migrate PBS Learn Documents into Discussion Lessons","created_at":"2026-03-27","updated_at":"2026-03-27","tags":["compiler","pbs","migration","discussion-framework","lessons","learn-prune"],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0018","file":"discussion/lessons/DSC-0007-pbs-learn-to-discussion-lessons-migration/LSN-0018-pbs-ast-and-parser-contract-legacy.md","status":"done","created_at":"2026-03-27","updated_at":"2026-03-27"},{"id":"LSN-0019","file":"discussion/lessons/DSC-0007-pbs-learn-to-discussion-lessons-migration/LSN-0019-pbs-name-resolution-and-linking-legacy.md","status":"done","created_at":"2026-03-27","updated_at":"2026-03-27"},{"id":"LSN-0020","file":"discussion/lessons/DSC-0007-pbs-learn-to-discussion-lessons-migration/LSN-0020-pbs-runtime-values-identity-memory-boundaries-legacy.md","status":"done","created_at":"2026-03-27","updated_at":"2026-03-27"},{"id":"LSN-0021","file":"discussion/lessons/DSC-0007-pbs-learn-to-discussion-lessons-migration/LSN-0021-pbs-diagnostics-and-conformance-governance-legacy.md","status":"done","created_at":"2026-03-27","updated_at":"2026-03-27"},{"id":"LSN-0022","file":"discussion/lessons/DSC-0007-pbs-learn-to-discussion-lessons-migration/LSN-0022-pbs-globals-lifecycle-and-published-entrypoint-legacy.md","status":"done","created_at":"2026-03-27","updated_at":"2026-03-27"}]}
{"type":"discussion","id":"DSC-0008","status":"done","ticket":"pbs-low-level-asset-manager-surface","title":"PBS Low-Level Asset Manager Surface for Runtime AssetManager","created_at":"2026-03-27","updated_at":"2026-03-27","tags":["compiler","pbs","runtime","asset-manager","host-abi","stdlib","asset"],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0023","file":"discussion/lessons/DSC-0008-pbs-low-level-asset-manager-surface/LSN-0023-lowassets-runtime-aligned-sdk-surface.md","status":"done","created_at":"2026-03-27","updated_at":"2026-03-27"}]} {"type":"discussion","id":"DSC-0008","status":"done","ticket":"pbs-low-level-asset-manager-surface","title":"PBS Low-Level Asset Manager Surface for Runtime AssetManager","created_at":"2026-03-27","updated_at":"2026-03-27","tags":["compiler","pbs","runtime","asset-manager","host-abi","stdlib","asset"],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0023","file":"discussion/lessons/DSC-0008-pbs-low-level-asset-manager-surface/LSN-0023-lowassets-runtime-aligned-sdk-surface.md","status":"done","created_at":"2026-03-27","updated_at":"2026-03-27"}]}

View File

@ -0,0 +1,126 @@
---
id: LSN-0054
ticket: variable-tile-bank-palette-serialization
title: Runtime-Owned Variable Glyph Palette Counts
created: 2026-07-14
tags:
- packer
- studio
- glyph-bank
- palette-serialization
- rgba8888
- runtime-alignment
---
# Runtime-Owned Variable Glyph Palette Counts
### Original Problem
The first RGBA8888 alignment wave made Studio and packer emit palette colors in
the runtime channel order, but it deliberately kept the old fixed glyph-bank
palette payload shape. Every `GLYPH/indexed_v1` payload still reserved room for
64 palettes, so the emitted palette block was always `64 * 16 * 4 = 4096`
bytes even when the bank used one or a few palettes.
That fixed shape left two problems:
- packer output was larger than the runtime needed;
- `palette_count` could not be trusted as the effective runtime resident count,
because the payload still looked like a 64-palette bank.
Runtime later accepted the variable-palette protocol for
`GLYPH/indexed_v1`. Studio and packer had to follow that runtime-owned wire
contract instead of keeping a stale producer-side convention.
### Consolidated Decision
Runtime owns the `GLYPH/indexed_v1` protocol. Studio and packer are downstream
producers of runtime-conforming `assets.pa` payloads.
The accepted rule is:
1. `palette_count` is the effective serialized and resident palette count.
2. `palette_count` must be in the inclusive range `1..=64`.
3. Palette bytes are exactly `palette_count * 16 * 4`.
4. `size = ceil(width * height / 2) + palette_count * 16 * 4`.
5. `decoded_size = width * height + palette_count * 16 * 4`.
6. Palette bytes remain RGBA8888 in `R`, `G`, `B`, `A` order.
7. `GLYPH/indexed_v1` remains the format name. This change does not introduce
`GLYPH/indexed_v2`.
8. There is no compatibility mode for the old fixed 64-palette padding.
9. Palette IDs remain direct. There is no sparse-to-dense remapping metadata in
v1.
10. `palette_authored`, when present, is informative tooling metadata only.
### Implementation Result
The packer specs now define `palette_count` as runtime-effective metadata for
glyph banks and describe the variable palette payload in the build-artifact
contract. Studio-facing asset workspace docs now keep `palette_count` distinct
from any authored or tooling-only palette count.
The packer metadata model derives and validates effective palette count instead
of hard-coding `64`. Sparse direct palette IDs are preserved by materializing
intermediate palette slots up to the highest referenced ID; those slots are not
a remapping table.
Payload emission now writes exactly the effective number of palette slots. Size
and decoded-size accounting use the same formula as the runtime contract, so
metadata, asset-table entries, and payload lengths agree.
Tests and fixtures cover `palette_count = 1`, intermediate counts, `64`, sparse
direct identity, invalid counts above `64`, RGBA8888 byte order, and payload
size accounting. Final validation passed with:
- `discussion validate`;
- `./gradlew :prometeu-packer:prometeu-packer-v1:test`;
- `./gradlew build`.
### Practical Examples
A 256 by 256 glyph bank with one palette has:
```text
pixel bytes = ceil(256 * 256 / 2) = 32768
palette bytes = 1 * 16 * 4 = 64
size = 32768 + 64 = 32832
decoded_size = 256 * 256 + 64 = 65600
```
A bank that references palette ID `6` has an effective `palette_count` of at
least `7`. Palette slots `0` through `6` exist in the serialized palette block.
If some lower slots were not authored directly, they are deterministic
placeholders; palette `6` is not remapped to palette `0`.
### Common Pitfalls and Anti-patterns
- Do not infer runtime payload length from the maximum allowed palette count.
`64` is the upper bound, not the default emitted count.
- Do not use `palette_authored` as a runtime-effective field. It may describe a
tool view, but runtime loads `palette_count`.
- Do not preserve fixed 4096-byte palette padding for banks with fewer than 64
effective palettes.
- Do not create `GLYPH/indexed_v2` to carry this change. The accepted runtime
protocol keeps the v1 format name.
- Do not introduce sparse-to-dense palette remapping metadata. Existing scene,
sprite, packer, and runtime references use direct palette identity.
- Do not combine RGBA8888 channel-order work with palette-count semantics.
RGBA8888 defines each color value; `palette_count` defines how many palettes
are serialized and resident.
### References
- Runtime decision:
`../runtime/discussion/workflow/decisions/DEC-0041-variable-glyph-bank-palette-protocol.md`.
- Studio/packer decision:
`discussion/workflow/decisions/DEC-0038-variable-glyph-bank-palette-serialization.md`.
- `PLN-0087`: Variable glyph palette spec propagation.
- `PLN-0088`: Variable glyph palette metadata and count model.
- `PLN-0089`: Variable glyph palette payload emission and size accounting.
- `PLN-0090`: Studio and packer projections for variable glyph palettes.
- `PLN-0091`: Variable glyph palette tests, fixtures, and final validation.
- Prior lesson:
`discussion/lessons/DSC-0038-studio-packer-rgba8888-asset-pipeline/LSN-0053-rgba8888-is-the-canonical-studio-packer-palette-contract.md`.
- `docs/specs/packer/3. Asset Declaration and Virtual Asset Contract Specification.md`.
- `docs/specs/packer/4. Build Artifacts and Deterministic Packing Specification.md`.
- `docs/specs/studio/4. Assets Workspace Specification.md`.

View File

@ -1,185 +0,0 @@
---
id: AGD-0005
ticket: variable-tile-bank-palette-serialization
title: Variable Glyph Bank Palette Serialization
status: accepted
created: 2026-03-26
resolved: 2026-07-14
decision: DEC-0038
tags:
- packer
- legacy-import
- glyph-bank
- palette-serialization
- rgba8888
- runtime-alignment
---
## Pain
Domain owner: `packer`, with runtime-facing impact through `assets.pa`.
The current `GLYPH/indexed_v1` glyph-bank contract serializes a fixed block of
`64` palettes even when an asset authors far fewer palettes.
After `DSC-0038`, each palette entry is RGBA8888, so the fixed palette block is
now `64 * 16 * 4 = 4096` bytes. That keeps decoding simple, but it wastes
cartridge space and leaves a deliberate mismatch between authored palette count
and serialized palette count.
## Context
Legacy source: `docs/packer/agendas/Variable Tile Bank Palette Serialization Agenda.md`
Cross-domain dependency:
- runtime
Runtime follow-up:
- `../runtime/discussion/workflow/decisions/DEC-0041-variable-glyph-bank-palette-protocol.md`
is accepted and normative for the runtime side.
- Runtime `DSC-0046` keeps `GLYPH/indexed_v1`, adopts variable glyph-bank
palette serialization, and treats this as an incompatible v1 correction.
- Runtime plans `PLN-0167` through `PLN-0172` are done and publish the
downstream handoff.
Current runtime-owned `GLYPH/indexed_v1` contract:
- pixels are serialized as packed `u4`;
- palettes are serialized as RGBA8888 values in runtime `R`, `G`, `B`, `A`
byte order;
- `palette_count` is the number of serialized and resident palettes;
- `palette_count` must be in `1..=64`;
- payload size includes exactly `palette_count * 16 * 4` palette bytes;
- palette index `0` is ordinary;
- each palette has 16 usable colors;
- transparency is represented by alpha, not by a reserved index or magenta
color-key;
- resident runtime memory materializes exactly `palette_count` palettes;
- `palette_id` is a direct palette identity inside the loaded glyph bank and is
valid only when `palette_id < palette_count`;
- sparse-to-dense palette remapping is not part of v1;
- missing palettes must fail explicitly in scene/sprite/composer use, not
silently resolve to a default color.
Downstream producers must emit:
- root effective metadata fields `tile_size`, `width`, `height`, and
`palette_count`;
- `size = ceil(width * height / 2) + palette_count * 16 * 4`;
- `decoded_size = width * height + palette_count * 16 * 4`;
- exactly `palette_count * 16 * 4` RGBA8888 palette bytes;
- no `GLYPH/indexed_v2` payload for this change;
- no fixed 64-palette padding unless `palette_count = 64` and the payload
directly satisfies the runtime v1 contract;
- no effective runtime behavior based on `palette_authored`.
`DSC-0038` intentionally did not solve variable palette-count serialization.
It changed the color encoding from RGB565-era semantics to RGBA8888 and kept
the fixed 64-palette model stable for that wave.
Runtime `DEC-0041` now closes the cross-domain protocol questions that this
agenda previously carried as open. The remaining Studio/packer work is
downstream alignment with the runtime-owned contract.
## Open Questions
- [x] Should variable palette serialization arrive as a new payload version or
as an incompatible change to the current one?
- Runtime `DEC-0041` resolves this as an incompatible correction to
`GLYPH/indexed_v1`, with no v2 format.
- [x] If `palette_count` becomes variable, should runtime still materialize a
64-slot resident bank, or truly shrink in-memory representation too?
- Runtime `DEC-0041` resolves this: resident runtime memory materializes
exactly `palette_count` palettes.
- [x] Should sparse authored palette indices remain sparse in serialization, or
be canonicalized into a dense runtime block?
- Runtime `DEC-0041` rejects sparse-to-dense remapping. `palette_id` remains
direct identity inside the loaded glyph bank.
- [x] Should this repository create the owner agenda/decision for the runtime
side, or should a matching runtime `discussion/` artifact be opened before
implementation planning?
- Runtime `DSC-0046` now owns the protocol through accepted `DEC-0041`.
Studio/packer must follow that handoff.
- [x] Which domain owns compatibility for existing cartridges: `packer`,
`runtime`, or `shipper`?
- Runtime `DEC-0041` introduces no compatibility mode. Old payloads with
`palette_count = 64` remain valid only when they satisfy the new contract
directly.
## Options
### Option A - Keep fixed 64-palette serialization in v1
- **Approach:** Preserve the current fixed v1 payload with zero-filled unused palette slots.
- **Pro:** No runtime change and current specs/tests remain stable.
- **Con:** Every glyph bank keeps paying the full 4096-byte palette cost.
- **Maintainability:** Medium.
### Option B - Align packer output with runtime variable palette serialization
- **Approach:** Keep the `GLYPH/indexed_v1` format name, serialize only
`palette_count` palettes, and make packer metadata, payload sizes, fixtures,
and Studio projections follow runtime `DEC-0041`.
- **Pro:** Removes fixed padding while the project is still in v1, keeps the
public format vocabulary stable, and makes runtime metadata match the payload.
- **Con:** Requires coordinated packer/spec/test changes and fixture
regeneration because the current producer still emits the old fixed-padding
shape.
- **Maintainability:** Strong if implemented as an explicit contract update,
weak if done as an incidental size tweak. Runtime has already closed the
protocol questions.
### Option C - Keep fixed external metadata but trim trailing palettes
- **Approach:** Keep some 64-slot assumptions in metadata or runtime memory, but
serialize only a shortened trailing subset of palettes in the payload.
- **Pro:** Can reduce cartridge size while limiting some runtime changes.
- **Con:** Creates a split-brain contract where serialized count, logical count,
and resident count can disagree.
- **Maintainability:** Weak. It preserves the ambiguity this agenda is trying
to remove.
## Discussion
The retained concern is still valid after `DSC-0038`, but runtime `DEC-0041`
has now closed the protocol. The problem is no longer an open cross-domain
design question; it is a downstream producer-alignment task for Studio/packer.
The old recommendation favored a versioned follow-up because compatibility and
runtime stability were treated as constraints. Runtime `DEC-0041` removes that
constraint: the project is still in v1, keeps `GLYPH/indexed_v1`, and does not
need compatibility for the old fixed 64-palette payload.
That makes Option B the required direction for this repository. Runtime already
changed the contract directly; Studio/packer must now emit the runtime-owned
shape and stop treating `palette_authored` or the old 64-padding model as
effective runtime behavior.
Option C should be avoided because it preserves multiple meanings for palette
count. If the payload becomes variable, `palette_count` should mean the number
of serialized palettes, not an unrelated fixed resident capacity.
## Resolution
Recommended direction: adopt **Option B**.
Updated recommendation:
1. keep the format name `GLYPH/indexed_v1`;
2. follow runtime `DEC-0041` as the protocol authority;
3. remove the fixed 64-palette payload block from packer output;
4. make packer `palette_count` describe the serialized and resident RGBA8888
palette count;
5. emit exactly `palette_count * 16 * 4` palette bytes;
6. update `size` and `decoded_size` formulas to use variable `palette_count`;
7. do not create a v2 format solely for this change;
8. do not preserve compatibility with the old fixed-padding payload;
9. do not introduce sparse-to-dense palette remapping metadata;
10. treat `palette_authored` as informative only unless a later runtime
decision promotes it to effective metadata;
11. add downstream fixture coverage for `palette_count = 1`, an intermediate
count, and `palette_count = 64`;
12. add a negative producer validation case for metadata/payload mismatch.
Next step suggestion: convert this agenda into a Studio/packer decision that
references runtime `DEC-0041` and scopes implementation to specs, packer
payload emission, Studio projections if needed, tests, and fixtures.

View File

@ -1,208 +0,0 @@
---
id: DEC-0038
ticket: variable-tile-bank-palette-serialization
title: Variable Glyph Bank Palette Serialization for Studio and Packer
status: accepted
created: 2026-07-14
accepted: 2026-07-14
ref_agenda: AGD-0005
plans:
- PLN-0087
- PLN-0088
- PLN-0089
- PLN-0090
- PLN-0091
tags:
- packer
- studio
- glyph-bank
- palette-serialization
- rgba8888
- runtime-alignment
---
## Status
Accepted. Drafted from accepted agenda `AGD-0005` and accepted on
2026-07-14.
## Context
This decision belongs to the `packer` domain, with Studio-facing projection and
fixture impact. Runtime protocol ownership remains in `../runtime`.
Studio/packer already aligned glyph-bank colors with RGBA8888 through
`DSC-0038`. That work kept the `GLYPH/indexed_v1` format name and changed the
palette color encoding from RGB565-era data to RGBA8888 in runtime channel
order. It deliberately preserved the fixed 64-palette payload model for that
wave.
Runtime `DEC-0041` now changes the authoritative `GLYPH/indexed_v1` contract:
- `palette_count` is the number of serialized and resident palettes;
- `palette_count` MUST be in `1..=64`;
- payloads contain exactly `palette_count * 16 * 4` RGBA8888 palette bytes;
- `size = ceil(width * height / 2) + palette_count * 16 * 4`;
- `decoded_size = width * height + palette_count * 16 * 4`;
- resident runtime memory materializes exactly `palette_count` palettes;
- `palette_id` is direct identity within the loaded glyph bank and is valid
only when `palette_id < palette_count`;
- v1 has no sparse-to-dense palette remapping metadata;
- this remains `GLYPH/indexed_v1`, not a new v2 payload.
Studio/packer must now follow that runtime-owned contract as downstream
producers of runtime-conforming `assets.pa` payloads.
## Decision
Studio and packer SHALL adopt variable glyph-bank palette serialization for
`GLYPH/indexed_v1`, following runtime `DEC-0041` as the protocol authority.
Packer MUST stop emitting a fixed 64-palette block for glyph banks unless the
effective `palette_count` is actually `64`.
Packer MUST emit exactly `palette_count * 16 * 4` palette bytes for each
`GLYPH/indexed_v1` glyph-bank payload.
Packer MUST compute glyph-bank `size` as:
```text
size = ceil(width * height / 2) + palette_count * 16 * 4
```
Packer MUST compute glyph-bank `decoded_size` as:
```text
decoded_size = width * height + palette_count * 16 * 4
```
Packer MUST publish root effective metadata fields required by runtime:
- `tile_size`
- `width`
- `height`
- `palette_count`
For `GLYPH/indexed_v1`, `palette_count` MUST describe the number of serialized
RGBA8888 palettes and the number of resident palettes expected by runtime.
`palette_count` MUST be in the inclusive range `1..=64`.
Packer and Studio MUST NOT introduce `GLYPH/indexed_v2` for this change.
Packer and Studio MUST NOT preserve compatibility with the old fixed-padding
payload shape as a special mode.
Packer and Studio MUST NOT introduce sparse-to-dense palette remapping metadata
for v1.
`palette_authored`, when present in tooling or pipeline metadata, is
informative only. It MUST NOT be treated as effective runtime metadata unless a
later runtime decision promotes it.
Palette bytes SHALL remain RGBA8888 in runtime `R`, `G`, `B`, `A` byte order.
Palette index `0` and color index `0` remain ordinary indices. Transparency
remains represented by the alpha channel of the resolved RGBA8888 color.
## Rationale
Runtime owns the `GLYPH/indexed_v1` wire contract. Once runtime `DEC-0041`
accepted variable palette serialization, keeping packer output fixed at 64
palettes would make Studio/packer produce stale runtime payloads.
Making `palette_count` the effective serialized and resident count removes the
old mismatch between authored palette count and payload shape. The packer no
longer needs to pad every glyph bank to 4096 palette bytes unless the bank
really uses all 64 palettes.
Keeping the existing format name is correct because the project is still in v1
and runtime explicitly accepted this as an incompatible v1 correction. A v2
name would add migration surface without protecting any required compatibility
contract.
Rejecting sparse-to-dense remapping keeps `palette_id` direct. Scene, sprite,
packer output, and runtime lookup all refer to the same palette identity inside
the loaded glyph bank.
## Implications
### Specs
Packer specs MUST be updated so `GLYPH/indexed_v1` no longer describes a fixed
`64 * 16 * 4 = 4096` palette block as the normal payload shape.
Packer specs MUST define `palette_count` as the effective serialized palette
count for glyph banks, constrained to `1..=64`.
Studio specs MUST be updated only where Studio-facing projections, asset
details, pack wizard behavior, or fixtures expose the old fixed-padding model.
### Code
Packer payload emission MUST write only `palette_count` palettes.
Packer payload validation/materialization helpers MUST compute size and decoded
size from variable `palette_count`.
Packer metadata projection and Studio-facing read/detail APIs MUST expose the
runtime-effective `palette_count` correctly.
Studio code MUST NOT treat `palette_authored` as the runtime-effective count.
### Tests and Fixtures
Tests MUST cover:
- `palette_count = 1`;
- an intermediate `palette_count`;
- `palette_count = 64`;
- size and decoded-size formulas for variable counts;
- emitted RGBA8888 palette byte count;
- metadata/payload mismatch rejection or producer validation.
Fixtures that encode the old fixed-padding assumption MUST be regenerated or
updated unless they intentionally use `palette_count = 64` and satisfy the new
runtime contract directly.
### Non-goals
This decision does not change RGBA8888 channel order.
This decision does not change the packed `u4` indexed pixel plane.
This decision does not change scene `palette_id` payload shape.
This decision does not introduce v2, compatibility branches, or palette
identity remapping.
## Propagation Targets
- Specs:
- `docs/specs/packer/3. Asset Declaration and Virtual Asset Contract Specification.md`
- `docs/specs/packer/4. Build Artifacts and Deterministic Packing Specification.md`
- `docs/specs/studio/4. Assets Workspace Specification.md`, if Studio-facing
palette count projection is documented there.
- Code:
- packer glyph-bank payload emission;
- packer asset walking/materialization;
- packer read/detail projections;
- Studio asset details or pack wizard surfaces if they expose palette counts.
- Tests:
- packer parser, walker, materializer, workspace service, and fixture tests;
- Studio tests if Studio projections or UI logic expose palette counts.
- Docs:
- downstream implementation plans derived from this decision.
## References
- Agenda: `AGD-0005`
- Runtime decision:
`../runtime/discussion/workflow/decisions/DEC-0041-variable-glyph-bank-palette-protocol.md`
- Runtime handoff:
`../runtime/discussion/workflow/plans/PLN-0172-runtime-spec-handoff-to-packer-and-studio.md`
- Prior Studio/packer RGBA8888 lesson:
`discussion/lessons/DSC-0038-studio-packer-rgba8888-asset-pipeline/LSN-0053-rgba8888-is-the-canonical-studio-packer-palette-contract.md`
## Revision Log
- 2026-07-14: Initial accepted decision from `AGD-0005`, aligned with runtime
`DEC-0041`.

View File

@ -1,132 +0,0 @@
---
id: PLN-0087
ticket: variable-tile-bank-palette-serialization
title: Variable Glyph Palette Spec Propagation
status: done
created: 2026-07-14
completed: 2026-07-14
ref_decisions:
- DEC-0038
tags:
- specs
- packer
- studio
- glyph-bank
- palette-serialization
---
## Objective
Propagate `DEC-0038` into the canonical Studio and packer specifications before
code changes start.
## Background
Runtime `DEC-0041` makes `palette_count` the serialized and resident palette
count for `GLYPH/indexed_v1`. Studio/packer `DEC-0038` adopts that runtime
contract downstream. Current packer specs still describe a fixed
`64 * 16 * 4 = 4096` palette block and `palette_count = 64`.
## Scope
### Included
- Update packer specs for glyph-bank metadata, payload layout, and size formulas.
- Update Studio specs only where Studio-facing palette count projection or asset
details are documented.
- Preserve RGBA8888 channel order, packed `u4` pixels, and `GLYPH/indexed_v1`.
### Excluded
- Code changes.
- Fixture regeneration.
- Runtime spec changes.
- Any `GLYPH/indexed_v2` design.
## Execution Steps
### Step 1 - Update asset declaration metadata rules
**What:** Define `palette_count` as the effective runtime metadata field.
**How:** Update glyph-bank declaration language so `palette_count` means the
number of serialized and resident RGBA8888 palettes, constrained to `1..=64`.
State that `palette_authored`, if present, is informative and not runtime
effective.
**File(s):**
- `docs/specs/packer/3. Asset Declaration and Virtual Asset Contract Specification.md`
### Step 2 - Update glyph payload layout
**What:** Replace fixed 4096-byte palette block text.
**How:** Change the layout to `palette_count * 16 * 4` palette bytes and update
formulas to:
```text
size = ceil(width * height / 2) + palette_count * 16 * 4
decoded_size = width * height + palette_count * 16 * 4
```
**File(s):**
- `docs/specs/packer/4. Build Artifacts and Deterministic Packing Specification.md`
### Step 3 - Preserve v1 boundaries
**What:** Explicitly prohibit v2, compatibility padding, and remapping.
**How:** Add rules that this remains `GLYPH/indexed_v1`, old fixed-padding is
not a compatibility mode, and v1 has no sparse-to-dense palette remapping.
**File(s):**
- `docs/specs/packer/4. Build Artifacts and Deterministic Packing Specification.md`
### Step 4 - Update Studio-facing spec text
**What:** Align Studio projections if they mention palette count or fixed bank
shape.
**How:** Search the Studio asset workspace spec for palette projection, details,
or pack wizard language and update only stale fixed-count wording.
**File(s):**
- `docs/specs/studio/4. Assets Workspace Specification.md`
## Test Requirements
### Unit Tests
- Not applicable for this spec-only plan.
### Integration Tests
- Not applicable for this spec-only plan.
### Manual Verification
- Search specs for stale normal-path `palette_count = 64`, `4096`, fixed
64-palette block, `GLYPH/indexed_v2`, and remapping language.
## Acceptance Criteria
- [x] Packer specs define `palette_count` as runtime-effective `1..=64`.
- [x] Packer specs use variable palette byte and size formulas.
- [x] Specs keep `GLYPH/indexed_v1` and reject v2 for this change.
- [x] Specs reject fixed-padding compatibility and sparse-to-dense remapping.
- [x] Studio specs contain no stale fixed 64-palette projection wording.
## Dependencies
- Depends on accepted `DEC-0038`.
- Should complete before code plans.
## Risks
- Leaving stale fixed 4096-byte examples will make implementation review
ambiguous.
- Over-editing Studio specs could imply UI behavior not required by `DEC-0038`.

View File

@ -1,140 +0,0 @@
---
id: PLN-0088
ticket: variable-tile-bank-palette-serialization
title: Variable Glyph Palette Metadata and Count Model
status: done
created: 2026-07-14
completed: 2026-07-14
ref_decisions:
- DEC-0038
tags:
- packer
- metadata
- glyph-bank
- palette-count
---
## Objective
Make packer metadata compute and expose runtime-effective glyph-bank
`palette_count` from declared palette data instead of hard-coding `64`.
## Background
`DEC-0038` requires `palette_count` to describe the number of serialized and
resident palettes expected by runtime. Current packer code emits
`palette_count = 64` and uses `palette_authored` for the actual authored count.
That makes the informative count and effective runtime count diverge.
## Scope
### Included
- Compute effective glyph palette count from declared `output.pipeline.palettes`.
- Validate `palette_count` in `1..=64`.
- Keep palette identity direct; do not remap sparse authored indices.
- Stop using `palette_authored` as a runtime-effective field.
### Excluded
- Binary payload byte emission.
- Size formula changes.
- Studio UI changes except compile-safe DTO/projection adjustments.
## Execution Steps
### Step 1 - Add a runtime-effective palette count helper
**What:** Centralize effective glyph palette count calculation.
**How:** Add or update helper logic so packer derives `palette_count` from
declared palette indices. Because v1 has no remapping, the effective count must
cover the highest direct palette id: `max(index) + 1`. Reject no palettes,
negative indices, duplicate indices, and any effective count above `64`.
**File(s):**
- `prometeu-packer/prometeu-packer-v1/src/main/java/p/packer/services/FileSystemPackerWorkspaceService.java`
- `prometeu-packer/prometeu-packer-v1/src/main/java/p/packer/repositories/PackerAssetWalker.java`
- `prometeu-packer/prometeu-packer-v1/src/main/java/p/packer/services/PackerAssetDeclarationParser.java`
### Step 2 - Replace fixed runtime metadata
**What:** Stop writing `palette_count = 64` unconditionally.
**How:** Replace runtime metadata emission so glyph-bank entries publish the
computed runtime-effective `palette_count`. Keep `palette_authored` only if it
is useful as pipeline/tooling information and never as runtime-effective root
metadata.
**File(s):**
- `prometeu-packer/prometeu-packer-v1/src/main/java/p/packer/services/FileSystemPackerWorkspaceService.java`
- `prometeu-packer/prometeu-packer-v1/src/main/java/p/packer/repositories/PackerRuntimeAssetMaterializer.java`
### Step 3 - Validate direct palette identity
**What:** Preserve runtime direct `palette_id` semantics.
**How:** Ensure packer does not compact or renumber palette indices. If palette
indices are sparse, emitted palette slots up to `palette_count - 1` must keep
their direct identity, with missing slots represented by deterministic default
RGBA8888 palette data only when required to preserve direct ids.
**File(s):**
- `prometeu-packer/prometeu-packer-v1/src/main/java/p/packer/services/FileSystemPackerWorkspaceService.java`
- `prometeu-packer/prometeu-packer-v1/src/main/java/p/packer/repositories/PackerGlyphBankWalker.java`
### Step 4 - Update projections that expose metadata
**What:** Align details/read projections with the effective count.
**How:** Ensure packer read/details APIs expose `palette_count` consistently
where runtime metadata is projected, and do not present `palette_authored` as
the field that runtime consumes.
**File(s):**
- `prometeu-packer/prometeu-packer-v1/src/main/java/p/packer/services/PackerAssetDetailsService.java`
- `prometeu-packer/prometeu-packer-v1/src/main/java/p/packer/services/PackerReadMessageMapper.java`
## Test Requirements
### Unit Tests
- Parser/metadata tests for `palette_count = 1`, intermediate count, and `64`.
- Rejection tests for zero effective palettes, duplicate indices, negative
indices, and count above `64`.
- Sparse direct identity tests where palette index `3` implies
`palette_count = 4`, without remapping palette `3` to `0`.
### Integration Tests
- Workspace read/build test proving asset table metadata reports variable
`palette_count`.
### Manual Verification
- Search packer code for `palette_count = 64` and `GLYPH_BANK_PALETTE_COUNT`
assumptions after the change.
## Acceptance Criteria
- [x] Packer computes runtime-effective `palette_count` from declared palettes.
- [x] `palette_count` is validated as `1..=64`.
- [x] Sparse palette ids are not remapped.
- [x] `palette_authored` is not treated as runtime-effective metadata.
- [x] Read/details projections do not expose stale fixed-count assumptions.
## Dependencies
- Depends on `PLN-0087`.
- Must complete before payload emission changes in `PLN-0089`.
## Risks
- Sparse palette handling can accidentally become remapping if implemented by
sorting and compacting declarations.
- Keeping `palette_authored` in tooling may confuse readers unless tests prove
runtime-effective metadata uses `palette_count`.

View File

@ -1,140 +0,0 @@
---
id: PLN-0089
ticket: variable-tile-bank-palette-serialization
title: Variable Glyph Palette Payload Emission and Size Accounting
status: done
created: 2026-07-14
completed: 2026-07-14
ref_decisions:
- DEC-0038
tags:
- packer
- assets-pa
- glyph-bank
- payload
---
## Objective
Change packer `GLYPH/indexed_v1` payload emission from a fixed 64-palette block
to exactly `palette_count * 16 * 4` RGBA8888 bytes, with matching size and
decoded-size accounting.
## Background
`FileSystemPackerWorkspaceService` currently defines fixed palette constants
and emits a fixed `GLYPH_BANK_PALETTE_BYTES` block. `DEC-0038` requires packer
to emit only the runtime-effective palette count and compute asset table sizes
from that count.
## Scope
### Included
- Replace fixed palette byte constants with count-dependent formulas.
- Emit exactly `palette_count` palettes in RGBA byte order.
- Update asset table `size` and `decoded_size`.
- Reject metadata/payload mismatches.
### Excluded
- Palette model extraction changes covered by `PLN-0088`.
- Studio UI changes.
- Runtime code changes.
## Execution Steps
### Step 1 - Replace fixed palette byte constants
**What:** Remove normal-path fixed `64 * 16 * 4` size assumptions.
**How:** Keep maximum constants such as `MAX_PALETTE_COUNT = 64`, but compute
payload palette bytes as `palette_count * 16 * 4` at each glyph-bank packing
boundary.
**File(s):**
- `prometeu-packer/prometeu-packer-v1/src/main/java/p/packer/services/FileSystemPackerWorkspaceService.java`
- `prometeu-packer/prometeu-packer-v1/src/main/java/p/packer/repositories/PackerAssetWalker.java`
- `prometeu-packer/prometeu-packer-v1/src/main/java/p/packer/repositories/PackerRuntimeAssetMaterializer.java`
### Step 2 - Emit variable palette bytes
**What:** Write only runtime-effective palettes.
**How:** Update palette byte generation to allocate
`palette_count * 16 * 4` bytes and fill direct palette ids from `0` through
`palette_count - 1`. Each color remains RGBA8888 in `R`, `G`, `B`, `A` order.
**File(s):**
- `prometeu-packer/prometeu-packer-v1/src/main/java/p/packer/services/FileSystemPackerWorkspaceService.java`
### Step 3 - Update size and decoded-size formulas
**What:** Align asset table sizes with runtime `DEC-0041`.
**How:** Compute:
```text
size = ceil(width * height / 2) + palette_count * 16 * 4
decoded_size = width * height + palette_count * 16 * 4
```
Use these formulas for asset table entries, materializer expectations, and
workspace build outputs.
**File(s):**
- `prometeu-packer/prometeu-packer-v1/src/main/java/p/packer/services/FileSystemPackerWorkspaceService.java`
- `prometeu-packer/prometeu-packer-v1/src/main/java/p/packer/repositories/PackerRuntimeAssetMaterializer.java`
### Step 4 - Reject metadata/payload mismatches
**What:** Prevent stale fixed-padding artifacts.
**How:** Add validation that emitted palette byte length, root metadata
`palette_count`, `size`, and `decoded_size` agree. Do not allow a fixed
64-palette block when `palette_count < 64`.
**File(s):**
- `prometeu-packer/prometeu-packer-v1/src/main/java/p/packer/services/FileSystemPackerWorkspaceService.java`
- `prometeu-packer/prometeu-packer-v1/src/main/java/p/packer/repositories/PackerRuntimeAssetMaterializer.java`
## Test Requirements
### Unit Tests
- Assert emitted palette bytes for `palette_count = 1`, an intermediate count,
and `64`.
- Assert `size` and `decoded_size` formulas for variable counts.
- Assert RGBA byte order is unchanged.
### Integration Tests
- Build a workspace and inspect `assets.pa` asset table and payload length for
variable palette counts.
### Manual Verification
- Search for fixed normal-path `4096`, `64 * 16 * 4`, and
`GLYPH_BANK_PALETTE_BYTES` residue.
## Acceptance Criteria
- [x] Glyph payloads emit exactly `palette_count * 16 * 4` palette bytes.
- [x] Asset table `size` and `decoded_size` use variable formulas.
- [x] RGBA byte order is unchanged.
- [x] Fixed 64-palette padding is emitted only when `palette_count = 64`.
- [x] Metadata/payload mismatch is rejected or impossible by construction.
## Dependencies
- Depends on `PLN-0088`.
## Risks
- Updating metadata without payload length will corrupt runtime slicing.
- Updating payload length without decoded-size metadata will fail runtime asset
validation.

View File

@ -1,147 +0,0 @@
---
id: PLN-0090
ticket: variable-tile-bank-palette-serialization
title: Studio and Packer Projections for Variable Glyph Palettes
status: done
created: 2026-07-14
completed: 2026-07-14
ref_decisions:
- DEC-0038
tags:
- studio
- packer
- api
- projections
- glyph-bank
---
## Objective
Align Studio-facing and packer-facing projections so variable glyph
`palette_count` is visible and not confused with `palette_authored`.
## Background
`DEC-0038` says packer metadata projection and Studio-facing read/detail APIs
must expose the runtime-effective `palette_count` correctly. Studio code must
not treat `palette_authored` as the runtime-effective count.
## Scope
### Included
- Update packer read/detail DTO projections where runtime metadata is surfaced.
- Update Studio asset details, palette overhauling, schema, or pack wizard code
if it reads fixed counts or authored counts as runtime-effective.
- Keep `rgba8888` color projection unchanged.
### Excluded
- Binary payload emission.
- General palette UI redesign.
- `originalArgb8888` UI fallback cleanup unrelated to variable `palette_count`.
## Execution Steps
### Step 1 - Audit projection boundaries
**What:** Find all Studio/packer paths that expose glyph palette metadata.
**How:** Search for `palette_count`, `palette_authored`,
`GLYPH_BANK_PALETTE_COUNT`, fixed `64`, and related asset details projections.
Classify each match as runtime-effective metadata, tooling-only metadata, UI
fallback, or unrelated.
**File(s):**
- `prometeu-packer/prometeu-packer-v1/src/main/java/p/packer/services/PackerAssetDetailsService.java`
- `prometeu-packer/prometeu-packer-v1/src/main/java/p/packer/services/PackerReadMessageMapper.java`
- `prometeu-studio/src/main/java/p/studio/workspaces/assets/**`
### Step 2 - Update packer details/read surfaces
**What:** Expose runtime-effective `palette_count`.
**How:** Ensure details/read projections show the `palette_count` that will be
written to the runtime asset table. Preserve `palette_authored` only as
explicitly tooling-only information if it remains useful.
**File(s):**
- `prometeu-packer/prometeu-packer-v1/src/main/java/p/packer/services/PackerAssetDetailsService.java`
- `prometeu-packer/prometeu-packer-v1/src/main/java/p/packer/services/PackerReadMessageMapper.java`
### Step 3 - Update Studio consumers
**What:** Prevent Studio from using authored count as runtime count.
**How:** Adjust Studio asset details and pack wizard code so any displayed or
validated runtime count comes from effective `palette_count`. Keep palette
color rendering based on `rgba8888`.
**File(s):**
- `prometeu-studio/src/main/java/p/studio/workspaces/assets/details/**`
- `prometeu-studio/src/test/java/p/studio/workspaces/assets/details/**`
### Step 4 - Preserve scene palette id shape
**What:** Avoid accidental scene payload changes.
**How:** Confirm scene projections still carry `palette_id` unchanged and only
runtime/packer validation changes count semantics.
**File(s):**
- `prometeu-studio/src/main/java/p/studio/workspaces/assets/**`
- `prometeu-packer/prometeu-packer-v1/src/main/java/p/packer/services/FileSystemPackerWorkspaceService.java`
## Test Requirements
### Unit Tests
- Packer details/read tests for variable `palette_count`.
- Studio asset details tests proving runtime count and authored/tooling count
are not conflated.
### Integration Tests
- Workspace read/build flow where a glyph bank with an intermediate
`palette_count` is projected through packer/Studio surfaces.
### Manual Verification
- Search Studio and packer projection code for stale assumptions that
`palette_authored` is runtime-effective.
## Acceptance Criteria
- [x] Packer read/details projections expose effective `palette_count`.
- [x] Studio consumers do not use `palette_authored` as runtime-effective count.
- [x] `rgba8888` color projection remains unchanged.
- [x] Scene `palette_id` payload shape is unchanged.
- [x] Tests cover variable count projection.
## Execution Notes
- Packer runtime output projection is the `assets.pa` asset table generated by
`FileSystemPackerWorkspaceService`; `PLN-0088` and `PLN-0089` now project the
runtime-effective `palette_count` there.
- `PackerAssetDetailsService` and `PackerReadMessageMapper` project palette
color data through `pipelinePalettes` and do not expose
`palette_authored` as runtime-effective metadata.
- Studio asset details mapping forwards packer details without deriving a
runtime count from `palette_authored`.
- No DTO field was added because doing so would create a new Studio/packer API
surface not required by `DEC-0038`.
## Dependencies
- Depends on `PLN-0088`.
- Can run in parallel with `PLN-0089` after metadata semantics are stable.
## Risks
- UI code may still need ARGB helper fields for presentation. This plan must not
turn that into a runtime metadata decision.
- Overbroad projection edits could accidentally change scene contracts.

View File

@ -1,167 +0,0 @@
---
id: PLN-0091
ticket: variable-tile-bank-palette-serialization
title: Variable Glyph Palette Tests, Fixtures, and Final Validation
status: done
created: 2026-07-14
completed: 2026-07-14
ref_decisions:
- DEC-0038
tags:
- tests
- fixtures
- validation
- glyph-bank
- palette-serialization
---
## Objective
Update tests and fixtures to prove Studio/packer emit runtime-conforming
variable glyph palette payloads and contain no stale fixed-padding assumptions.
## Background
`DEC-0038` requires downstream fixture coverage for `palette_count = 1`, an
intermediate count, and `palette_count = 64`, plus producer validation for
metadata/payload mismatch. Earlier tests still assert `palette_count = 64`,
4096-byte palette blocks, and fixed glyph payload sizes.
## Scope
### Included
- Update packer unit tests and integration-style workspace tests.
- Update packer fixture `asset.json` files and expected runtime payload checks.
- Update Studio tests only where Studio projections or UI logic expose
effective palette count.
- Run focused and broad validation.
### Excluded
- Runtime repository tests.
- New feature design.
- Palette remapping behavior.
## Execution Steps
### Step 1 - Update packer parser and metadata tests
**What:** Prove effective `palette_count` validation.
**How:** Add tests for `palette_count = 1`, intermediate counts, `64`,
duplicate/sparse direct identity behavior, and rejection above `64`.
**File(s):**
- `prometeu-packer/prometeu-packer-v1/src/test/java/p/packer/services/PackerAssetDeclarationParserTest.java`
- `prometeu-packer/prometeu-packer-v1/src/test/java/p/packer/repositories/PackerGlyphBankWalkerTest.java`
### Step 2 - Update payload and asset table tests
**What:** Prove variable payload lengths and size formulas.
**How:** Replace fixed 4096-byte expectations with
`palette_count * 16 * 4`. Assert `size`, `decoded_size`, payload offsets, and
RGBA bytes for several counts.
**File(s):**
- `prometeu-packer/prometeu-packer-v1/src/test/java/p/packer/services/FileSystemPackerWorkspaceServiceTest.java`
- `prometeu-packer/prometeu-packer-v1/src/test/java/p/packer/repositories/PackerRuntimeAssetMaterializerTest.java`
- `prometeu-packer/prometeu-packer-v1/src/test/java/p/packer/services/PackerRuntimePatchServiceTest.java`
- `prometeu-packer/prometeu-packer-v1/src/test/java/p/packer/services/PackerRuntimeRegistryTest.java`
### Step 3 - Update fixtures
**What:** Replace stale fixed-padding fixtures.
**How:** Regenerate or edit packer test fixtures so at least one glyph bank uses
`palette_count = 1`, one uses an intermediate count, and one uses `64`.
Fixtures with fixed 64 padding are valid only when metadata says
`palette_count = 64`.
**File(s):**
- `prometeu-packer/prometeu-packer-v1/src/test/resources/fixtures/**/asset.json`
- Related binary or generated expected payload fixtures under packer test
resources.
### Step 4 - Update Studio tests
**What:** Cover Studio-facing projection changes.
**How:** Adjust tests only where Studio surfaces effective palette counts or
metadata. Keep color rendering assertions focused on `rgba8888`.
**File(s):**
- `prometeu-studio/src/test/java/p/studio/workspaces/assets/details/**`
### Step 5 - Run validation and residue scans
**What:** Prove no normal-path fixed-padding residue remains.
**How:** Run relevant Gradle tests and search normal specs/code/tests/fixtures
for stale `palette_count = 64`, `4096`, fixed `64 * 16 * 4`, `GLYPH/indexed_v2`,
and sparse remapping language. Classify any remaining match as historical,
max-bound, or a bug.
**File(s):**
- `docs/specs/packer/**`
- `docs/specs/studio/**`
- `prometeu-packer/**`
- `prometeu-studio/**`
## Test Requirements
### Unit Tests
- Packer parser, walker, materializer, details/read, and workspace service tests
pass.
- Studio asset details tests pass where touched.
### Integration Tests
- Packer workspace build/materialization tests pass.
- Repository build or narrow Studio/packer build validation passes.
### Manual Verification
- Residue scan finds no normal-path fixed-padding contract text or code.
- `discussion validate` passes.
## Acceptance Criteria
- [x] Tests cover `palette_count = 1`, an intermediate count, and `64`.
- [x] Tests cover variable `size` and `decoded_size`.
- [x] Tests cover emitted palette byte length and RGBA order.
- [x] Tests cover metadata/payload mismatch rejection or producer validation.
- [x] Fixtures no longer rely on fixed 64-palette padding unless count is `64`.
- [x] Validation commands pass.
- [x] Residue scan results are clean or explicitly classified.
## Execution Notes
- Added packer workspace coverage for `palette_count = 1` and intermediate
`palette_count = 7`.
- Existing fixture and build paths continue to cover `palette_count = 64` where
a max-count payload is intended.
- Added parser coverage rejecting palette declaration index `64`, preserving
the v1 maximum effective count of `64` through direct ids `0..63`.
- `:prometeu-packer:prometeu-packer-v1:test` passed.
- `./gradlew build` passed.
- Residue scan found only intentional normative statements rejecting
`convertedRgb565`, `GLYPH/indexed_v2`, fixed-padding compatibility, and
sparse-to-dense remapping.
## Dependencies
- Depends on `PLN-0087`, `PLN-0088`, `PLN-0089`, and `PLN-0090`.
## Risks
- Generated project fixtures may require regeneration rather than manual edits.
- Broad residue scans may include historical discussions; scope final checks to
active specs, code, tests, and fixtures.