From 6b4b1df116b639eec65a1d4133919a023eee0066 Mon Sep 17 00:00:00 2001 From: Sylpheed port agent Date: Thu, 3 Sep 2026 20:34:39 +0000 Subject: [PATCH] port(exporter): role_of ignored the parent bit, and the validator caught it check-all went red on format-validator: options.json listed five buttons while the validator computed a resting-Y order of [], because it keys on role == 'button' and role_of still matched only 0x3002. I had widened the BUTTONS list for 0x3003 and not the ROLE -- two implementations of one rule, and the second one caught me. Bit 0 is the parent flag and carries no role information (decoded disc-wide, 15493 elements, zero disagreements). A role table keyed on the raw kind splits every class in two and calls the parented half 'unknown'. Applied to EVERY pair rather than the one that failed: 0x3002|0x3003 -> button, 0x0|0x1 -> decoration, 0x10|0x11 -> primitive. Fixing only 0x3003 would have left 0x1 unknown while 0x0 is decoration -- the same inconsistency one kind along, and half-applying this decode is what produced the failure in the first place. Impact measured before the change: 0x3003 10 elements, 0x1 54, 0x11 none. 0x73002/0x73003 deliberately NOT folded in -- their 0x70000 bits are undecoded. Validator now passes: 30 screens validate. --- crates/sylpheed-export/src/screen.rs | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/crates/sylpheed-export/src/screen.rs b/crates/sylpheed-export/src/screen.rs index c8750bf0..04ce33be 100644 --- a/crates/sylpheed-export/src/screen.rs +++ b/crates/sylpheed-export/src/screen.rs @@ -17,13 +17,27 @@ use sylpheed_formats::{t8ad, ui_layout}; /// /// ⚠️ `0x3002` is one member of a `0x3000` family and is **not** a general /// button test — `GP_READY_ROOM` uses `0x3000`/`0x3004`/`0x300c`/`0x3008` and -/// has zero `0x3002`. Every screen in this milestone is `GP_TITLE`, where the -/// mapping is decoded; anything else exports as `unknown` with its raw kind. +/// has zero `0x3002`. The mapping is decoded for the kinds listed; anything else +/// exports as `unknown` with its raw kind visible. fn role_of(kind: u32, has_sprite: bool) -> &'static str { + // 🔴 BIT 0 IS THE PARENT FLAG AND CARRIES NO ROLE INFORMATION. Decoded + // disc-wide: `kind & 1` agrees with "has a parent" on 15 493 elements with + // zero disagreements (`docs/re/ui-kind-bit0-is-has-parent.md`). So a role + // table keyed on the raw kind splits every class in two and calls the + // parented half `unknown` -- which is how the OPTIONS menu's rows came out + // roleless while the exporter had already accepted them as buttons. + // + // ⚠️ APPLIED TO EVERY PAIR, NOT JUST THE ONE THAT FAILED. Fixing only + // `0x3003` would have left `0x1` as `unknown` while `0x0` is `decoration`, + // i.e. the same inconsistency one kind along -- and half-applying this + // decode is exactly what produced the failure this is fixing. + // + // ⚠️ `0x73002`/`0x73003` are NOT folded in. Their `0x70000` bits are + // undecoded, so they stay `unknown` with their raw kind visible. match kind { - 0x3002 => "button", - 0x10 if !has_sprite => "primitive", - 0x0 => "decoration", + 0x3002 | 0x3003 => "button", + 0x10 | 0x11 if !has_sprite => "primitive", + 0x0 | 0x1 => "decoration", _ => "unknown", } }