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.
This commit is contained in:
Sylpheed port agent
2026-09-03 20:34:39 +00:00
parent b24e1a681a
commit 6b4b1df116

View File

@@ -17,13 +17,27 @@ use sylpheed_formats::{t8ad, ui_layout};
/// ///
/// ⚠️ `0x3002` is one member of a `0x3000` family and is **not** a general /// ⚠️ `0x3002` is one member of a `0x3000` family and is **not** a general
/// button test — `GP_READY_ROOM` uses `0x3000`/`0x3004`/`0x300c`/`0x3008` and /// button test — `GP_READY_ROOM` uses `0x3000`/`0x3004`/`0x300c`/`0x3008` and
/// has zero `0x3002`. Every screen in this milestone is `GP_TITLE`, where the /// has zero `0x3002`. The mapping is decoded for the kinds listed; anything else
/// mapping is decoded; anything else exports as `unknown` with its raw kind. /// exports as `unknown` with its raw kind visible.
fn role_of(kind: u32, has_sprite: bool) -> &'static str { 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 { match kind {
0x3002 => "button", 0x3002 | 0x3003 => "button",
0x10 if !has_sprite => "primitive", 0x10 | 0x11 if !has_sprite => "primitive",
0x0 => "decoration", 0x0 | 0x1 => "decoration",
_ => "unknown", _ => "unknown",
} }
} }