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