the interface code is ours: the transcription debt is paid

- forty files that carried the reference's literal Lua are rewritten as our own expression of the behaviour — worst identical run 61 lines down to 7 — and the README now says exactly that
- the overlap gate measures the code itself across all four reference corpora, and ratchets: the number may only go down
- a lost session ends at the login screen instead of silently re-authenticating and stealing the account back
- a building's skybox is a real model: Caverns of Time's white ceiling becomes its painted nebula and additive stars

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Sam
2026-08-14 19:21:03 +07:00
co-authored by Claude Fable 5
parent 6e7867147d
commit a683d5524f
84 changed files with 6620 additions and 4629 deletions
@@ -63,6 +63,27 @@ macro_rules! corpus_or_skip {
};
}
/// The corpus **and** a client install — for the tests whose subject is a global that comes from
/// the reference file this client SOURCES off the player's own patch chain rather than shipping
/// ([`super::reference_ui`], decision 1234).
///
/// `corpus_or_skip!` alone is the wrong precondition for them. With the corpus present but no
/// install, `ContainerFrameItemButton_OnEnter`/`_OnClick` are *legitimately* nil — that is the
/// documented "no install, no file" behaviour, not a defect — and the test then fails for a reason
/// that is not a bug. `reference_ui`'s own header already says tests that need the file gate on the
/// install the way every other client-data test does; these four never got that gate when 1234
/// added the sourcing seam and the tests in one landing.
///
/// It stayed invisible because it only bites where the install is *not* found, which on a dev
/// machine is only `scripts/gates.sh`'s `player-tests` rung: `--no-default-features` compiles out
/// the `dev` project-folder candidate, so the `WoW` symlink beside the worktree stops being visible.
macro_rules! corpus_and_install_or_skip {
() => {{
let _data = benilla_formats::wow_data_or_skip!();
corpus_or_skip!()
}};
}
fn read_toc(root: &Path, name: &str) -> Toc {
let path = root.join(name).join(format!("{name}.toc"));
Toc::parse(&benilla_ui::source::decode(
@@ -537,7 +558,7 @@ fn the_roster_seat_names_the_character_the_addons_will_meet() {
/// hover over every slot raised and no tooltip ever appeared.
#[test]
fn hovering_a_bagnon_slot_shows_the_items_tooltip() {
let root = corpus_or_skip!();
let root = corpus_and_install_or_skip!();
let mut s = open_bagnon(&root);
let occupied = bagnon_button_for_slot(&s, 0, 1);
@@ -574,7 +595,7 @@ fn hovering_a_bagnon_slot_shows_the_items_tooltip() {
/// `PickupContainerItem(this:GetParent():GetID(), this:GetID())`. The observable is the cursor.
#[test]
fn left_clicking_a_bagnon_slot_picks_the_item_up() {
let root = corpus_or_skip!();
let root = corpus_and_install_or_skip!();
let mut s = open_bagnon(&root);
let occupied = bagnon_button_for_slot(&s, 0, 1);
@@ -615,7 +636,7 @@ fn left_clicking_a_bagnon_slot_picks_the_item_up() {
/// `UseContainerItem(bag, slot)` — use/equip the item.
#[test]
fn right_clicking_a_bagnon_slot_uses_the_item() {
let root = corpus_or_skip!();
let root = corpus_and_install_or_skip!();
let mut s = open_bagnon(&root);
let occupied = bagnon_button_for_slot(&s, 0, 1);
@@ -638,7 +659,7 @@ fn right_clicking_a_bagnon_slot_uses_the_item() {
/// `ignoreModifiers` arm. Driven as a real gesture: press, move past the threshold, release.
#[test]
fn dragging_a_bagnon_slot_picks_the_item_up() {
let root = corpus_or_skip!();
let root = corpus_and_install_or_skip!();
let mut s = open_bagnon(&root);
let occupied = bagnon_button_for_slot(&s, 0, 1);
let empty = bagnon_button_for_slot(&s, 0, 2);
@@ -1,4 +1,4 @@
//! The combo-point dots (decisions 0869, 0875) — the reference `ComboFrame` transcription driven
//! The combo-point dots (decisions 0869, 0875) — our `ComboFrame` implementation driven
//! through the real loader: the show/hide edges, the per-point highlight/shine fade chain, the
//! "only newly-earned points flare" rule that `COMBO_FRAME_LAST_NUM_POINTS` exists to enforce, and
//! the two gates that live in `GetComboPoints` rather than in this Lua — rogue-or-druid only, and
@@ -37,8 +37,8 @@ fn minimap_zoom_buttons_resync_when_switching_inside_and_outside() {
.unwrap();
s.run("function PlaySound() end").unwrap();
load_xml(&s, "Fonts.xml");
// The shipped load order provides GameTooltip before the cluster; Minimap_Update's verbatim
// ref block (the PVP tint slice, decision 0287) touches it from OnLoad on.
// The shipped load order provides GameTooltip before the cluster; Minimap_Update's tooltip
// half (the PVP tint slice, decision 0287) touches it from OnLoad on.
load_xml(&s, "GameTooltip.xml");
load_xml(&s, "MinimapCluster.xml");
@@ -155,7 +155,7 @@ fn tod_window(s: &UiScript) -> (f64, f64, f64, f64) {
.unwrap()
}
/// The verbatim `GameTimeFrame_Update` law: the 50-px window over the 128×64 UI-TOD-Indicator
/// `GameTimeFrame_Update`'s law, exactly: the 50-px window over the 128×64 UI-TOD-Indicator
/// sits on the LEFT half (the sun) through the game day and slides +0.5 to the RIGHT half (the
/// moon) outside it — night is before 5:30 AM or from 9:00 PM, boundaries included exactly as
/// the ref compares (`< DAWN or >= DUSK`).
@@ -189,7 +189,7 @@ fn game_time_frame_slides_the_sun_moon_window_on_the_game_clock() {
/// Hovering the indicator through the REAL pointer path (hit-test → OnEnter) shows the game-time
/// tooltip, live-updates it while owned (the `IsOwned` refresh branch), and hides it on leave.
/// This also pins the two loader-side pieces the transcription leans on: the `<Scripts>` walker's
/// This also pins the two loader-side pieces this frame leans on: the `<Scripts>` walker's
/// mouse auto-enable (the frame declares no enableMouse, like the reference — without the law the
/// hit-test never captures) and the `<HitRectInsets>` hull.
#[test]
@@ -210,7 +210,7 @@ fn hovering_the_indicator_shows_and_live_updates_the_game_time_tooltip() {
s.eval::<bool>("return GameTooltip:IsVisible()").unwrap(),
"OnEnter owns the tooltip (the Scripts-walker auto-enable capturing at {x},{y})"
);
// TwentyFourHourTime = 1 (enGB LocalizeFrames, the transcription header): 21:07, not 9:07 PM.
// TwentyFourHourTime = 1 (enGB LocalizeFrames, per GameTime.xml's header): 21:07, not 9:07 PM.
let text = |s: &UiScript| {
s.eval::<String>("return GameTooltipTextLeft1:GetText()")
.unwrap()
@@ -1,6 +1,6 @@
//! The shipped `assets/ui/MoneyFrame.xml` — the reference's `MoneyFrameTemplate` /
//! `SmallMoneyFrameTemplate` kit and the `MoneyTypeInfo` table behind it (decision 1190: a name
//! the shipped 1.12 UI defines is FrameXML's to transcribe).
//! `SmallMoneyFrameTemplate` kit and the `MoneyTypeInfo` table behind it (decision 1190: a name the
//! shipped 1.12 UI defines is a name we publish too — under our own implementation of it, 1260).
//!
//! Nothing benilla ships consumes this file yet — our own eight coin displays run on
//! MerchantFrame.xml's `BenillaMoney_*` slot kit, and MoneyFrame.xml's header is where the two are
@@ -302,11 +302,17 @@ fn an_input_box_from_the_template_carries_its_border_and_takes_text() {
/// `MyScrollScrollBarScrollUpButton` through **two** levels of `$parent` — which is precisely what
/// `ScrollFrame_OnLoad` getglobals on the way past.
///
/// The `UpdateScrollChildRect` leg is also the falsifier for this file's one Lua divergence:
/// `ScrollFrame_OnScrollRangeChanged` reaches the thumb through `GetThumbTexture()` rather than the
/// reference's `getglobal(bar:GetName().."ThumbTexture")`, because our loader never publishes a
/// named `<ThumbTexture>` as a global. If that divergence were reverted, this call would raise on a
/// The `UpdateScrollChildRect` leg is also the falsifier for the `<ThumbTexture>` publication:
/// `ScrollFrame_OnScrollRangeChanged` reaches the thumb through
/// `getglobal(bar:GetName().."ThumbTexture")`, which resolves only because our loader publishes a
/// named `<ThumbTexture>` as a global. If that publication regressed, this call would raise on a
/// nil index and `s.errors()` would not be empty.
///
/// (This used to claim the opposite — that we diverged to `GetThumbTexture()` "because our loader
/// never publishes a named `<ThumbTexture>`", and called it "this file's one Lua divergence". It
/// was already false when written: the XML has used `getglobal` throughout, at HEAD and now.
/// Corrected rather than deleted, because a doc comment asserting a divergence that does not exist
/// is exactly how someone later introduces a real one by "restoring" it.)
#[test]
fn a_scroll_frame_from_the_template_wires_its_bar_two_parents_deep() {
let mut s = harness();