Commit Graph

25 Commits

Author SHA1 Message Date
Sam Sung ab15e9c933 Script errors reach the error handler at the raise, as 1.12.1 does (#2674)
A script error reached the `seterrorhandler` function once per frame, from a queue, after every other listener had run. In 1.12.1 the handler is the error function of the pcall each script runner makes (`0x704e4f`-`0x704e79`; the error function `0x703b40`). So it runs at the raise, inside the failing script: `this`, `event` and `arg1` are still the failing handler's, `debugstack()` shows the failing call, and the event's next listener has not run yet.

Every benilla runner now passes that error function: handlers, OnLoad, file chunks, RunScript, key bindings and slash commands. It returns the handler's result, as `0x703b40` does. The queue is gone.

A handler body that fails to compile reaches no handler (`0x704c70`). benilla's host log keeps each original fault, and `/errors` replays the ones raised before benilla's layer loaded.

Tests cover the raise-time globals, the stack, the listener order, OnUpdate and chunks.

Fixes #2656

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-27 07:46:07 +07:00
Sam Sung b18d08f64f Lua's string, base and math libraries and the aliases match 1.12.1 (#2660)
Lua 5.0 behaviours of the client that an addon can observe, which benilla-lua's 5.1 base got differently:
- string.sub and string.find keep a position's low 32 bits (`0x7fbd55`).
- An escaped byte at or above 0x80 matches nothing (`0x7fcbc6`).
- `error()` checks its argument (`0x702993`) and adds the position at any level but 0 (`0x7029a8`).
- `__unm` gets the operand and nil (`0x6f8edc`).
- `__index` chains reach 102 tables and `__newindex` 101.
- math.deg multiplies by 180/pi (`0x7fb14d`).

The bare aliases run as their own `compat.lua` chunk (`0x703b21`), each on the client's line. Its closures keep a local `math`, so their error lines match and replacing the global `math` leaves them working.

`seterrorhandler` keeps the top value, and nil clears it (`0x702930`).

Each fix has a test.

Fixes #2632 Fixes #2633 Fixes #2634 Fixes #2635 Fixes #2636 Fixes #2637 Fixes #2638 Fixes #2639 Fixes #2640 Fixes #2654

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-27 04:45:57 +07:00
Sam Sung 53e088b678 Console, follow, cache asks and plate verbs act inside their calls (#2354)
More Lua verbs do their work inside the call, as 1.12.1's do. The chunk's next line sees the effect, and packets go out in call order.

- **`ConsoleExec`** runs its line in the call (`0x515f43` → `0x63ce00`): cvarlist, help, ver, the port commands, togglehelm, togglecloak, whois and reloadUI.
- **`FollowUnit` and `FollowByName`** run in the call (`0x60fed0`). A refusal shows its line, a re-follow fires its end (`0x60fb84`), and the begin fires at `0x610071`.
- **Cache misses ask in the call:** `UnitName` (`0x5171eb`), the trade getters (`0x4c017f`) and `GetGuildInfo` (`0x4c93d2`) send their query on a miss. A getter never raises.
- **The nameplate verbs** set their bits in the call (`0x489450`), and **`OpeningCinematic`** sends in the call (`0x48c8f6`).

Each converted verb has a test that mixes it with `RandomRoll` and checks the order.

Part of #2202

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-24 21:30:50 +07:00
Sam Sung 615198d3bb The Lua library answers as 1.12.1's does (#1862)
Six places where benilla's Lua answered unlike 1.12.1's:

- The lexer took `[=[` long-string levels; 1.12.1's `luaX_lex` tests one byte after `[` (`0x6ff793`) and `--[=[` is a line comment (`0x6ff6c9`).
- `math.random` ran a glibc-style `rand` seeded with 1; now MSVC's (`0x7400e5`, `% 0x7fff` times 1/32767 at `0x7fb310`), clock-seeded as the client is (`0x5d1c8b`), fixed in captures and the addon harness.
- `getfenv`/`setfenv` honour a raw `__fenv` field (`0x702ba0`), and `setfenv` returns nothing.
- An object's text is `type: %08X` in the embedding API too (`0x74301d`).
- `time` converts a date table through MSVC's `_mktime` (`0x74066b`).
- `date` formats with MSVC's C-locale patterns (`0x8323a0`): `%c` is `09/09/01 01:46:40`, `#` drops zeros.

Each has a test that fails without it; the addon corpus parses as before.

Fixes #1257
Fixes #1258
Fixes #1510
Fixes #1511
Fixes #1503
Fixes #1504

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-18 10:35:43 +07:00
Sam Sung c97fd03a57 Lua tables, ipairs and globals behave as the client's 5.0 (#1792)
benilla-lua's tables and globals now follow the client's Lua 5.0, not 5.1.

Tables:
- They size, fill and rehash as 5.0's ltable.c does: the hash part doubles (`0x6fab90`), and a log size of 0 is the shared dummy (`0x6fa601`).
- A hash part past 2^24 nodes raises `table overflow`.
- Constructors store every 32 items.
- A weak table's clearing removes the key, so `next` from it raises (`0x6f79d0`).
- A weak-keyed table keeps its string keys (`0x6f79f0`).

Globals and libraries:
- `ipairs` returns itself, and a second argument steps once.
- `setglobal` assigns the top of the stack.
- The state opens in the client's order, with no `_G`.

Each new test fails without its fix.

Fixes #1487
Fixes #1789
Fixes #1790
Fixes #1169

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-17 17:49:05 +07:00
Sam Sung d8a55240e0 Lua's collector paces and sizes its stack as the client's 5.0 (#1791)
The collector now paces as the client's Lua 5.0 does.

The threshold:
- The state opens at 4× its count (`0x6f6ec8`), and InitLua then sets 256 KB (`0x7039f2`).
- After a collection it is the count plus the larger of the old headroom and a quarter of the count (`0x6fae00`). The headroom is capped at the free space in the client's six block pools, which a new book models (`0x6fae90`).
- The memory watch collects from a threshold of 0 (`0x703bd6`), and varargs never collect.

The stack and call records start at 45 and 8 slots and grow by 5.0's rule (`0x6f5f60`). They are checked once per collection, during mark, and halved under a quarter's use (`0x6f7949`). A tail call checks the stack where the call is made (`0x6f922c`).

A collection of a 10 MB heap takes about 1 ms; each change fails its test without it.

Fixes #1783
Fixes #1784

🤖 Generated with [Claude Code](https://claude.com/claude-code)
2026-10-17 17:20:11 +07:00
Sam Sung 80f751ffe5 Lua memory counts as the client's 5.0; the old shim's overrides are gone (#1788)
Lua memory now counts as the client's does:
- Every object is charged at its 32-bit Lua 5.0 size: a string is 17 bytes plus its length (`0x6f9da1`), a table header 32 (`0x6fa500`), a node 40, and a closure 36 plus 4 per upvalue (`0x6f9ebf`).
- Prototypes count 5.0's instructions and constants (`0x6fcb2b`).
- The string table and the concat buffer are counted as 5.0 sizes them.

The stock UI reads 10,618 KB, against 13,294 KB before.

The host's old C-host shim overrode benilla-lua's natives. It is gone:
- `collectgarbage` now moves the real collector, taking `__ftol`'s low word (`0x6f4400`);
- `gcinfo` reports that collector;
- `^` is the client's `math_pow` (`0x7fb4bd`);
- `loadstring` returns one value (`0x7032ba`).

An audit re-derived every size from the bytes. Each fix fails its test without it.

Fixes #1779
Fixes #1780

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-17 16:01:55 +07:00
Sam Sung d5e43dd3e1 Lua's table, bit and error paths behave as the client's 5.0 (#1774)
The table library and `unpack` now run as the client's 5.0 natives (`0x822d40`). benilla's closure layer over them is gone. `unpack` refuses past 2,048 slots (`0x6f2f43`) and reads its table alone. `getn` converts a numeric-string `n` (`0x6f4f80`). `next` says "for" (`0x871aac`).

The bit library answers unsigned except `arshift` and `mod` (`0x7faa6d`). Its folds take every argument, and `math.pow`, `atan2` and `mod` check argument 1 first.

A Rust callback's error now carries the caller's `file:line`, as `luaL_error` does (`0x6f4940`); only the sound verbs raise bare. Error text keeps its bytes, from `assert` to the error handler.

An audit re-derived every commit from the bytes. Each fix fails its test without it.

Fixes #1435
Fixes #1448
Fixes #1449
Fixes #1480
Fixes #1482
Fixes #1483
Fixes #1484
Fixes #1485
Fixes #1760
Fixes #1761
Fixes #1762
Fixes #1763
Fixes #1764
Fixes #1765
Fixes #1766
Fixes #1771

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-17 13:26:34 +07:00
Sam Sung a04df2d17d benilla-lua's VM and compiler behave as the client's Lua 5.0 (#1768)
benilla-lua now matches the client's Lua 5.0 wherever an addon can see the difference:
- Number keys hash as `hashnum` does (`0x6fa260`), so `pairs` walks them in the client's order.
- Calls nest at most 4096 deep (`0x6f61c0`).
- `^` calls the global `__pow` (`0x6f9b5e`).
- The parser's limits and messages are the client's (`0x6ff440`); the client has no assignment limit.
- A numeric for's variable is its counter (`0x6fe380`, `0x6f9262`).
- A generic for uses `forlist`'s layout (`0x6fe540`): the first name is the control, and closures share the variables.
- Only calls name a callee (`0x6fc499`), and a stray token reports `<eof> expected` (`0x871cf4`).

Each fix has a test that fails without it. Two audits re-derived every address from the bytes. The bench is faster or level.

Fixes #1369
Fixes #1370
Fixes #1371
Fixes #1372
Fixes #1374
Fixes #1377
Fixes #1752
Fixes #1753
Fixes #1754

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-17 11:07:05 +07:00
Mathih13 8100fe9820 Run the script host on benilla-lua; remove the vendored C Lua and mlua (#1255)
The script host now runs on benilla-lua alone. The vendored C Lua 5.1.5 (`third_party/lua-src`) and mlua are removed, about 17k lines. `vm_parity` checks benilla-lua against the answers the C build recorded on Linux and macOS, and `front_end` checks every corpus chunk's compiled shape against the C build's digest. `GRAMMAR.md` records each grammar change from 5.1, by client address.

A handler's `this`, `event` and `arg1`… are bound in one VM call. An event fire saves and restores `event`, while the handler runner saves only `this` (`0x704d50`).

Ours on the branch: VM fixes from review (hook dispatch counts, registers and frames around a collection, protected-call handlers, library errors) and `vm_parity`'s two-VM leftovers removed.

Tests: the full gate chain on the merged tree, `vm_parity` and `front_end` among them. Live: smoke and a stock-glue login. Load time is level with C Lua, and memory is within 7%.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Sam <samuv.eth@gmail.com>
2026-10-17 08:51:37 +07:00
Mathih13 d6655d8c10 benilla-lua: benilla's own 1.12 Lua VM, opt-in behind benilla-vm (#1254)
benilla-lua is a Lua 5.1.5 interpreter in Rust that speaks the 1.12.1 client's grammar. It is opt-in behind the `benilla-vm` feature, with `benilla-mlua`, the slice of mlua that benilla-ui uses, over it. The C build stays the default. Its front end ports 5.1.5's `lparser.c` and `lcode.c`, so registers, limits and messages match the C build's.

Our finish on top:
- the collector counts growth as C does, off the write path;
- frames under a leaky generic `for` start nil, as `luaD_precall`;
- the budget hook counts what C dispatches, and costs nothing when unset;
- `__index` chains stop at 100;
- mlua 0.11's conversions;
- `vm_parity` answers recorded per platform.

Tests: `vm_parity` on both VMs; the front-end corpus (8,543 chunks) against `string.dump`; 7,613 app and UI tests on benilla-lua. Built on macOS; Linux by CI.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Sam <samuv.eth@gmail.com>
2026-10-16 16:16:09 +07:00
Sam Sung c49c201176 CVars refuse what 1.12.1's callbacks refuse; Lua arguments and numerals (#1286)
CVars and Lua arguments, each against the client's code:

- A CVar row carries the reference's refusing callback, run before the value is stored (`CVar::Set`, 0x63df7d): the video rows, six camera rows, `farclip` (NaN passes, as 0x688d40's unordered compare lets it), `frillDensity`, `gxTripleBuffer` (0 or 1, 0x63afe0) and `gxRefresh` (the 11 rates at 0x8645e0).
- `RegisterCVar` creates at most 30 CVars per process (0x488b25); `GetCVar` and `GetCVarDefault` raise their usage lines.
- `Minimap:SetMaskTexture`, `CloseLoot(1)` (ERR_LOOT_NO_UI, 0x48f27b) and the onSelf of `UseContainerItem`/`UseInventoryItem` follow the client.
- Lua's numeral reader has no hex and takes `d` as an exponent, as the client's strtod (0x4112d1).

Each has a test that fails without it.

Fixes #558
Fixes #559
Fixes #567
Fixes #696
Fixes #988
Fixes #989
Fixes #1025
Fixes #302
Fixes #366
Fixes #1275

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-15 15:20:23 +07:00
Sam Sung 994f9f9610 reference/ vendors benilla-re's tables at a pinned commit (#1282)
`reference/` held benilla's own copies of the reference's tables, some derived by its own scripts from older inputs: the fire-site table kept one event id where a site fires two, and credited glue-screen sites to in-game events.

Now `reference/` is benilla-re's tables at the commit `reference/PIN` names, byte for byte: bindings, events, glue events, messages, event arguments, verb events, the glue surface, the Lua globals, chat types and groups, and CVars. `scripts/sync-reference.py` copies them, and its `--check` runs in the gates and in CI. Four generators and nine old files go, and every reader moves to the new columns.

New tests hold the chat type, chat group and CVar tables to the copies; the CVar rows already filed are listed as known.

Fixes #245
Fixes #960
Part of #244

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-15 11:09:45 +07:00
Sam Sung 9c32e5126e String literals in benilla-ui, -world and -formats carry no record numbers (#299)
Part of #92, for `benilla-ui`, `benilla-world` and `benilla-formats`.

- 88 string literals drop private record and bug numbers, the dates of private incidents, and the workspace's name for the maintainer. They are assert and panic texts, log and printout lines, the `--` comments of the Lua prelude and of test fixtures, and one Lua assert. Each keeps its fact in its own words.
- Two test names lose their numbers: `burning_steppes_lava_builds_a_magma_surface_at_the_reported_pin` and `join_channel_by_name_answers_the_row_custom_and_nil_legs`.
- A test-only event, `B271_PROBE`, is now `ERROR_PROBE` in the two crates that register and fire it. A fixture's error text in `benilla-app`'s `ui_script` tests drops its bug number, together with the assertion that reads it.
- Doc comments that named a client function by a disassembler's label (`FUN_0068a830`) now give its address, in `benilla-formats`, `benilla-assets` and one `benilla-app` file.
- Every literal change keeps each literal's line count, proven with comments stripped and every literal masked. The two renamed tests differ only in their names.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-25 17:01:02 +07:00
Sam Sung fd386e75ae Comments in benilla-ui: one line of fact each, no history, no record numbers (#143)
Part of #41: the comments of `benilla-ui` (the Lua UI engine, its FrameXML loader and its widgets) are rewritten to the rule in `docs/METHOD.md`, which is what the code does and the reference fact behind it, in a line. 43,140 comment lines become 15,161.

- **The mechanical strip.** The citations that were only a private record number go first, and each edit is shown to be a pure removal.
- **Wrong facts corrected.** The rewrite corrects the comments that stated wrong facts. Among them:
  - `0x64a480` is the case-sensitive compare (a byte `repz cmpsb`), and `0x64a4c0` the case-insensitive one.
  - A frame's id sits at `+0xb0`, not `+0xb4`. `EnableKeyboard`/`IsKeyboardEnabled` are `0x776ec0`/`0x776f90`.
  - A region's unpinned edge has no fallback to its owner's rect: the owner supplies only the scale.
  - `$parent` expands to the nearest named ancestor, or "Top" when none is named (`0x76c5b0`), not simply to the parent.
  - A StatusBar fills from its internal normalised fraction, not from `GetValue()`.
  - The addresses of `StartDuel` and `StartDuelUnit` were swapped.
  - Many "untraced" notes now give the traced reference fact: the drag threshold, the per-grip sizing edges, the empty-`autoFocus` skip, and `SetTexCoordModifiesRect`'s default.
  - Stock FrameXML line citations are checked against the stock 1.12 files and corrected. `ref-` file names become the stock file names.
- **Deviation labels.** "Deviation:" now marks only a choice with a reason. A surface that exists only for the retired Era addon target says so plainly: it is not 1.12.
- **Verification.** Every file strips to identical code, and `cargo fmt --check` is clean. Nine second readers compared every file old against new, restored the facts the rewrite had dropped, and checked each new citation against the code, the stock files, vmangos and the reference.

Behaviour differences the rewrite surfaced are filed as their own issues (#131–#142), and more are being validated. The comments here state what the code does. String literals are untouched; they are #92.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-25 01:58:49 +07:00
Sam Sung 8952d590e6 comments cite the reference by address, not by private note (#30)
Comments that pointed into the maintainer's private reverse-engineering notes (a note by name, a
path, a section or finding id, the analysis's own name for a client function, a process word) now
carry the fact itself, cited by the reference client's address, by vmangos file and line, or as
"the reference". Nobody outside could follow those pointers.

Comment text only, plus the test-assert and log strings that carried the same pointers. No claim
changes: a comment the notes have since corrected keeps its wording here, and correcting it is
separate work.

The two reference generators, `scripts/gen-reference-globals.py` and
`scripts/gen-reference-verb-events.py`, named the private notes' layout to find their inputs. They
now take the input files as arguments (`--capture`, `--framexml`, `--names`, `--extents`,
`--disasm`). Run on the same inputs, both write the committed tables row for row; only the two
header lines that named the old environment variable change.

Checked per file:
- the code is identical: each file with its comments stripped compares equal before and after; a
  changed string literal is compared under a mask that proves only literal text moved and every
  literal kept its line count;
- no client address the old text cited was dropped;
- a second reviewer checked every added address against its derivation;
- a detector for the notes' names, paths, ids, function names and process words finds none left;
- `scripts/gates.sh` is green.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-24 12:14:08 +07:00
Sam 84cd2336ab widget calls cost one index, and a reparent keeps the layout ledger
- a frame's __index is its kind's method table and the Region map's 19 shared verbs dispatch in Rust: a widget method call costs one table index instead of a Lua re-entry — the idle UI tick ~20 % lighter, client-wide (2310)
- SetParent names the subtree it moved instead of giving the layout ledger up: a pooled map note's recycle no longer re-derives the whole interface, and a Questie quest-log change's worst frame halves, 166 → 83 ms (2314)
- thirteen single-store windows — honor, talent wipe, the dialog verbs, scoreboard, battlemaster, battle map, book, mirror timers, minimap ping — register their handlers; 18 kinds leave the match (2313)
- the addon-enable RE lands: DefaultState is a seeded byte, the node set is the character list, and a character the store has never seen inherits nothing — 2311's one wrong branch corrected (2316)

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-19 17:10:44 +07:00
Sam 5af3a15d0e plate text settles, mobs stop sinking, and select goes with Lua 5.1
- a nameplate's name and level stop popping a pixel every other step as the plate slides, and the whole plate no longer jumps 19 px to the top of the screen on a rounding tie; the chat bubble takes the same fix (2172)
- creatures and other players stop sinking through the ground while the world is still streaming in, where a Stormwind patroller had been 31 yd under its street: a body our world cannot yet answer for holds the server's pose (2174)
- select and the string metatable are gone, as in 1.12's Lua 5.0: pfUI's heal prediction parses its messages with the right format, BuffCheck2's own select wins its fallback, and a method call on a string raises the reference's own error (2171)
- the camera's water collision comes back out for now: with the pivot a hair under the plane, a surface swimmer's camera snapped in and out against the waterline, so the boom ignores water again (2173)

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-11 21:03:05 +07:00
Sam 99b55f58ee a bad macro fails on its own, and script errors name their frame
- a macro with a Lua error fails on its own and lands in the script error channel instead of aborting the UI function that ran it; RunScript names its chunk by the source text, and a bad or empty argument is a quiet no-op (2136)
- a script error or debugstack frame names its handler as Frame:OnClick instead of a whole CreateFrame sentence, an inline <Script> block is no longer mistaken for the .lua beside it, and a handler's line numbers stop reading one too high (2136)
- GetAddOnInfo and its seven siblings raise the reference's own Usage and out-of-range messages, GetAddOnInfo("2") is the second addon, and assert(a, b) answers one value, as the client's Lua 5.0 does (2139)
- frillDensity and gxApi are real settings: pfUI's hdgraphic module reads world detail through frillDensity, its system tooltip names the live render backend, and the two spellings of the ground clutter knob stay one knob (2151)

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-11 20:54:29 +07:00
Sam 94945e8339 two addons that need each other load, and pfUI's memory row fills in
- loading two LoadOnDemand addons that depend on each other loads both instead of killing the client with a stack overflow; each is counted loaded before its own files run, as on the real client (2139)
- the memory report gets its second number, so AceAddon-2.0's memory line (36 copies in the corpus) stops raising and pfUI's panel prints a figure where it printed UNAVAILABLE; garbage collection takes a number and answers nothing, like 1.12's (2136)
- a disabled addon you have uninstalled keeps its row in AddOns.txt through a logout, and a hand-edited name keeps its spelling instead of taking the folder's case (2139)
- a loaded chunk's error lines name it the way the real client does, and a /console argument containing ]] no longer trips a syntax error the 1.12 lexer would raise (2136)

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-11 20:52:00 +07:00
Sam c343d236e9 cooldowns survive a relog, the MOTD prints, and lost channels come back
- a cooldown still running when you log out and back in keeps sweeping instead of vanishing, and another character no longer inherits the previous session's cooldowns (2116)
- the server's Welcome and Patch 1.12 lines print at login in system yellow, and a character whose General, Trade and LocalDefense had gone silent for good gets them back at the next login (2119, 2120)
- the stock Interface Options window loads hidden beside ours, so pfUI's options skin finds the real thing; the Auto-join Guild Recruitment Channel row has a real store, and a /reload no longer trips on its camera dropdowns (2115)
- the combat log words a power gain on the display scale, so MikScrollingBattleText shows +1 Rage where it showed +10; a 1.12 predicate answers 1 or nil rather than a Lua boolean, the test ColorPickerPlus makes (2117, 2118)
- a Lua error quotes a program element with a backquote the way 5.0 does, so AceLibrary's argument checks report their caller instead of raising inside the error path (2122)

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-11 20:50:37 +07:00
Sam 321bcbb393 the cooldown pie survives a /reload, and Bagnon's bags keep their order
- the cooldown pie, the GCD sweep, minimap pings and the map arrow draw again after a logout, login or /reload; they went blank until a restart, which read as OmniCC killing the cooldowns (2113)
- an addon's own font on a button label keeps its face, size and outline instead of being undone every frame, MikScrollingBattleText's reported look (2112)
- an empty label reads as nothing rather than an empty string, so Cartographer's map label keeps its colour; a slider thumb with no authored size takes its art's own size, so Dewdrop's Look'n'Feel slider moves (2109, 2110)
- Bagnon's saved bag list comes back in the order it was written, so the keyring stops jumping to the front after a restart; hovering a Bagnon bag costs a third of what it did (2111, 2114)

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-11 20:49:50 +07:00
Sam 99b5600e25 idle sits you down and camps you, and the addons anchor, parse and draw
- five idle minutes sit you down and flag you AFK, thirty log you out through the ordinary countdown; holding a key is idle, moving the mouse is not, and a swimmer stays afloat (2092)
- a knockdown no longer wedges: the landing froze the clip that held the base-animation lock, leaving a knocked-down player on their back for the session (2098); the perf cost pill starts hidden (2099)
- Lua is exactly 1.12's 5.0 — no vararg expression, no #, no %, the remembered table size — so Cartographer loads without errors and Mik's Scrolling Battle Text shows its text, in its own shipped font now that addon TTFs load (2101, 2102, 2103)
- a widget name is a Lua global for SetPoint and its kin, so Bartender2's bars spread out; a button's NormalText disowns its justify, the raise renumbers hidden frames too, and a missing toc file warns instead of erroring (2105, 2100, 2104, 2107, 2106)

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-08 16:35:03 +07:00
Sam 149a1beb47 the colour picker, guild charter, honour page and four more go stock
- the colour dialog is the reference's own `ColorPickerFrame.xml` — the window with the largest reach in the addon corpus (86 of 218 addons name it, 64 of those Dewdrop-2.0, so every Ace2 config menu's colour row opens it), and the guild charter, the guild registrar, the error toasts with the raid warning (which our copy had declared with NO scripts at all, so the big centre text and its sound had been inert scenery), the honour page, the quest timer and the stack-split spinner follow — each a toc line and a deletion
- the swaps caught our own bugs on the way: the registrar's two service rows were hidden by a template modelled on the quest list's pooled rows, leaving a bare "Available Services" heading over blank parchment; the stack spinner CLAMPED a too-big digit where the reference ignores it (37 against a 5-stack leaves the 3 standing, `StackSplitFrame.lua:72-85`) — a divergence with a test defending it; and 1.12's Lua-5.0 `arg`/`arg.n` varargs turn out to work in this VM (mlua's vendored 5.1 has `LUA_COMPAT_VARARG`), which unblocks every stock file written in that idiom
- 42 test modules carried five near-identical private copies of a disk-only XML loader that structurally cannot name a chain file; they are one shared reader now (733 lines out), with a strict variant that fails on an unknown-template WARNING — the case where a frame builds with none of its art — which is how the registrar bug was caught on the first window after

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-02 16:58:29 +07:00
Sam b5bc569156 the addon arc: the AddOns folder opens
- benilla loads real 1.12 addons from Interface/AddOns — TOC, XML and Lua through one loader, with per-addon saved variables, Bindings.xml and the lifecycle events addons expect
- both AddOns screens are in: the character-select list with per-addon enable state, and the ESC menu's in-game list
- the API surface is measured, not guessed — a corpus harness runs hundreds of real 1.12 addons and ranks exactly which globals, templates and verbs they demand
- the Lua dialect is the client's own, read off the binary — 5.0 semantics with the 1.12 additions, and UI source files are bytes, not UTF-8

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-11 18:18:31 +07:00