the hover tax is pinned and cut, and a spell-less macro is a button

- a tooltip change costs ~1.3 ms — five whole-interface recomputes, each working as designed: the quad re-convert at 474 µs, the Lua tick at 287, the layout resolve at 200, bevy's `Assets<Mesh>` tax at ~270 and the mesh rebuild at 146 — pinned with new hover probes (a jitter dial, a `WOW_PROBE_HOVER_DUTY` duty cycle so run drift cancels, an `AssetChanged` tax meter), and the layout preamble's two whole-roster scans become lists maintained at the writer (52–83 µs → 1–11)
- the splice compared this frame's entries against last frame's by index, so one inserted highlight shifted the 160 entries behind it and read as "everything changed"; it now aligns on `z` — an identity, not a position — and a `Text` entry that writes only quads became spliceable, so a tooltip change re-converts 22 entries instead of 520 (`convert` +439 µs → +107), with `WOW_UI_SPLICE_VERIFY` running the full conversion behind every spliced frame: 0 mismatches over 1,078
- a spell-less macro is a usable action button, not the 0.4 grey — the reference's usable compute has a dedicated leg answering usable for the bound-spell zero, cross-checked at the bytes in the reference's disassembly — and the button's Name line is written unconditionally from `GetActionText` as the reference does, so the macro's name sits under its icon and a `/cast` of a spell the character does not know now greys, which is also 1.12's behaviour (B340)
- a capture bounds its run in wall-clock seconds, because a frame cap is no cap at the ~1 fps a starved `nextDrawable` leaves — 1800 frames is thirty minutes there — and the teardown backstop runs on every run as a liveness guarantee, carrying the exit code the run asked for; the Multisampling row reads Off / 2x / 4x, since "1x" contradicts the no-multisampling byte both of the reference's enumerators normalise to and the bit-depth prefix was identical on every row

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Sam
2026-08-27 15:13:58 +07:00
co-authored by Claude Fable 5
parent a0447c171d
commit 45f001bbc5
26 changed files with 1599 additions and 257 deletions
@@ -159,3 +159,54 @@ fn set_script_on_size_changed_is_accepted_because_the_resolve_pass_fires_it() {
s.resolve();
assert!(s.eval::<bool>("return ran").unwrap(), "…and it FIRED");
}
/// **The watch list is exactly the frames carrying the script.** The resolve's "before" snapshot
/// reads `SetScript`'s maintained `on_size_changed_frames` rather than filtering the whole scripts
/// map (decision 1634), so the list itself is now load-bearing: `SetScript(…, nil)` must remove
/// the frame, and re-registering must not enrol it twice.
///
/// Asserted on the LIST, not on the fire count, and that is the point. A stale entry fires nothing
/// — `fire` looks the handler up in Lua and finds nil — so behaviour hides the bug completely and
/// the only symptom is the snapshot silently growing forever, one dead frame at a time. (Written
/// as a fire-count test first; it passed with the `retain` deleted.)
#[test]
fn the_on_size_changed_watch_list_is_exactly_the_frames_carrying_the_script() {
use crate::script::model::Model;
let mut s = script();
s.set_screen_size(800.0, 600.0);
s.run(
r#"
fires = 0
Watched = CreateFrame("Frame", "WatchedPanel")
Watched:SetPoint("BOTTOMLEFT", 0, 0)
Watched:SetSize(10, 10)
Other = CreateFrame("Frame", "UnwatchedPanel")
Other:SetScript("OnShow", function() end) -- another kind never enrols
local bump = function() fires = fires + 1 end
Watched:SetScript("OnSizeChanged", bump)
Watched:SetScript("OnSizeChanged", bump) -- re-registering is not a second enrolment
"#,
)
.unwrap();
let watched = |s: &crate::script::UiScript| {
s.lua()
.app_data_ref::<Model>()
.expect("model app_data")
.on_size_changed_frames
.len()
};
assert_eq!(watched(&s), 1, "one frame carries the script");
s.resolve();
s.run("Watched:SetSize(40, 40)").unwrap();
s.resolve();
assert_eq!(
s.eval::<i64>("return fires").unwrap(),
2,
"one fire per resolve whose size moved — the 0×0→10×10 birth, then the resize"
);
s.run(r#"Watched:SetScript("OnSizeChanged", nil)"#).unwrap();
assert_eq!(watched(&s), 0, "clearing the script un-watches the frame");
}