implements PLN-0085

This commit is contained in:
bQUARKz 2026-05-23 22:24:27 +01:00
parent cfb842c56f
commit 4bf51998dc
Signed by: bquarkz
SSH Key Fingerprint: SHA256:Z7dgqoglWwoK6j6u4QC87OveEq74WOhFN+gitsxtkf8
7 changed files with 35 additions and 56 deletions

View File

@ -1,5 +1,5 @@
{"type":"meta","next_id":{"DSC":39,"AGD":42,"DEC":38,"PLN":87,"LSN":53,"CLSN":1}}
{"type":"discussion","id":"DSC-0038","status":"open","ticket":"studio-packer-rgba8888-asset-pipeline","title":"Studio and Packer RGBA8888 Asset Pipeline Alignment","created_at":"2026-05-23","updated_at":"2026-05-23","tags":["studio","packer","assets","glyph-bank","palette","rgba8888","runtime-alignment"],"agendas":[{"id":"AGD-0041","file":"AGD-0041-studio-packer-rgba8888-asset-pipeline.md","status":"accepted","created_at":"2026-05-23","updated_at":"2026-05-23"}],"decisions":[{"id":"DEC-0037","file":"DEC-0037-studio-packer-rgba8888-asset-pipeline.md","status":"accepted","created_at":"2026-05-23","updated_at":"2026-05-23","ref_agenda":"AGD-0041"}],"plans":[{"id":"PLN-0081","file":"PLN-0081-rgba8888-packer-and-studio-spec-propagation.md","status":"done","created_at":"2026-05-23","updated_at":"2026-05-23","ref_decisions":["DEC-0037"]},{"id":"PLN-0082","file":"PLN-0082-rgba8888-palette-model-and-argb-conversion.md","status":"done","created_at":"2026-05-23","updated_at":"2026-05-23","ref_decisions":["DEC-0037"]},{"id":"PLN-0083","file":"PLN-0083-rgba8888-glyph-payload-emission-and-sizes.md","status":"done","created_at":"2026-05-23","updated_at":"2026-05-23","ref_decisions":["DEC-0037"]},{"id":"PLN-0084","file":"PLN-0084-rgba8888-packer-projections-and-workspace-apis.md","status":"done","created_at":"2026-05-23","updated_at":"2026-05-23","ref_decisions":["DEC-0037"]},{"id":"PLN-0085","file":"PLN-0085-rgba8888-tests-fixtures-and-conformance.md","status":"review","created_at":"2026-05-23","updated_at":"2026-05-23","ref_decisions":["DEC-0037"]},{"id":"PLN-0086","file":"PLN-0086-rgba8888-final-integration-and-residue-removal.md","status":"review","created_at":"2026-05-23","updated_at":"2026-05-23","ref_decisions":["DEC-0037"]}],"lessons":[]}
{"type":"discussion","id":"DSC-0038","status":"open","ticket":"studio-packer-rgba8888-asset-pipeline","title":"Studio and Packer RGBA8888 Asset Pipeline Alignment","created_at":"2026-05-23","updated_at":"2026-05-23","tags":["studio","packer","assets","glyph-bank","palette","rgba8888","runtime-alignment"],"agendas":[{"id":"AGD-0041","file":"AGD-0041-studio-packer-rgba8888-asset-pipeline.md","status":"accepted","created_at":"2026-05-23","updated_at":"2026-05-23"}],"decisions":[{"id":"DEC-0037","file":"DEC-0037-studio-packer-rgba8888-asset-pipeline.md","status":"accepted","created_at":"2026-05-23","updated_at":"2026-05-23","ref_agenda":"AGD-0041"}],"plans":[{"id":"PLN-0081","file":"PLN-0081-rgba8888-packer-and-studio-spec-propagation.md","status":"done","created_at":"2026-05-23","updated_at":"2026-05-23","ref_decisions":["DEC-0037"]},{"id":"PLN-0082","file":"PLN-0082-rgba8888-palette-model-and-argb-conversion.md","status":"done","created_at":"2026-05-23","updated_at":"2026-05-23","ref_decisions":["DEC-0037"]},{"id":"PLN-0083","file":"PLN-0083-rgba8888-glyph-payload-emission-and-sizes.md","status":"done","created_at":"2026-05-23","updated_at":"2026-05-23","ref_decisions":["DEC-0037"]},{"id":"PLN-0084","file":"PLN-0084-rgba8888-packer-projections-and-workspace-apis.md","status":"done","created_at":"2026-05-23","updated_at":"2026-05-23","ref_decisions":["DEC-0037"]},{"id":"PLN-0085","file":"PLN-0085-rgba8888-tests-fixtures-and-conformance.md","status":"done","created_at":"2026-05-23","updated_at":"2026-05-23","ref_decisions":["DEC-0037"]},{"id":"PLN-0086","file":"PLN-0086-rgba8888-final-integration-and-residue-removal.md","status":"review","created_at":"2026-05-23","updated_at":"2026-05-23","ref_decisions":["DEC-0037"]}],"lessons":[]}
{"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-0035","status":"done","ticket":"pbs-lsp-editor-assistance-wave-1","title":"Wave 1 de assistencia editorial via LSP para PBS no VS Code","created_at":"2026-05-08","updated_at":"2026-05-08","tags":["studio","lsp","vscode","compiler","compiler-pbs","editor","completion","hover","signature-help"],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0051","file":"discussion/lessons/DSC-0035-pbs-lsp-editor-assistance-wave-1/LSN-0051-compiler-backed-editor-assistance-for-pbs.md","status":"done","created_at":"2026-05-08","updated_at":"2026-05-08"}]}

View File

@ -2,9 +2,9 @@
id: PLN-0085
ticket: studio-packer-rgba8888-asset-pipeline
title: RGBA8888 Tests, Fixtures, and Conformance Updates
status: review
status: done
created: 2026-05-23
completed:
completed: 2026-05-23
ref_decisions:
- DEC-0037
tags:
@ -123,12 +123,12 @@ RGB565 glyph palette payload expectations.
## Acceptance Criteria
- [ ] Tests use `rgba8888` as canonical palette data.
- [ ] Tests assert RGBA channel order and alpha preservation.
- [ ] Tests assert 16 usable palette entries.
- [ ] Tests assert magenta is ordinary or no longer special.
- [ ] Tests assert 4096-byte palette blocks where payload size is checked.
- [ ] Packer test fixtures no longer rely on `convertedRgb565`.
- [x] Tests use `rgba8888` as canonical palette data.
- [x] Tests assert RGBA channel order and alpha preservation.
- [x] Tests assert 16 usable palette entries.
- [x] Tests assert magenta is ordinary or no longer special.
- [x] Tests assert 4096-byte palette blocks where payload size is checked.
- [x] Packer test fixtures no longer rely on `convertedRgb565`.
## Dependencies

View File

@ -349,10 +349,7 @@ public class PackerAssetWalker {
for (byte value : tile.paletteIndices()) {
maxUsedIndex = Math.max(maxUsedIndex, Byte.toUnsignedInt(value));
}
if (maxUsedIndex == 0) {
continue;
}
final int requiredColorCount = maxUsedIndex;
final int requiredColorCount = maxUsedIndex + 1;
final Optional<DeclaredPalette> fragilePalette = declaredPalettes.stream()
.filter(palette -> palette.colorCount() < requiredColorCount)
.findFirst();

View File

@ -250,8 +250,7 @@ final class PackerRuntimeAssetMaterializerTest {
private static Map<String, JsonNode> palettePipeline() {
final var payload = MAPPER.createObjectNode();
payload.putArray("originalArgb8888").add(0xFFFF0000);
payload.putArray("convertedRgb565").add(0xF800);
payload.putArray("rgba8888").add(0xFF0000FF);
final var declaration = MAPPER.createObjectNode();
declaration.put("index", 0);
declaration.set("palette", payload);

View File

@ -295,9 +295,7 @@ final class FileSystemPackerWorkspaceServiceTest {
final ObjectNode palette = palettes.addObject();
palette.put("index", 0);
palette.putObject("palette")
.putArray("originalArgb8888").add(0xFFFF0000);
((ObjectNode) palette.path("palette"))
.putArray("convertedRgb565").add(0xF800);
.putArray("rgba8888").add(0xFF0000FF);
final var artifacts = manifest.putArray("artifacts");
artifacts.addObject().put("file", "confirm.png").put("index", 0);
MAPPER.writerWithDefaultPrettyPrinter().writeValue(manifestPath.toFile(), manifest);
@ -330,8 +328,10 @@ final class FileSystemPackerWorkspaceServiceTest {
final int packedPixelBytes = (assetTable.get(0).path("metadata").path("width").asInt()
* assetTable.get(0).path("metadata").path("height").asInt()) / 2;
final int paletteStart = payloadOffset + assetOffset + packedPixelBytes;
assertEquals(0xF81F, readLeUnsignedShort(assetsPa, paletteStart));
assertEquals(0xF800, readLeUnsignedShort(assetsPa, paletteStart + 2));
assertEquals(0xFF, assetsPa[paletteStart] & 0xFF);
assertEquals(0x00, assetsPa[paletteStart + 1] & 0xFF);
assertEquals(0x00, assetsPa[paletteStart + 2] & 0xFF);
assertEquals(0xFF, assetsPa[paletteStart + 3] & 0xFF);
assertEquals(1, assetTable.get(0).path("asset_id").asInt());
assertEquals("GLYPH", assetTable.get(0).path("bank_type").asText());
assertEquals("NONE", assetTable.get(0).path("codec").asText());
@ -369,9 +369,7 @@ final class FileSystemPackerWorkspaceServiceTest {
final ObjectNode palette = palettes.addObject();
palette.put("index", 0);
palette.putObject("palette")
.putArray("originalArgb8888").add(0xFF00FF00).add(0xFFFF0000);
((ObjectNode) palette.path("palette"))
.putArray("convertedRgb565").add(0x07E0).add(0xF800);
.putArray("rgba8888").add(0x00FF00FF).add(0xFF0000FF);
final var artifacts = manifest.putArray("artifacts");
artifacts.addObject()
.put("artifact_id", "art-confirm")
@ -417,7 +415,7 @@ final class FileSystemPackerWorkspaceServiceTest {
final int payloadOffset = (int) readLeLong(assetsPa, 12);
final var assetTable = MAPPER.readTree(projectRoot.resolve("build/asset_table.json").toFile());
final int assetOffset = assetTable.get(0).path("offset").asInt();
assertEquals(0x21, assetsPa[payloadOffset + assetOffset] & 0xFF);
assertEquals(0x10, assetsPa[payloadOffset + assetOffset] & 0xFF);
}
@Test
@ -436,9 +434,7 @@ final class FileSystemPackerWorkspaceServiceTest {
final ObjectNode palette = palettes.addObject();
palette.put("index", 0);
palette.putObject("palette")
.putArray("originalArgb8888").add(0xFFFF0000);
((ObjectNode) palette.path("palette"))
.putArray("convertedRgb565").add(0xF800);
.putArray("rgba8888").add(0xFF0000FF);
final var artifacts = manifest.putArray("artifacts");
artifacts.addObject().put("file", "selected.png").put("index", 0);
MAPPER.writerWithDefaultPrettyPrinter().writeValue(manifestPath.toFile(), manifest);
@ -502,9 +498,7 @@ final class FileSystemPackerWorkspaceServiceTest {
final ObjectNode palette = palettes.addObject();
palette.put("index", 0);
palette.putObject("palette")
.putArray("originalArgb8888").add(0xFFFF0000);
((ObjectNode) palette.path("palette"))
.putArray("convertedRgb565").add(0xF800);
.putArray("rgba8888").add(0xFF0000FF);
final var artifacts = manifest.putArray("artifacts");
artifacts.addObject().put("file", "oversized.png").put("index", 0);
MAPPER.writerWithDefaultPrettyPrinter().writeValue(manifestPath.toFile(), manifest);
@ -533,9 +527,7 @@ final class FileSystemPackerWorkspaceServiceTest {
final ObjectNode palette = palettes.addObject();
palette.put("index", 0);
palette.putObject("palette")
.putArray("originalArgb8888").add(0xFFFF0000);
((ObjectNode) palette.path("palette"))
.putArray("convertedRgb565").add(0xF800);
.putArray("rgba8888").add(0xFF0000FF);
final var artifacts = manifest.putArray("artifacts");
artifacts.addObject().put("file", "checker.png").put("index", 0);
MAPPER.writerWithDefaultPrettyPrinter().writeValue(manifestPath.toFile(), manifest);
@ -1016,8 +1008,7 @@ final class FileSystemPackerWorkspaceServiceTest {
project(projectRoot),
AssetReference.forAssetId(1),
List.of(Map.of(
"originalArgb8888", List.of(0xFFFF0000),
"convertedRgb565", List.of(0xF800))))).success());
"rgba8888", List.of(0xFF0000FF))))).success());
final var manifest = MAPPER.readTree(assetRoot.resolve("asset.json").toFile());
final var selectedArtifact = manifest.path("artifacts").get(0);
@ -1074,8 +1065,7 @@ final class FileSystemPackerWorkspaceServiceTest {
project(projectRoot),
AssetReference.forAssetId(1),
List.of(Map.of(
"originalArgb8888", List.of(0xFFFF0000),
"convertedRgb565", List.of(0xF800))))).success());
"rgba8888", List.of(0xFF0000FF))))).success());
final var manifest = MAPPER.readTree(assetRoot.resolve("asset.json").toFile());
final var selectedArtifact = manifest.path("artifacts").get(0);
@ -1129,20 +1119,18 @@ final class FileSystemPackerWorkspaceServiceTest {
AssetReference.forAssetId(1),
List.of(
Map.of(
"originalArgb8888", List.of(0xFFFF0000, 0xFF00FF00),
"convertedRgb565", List.of(0xF800, 0x07E0)),
"rgba8888", List.of(0xFF0000FF, 0x00FF00FF)),
Map.of(
"originalArgb8888", List.of(0xFF0000FF),
"convertedRgb565", List.of(0x001F)))));
"rgba8888", List.of(0x0000FFFF)))));
assertTrue(response.success());
final var manifest = MAPPER.readTree(projectRoot.resolve("assets/ui/atlas/asset.json").toFile());
assertEquals(2, manifest.path("output").path("pipeline").path("palettes").size());
assertEquals(0, manifest.path("output").path("pipeline").path("palettes").get(0).path("index").asInt());
assertEquals(0xFFFF0000, manifest.path("output").path("pipeline").path("palettes").get(0).path("palette").path("originalArgb8888").get(0).asInt());
assertEquals(0xFF0000FF, manifest.path("output").path("pipeline").path("palettes").get(0).path("palette").path("rgba8888").get(0).asInt());
assertEquals(1, manifest.path("output").path("pipeline").path("palettes").get(1).path("index").asInt());
assertEquals(0x001F, manifest.path("output").path("pipeline").path("palettes").get(1).path("palette").path("convertedRgb565").get(0).asInt());
assertEquals(0x0000FFFF, manifest.path("output").path("pipeline").path("palettes").get(1).path("palette").path("rgba8888").get(0).asInt());
}
@Test

View File

@ -158,8 +158,7 @@ final class PackerAssetDeclarationParserTest {
{
"index": 1,
"palette": {
"originalArgb8888": [4294901760],
"convertedRgb565": [63488]
"rgba8888": [-16776961]
}
}
]
@ -174,7 +173,7 @@ final class PackerAssetDeclarationParserTest {
assertTrue(result.valid());
assertTrue(result.declaration().outputPipelineMetadata().get("palettes").isArray());
assertEquals(1, result.declaration().outputPipelineMetadata().get("palettes").get(0).path("index").asInt());
assertEquals(63488, result.declaration().outputPipelineMetadata().get("palettes").get(0).path("palette").path("convertedRgb565").get(0).asInt());
assertEquals(0xFF0000FF, result.declaration().outputPipelineMetadata().get("palettes").get(0).path("palette").path("rgba8888").get(0).asInt());
}
@Test
@ -194,15 +193,13 @@ final class PackerAssetDeclarationParserTest {
{
"index": 0,
"palette": {
"originalArgb8888": [4294901760],
"convertedRgb565": [63488]
"rgba8888": [-16776961]
}
},
{
"index": 0,
"palette": {
"originalArgb8888": [4278255360],
"convertedRgb565": [2016]
"rgba8888": [16711935]
}
}
]

View File

@ -66,9 +66,7 @@ final class PackerAssetDetailsServiceTest {
final ObjectNode declaration = palettes.addObject();
declaration.put("index", 3);
declaration.putObject("palette")
.putArray("originalArgb8888").add(0xFFFF0000).add(0xFF00FF00);
((ObjectNode) declaration.path("palette"))
.putArray("convertedRgb565").add(0xF800).add(0x07E0);
.putArray("rgba8888").add(0xFF0000FF).add(0x00FF00FF);
mapper.writerWithDefaultPrettyPrinter().writeValue(manifestPath.toFile(), manifest);
final PackerAssetDetailsService service = service();
@ -77,8 +75,8 @@ final class PackerAssetDetailsServiceTest {
assertEquals(1, result.details().pipelinePalettes().size());
assertEquals(3, result.details().pipelinePalettes().getFirst().get("index"));
assertEquals(
List.of(0xFFFF0000, 0xFF00FF00),
result.details().pipelinePalettes().getFirst().get("originalArgb8888"));
List.of(0xFF0000FF, 0x00FF00FF),
result.details().pipelinePalettes().getFirst().get("rgba8888"));
}
@Test
@ -202,7 +200,7 @@ final class PackerAssetDetailsServiceTest {
final var palette = (Map<?, ?>) selectedFile.metadata().get("palette");
assertEquals(16, ((Number) tile.get("width")).intValue());
assertEquals(16, ((Number) tile.get("height")).intValue());
assertFalse(((List<?>) palette.get("originalArgb8888")).isEmpty());
assertFalse(((List<?>) palette.get("rgba8888")).isEmpty());
}
@Test