Commit Graph
17 Commits
Author SHA1 Message Date
Sam SungandClaude Opus 5.5 eba558a5d2 Comments in benilla-app, the UI script layer: one line of fact each, no history, no record numbers (#184)
Part of #41: the first of five `benilla-app` pieces. This one is the UI script layer: `ui_script` with its test harnesses, the text engine and layout (`ui_text`), the UI pass and the UI model panes. Its comments are rewritten to the rule in `docs/METHOD.md`, which is what the code does and the reference fact behind it, in a line. 22,041 comment lines become 7,133.

- **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:
  - On a fresh login the reference fires `PLAYER_LOGIN` and `PLAYER_ENTERING_WORLD` from the player's create (`0x5deb60` → `0x4908c0`); only a `/reload` goes through `0x490168`. The comments now state both paths.
  - `ComputeStep` (`0x5ca2d0`) applies negative pair kerns and rounds up. It does have a kerning term.
  - A fallback icon global and the retired `UiPanels.xml` panels no longer exist. The comments that named them now describe the stock FrameXML mechanism that replaced them.
  - Stock FrameXML line citations are checked against the stock 1.12 files and corrected, and several misattributed files are fixed (`MainMenuBarArtFrame` lives in `MainMenuBar.xml`).
  - Dozens more turned up on the way: docs sitting on the wrong item, removed functions, stale counts and links.
- **Deviation labels.** "Deviation:" now marks only a choice with a reason. An unbuilt behaviour says so plainly.
- **Verification.** Every file strips to identical code, and `cargo fmt --check` is clean. Five 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 (#183 among them). 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 08:20:21 +07:00
Sam SungandClaude Opus 5.5 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
SamandClaude Fable 5.1 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
SamandClaude Fable 5.1 c965b5425d the tooltip and five windows go stock, and the battleground keeps score
- the tooltip is the reference's own file: `GameTooltip.xml` loads off the chain, ours is deleted, and every verb it calls was already bound, so this is a plain swap; retired with it: the `$parentThicken` plate fill that thickened the plate from the art's ~73% to ~84% opacity — the reference's plate is the raw `UI-Tooltip-Background` tint, and that is what ships; the one engine fact the transcription had been hiding: the reference's instance declares no size, and a frame with one anchor and no size resolves to NO rect under the reference's own layout law — our declared size had been a harness crutch (1968); and the dressing room goes stock with `<DressUpModel>` as a widget kind (factory `0x495c00`): a `PlayerModel` plus its own `Undress`/`Dress`/`TryOn`, where `Undress` strips the body and not the hands, and Close is read off the window since the stock OnHide queues nothing (1969)
- the mail window and the auction house are the reference's own: `MailFrame.xml` loads off the chain and brings the stationery picker, invoice pane and autocomplete ours had left out; the stationery family is built off wow-re's carve over a list computed off `Stationery.dbc` rows × the player's bags (`0x622270`, not the bank); the selection rides `CMSG_SEND_MAIL` field 6 and a send with none silently aborts; its two events fire where the client fires them (1970); `Blizzard_AuctionUI` loads on demand from the `AUCTION_HOUSE_SHOW` arm, and three root fixes its Lua surfaced: `GetAuctionItemClasses()` is static — read at the addon's load, before any session, so the class tree is a login-scoped push; `SetAuctionCompareItem` (`0x535d70`) on the vendor compare's one body; `NEW_AUCTION_UPDATE` resets the create form; its dressing-room pane shares the app's one room (1971)
- the battleground keeps score: `WorldStateFrame.xml` loads off the chain and ours is deleted; the stock file is three things where ours was one: the readout, the capture bars, and the battleground scoreboard this client never had, built off wow-re's round — `MSG_PVP_LOG_DATA` both ways (throttled to 5000 ms client-side, `0x4aa170`) and `CMSG_LEAVE_BATTLEFIELD`; eleven score verbs over a board the app pushes, where the filter is a SORT, not a compaction — team first, killing blows descending, deaths ascending, honor descending, name — so the filtered count shrinks while `GetBattlefieldScore` still reaches every wire row; `HIDE_OUTDOOR_WORLD_STATE` joins the options uvar block, a capture point is a bar, and the scoreboard and battlefield-minimap toggles become bound specs at the install's own `SHIFT-SPACE`/`SHIFT-M` (1972)
- the trade skill and craft windows go stock as `Blizzard_TradeSkillUI`/`Blizzard_CraftUI` on demand, from the reference's own UIParent arms; our two transcriptions are deleted; the four item-link verbs are built off wow-re's carve on the client's link builder (`0x52adb0`) — zero values on any miss, `GetTradeSkillReagentItemLink` raising Blizzard's own typo'd Usage, kept, and `GetCraftItemLink` the `|Henchant:` link in fixed white; `SetTextColor`'s channels coerce nil to 0 on FontString, Font and Button where ours had raised (1973); and the Inspect, Talent, Macro and Raid addons load on demand — `benilla.toc` lists no `Interface\AddOns` row, and below level 10 the talent addon is never even loaded; the gates walk every reached addon and found `Blizzard_GMSurveyUI`'s four engine verbs nothing answers, reachable only through `GMSURVEY_DISPLAY`, which nothing fires (1889; 1967)

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-04 20:59:04 +07:00
SamandClaude Fable 5.1 058ca4b6c8 every dialog is the reference's own, and the trainer loads on demand
- every dialog is the reference's own: `StaticPopup.xml` + `StaticPopup.lua` load off the player's chain, and 0308's engine with its 37 dialogs leaves `UiPanels.xml`; all 76 of the reference's dialogs are the stock table's, 28 of which no file of ours had ever registered (the resurrect family among them); the nine hidden listener frames that existed only because benilla once had no `UIParent_OnEvent` come home to it verbatim from UIParent.lua, and the seven files that were nothing but a dialog and its driver are deleted; what the swap surfaced: the reference capitalises the countdown's unit word ("5 Minutes until release") where ours had lowercased it, and ESC in the typed delete confirm's box is swallowed — the entry names no escape handler; arms for events this engine never fires (PLAYER_SKINNED, TRADE_REQUEST) wait on their feeds rather than being armed blind (1960)
- the social window and the unit menus are the reference's own files: `FriendsFrame.xml` loads off the chain and our transcription is deleted — its twelve dialogs re-homed, `FRIENDLIST_SHOW` fired as the answer to an explicit `ShowFriends()`, and `Get`/`SetLookingForGroup` a client-side flag until their bodies are carved; `UnitPopup.xml` loads off the chain, our row catalogue and its driver frame go, and nine verbs are built for it — `HasFullControl` off the player-control flag the reference reads at `0x51a158`, `UnitPlayerOrPetInParty`/`InRaid` over a new unit owner, and the six pet one-shots, each pressing the bar's own reaction or command slot word through the same latch and `CMSG_PET_ACTION`, confirmed by wow-re's carve; the Guild Leave/Promote confirms 1958 believed nothing registered were our social file's all along, and the duplicate went with it (1958, 1959)
- the trainer loads on demand: our `TrainerFrame.xml` is deleted and no row replaces it — `Blizzard_TrainerUI` loads off the player's own chain through the reference's `ClassTrainerFrame_LoadUI`, and the LoadOnDemand `Blizzard_*` addons are registry rows read off the chain; the timing IS the mechanism: the list builder writes the state-filter mask to 3 on every `SMSG_TRAINER_LIST` (`0x4d75d9`) and the stock addon pushes its saved filters exactly once, on its own ADDON_LOADED — which fires on the session's first trainer, after that packet, so the saved filters win that open and an eager load would never have applied them; the loader holds an anchor to a sibling not built yet and applies it once the subtree exists; and `UNIT_FLAGS` fires only on a change between two snapshots — wow-re's trio found the per-field watch bridge runs no notify pass on the create leg, correcting 1953 (1957)
- the additive window, built and withdrawn the same hour: under `BLEND_ADD` every additive particle draw commutes with every other, so same-key additive draws can be regrouped exactly — built in the effect lane's merge walk and measured on the crowd rig (Stormwind, forty partybots): the adjacency merge already folds about half the effect items and the regroup found two more folds in a frame of ninety-three, so the pre-regroup walk is what runs; what stays: an `fx=` items/merged census on the FPS probe line, a `DRESS_PART` line per drawn part of the self body on the dress census, and the regression the A/B uncovered: 1948's stock chat migration dropped the drain's plain-line sender, so every `WOW_PROBE_CHAT` rig — the crowd rig's forty `.partybot add`s among them — had gone silent on the server; a probe's slash-less line reaches the wire as SAY again (1955)

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-04 20:57:24 +07:00
SamandClaude Fable 5.1 fd595b7119 the quest windows go stock, and the 20 ms frames were mis-split pairs
- the quest giver's dialog and the quest log are the reference's own `QuestFrame.xml` and `QuestLogFrame.xml`, run off the player's chain at the reference's own toc seats; our 1366-line and 1999-line copies are deleted, and the verbs the stock files call are built — the four `GameTooltip` quest-item and reward-spell setters, the reward spell itself (parsed on all three packets and dropped by the model until now), and two verbs; the detail pane could never scroll because `UpdateScrollChildRect` measured a frame late where the reference's measure is synchronous, so it measures through the installed font engine now; and ten things the reference does that ours did not, each found by a test that had enshrined ours — a shift-click never selects, an empty log hides the whole detail pane and says "No Active Quests", the abandon confirm lives in the popup registry (1944)
- the quest bindings' law, read off the binary and folded back: no 1.12 packet carries a quest background material — `GetQuestBackgroundMaterial` (`0x502230`) forks on the dialog's SOURCE object, an item answering its template's PageMaterial, a GameObject its template data, a creature nil (FrameXML's "Parchment"), the id naming a `PageTextMaterial.dbc` row whose six words are nowhere in the binary; its twin `ItemTextGetMaterial` has the same body, so the reader window already held every piece and the giver's feed runs the same resolve; `QuestChooseRewardError` is game-error row `0x98`, and the row plays `igQuestFailed` first, which the verb now queues; the reward-spell getters' third return is `Spell.dbc` Attributes bit 5 (1161 of 22357 rows set — craft-cast spells set, `Pattern:` teaching spells clear), read off the catalog now (1946)
- the "20 ms frames" of a raid, chased to their number: the probe's worst frames now carry their churn (entities, assets, first-play sound decodes, live particles, the GPU reading) and in a Blackrock raid with sound on every one of those read flat; then the same window on the PACED clock — under vsync with pipelined rendering the raw delta is mis-split into long/short pairs that sum to exact refresh multiples, so an alone Stormwind leg read 115 of 300 frames over budget with cpu and gpu both at their means, while the paced clock read 0 skipped frames in every leg; what remains real in the raid is `cpu_p99` at 22–23 ms with sound on; and every submesh the streamer spawns now carries why it is an entity, counted per reason — 5.8k resident ADT-doodad submeshes at the Stormwind auction house, 5.3k of them hidden, three prop families the retained pass declines by rule, each riding every per-`Mesh3d` sweep for ~0.4 ms of the alone frame (1947)
- a raid's dozen voices cost the mixer ~1.5 ms of every 60 Hz frame: upstream kira spatializes every frame — normalizes, the attenuation curve and a dB→amplitude `powf` per frame per spatial track, two more `powf`s for the volume tween, ~1.7 M `powf`s a second at 48 kHz × 12 tracks for gains that change imperceptibly across a chunk — so kira 0.12.1 is vendored with one patch: the spatial gains and the volume × fade amplitude are evaluated at the chunk's two ends and interpolated across its ~10.7 ms, the granularity FMOD 3, the reference's own mixer, updates them at; nothing a listener can name changes (1945); and rig poses are evaluated in parallel over rigs — each reads its shared clips and writes only its own pose, and a raid's ~400 live rigs were 0.4 ms of one thread walked serially on the main thread's critical path (1947)

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-04 20:55:12 +07:00
SamandClaude Fable 5.1 f0d1bacf0a the help window is the reference's own, and a ding carries nine gains
- the help window is the reference's own `HelpFrame.xml`, and ours was less than half its size, so this is mostly arrival: the category list, the per-category GM and harassment pages, the stuck page, the bug report, the PvP policy line; four things we had built go with the swap — one-click filing from Home, the Home unstick button, the downed-queue refusal message, and ticket abandonment, a capability loss rather than a look change, since `AbandonTicket` exists in neither the binding table nor the 1.12 FrameXML corpus and any return of it goes on top of the stock window; `GMSURVEY_DISPLAY` arrives with no producer, a real 1.12 event (`SignalEvent` `0x5e797b`) whose whole UI is a LoadOnDemand addon not on our chain; and the stock file needs two orderings ours did not, the micro-button row before its GM status ask and the buff frame before its repoll timer (1889, superseding 1687)
- the cast bar, the action-button regions and the font registry are the reference's own files too: our `CastingBar.xml` was `CastingBarFrame.xml` under another name, with the literal "Failed" where the reference reads the `FAILED` GlobalString (1886); `ActionButtonTemplate.xml` seats above our `ActionBar.xml` because the later-registered template wins, and it declares zero scripts, so the regions migrate while the handlers stay ours until `ActionButton.lua`'s verbs do (1887); `Fonts.xml` is manifest entry 0, all 51 fonts match by name, and its one real difference, `ITEM_QUALITY_COLORS`, moves to UIParent where the reference declares it (1888); the harnesses were the real cost — those reading our files off disk could not name a chain file and now read through the manifest's own rule — and the event-producer gate, having cried wolf at the cast bar's `SPELLCAST_INTERRUPTED` fired through a variable, now matches the fired tuple's shape
- of the 189 events benilla fires, three are not in the client — `BAG_UPDATE_DELAYED` (a Classic Era name), `LOOT_UPDATE` and `UPDATE_LOOT_ROLL` (invented here, no listener anywhere) — found against the reference binary's own string table, and a gate now fails any fire of a name the client cannot dispatch unless it wears a `BENILLA_` prefix (1883); two payloads the reference gives that we did not: `UNIT_HAPPINESS` carries its unit token, without which no `UNIT_*` consumer reads it, and `CHARACTER_POINTS_CHANGED` carries the point deltas `ChatFrame.lua` compares unguarded, so nil raised (1884); and `PLAYER_LEVEL_UP` carries all nine — level, health and mana gain, talent points (not on the wire: the client derives `(newLevel >= 10) ? 1 : 0` at `0x5e407c`) and the five stat gains — matched to the ding by level, a demotion's absent gains sent as zeros since a nil raises where a zero reads as no line
- the chain gap report could not run — one of its six probes had no player seated where a stock addon formats `UnitName("player")` at load, the other five each carrying an identical copy-pasted seed — and the repaired instrument prices each window's cost: 13 stock files load clean with nothing missing (the action bars, the cast bar, the fonts, the help, friends, game-menu and sound-options windows among them) and the near ones name their missing verb, with "loads clean" still not "swapped" (1885); and `UpdateNameplates`, recorded as the missing engine verb blocking the UIParent keystone, is FrameXML — defined in `UIOptionsFrame.lua`, absent from the binding table, its whole body four nameplate verbs that are already ours — so it is twelve lines transcribed into our options frame, the reference's own Show-then-Hide no-op included (1890 corrects 1878)

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-04 20:50:36 +07:00
SamandClaude Fable 5.1 7e68267395 the raid and reputation panes go stock, and a faction header folds
- the raid and reputation panes are the reference's own files: two manifest lines replace our `RaidFrame.xml` (83 of 84 frame names were already the reference's; the tear-off pullouts arrive) and one replaces our `ReputationFrame.xml`; the raid swap surfaced a loader defect (a font object inherited one level down was the 26 unexplained warnings), rehomed `RaidFrame_LoadUI` and two popup dialogs, and reproduces one reference DEFECT: an emptied lockout list keeps its last row painted (1874); the reputation swap moved the WATCH BAR out of `ActionBar.xml`, where it would have shadowed the chain's own, and exposed an ENGINE gap: `CollapseFactionHeader`/`ExpandFactionHeader` fire `UPDATE_FACTION` (`0x4d5dab`) and ours fired nothing, so with the stock pane repainting on that event alone, a fold painted nothing and the header kept its minus — invisible while our own file repainted itself (1875)
- a wanted poster is a questgiver on the wire as a creature is, and benilla never asked about one; the RE round came back in two halves: the reference DOES send `CMSG_QUESTGIVER_STATUS_QUERY` for a GameObject, gated on `GAMEOBJECT_FLAGS` bit 2, seen in 20 of 62 sniffed sessions — and it can never render the answer (the status handler's typemask excludes a GameObject, its status slot lies past the object's end, and no poster, sign or plaque carries attachment 18); vmangos DOES answer, so the sweep gains a GameObject arm on the reference's own gate and the apply side refuses a non-unit guid, without which a gold `!` would hang over a poster no 1.12 client draws; two shipped claims fall with it (`0x5eb3c0` is the FULL re-query sweep; a status never suppresses a GameObject's minimap dot), and `WOW_PROBE_GOQUEST` at the Goldshire wanted poster reads the server's 1 then 5, both refused (1872)
- the money entry comes off the chain: Trade, Mail and Auction switch to the reference's `MoneyInputFrameTemplate` and its verbs, and our `BenillaMoneyInput_*` kit retires — it was the exact answer while benilla fired `OnTextChanged` synchronously inside `SetText`, and the engine now raises it deferred and coalesced, matching `0x77d3e0` (1831), so the reference's `expectChanges` guard works and our bracket flag was a duplicate; most of the 430 deleted lines are verbatim art — all three windows carried an inline copy of the template's three edit boxes, AuctionFrame a whole second copy; one visible change: TradeFrame now makes the reference's own `MoneyInputFrame_SetMode(this, "compact")` call, which tightens the trade money boxes (Gold 58→56 wide, Silver's offset 26→22, Copper's 16→11), and two stale claims in the kit's comments are corrected, and a verb nothing called goes (1882)
- the `UIFrameFlash` family is transcribed — six FrameXML names from `UIParent.lua`, which we do not load — unblocking SpellBookFrame and HelpFrame, which called it into silence; re-arming a flashing frame is a RETURN and `-1` flashes forever (1879); UIParent is recounted — `UpdateNameplates` and the `*_Show`/`*_Hide` family around it are FrameXML, not engine, missed by a survey that skipped the LoadOnDemand addons — so its engine surface is four verbs, not a wall: `GetLocale` answers `enUS`, `IsMacClient` answers nil (the whole verb on the PC build), and `CheckReadyCheckTime` and `RequestBattlefieldPositions` are the two it waits on (1880); and `BasicControls.xml` comes off the chain by pure deletion — ours differed by nothing but line-wrapping and one comment — with `FailedAddOnLoad` and `UIParentLoadAddOn` moving to `UIParent.xml`, their reference home, below their four callers (1881)

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-04 20:50:12 +07:00
SamandClaude Fable 5.1 b45bce8184 bindings answer the reference's shapes, and the panel kit goes stock
- four return shapes were wrong — `UnitPowerType` returns ONE value in 5875 (the Era `(type, "RAGE")` pair does not exist, and its miss arm pushes the NUMBER 0, which `UnitFrame.lua:122` indexes `ManaBarColor` with), `UnitName` returns `(name, server)`, `GetTexCoord` returns EIGHT (ours four — a shape that exists nowhere, with zero call sites in FrameXML, so only the binary could have caught it), `GetLootMethod` answers `freeforall` ungrouped — the fifth right-name-wrong-arity finding in two days, so wow-re's `binding-shapes.tsv` (1722 rows over all 82 registrar tables) is vendored and a gate probes every binding's arity against it: 313 probes, eight divergences (seven global, one widget); `GetBuildInfo` pushed a fourth value no 1.12 client does (458 corpus sites take one, the four that destructure a fourth read nil on the real client), `GetAddOnInfo` RAISES on a numeric index, `Model:GetFogColor` is a packed `0xAARRGGBB` dword with no unset state, and the five miss branches are the reference's exact tuples
- the panel-template kit is the reference's own `UIPanelTemplates` pair (our 18 templates were a strict subset — `TabButtonTemplate` and the `ScrollingEdit_*` family arrive, which unblocks the macro window and HelpFrame), and the swap found two structural facts: `FauxScrollFrameTemplate` is a `<ScrollFrame>` while every instance we declared was a `<Frame>` (fifteen elements across twelve files), and an instance `<OnLoad>` REPLACES the template's — four FriendsFrame lists set `updateFunc` in their own OnLoad, so `ScrollFrame_OnLoad` never ran and guild/friends/ignore/who had been silently painting nothing behind a `frame.offset or 0`
- the options widget kit (`OptionFrameBoxTemplate`, `OptionsButtonTemplate`, `OptionsCheckButtonTemplate`, `OptionsSliderTemplate`) comes off the chain too, giving back the reference's own per-widget hover; one template of ours stays because `UIOptionsFrame.xml` is not built here, and the lesson is general — when a file SHRINKS rather than dies, every harness that named it gains the chain entry beside it, not instead of it

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-02 17:06:36 +07:00
SamandClaude Fable 5.1 7308046d60 the screen warps underwater, and the ocean darkens with depth
- the screen warps underwater: submerged, the reference runs a second pass list whose third pass is `FFXGlowWave` (`0x6cb1f0`), binding a 128×128 two-channel sine bump map that displaces both the screen and the blur texcoords by 3.0 full-res pixels — uv rotated 10°, scaled W/128 × 0.88·H/128, two phases at 3174 and 2805 ms; wow-re had carried the swap as "GlowWave, or a duplicate Glow" and the cross-check settled it (the two arms are mutually exclusive and the plain-Glow arm is unreachable on both backends; lava and slime warp too, and a ghost's death pass replaces the glow outright); a dry frame binds the same pipeline object as before this existed, and the phases advance live at 0.313/s and 0.355/s against a predicted 0.315 and 0.357
- ocean is a fifth submersion state — 96.8% of every wet sub-tile in the shipped corpus, so essentially all open water — and it alone runs a depth ramp on the light: `t = clamp(eye.z, −30, 0)`, ambient at `(k+1)/2`, diffuse at `k/4 + 3/4`, exactly k = 0 at −30 yd, gated on the full dword `== 1` at `0x6d2821` (the ramp does NOT drive the fog colour — that store is dead, overwritten before submit); the sun and moon glare fade over a 10-yard depth ramp applied to the slew TARGET, not the drawn alpha — a read one indirection out that two notes had published a verified negative on; the MCLQ fishable bit (0x40) is deliberately unread, since `0x69b5d0` has zero callers in the image and fishability is the server's verdict
- the dropdown kit is the reference's own `UIDropDownMenu.xml` (one manifest line for 1150 lines of ours, `DropDownList3` gained, and two fixtures that only worked because our copy was more forgiving); `UnitFactionGroup` returns the English name AND the localized one — ours returned the localized string twice, and the first return names a TEXTURE in every stock consumer (`UI-PVP-`..factionGroup), so on a non-English client every one of them named a file that does not exist

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-02 17:05:57 +07:00
SamandClaude Fable 5.1 9105fa72a4 the flight map goes stock, and vendors refuse in 1.12's own words
- the pet stable and the flight map are the reference's own files: `TaxiRouteFrame` maps to a plain Frame (factory `0x495ba0` allocates the base size, the ctor adds no field, no new virtual, no method table — and `GetObjectType` is not overridden, so its own kind would have been the divergence), and the swap found three silent behaviours — the close button did nothing (an unknown `inherits=` is a WARNING, so it loaded as a bare button), the "no paths" line drew empty, and the title is READ off `UnitName("npc")`, not received; the WMO skybox rides the interior crossfade — one weight (`[0xce9bdc]`, the same number the MFOG lerp rides), a 4 s alpha fade, so a skybox the flood publishes through a doorway draws at weight 0 instead of popping in whole
- a widget predicate answers the NUMBER 1 or nil, never a boolean: eleven of them (`IsShown`, `IsVisible`, `IsMovable`, `GetChecked`…) move to the 1.12 shape — the reference proves it in its own source (`tostring(this:GetChecked())` saved and read back `== "1"`; `tostring(true)` would never match and buff timers would never appear), 21 corpus sites compare directly (`IsVisible() == nil`, `GetChecked() == 1`), and one of our own tests had the guild rank editor sending `true` where a real client sends 1
- the vendor's refusals are the reference's table: `SMSG_BUY_FAILED`/`SMSG_SELL_ITEM` route through `0x5dcd60`/`0x5dd1f0`'s switches, six lines were wrong (code 3 printed "That vendor can't be found." — vmangos's identifier — where 1.12 prints "That merchant doesn't like you."), silence is now expressible, and keying them gives the vendor a voice (`ERR_NOT_ENOUGH_MONEY` carries error-speech line 0x28); the bank's three ids were right and its "purchase failed (n)" an invention; the logout refusal is one key, `ERR_LOGOUT_FAILED`, for every non-zero reason; the two mail codes we said had no string have one (`ERR_PLAYER_WRONG_FACTION`, `ERR_RESTRICTED_ACCOUNT`) and a sent mail says `ERR_MAIL_SENT` in yellow; a test runs the chain's own `GlobalStrings.lua` and requires non-empty text for all 193 `ERR_*` the workspace names
- a clicked quest timer no longer raises — stock `QuestTimerFrame.lua` calls `QuestLog_SetSelection`/`QuestLog_Update`, which existed nowhere in this tree; our quest log owns the reference's two names now, which also shrinks the delta when that window itself migrates

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-02 17:05:15 +07:00
SamandClaude Fable 5.1 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
SamandClaude Fable 5.1 3cce6f5ac3 seven more windows are the reference's own files
- seven more windows run off the player's own patch chain: the durability shield (`DurabilityFrame.xml`, with a Rust-side repair for the reference's own stale side-glyph inset the director caught on screen), `Localization.xml` + `GameTime.xml` (so `LocalizeFrames` finally runs from `VARIABLES_LOADED`, and the clock's 24-hour flag comes from where 1.12 sets it), the chat-link tooltip (`ItemRef.xml` — draggable now, and its shift-click arm fills the friend/ignore/who boxes as the reference's does), the mirror timers (`MirrorTimer.xml`, which exposed that our `STATICPOPUP_NUMDIALOGS` was 2 against the reference's 4, so a third breath/fatigue/feign bar could never be claimed), the zone splash with the fading kit, the item-text reader and the combo-point dots — each under the reference's published frame names, which is what an addon reaches for
- `AddMessage` swallows a text it cannot use, silently, as the reference does: `0x795590` is a `lua_isstring` gate whose failure edge jumps straight to the epilogue — no line, no error, no record — and stock FrameXML takes that path: a full keyring calls `AddMessage(NO_EMPTY_KEYRING_SLOTS, …)` and no such GlobalString exists in 1.12, so it is a dead click on a real client where benilla put a script-error dialog on it; byte-verified by a four-worker cross-check in wow-re, and NOT generalised — a bad r/g/b/a still adds the line opaque white, only a bad text shows nothing

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-02 16:58:13 +07:00
SamandClaude Fable 5 c4f432d0c3 the world map blips are the reference's, and particles go untinted
- the world map speaks the reference's names: WorldMapTooltip is declared (six corpus addons index it; pfUI dies on it at file scope), the blackout frame takes the reference's spelling BlackoutWorld, and the four hand-written party blips become the reference's own unit-blip templates — all 44 blips as instances, each with its published $parentIcon, the name pfUI recolours group blips by class through; the 40 raid ones are declared but not positioned yet, named in the OUT list rather than faked
- the templates addons build their own buttons from are published: ItemButtonTemplate, ContainerFrameItemButtonTemplate and the bag-slot chain — most of the handler scripts were live the whole time (this client executes the reference's own container and paper-doll code off the player's patch chain), so what was missing was mostly declarations, not behaviour — the bank arm stays out and is named as the omission it is; OptionsFrameSliders becomes real, with the three Graphics rows reading it and re-reading on show, so an addon's write to a slider's bounds actually moves the slider; and the template census that had ranked these at "zero demand" learns to see a local bound to a literal — its table went from 3 rows to 7
- the bindings answer in 1.12's own shapes: Button:IsEnabled() answers the NUMBER 1 or 0 (0 is truthy in Lua, so the reference's own == 0 tests got false forever, and three of our files had hand-worked around the divergence rather than fixed it); the constructors' string arguments are four shapes, not one rule — pfUI passes a Button where a template name goes and the reference constructs the FontString and ignores it; SetInventoryItem returns THREE values, the reference's own paper doll destructuring repairCost; UnitIsVisible is object presence and nothing else (57 bytes, one branch, no distance — an out-of-range party member is exists-yes, visible-nil); the tapped pair reads the two dynamic-flags bits, and its repaint wire fires UNIT_FACTION on the tap bit — the half a passing predicate test never sees; UnitIsPartyLeader is two ORed legs covering disjoint failures (a held stranger leading their own party, and an out-of-range member with no object to read a flag from); and the four nameplate verbs take no argument and return zero values
- the ghost's wisps compose onto its body instead of over it — the four emitters drew at full strength over a body at alpha 0.5, and now inherit the instance alpha down the attachment chain the way the reference recomposes it per frame; the residual we had parked ("the wisps should inherit the tint too") is REFUTED at the bytes: a particle batch commits hardcoded white RGB, and even that never reaches the fragment — particles are never tinted, only the alpha crosses, applied to the alpha byte alone — so the shipped shader split was already right and no code changes

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-31 20:15:16 +07:00
SamandClaude Fable 5 ab235bad6e the target-of-target frame, and talents can be unlearned again
- the target-of-target frame and its option: 1.12's frame with its five display modes, fed one hop off the selected unit's own target field through the same read `/assist` runs, in four feeds (snapshot and transitions, the debuff buttons, the portrait booth, TargetUnit's click arm); ships off, as 1.12 does, on its own pair of saved globals
- talents can be unlearned again: the trainer's `MSG_TALENT_WIPE_CONFIRM` had no handler since the wipe flow was deferred, so the gossip line closed the menu and did nothing — the question is an NPC session (walking away retracts it), the popup shows the cost on the StaticPopup money variant, Accept answers it behind the client's own purse check
- Sprint's sparkles hang in the air behind you along the trail instead of collapsing into your torso: ride-vs-trail is the emitter's own file flag 0x10, not the host class — the finding wow-re returned eighteen days ago and nobody folded; the particle dump names the two flag bits it had been mis-reporting
- `/sleep` takes both movement masks (the strictest posture), correcting the day's sit gate which let you lie down on a lake bottom while `/sit` was refused; a Lua-driven selection (TargetUnit on an attackable token) starts the swing exactly as a click does, through the one select path

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-25 18:40:16 +07:00
SamandClaude Fable 5 eeb607e5e6 the raid tab lands, and sounds take the reference's voice buses
- the social window's fourth tab, Raid: the eight-subgroup grid over the roster, drag a member between subgroups, Convert To Raid, promote / demote assistant, uninvite, Ready Check with its popup, and the Raid Info flyout on the new `CMSG_REQUEST_RAID_INFO` / `SMSG_RAID_INSTANCE_INFO` wire (byte-golden against vmangos, an empty answer decoding as an empty list); `raid1`..`raid40` unit tokens, and `/partytest raid` stages a roster for a solo look
- an imbue pressed with an empty weapon hand says "Your weapon hand is empty" instead of raising a cursor — the attribute bit has two readers in the reference and the second is the error (corrects the day's first cut)
- sounds route onto the reference's own voice buses with its per-bus caps (the 0x87ce60 table, pinned as bytes): weapon impacts and clangs share four voices, footsteps six, the attacker's grunt one, the victim's injury two — so a pack swinging together makes about a dozen voices where it made dozens

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-25 18:22:17 +07:00
SamandClaude Opus 5 9a184d3476 the guild window opens: roster, ranks, notes and the message of the day
- the social window's third tab is live — the roster in both its views, the member card with its promote/demote/remove verbs, the rank editor's thirteen permissions, the guild information board, and the invite, leave, kick and note dialogs behind them
- setting your hearthstone at an innkeeper now asks before it takes and says so afterwards, and the innkeeper's gossip lines get their own icons back
- unavailable talents grey out, and every greyed icon in the client now goes through the same luminance fold the original used
- the buff tooltip's remaining-time line reads gold with the client's own hour/minute ladder, the macro editor takes a shift-click to paste a spell, trainer rows repaint after a purchase, and a long book page stops flickering its ellipsis

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-16 17:38:54 +07:00