Roth UI - Changelog
===================

Version 3.1.1 - Taint Regression Hotfix & Codebase Audit Pass
--------------------------------------------------------------

OVERVIEW — WHAT SHIPPED IN 3.1.1:
• Buff/debuff positioning (modules/MovableBuffs.lua,
  modules/MovableDebuffs.lua): restored the hooksecurefunc + dirty-flag +
  OnUpdate design (no SetPoint/ClearAllPoints replacement — avoids GameMenu /
  CompactRaidFrame taint). Lazy-created AuraContainer now gets hooks installed
  on retry so icons stay on Roth anchors across instances and BGs.
• Roth_UI_Protection.isLoggingOut (embeds/rLib/core.lua, FixBlizzBarNil.lua,
  embeds/rMinimap/core.lua): flag now clears on PLAYER_ENTERING_WORLD so it
  does not latch true forever after the first load screen (was blocking
  movable aura re-anchor, oUF_Smooth, framefader, rMinimap re-apply).
• Mid-combat aura drift: removed InCombatLockdown gates from the movable
  aura ApplyAnchor / OnUpdate path so Blizzard grid layout cannot leave
  debuffs at default TOPRIGHT until combat ends.
• ShinyBuffs (embeds/Roth_ShinyBuffs/Roth_ShinyBuffs.lua): single "Font Sizes"
  UI drives buff + debuff duration/count text; SyncFontSizes migration;
  aligned defaults.
• rInfoStrings (embeds/rInfostrings/core/core.lua): Level Time / Total Time
  below minimap button bar; XP/rep line hidden at max level (rep math /
  MAXED OUT audit documented in-file); sub-max XP/rep hangs below time block.
• rChat (embeds/rChat/core/core.lua): reclaimChatBottomGap removes dead strip
  below chat when editbox is anchored above the frame (absolute floor pin,
  idempotent across /reload).
• rMinimap Alt+Z / minimap fixes; codebase audit pass (compat, tooltip typo,
  zoom hooks, init_coordinator errors, ShinyBuffs debug gating, etc.);
  BugSack triage narrative unchanged below.

DEFERRED / FUTURE WORK (NOT IN THIS RELEASE):
• Hook Blizzard Edit Mode together with Roth's custom unlock (/roth unlock*,
  drag overlays) so chat bottom-pin vs manual placement, cast bar drag frames,
  and buff/debuff anchors can be tuned from one workflow — pending follow-up.

RCHAT — RECLAIM EMPTY EDITBOX-RESERVATION SPACE BELOW CHAT FRAME:
• Symptom: Empty vertical strip between the bottom of the chat frame
  and the bottom of the screen. Blizzard's default layout reserves
  ~25-30 px there for the editbox, but rChat moves the editbox to
  ABOVE the chat frame (eb:SetPoint("BOTTOM", self, "TOP", 0, 22)) so
  the bottom strip became dead space.
• Fix: New reclaimChatBottomGap helper called at the end of skinChat
  for every chat frame. Pins the chat frame's bottom edge to an
  absolute floor (CHAT_BOTTOM_FLOOR = 5 px above UIParent.BOTTOM)
  rather than subtracting a relative delta — this is critical because
  Blizzard saves chat dimensions across /reload via
  FCF_SavePositionAndDimensions, and a relative delta would
  accumulate height every session. The absolute-floor approach makes
  subsequent skinChat passes no-ops once the frame is already at the
  floor.
• Behavior: For bottom-anchored chat frames the bottom anchor's y is
  shifted down to the floor and height grows by the same delta so the
  top edge (and the editbox above it) doesn't move. For top-anchored
  frames, height alone grows so the bottom extends down toward the
  floor. Wrapped in pcall and guarded against missing GetPoint /
  GetBottom returns.

INFOSTRINGS — XP/REP LINE RELOCATED BELOW LEVEL TIME / TOTAL TIME:
• Anchor chain reorganized so the f3 XP/rep line hangs from f4's
  bottom edge instead of stacking inside the minimap above f4. New
  vertical order under the minimap is:
    f1 zone           (inside minimap, top)
    f2 coords/lat/fps (inside minimap, below f1)
    [button bar]      (below minimap)
    f4 Level / Total Time
    f3 XP / rep       (only renders below max level)
• f3 still renders empty at max level (returns "" from rsiExpRep), so
  there's no visible gap there for capped characters.

INFOSTRINGS — XP/REP LINE HIDDEN AT MAX LEVEL + REP-LOGIC AUDIT:
• rsiExpRep now returns "" once the player hits MAX_PLAYER_LEVEL,
  removing the green reputation line entirely once you're at cap. The
  XP branch (sub-max levels, with rested chunk in gold) is unchanged.
• Audit notes left as a code comment (legacy max-level rep branch
  preserved in --[[ ]] form for future reference). Two long-standing
  bugs were identified in the disabled rep code:
    1. MAXED OUT detection compared `(value-minimum)==999 and
       (maximum-minimum)==1000`, which only matches when the bar sits
       at exactly 999/1000. For Exalted in TBC GetWatchedFactionInfo
       returns minimum=42000, maximum=43000, value sweeps 42000..43000,
       so value-minimum is 0..1000 and never 999 except by coincidence
       — MAXED OUT effectively never fired.
    2. The `_, _, minimum, ...` destructure threw away standingId, so
       even fixing the test required re-capturing it.
  Recommended fix if max-level rep is ever re-enabled in this slot:
  capture standingId and use `standingId == 8 and value >= maximum`.

INFOSTRINGS — LEVEL TIME / TOTAL TIME RELOCATED BELOW BUTTON BAR:
• The f4 container (Level Time + Total Time, populated from
  TIME_PLAYED_MSG) used to stack vertically with the rest of the info
  strings INSIDE the minimap, which caused it to overlap the map view
  on smaller minimap setups.
• Re-anchored f4 directly to TOP, Minimap, BOTTOM, 0, -40 so it sits
  cleanly below rMinimap's bottom button bar (bar lives at y=[-35,-2]
  given BUTTON_SIZE=33 / BOTTOM_OFFSET=-2). Falls back to the old
  stacked anchor if Minimap isn't available when rInfoStrings loads.
• f1 (zone) / f2 (coords+latency+fps) / f3 (xp/rep) still stack inside
  the minimap as before — only the Level Time / Total Time pair moved.

SHINYBUFFS — UNIFIED FONT SIZES FOR BUFFS + DEBUFFS:
• Options panel "Buff Font Sizes" and "Debuff Font Sizes" sections
  collapsed into a single "Font Sizes" group. Duration size and Count
  size sliders now drive both buff and debuff text. The Font selector
  and Font Flag selector were already shared.
• Implementation keeps the dual storage (db.buffs.dfsize /
  db.debuffs.dfsize, etc.) because the Skinning pipeline keys font
  sizes off db[svtable].* per aura type. The unified slider's set
  function mirrors the value into both tables and reskins both sides.
• One-time migration on PEW (SyncFontSizes) converges existing saved
  variables that had mismatched buff vs debuff sizes — both tables are
  set to the buff side's value (which is what the unified slider's get
  reads from), so what you see in the slider matches what's rendered.
• Defaults updated so a fresh install starts both tables at the same
  values (dfsize=14, cfsize=17 for both) and won't reintroduce the
  mismatch on a SavedVariables wipe.

MOVABLE BUFFS/DEBUFFS — DRIFT DURING COMBAT (esp. DEBUFFS):
• Symptom: During combat, debuffs (and to a lesser extent buffs) would
  visibly drift to Blizzard's grid-default position whenever an aura
  churned (took damage / ticking poisons / ramping debuffs). They would
  snap back to the user's anchor only after combat ended.
• Root cause: ApplyAnchor and the OnUpdate processor in MovableBuffs.lua
  / MovableDebuffs.lua both gated on InCombatLockdown(). Each time
  Blizzard's UpdateGridLayout called AuraContainer:SetPoint (which fires
  on every aura add/remove — extremely frequent in combat for debuffs),
  our hook flipped dirty=true, but the OnUpdate processor's combat
  check made ApplyAnchor a no-op until combat ended. The container sat
  at Blizzard's grid position for the duration of the fight.
• Fix: Removed the InCombatLockdown gates from ApplyAnchor and the
  OnUpdate processor in both modules. BuffFrame / DebuffFrame /
  AuraContainer are EditModeSystem / GridLayoutFrame frames — none of
  them are SecureTemplate-protected, so their SetPoint /
  ClearAllPoints can safely be called during combat. Blizzard's own
  UpdateGridLayout calls these methods mid-combat constantly; our
  re-anchor doing the same is benign. The Roth_UI_Protection.isLoggingOut
  gate and the existing pcall around the re-anchor body remain as the
  safety net.

PROTECTION-FLAG REGRESSION — isLoggingOut STUCK TRUE AFTER FIRST ZONE CHANGE:
• Symptom: Buffs/debuffs would snap back to the upper-right Blizzard
  default position when loading into a battleground (and any other
  load-screen transition), and would NOT recover even after the
  AuraContainer-hook fix. /reload was the only workaround per session.
• Root cause: rLib/core.lua, FixBlizzBarNil.lua, and rMinimap/core.lua
  all set their `isLoggingOut` protection flag on PLAYER_LEAVING_WORLD
  AND PLAYER_LOGOUT, but never cleared the flag back to false.
  PLAYER_LEAVING_WORLD fires on every zone/instance/BG transition (just
  before the load screen) — not only on actual logout. So the very first
  time the player crossed any load screen in a session, the global
  Roth_UI_Protection.isLoggingOut (and the file-local equivalents in
  FixBlizzBarNil + rMinimap) latched true and stayed true forever.
  Every consumer that gates on it then silently bailed for the rest of
  the session: MovableBuffs/MovableDebuffs OnUpdate stopped processing
  the dirty flag (so re-anchor never ran), oUF_Smooth's bar driver
  stopped updating, framefader stopped, and rMinimap stopped re-applying
  its settings on subsequent zone changes.
• Fix in embeds/rLib/core.lua, FixBlizzBarNil.lua, and
  embeds/rMinimap/core.lua: each logout-tracking frame now also
  registers PLAYER_ENTERING_WORLD and clears its isLoggingOut flag back
  to false when that event fires. PLAYER_ENTERING_WORLD doesn't fire
  during real logout, so the protection during shutdown is preserved
  while zone/instance/BG loads correctly clear the flag.
• Frame ordering: in all three files the logout frame is created and
  registers PLAYER_ENTERING_WORLD BEFORE any consumer event frame in
  the same file, so WoW's registration-order event dispatch guarantees
  the flag is cleared before any consumer handler observes it.

MOVABLE BUFFS/DEBUFFS — AURACONTAINER NOT RE-ANCHORED ON INSTANCE CHANGE:
• Symptom: After zoning into an instance the buff icons snapped back to
  the upper-right of the screen (Blizzard's default TOPRIGHT position),
  ignoring the user's saved Roth_UIBuffAnchor / Roth_UIDebuffAnchor
  position. /reload fixed it; next instance change broke it again.
• Root cause: BuffFrame.AuraContainer (and DebuffFrame.AuraContainer)
  is created LAZILY by Blizzard — it is often nil at PLAYER_LOGIN and
  only materializes on the first PEW into a populated zone or the first
  UNIT_AURA dispatch. The initial InstallHooks() routine bundled both
  the BuffFrame and AuraContainer hook installs behind a single
  `hooksInstalled` boolean. If AuraContainer was nil the first time
  InstallHooks ran (overwhelmingly the case at PLAYER_LOGIN), the AC
  hooks were silently skipped AND the boolean was set to true,
  permanently locking out any subsequent install attempt. Because
  AuraContainer is what visually positions the aura buttons, skipping
  its hook meant Blizzard's EditModeManager / UpdateGridLayout could
  freely reset its position on every PEW and our addon never noticed.
  ApplyAnchor's AC branch was also a no-op because origAC_SetPoint /
  origAC_ClearAllPoints were never captured.
• Fix in modules/MovableBuffs.lua and modules/MovableDebuffs.lua:
  - Split InstallHooks into InstallBFHooks / InstallDFHooks (frame
    hooks, idempotent, runs once) and InstallACHooks (container hooks,
    re-attempted on every Attach call and on every OnUpdate tick).
  - Track the hooked AuraContainer reference (`hookedAuraContainer`) so
    InstallACHooks can detect both first-time installation AND a
    Blizzard-side container swap (defensive — in practice the container
    instance stays the same).
  - InstallACHooks sets dirty = true the moment it finishes installing,
    so a re-anchor is scheduled immediately rather than waiting for the
    next Blizzard layout pass to dirty the flag.
  - ApplyAnchor now falls back to the live AuraContainer SetPoint /
    ClearAllPoints methods when origAC_* aren't captured yet.
    hooksecurefunc never replaces the underlying method, so the live
    refs remain the genuine Blizzard implementations — safe to call.
  - OnUpdate processor now invokes InstallACHooks() every tick (cheap:
    early-exits when the container is already hooked) as a safety net
    for the case where Blizzard creates the container between events.
  - Same pattern mirrored on the Debuff side for DebuffFrame /
    DebuffFrame.AuraContainer.

TAINT — MOVABLE BUFFS / DEBUFFS REGRESSION FIX:
• Root cause: GameMenuFrame Logout / Exit Game buttons would stop
  responding after enough time online, requiring a /reload to restore
  them. MovableBuffs.lua and MovableDebuffs.lua had regressed to
  replacing BuffFrame.SetPoint / BuffFrame.ClearAllPoints (and the
  same on DebuffFrame + their AuraContainers) with empty no-op
  closures. Every Blizzard secure code path that later invoked
  BuffFrame:SetPoint (aura updates, party changes, group config,
  etc.) executed addon-owned tainted code, propagating taint through
  the secure call graph until it polluted GameMenuFrame's button
  handlers — which is exactly the failure mode the original 3.1.0
  notes warned about ("hooks now only set a boolean, zero frame
  modifications inside hook bodies").
• MovableBuffs / MovableDebuffs rewritten to the documented design:
  - NEVER replace SetPoint or ClearAllPoints on BuffFrame /
    DebuffFrame / their AuraContainers
  - Save references to the original Blizzard methods at first attach
    so re-anchoring always uses the genuine implementation
  - hooksecurefunc on SetPoint + ClearAllPoints; hook body only flips
    a `dirty` boolean (zero frame mutation inside the secure hook)
  - Single OnUpdate handler processes the dirty flag; gated on
    Roth_UI_Protection.isLoggingOut only (follow-up in this release:
    InCombatLockdown gate removed — see "MOVABLE BUFFS/DEBUFFS — DRIFT
    DURING COMBAT" above — those frames are not SecureTemplate-protected)
  - `reanchoring` guard suppresses the hook during our own re-anchor
    SetPoint call to prevent infinite re-trigger loops

MINIMAP — ALT+Z / UI HIDE-SHOW VISUAL FIX:
• Symptom: Hiding the UI with Alt+Z then restoring it left a
  duplicate "Thunder Ridge"-style zone header bar floating above the
  minimap (Blizzard's MinimapZoneTextButton re-shown by default
  layout) and the map texture appeared stretched until the next zone
  change.
• MinimapZoneTextButton is now also hidden alongside MinimapBorderTop
  in ApplyMinimapSettings (was the "duplicate Thunder Ridge")
• Both MinimapBorderTop and MinimapZoneTextButton get a one-time
  HookScript("OnShow", Hide) so Blizzard re-showing them after a
  UIParent hide/show cycle is immediately reverted (visual frames,
  no taint risk)
• Added DISPLAY_SIZE_CHANGED + UI_SCALE_CHANGED to rMinimap event
  list so resolution/scale changes trigger a debounced re-apply
• Hooked UIParent:OnShow to flip the pendingApply flag on the
  rMinimap debounce frame — Alt+Z restoring the UI now triggers an
  automatic minimap re-apply on the next OnUpdate tick, restoring
  the square mask, sizing, and child-frame hiding

BUGSACK / !BUGGRABBER TRIAGE (no additional code changes required):
• Triaged the cached errors attributed to Roth_UI in BugGrabberDB
  across both account profiles. All ADDON_ACTION_BLOCKED /
  ADDON_ACTION_FORBIDDEN errors below trace to the same root cause
  and are expected to be resolved by the MovableBuffs / MovableDebuffs
  rewrite above:
  - GameMenuFrame.lua:67 callback() ADDON_ACTION_FORBIDDEN
    (Logout / Exit Game stop responding)
  - CompactPartyFrameMember1:SetSize() / CompactPartyFrameMember2:
    SetSize() ADDON_ACTION_BLOCKED via CompactRaidFrameContainer:
    TryUpdate -> RefreshMembers -> CompactUnitFrame_SetUpFrame
    (most prevalent recurring error, counter 11 in the last session)
  - CompactRaidFrame{3,11,12,28}:Show() / Hide() ADDON_ACTION_BLOCKED
    via CompactUnitFrame_UpdateVisible -> CompactUnitFrame_UpdateAll
  - ArenaEnemyFrame2:SetPoint() ADDON_ACTION_BLOCKED via
    ArenaEnemyFrame_UpdatePlayer
  Mechanism: Once BuffFrame.SetPoint / ClearAllPoints (and the same
  on DebuffFrame and AuraContainer) were replaced with addon-owned
  no-op closures, every Blizzard secure code path that called those
  methods executed under our taint. GROUP_ROSTER_UPDATE,
  ARENA_PREP_OPPONENT_SPECIALIZATIONS, and aura update events all
  share secure handler chains with CompactRaidFrame /
  CompactPartyFrame / ArenaEnemyFrame layout, so the taint
  propagated to their SetSize / Show / Hide / SetPoint calls and to
  GameMenuFrame button callbacks.
• Out-of-scope errors (NOT Roth_UI bugs, no fix attempted):
  - C_UnitAuras.GetAuraSlots called with unit=nil from Blizzard's
    CompactUnitFrame_UpdateAuras (counter 1472) — pure Blizzard bug
    in CompactUnitFrame.lua. We deliberately removed the
    AuraUtil.ForEachAura wrapper in 3.0.0 because the wrapper itself
    propagated taint to arena/party frames; the resulting Lua error
    is cosmetic (visible in BugSack only, no functional impact).
  - GameTooltip:SetUnit usage error in Blizzard_UnitFrame/Classic/
    UnitFrame.lua:453 (UnitFrame_UpdateTooltip) — Blizzard bug.
  - TacoTip InterfaceOptionsFrame_OpenToCategory nil — TacoTip bug.
  - Details!/AtlasLootClassic DecompressString internal error —
    Details!/AtlasLootClassic comm bug.

CODEBASE AUDIT — BUGS, PERFORMANCE & QUALITY PASS:

BUGS:
• rInfostrings memory tooltip: `local enry, memory` declared the
  wrong name, so the loop body's `entry = { name = ..., memory = ...}`
  was a stray global. Fixed the typo; entries now stay local to the
  tooltip build (no cross-tooltip leakage, no global pollution).
• ShinyBuffs SkinTench_Legacy: `hooksecurefunc(TemporaryEnchantFrame,
  "SetWidth", ...)` was being registered INSIDE the per-slot for-loop
  on the first skin pass — registering the same hook up to
  NUM_TEMP_ENCHANT_FRAMES times and calling it that many times per
  width change. Hoisted out of the loop with a module-level
  `tenchWidthHookInstalled` guard so the hook is registered exactly
  once.
• rMinimap zoom hooks: copy-paste duplication had Minimap_ZoomIn and
  Minimap_ZoomOut each wrapped with `hooksecurefunc` TWICE, firing
  pendingApply twice per zoom event. Consolidated into a single named
  FlagPendingApply helper that's registered once on each of
  Minimap_ZoomIn / Minimap_ZoomOut / Minimap_Update.
• oUF_Reputation: gated everything on the legacy GetWatchedFactionInfo
  global only, so a client that exposes reputation only via
  C_Reputation.GetWatchedFactionData (path that already exists in
  core/compat.lua) would always Hide() the bar at max level.
  Routed all five tags + the Update path through ns.Compat.
  GetWatchedFactionInfo with proper nil guards. Also guarded
  FACTION_BAR_COLORS[standing] indexing — out-of-range standings
  returned nil and `color.r` would error.
• core/bars.lua createRepBar tooltip: same C_Reputation gap as above
  + same unguarded FACTION_BAR_COLORS[standing] indexing + division
  by (maxrep - minrep) without checking for zero. Routed through the
  compat shim, guarded the color lookup with an r,g,b = 1,1,1
  fallback, guarded the percentage math against a 0 span.
• rInfostrings rsiExpRep: same C_Reputation gap on the max-level
  branch (audit pass). Routed through the compat shim with full nil
  guards on `value / minimum / maximum`. Subsequently superseded for
  UI purposes: max-level branch hidden entirely — see INFOSTRINGS —
  XP/REP LINE HIDDEN AT MAX LEVEL above (rep display removed at cap).

PERFORMANCE:
• FixBlizzBarNil.lua: was attaching ArtFrameOnUpdate to the event
  frame at file load (`f:SetScript("OnUpdate", ArtFrameOnUpdate)`).
  Even though the handler early-exits when needsArtFrameCheck is
  false, the closure ran every single frame for the whole session.
  Removed the unconditional attach — the handler is now only
  installed by the PLAYER_ENTERING_WORLD branch and self-detaches
  after the retry intervals exhaust (which it already did).

CODE QUALITY / DEAD CODE:
• core/init_coordinator.lua: the executionFrame OnUpdate wrapped
  every callback in pcall and silently dropped errors — a broken
  module would never load and never explain why. Errors are now
  routed through geterrorhandler() so BugSack / !BugGrabber / the
  default error frame can show them, and the failed callback is
  marked executed so the same error doesn't re-fire on every event
  tick.
• embeds/oUF/ouf.lua: removed leftover `print("handling custom")` /
  `print("handling condition")` debug spam in the `visibility`
  branch of the header builder.
• embeds/Roth_ShinyBuffs/Roth_ShinyBuffs.lua: gated the seven
  unconditional login-time chat prints (API detection, hook setup,
  initial-skin notice, legacy-API detection) behind a new SB_Debug
  flag. /sbdiag remains unconditional as the user-facing diagnostic
  command, and the "No buff API detected" error stays unconditional
  because in that case the addon won't function at all.
• embeds/Roth_ShinyBuffs/Roth_ShinyBuffs.lua: removed
  `hooksecurefunc("BuffFrame_UpdateAllBuffAnchors", function() end)`
  — was a no-op hook with zero behavior; legacy skinning is driven
  entirely by SkinAuras_Legacy via UNIT_AURA.
• embeds/RothFont/Config.lua: removed leftover `print("setting")`
  debug from the headerFont set callback.

Version 3.1.0 - Minimap Overhaul & InfoStrings Redesign
---------------------------------------------------------

MINIMAP:
• Header (MinimapBorderTop) now hidden cleanly — square minimap with no
  overlapping header bar
• Minimap close/toggle (X) button repositioned to top-right corner of the
  minimap frame, positioned once to avoid taint
• Toggle button respects user choice — closing the minimap via X no longer
  gets overridden by periodic settings reapply
• Removed minimap opacity/alpha feature (was causing indoor/outdoor
  rendering conflicts on the Anniversary client)
• Removed direct Minimap:SetAlpha() call that broke indoor map transitions
• Fixed critical scoping bug: rMinimap module was referencing global
  'Roth_UI' (nil) instead of local addon table 'L' for DB access — this
  was silently breaking the alpha slider and font customization

MINIMAP ZONE TEXT FONT:
• Zone text font customization moved from MinimapZoneText (Blizzard header)
  to rInfoStrings zone line — avoids fighting Blizzard's font resets
• Font selector and size slider in Roth UI options now control the
  rInfoStrings zone text via Roth_UIApplyMinimapZoneFont global
• Default font changed from "Cracked" to "Morpheus"
• Font reads from DB every call (no stale captures) with safe fallback

INFOSTRINGS (BELOW MINIMAP):
• Zone name line (f1) restored — displays zone name without coordinates
• Coordinates moved to the latency/fps line (f2): shows coords + latency + fps
• Both lines anchored inside the top of the minimap frame for a clean overlay look
• Positioning config updated for new anchor point (TOP of Minimap, y=-5)

MINIMAP TOGGLE BUTTON FIX (MinimapButtonButton addon):
• Fixed nil 'options' error in MinimapButtonButton/Logic/Main.lua:74 —
  added nil guard for options.autoClose check that fires before init()

TAINT REDUCTION:
• MinimapToggleButton positioned once with combat lockdown check and
  rothPositioned flag to prevent repeated secure frame manipulation
• Removed AuraUtil.ForEachAura wrapper (was fixing Blizzard nil-unit bug
  but introduced taint propagation to arena/party frames)

CONFIG CLEANUP:
• Removed minimapAlpha slider from Roth UI options panel
• Removed minimapAlpha from ApplyResizeOptions
• Minimap section header renamed to "Minimap Zone Text"
• minimapZoneFont default updated to "Morpheus" in config defaults

Version 3.0.0 - Comprehensive Taint & Anniversary Compatibility Overhaul
--------------------------------------------------------------------------

SHINYBUFFS - FULL ANNIVERSARY EDITION REWRITE:
• Complete rewrite of ShinyBuffs to work with Anniversary Edition's modern
  BuffFrame/DebuffFrame API (BuffFrame.auraFrames / DebuffFrame.auraFrames)
• Dual-API engine: auto-detects modern vs legacy (BuffButton globals) API at
  login and uses the appropriate skinning path
• Modern API hooks: BuffFrame.UpdateAuraButtons, DebuffFrame.UpdateAuraButtons,
  BuffFrame.UpdateGridLayout, DebuffFrame.UpdateGridLayout — skins are applied
  after every Blizzard aura update, not on a timer
• UNIT_AURA event fallback with 0.15s debounce for redundancy
• Initial skin applied 0.5s after PEW to ensure Blizzard setup is complete
• IsSkinnableAura() guard filters out PrivateAuraAnchors and incomplete frames
• Shared duration bar driver (SB_DurationDriver) replaces per-icon OnUpdate
  handlers — single OnUpdate iterates all active bars at 0.1s interval
• Duration bars support both modern buttonInfo.expirationTime and legacy
  UnitBuff/UnitDebuff fallback for timer accuracy
• /sbdiag debug command prints API mode, frame counts, shown counts, and
  attempts a manual skin pass for troubleshooting

SHINYBUFFS - LAYOUT ENGINE:
• New layout system drives Blizzard's AuraContainer grid properties directly:
  iconStride, addIconsToRight, addIconsToTop, iconPadding
• ComputePadding() calculates correct iconPadding accounting for custom skin
  size, backdrop insets, and duration bar height
• Buffs Per Row slider (2-32) — controls how many buffs before wrapping
• Debuffs Per Row slider (2-32) — independent from buff row count
• Buff/Debuff Growth Direction dropdowns:
  - Horizontal: Left to Right / Right to Left
  - Vertical: Top to Bottom / Bottom to Top
• Buff Size slider (20-60px) — resizes buff icons, backgrounds, and bars live
• Debuff Size slider (20-60px) — independent from buff size
• Buff Padding slider (-10 to +30) — extra spacing between buff icons
• Debuff Padding slider (-10 to +30) — independent from buff padding
• All layout sliders apply changes in real-time as the slider moves (no
  confirm needed) via ApplyLayoutSettings() → UpdateGridLayout() → Reskin

SHINYBUFFS - OPTIONS PANEL:
• Full AceConfig options panel under Escape > Options > AddOns > ShinyBuffs
• Text Options: Font selector (LSM), Font Flag (None/Outline/Mono Outline),
  White Duration Text toggle, Who Cast tooltip toggle
• Buff Font Sizes: Duration size, Count size sliders (6-24)
• Debuff Font Sizes: Duration size, Count size sliders (6-24)
• Skin Options: Border texture/width/color (or by-class), Debuff Type Border
  toggle, Debuff Overlay Alpha, Statusbar texture/color (or by-class),
  Background texture/color (or by-class)
• Layout Options: X/Y Offset inputs, Show Anchor toggle, Buffs/Debuffs per
  row, growth directions, frame sizes, padding
• Profile: Character-specific settings toggle, Copy from Default, Profile Reset

MOVABLE BUFFS & DEBUFFS:
• Integrated MovableBuffs module into Roth_UI (no longer a separate addon)
  - Drag anchor frame with "Buffs - Drag Me" label
  - `/roth movebuffs` toggles buff frame lock/unlock (drag to reposition)
  - `/roth resetbuffs` resets buff frame to default position
  - Position saved per-character via Roth_UI_DB_GLOB.movableBuffs
  - AuraContainer locked to center of anchor for consistent buff placement
• New MovableDebuffs module mirroring buff anchor system
  - Separate drag anchor with "Debuffs - Drag Me" label
  - `/roth movedebuffs` toggles debuff frame lock/unlock
  - `/roth resetdebuffs` resets debuff frame to default position
  - Position saved per-character via Roth_UI_DB_GLOB.movableDebuffs
• Both modules use deferred SetPoint via dirty flag + OnUpdate to minimize taint
• Buff/debuff anchors grow from center of drag handle regardless of growth
  direction (up/down) for intuitive placement

TARGET FRAME DEBUFF SIZING:
• Added target frame debuff size slider to Roth UI options panel
  (Escape > Options > AddOns > Roth UI)
• Adjustable via `/roth` settings — changes apply in real-time

TAINT ELIMINATION - ACTION BARS (6 files):
• Replaced direct SetAlpha/ClearAllPoints/SetPoint on MainMenuBar with
  RegisterStateDriver(MainMenuBar, "visibility", "hide") — runs in secure
  context, zero taint (bar1.lua)
• Same RegisterStateDriver fix applied to MultiBarBottomLeft (bar2.lua),
  MultiBarBottomRight (bar3.lua), MultiBarRight + MultiBarLeft (bar4.lua),
  and MultiBarLeft (bar5.lua)
• Removed all SetAlpha(0)/EnableMouse(false)/ClearAllPoints()/SetPoint(-5000)
  patterns on Blizzard multi-bar frames — these tainted EditMode and propagated
  to CompactPartyFrame:SetSize() via ADDON_ACTION_BLOCKED

TAINT ELIMINATION - HIDE_BLIZZART.LUA:
• Removed MicroButtonAndBagsBar, EditModeExpandedState, and
  MainMenuBarVehicleLeaveButton from the framesToHide list (all secure frames)
• Removed blind iteration of MainMenuBar:GetChildren() and
  MainMenuBarArtFrame:GetChildren() that called SetAlpha(0)/Hide() on every
  non-action-button child — major taint source
• Removed ActionBarController child modifications

TAINT ELIMINATION - MICROMENU.LUA:
• Removed MainMenuBar:ClearAllPoints() and MainMenuBar:SetScript("OnShow", nil)
  — both directly tainted MainMenuBar
• Removed MicroMenuContainer width/height/position syncing code that wrote to
  a Blizzard-managed frame

TAINT ELIMINATION - CAST BARS (4 files):
• Removed CastingBarFrame.Show = CastingBarFrame.Hide method replacement in
  oUF castbar.lua, units/player.lua, units/pet.lua, and UITweaks.lua
• Replacing Show on Blizzard frames spreads taint through every secure code
  path that later calls Show — now uses UnregisterAllEvents + Hide only

TAINT ELIMINATION - CHAT:
• Replaced global FCF_FadeInChatFrame/FCF_FadeOutChatFrame/FCFTab_UpdateColors
  function replacements with hooksecurefunc — replacing Blizzard globals taints
  the entire FCF chat frame pipeline
• Fixed CombatLogQuickButtonFrame_Custom HookScript("OnShow", .Hide) infinite
  loop — now uses SetAlpha(0) + EnableMouse(false)
• Removed duplicate CHAT_FONT_HEIGHTS mutation (RothFont handles it)

TAINT ELIMINATION - BUFF/DEBUFF SYSTEM:
• Replaced GameTooltip.SetUnitAura method table replacement in ShinyBuffs with
  hooksecurefunc — method replacement taints tooltip execution paths
• Replaced BuffFrame_UpdateAllBuffAnchors global replacement with hooksecurefunc
• Guarded rButtonTemplate hooks for BuffFrame_UpdateAllBuffAnchors and
  DebuffButton_UpdateAnchors with existence checks (may not exist on Anniversary)
• MovableBuffs/MovableDebuffs: Deferred all SetPoint hook work to next frame
  via dirty flag + OnUpdate — hooks now only set a boolean, zero frame
  modifications inside hook bodies

TAINT ELIMINATION - MINIMAP:
• Replaced hooksecurefunc(btn, "Show", ...) on minimap buttons (LFG, tracking,
  calendar, zoom) with a lightweight periodic repositioner — Show hooks spread
  taint through secure button paths
• Changed Minimap:SetScript("OnMouseWheel") to HookScript to preserve existing
  scroll behavior

TAINT ELIMINATION - OTHER:
• Removed ZoneTextFrame/SubZoneTextFrame SetFrameStrata modification in
  target.lua (Blizzard notification frames)
• Removed dead event handler block in ouf.lua referencing undefined globals
  (toggleHeaders, id, isHacked, shouldHack) — was non-functional but hazardous

CRASH FIXES:
• Fixed rLib:CopyTable calling undefined copyTable() — now correctly calls
  rLib:CopyTable recursively
• Added SpellFlyout nil guard in framefader.lua — SpellFlyout does not exist
  on TBC Anniversary, caused Lua error on load
• Added missing defaultFadeIn/defaultFadeOut definitions in framefader.lua —
  rButtonBarFader would crash when called without explicit fade params

ANNIVERSARY EDITION API COMPATIBILITY:
• Defined ALTERNATE_POWER_INDEX in oUF power.lua with Enum fallback — was
  referencing undefined nil global
• Guarded UnitAlternatePowerInfo with existence check
• Guarded GetSpecializationInfoByID/GetArenaOpponentSpec in oUF health.lua
  and power.lua — these APIs may not exist on TBC Anniversary
• Guarded UnitIsTapDenied with existence check in health.lua and power.lua
• Fixed pvp.lua prestige detection — was using tocVersion >= 70000 which
  incorrectly activates on Anniversary; now checks UnitPrestige/GetPrestigeInfo
  API existence directly
• Fixed GetTalentInfo(3,2,1) in core/bars.lua — was using MoP-style 3-param
  call; now uses pcall with TBC-correct 2-param call and MAX_COMBO_POINTS fallback
• Guarded all retail-only constants in oUF classicons.lua: SPELL_POWER_CHI,
  SPELL_POWER_HOLY_POWER, SPELL_POWER_SOUL_SHARDS, SPELL_POWER_ARCANE_CHARGES,
  SPEC_MONK_WINDWALKER, SPEC_PALADIN_RETRIBUTION, SPEC_MAGE_ARCANE
• Guarded GetSpecialization() and IsPlayerSpell() in classicons.lua Visibility
• Guarded all retail-only oUF tags: curmana, maxmana (safe Enum fallback),
  soulshards, holypower, chi, arcanecharges (Enum + GetSpecialization checks),
  and arenaspec (GetArenaOpponentSpec + GetSpecializationInfoByID checks)
• Guarded C_Map.GetBestMapForUnit/GetPlayerMapPosition in rInfostrings with
  fallback to legacy GetPlayerMapPosition API
• Fixed coordinate format string from %.2d (integer) to %.0f (float)

KNOWN ISSUES:
• rMinimap still directly modifies MinimapCluster position/scale (functional,
  deferred to future refactor)
• PetActionBarFrame reparenting in petbar.lua modifies a Blizzard frame
  (low taint risk, pet bar is dynamic)

Version 2.2.2 - Note Tome Enhancements
----------------------------------------

NOTE TOME (EMBEDDED NOTEPAD):
• Added 9 page tabs per Account/Character tab for organizing notes
  - Vertically stacked numbered buttons on the left side of the edit area
  - Active page highlighted with gold border and text
  - Page content saved independently per tab and per page
• Added resizable frame with resize grip (bottom-right corner)
  - Resize lock/unlock toggle button in title bar
  - Frame size persists across sessions
  - Min size: 300x340, Max size: 800x600
• Halved Account/Character tab button widths for a cleaner layout
• Backward-compatible migration from old single-string note format
• Synced all features to standalone NoteTome addon (v1.2.1)

TAINT FIXES:
• Removed UIDropDownMenu hooks from TaintFix.lua that caused FocusUnit() taint
  - rawset on dropdown frames was propagating taint to arena/focus actions
• Removed EnsureActionBarEditModeFields from FixBlizzBarNil.lua
  - Writing oldActionBarSettings/oldGridSettings to Blizzard frames caused
    CompactPartyFrameMember1:SetSize() ADDON_ACTION_BLOCKED errors
• Simplified TaintFix.lua to only close dropdowns on combat entry

Version 2.2.1 - Performance Optimization & Feature Update
----------------------------------------------------------

NEW FEATURES:
• Integrated MovableBuffs into Roth_UI (no longer a separate addon)
  - `/roth movebuffs` toggles buff frame lock (drag to reposition when unlocked)
  - `/roth resetbuffs` resets buff frame to default position
  - Buff frame state saved per-character via Roth_UI_DB_GLOB
• Updated `/roth` slash command list to include all available commands
  - Added: resettemplates, resetorbs, reposestance, reposebags
  - Updated unlockall/lockall/resetall to include buffs

TARGET BAR FIXES:
• Fixed target health/power bars not updating properly in Classic
  - Added frequentUpdates polling (0.1s) to oUF health and power elements
  - Addresses throttled UNIT_HEALTH/UNIT_POWER_UPDATE events in Classic Era
• Fixed smooth animation causing stale bar values on target/focus switch
  - oUF_Smooth now instantly snaps bars on PLAYER_TARGET_CHANGED/PLAYER_FOCUS_CHANGED
  - Prevents bars from animating between old and new target values

PERFORMANCE - HIGH IMPACT:
• Removed `or true` debug hack from action bar OnUpdate handlers (bar1-5)
  - Bars no longer force full button updates every frame when idle
  - Update interval increased from 0.1s to 0.2s (still responsive for range coloring)
• Consolidated ~20 duplicate GameMenuFrame polling frames into one shared tracker
  - Single Roth_UI_Protection global replaces per-file gameMenuTracker + logoutFrame pairs
  - Eliminates ~19 redundant CreateFrame + OnUpdate loops that ran every frame
• Fixed createAuraIcon cooldown overhead
  - Removed perpetual OnUpdate that scanned all cooldown regions every frame
  - Consolidated duplicate SetCooldown hooks into a single hook
  - Default cooldown text hidden once at creation + on SetCooldown (not per-frame)
• Replaced per-buff/debuff OnUpdate handlers in ShinyBuffs with single shared driver
  - One update frame iterates all active duration bars instead of N parallel handlers

PERFORMANCE - MEDIUM IMPACT:
• Pre-allocated static color tables in updateHealth/updatePower/tags
  - Eliminates new {r=, g=, b=} table creation on every health/power update
  - Cached TRP3 addon detection at first call instead of per-tag evaluation
• Fixed global variable leaks
  - bars.lua: added local to mxp, xp, rxp, name, standing, minrep, maxrep, value
  - oUF_AuraWatch: uncommented local filter declaration
  - oUF_ComboPoints: localized MAX_COMBO_POINTS assignment
• One-shot OnUpdate handlers now self-remove after completion
  - UITweaks.lua: clears OnUpdate after setup finishes
  - FixBlizzBarNil.lua: clears OnUpdate after retry intervals exhaust, re-registers on events

PERFORMANCE - LOW IMPACT / CODE QUALITY:
• Deduplicated slash command logic
  - Roth_UIUnlock/Lock/Reset now share a categoryLists lookup + GetFrameList helper
• Removed dead code in init_coordinator.lua
  - Removed unused TryExecuteCallbacks, pendingCallbacks, callbackTimer
  - Fixed broken post-init callback path (callbacks were silently dropped)
• Replaced SafeTimer frame-per-call pattern with single scheduler
  - One shared frame + queue instead of creating a new frame per timer call
  - Removed unused originalCTimerAfter capture
• Fixed `verical` typo in lib.lua totalAbsorb
  - Party absorb bars now correctly read cfg.units.party.vertical
• Added early exit to oUF_Smooth OnUpdate when no bars are animating
  - Skips entire loop body when smoothing table is empty

Version 2.1.1 - Bug Fixes & Credits Update
------------------------------------------

HEALTH/MANA ORB FIXES:
• Fixed orbs not filling up or updating visually when health/power changes
• Fixed orb fill desynchronization between StatusBar and ScrollFrame visuals
• Disabled smooth animation for player orbs to ensure accurate visual state
• Updated event handlers for Anniversary Edition compatibility:
  - Changed UNIT_HEALTH_FREQUENT to UNIT_HEALTH
  - Changed UNIT_POWER_FREQUENT to UNIT_POWER_UPDATE

TAINT & STABILITY FIXES:
• Added TaintFix.lua module to mitigate UIDropDownMenu taint issues
  - Fixes UIDropDownMenu_Refresh accessing uninitialized buttons
  - Fixes displayMode taint during dropdown initialization (using rawset)
  - Protects ToggleDropDownMenu from combat taint propagation
  - Reduces FocusUnit() and other ADDON_ACTION_FORBIDDEN errors
• Removed UIDROPDOWNMENU_DEFAULT_TEXT_HEIGHT modification in RothFont
  - This was a major taint source causing FocusUnit() errors
• Added CompactPartyFrame disabling to prevent ADDON_ACTION_BLOCKED errors
• CompactPartyFrame members and pets are now properly hidden when oUF frames are used
• Completely disabled rRaidScale module to prevent additional taint
• Users should use Blizzard's Edit Mode for raid frame scaling instead
• Streamlined FixBlizzBarNil.lua to minimal error prevention only
• Removed bar positioning code - now fully relies on Blizzard's Edit Mode

CREDITS & DOCUMENTATION:
• Added Credits tab to in-game settings panel (Escape > Options > AddOns > Roth UI)
• Updated Credits.txt with complete addon history and proper attribution:
  - zork (Lars Norberg) - Original creator (~2008-2016)
  - Galaxy (Galaxy119/Joker119) - Previous maintainer (2012-2018)
  - EchoZulu69er - Current maintainer (2025)
• Updated author credits in .toc, config.lua, and README.txt
• Added third-party library credits and historical timeline

KNOWN ISSUES:
• C_UnitAuras errors may appear - this is a Blizzard bug, not addon-related
• GameTooltip:SetUnit errors may appear - this is a Blizzard bug, not addon-related
• Some taint errors may still occur (significantly reduced with TaintFix module)
  - Most FocusUnit/dropdown-related errors are now mitigated
  - Remaining errors are cosmetic only - functionality still works
  - Workaround for persistent issues: Use keybinds or /focus macro

Version 2.1.0 - UI Streamlining & Customization Update
-------------------------------------------------------

ACTION BARS:
• Disabled rActionBarStyler - now using Blizzard's default action bars
• This provides better stability and compatibility with stance changes
• Users can customize bars via Blizzard's Edit Mode or other bar addons

MINIMAP ENHANCEMENTS:
• Added configurable button bar along the bottom edge of minimap
• Button order: [Zoom-] [Tracking] [Calendar] [Queue] [Zoom+]
• Configurable button size (33px) and spacing (3px)
• All buttons now visible and functional

UI TWEAKS MODULE (UITweaks.lua):
• New standalone module for simple UI modifications
• Hides Blizzard's default cast bar (Roth oUF castbar used instead)
• Hides default XP/reputation bar
• Works independently of other modules

RESIZE OPTIONS:
• Removed: Bar 4 Scale, Bar 5 Scale, Party Frame Scale, Raid Frame Size
• Added: Target of Target Scale (default 1.3)
• Added: Focus Frame Scale (default 0.85)
• Streamlined options for commonly adjusted frames

FOCUS FRAME:
• Now displays health value below the frame
• Now displays mana/power value below the health value
• Font size increased to 15 for better readability

INFOSTRINGS:
• Repositioned location/latency/FPS text below minimap button bar
• Adjusted positioning to avoid overlap with new button bar

CODE CLEANUP:
• Removed unused bar scaling code from Roth_Config
• Simplified ApplyResizeOptions function
• Cleaned up GameTimeFrame hiding code (now shown in button bar)

Version 2.0.0 (BETA) - TBC Anniversary Compatibility Update
-------------------------------------------------------------

API COMPATIBILITY:
• Created comprehensive compatibility layer (core/compat.lua) for deprecated APIs
• Fixed GetWatchedFactionInfo() → C_Reputation.GetWatchedFactionData() migration
• Fixed GetNumAddOns(), LoadAddOn(), IsAddOnLoaded(), GetAddOnMetadata() → C_AddOns API migration
• Added fallback defaults for NUM_STANCE_SLOTS and NUM_PET_ACTION_SLOTS constants
• Implemented SafeCall and SafeGet utility functions for error handling

oUF FRAMEWORK FIXES:
• Fixed oUF element registration errors (AddElement nil value)
• Added existence checks before oUF:AddElement() calls in all element files
• Fixed oUF.colors access errors in health.lua and power.lua
• Fixed oUF frame_metatable access errors in colors.lua and events.lua
• Fixed GetAddOnMetadata calls in oUF core files
• Fixed CastingBarFrame and PetCastingBarFrame nil errors

HEALTH/POWER ORB FIXES:
• Fixed "attempt to index field 'HealthOrb' (a nil value)" errors
• Added comprehensive safety checks in all orb update functions
• Fixed syntax errors in updateHealthOrbGalaxiesAlpha and updatePowerOrbGalaxiesAlpha
• Added nil checks for ns.HealthOrb and ns.PowerOrb before access
• Fixed panel.lua initialization order issues

UNIT FRAME FIXES:
• Fixed boss frame positioning errors for protected frames
• Implemented combat-aware positioning with retry logic
• Added pcall protection for SetPoint operations
• Fixed player.lua panel access errors
• Fixed reputation bar GetWatchedFactionInfo calls

UI ELEMENT POSITIONING:
• Fixed MicroMenu positioning and visibility issues
• Fixed MicroMenuContainer nil comparison errors
• Added hooks for Blizzard's MicroMenu functions to prevent errors
• Fixed stance bar positioning and scale application
• Fixed bag button visibility when game loses focus
• Improved bag button detection and initialization
• Added proper retry logic for delayed UI element loading

EDIT MODE:
• Created editmode.lua helper module for custom drag system
• Separated Roth UI's custom edit mode from Blizzard's Edit Mode
• Fixed varargs syntax errors in hook functions

CODE QUALITY:
• Removed all debug print statements from chat output
• Added defensive programming throughout codebase
• Improved error handling with pcall and xpcall
• Cleaned up unused documentation files
• Streamlined initialization timing

COMPATIBILITY:
• Full compatibility with WoW Classic Anniversary - TBC (Interface 11508)
• Handles both old and new API versions gracefully
• Improved stability and error recovery

Version 1.4.1 - Classic Anniversary Patch Compatibility Update
---------------------------------------------------------------

MINIMAP FIXES:
• Fixed minimap disappearing in Orgrimmar and indoor areas
• Fixed minimap not displaying world mesh maps correctly
• Implemented proper hooking into Blizzard's minimap update functions (Minimap_ZoomIn, Minimap_ZoomOut, Minimap_Update)
• Fixed minimap reverting to default circular shape - restored square format
• Added event handlers for zone changes to maintain minimap settings
• Fixed minimap size resetting after zone transitions
• Removed problematic alpha modifications that caused map display issues
• Adjusted minimap size to 200x200 pixels
• Repositioned realm time display above minimap
• Repositioned day/night indicator (sun/moon icon)
• Moved information text blocks below minimap with proper positioning
• Fixed minimap mask texture application for square shape

ACTION BAR FIXES:
• Fixed "attempt to compare number with nil" errors in MultiActionBars.lua
• Fixed bar 3 (MultiBarBottomRight) buttons becoming unclickable after stance changes
• Fixed bars 1-3 not displaying properly after reload
• Fixed bar 3 buttons stacking vertically instead of horizontally
• Fixed bar resize functionality not matching green target overlay
• Fixed bar positions not saving after reload or relog
• Fixed /roth unlockbars command only unlocking reputation bar instead of all bars
• Implemented proper initialization timing for action bars
• Fixed bars reverting to default position/size after reload or relog
• Fixed bars 2-5 not showing after certain changes
• Fixed empty bar slots disappearing on mouseover
• Fixed bar 1 not showing empty slots
• Fixed bar 4 slots disappearing after mousing over
• Implemented proper user-placed flag persistence for all bars

UI ELEMENT POSITIONING:
• Repositioned keyring (increased size by 40%, adjusted position)
• Repositioned bag buttons
• Repositioned micromenu
• Repositioned class action bar (stance bar)
• Adjusted various UI element positions for better layout

INITIALIZATION & LOAD TIMING:
• Implemented InitCoordinator system for proper addon initialization order
• Fixed inconsistent load times causing Lua errors
• Synchronized all addon parts to load after Blizzard's UI is ready
• Minimized load errors through proper timing coordination
• Added proper event handling for PLAYER_LOGIN and PLAYER_ENTERING_WORLD

CODE CLEANUP:
• Removed unnecessary troubleshooting files
• Cleaned up unused code and deprecated features
• Removed problematic minimap close button toggle feature
• Streamlined minimap code to focus on core functionality

COMPATIBILITY:
• Full compatibility with WoW Classic Anniversary patch (Interface 11508)
• Fixed compatibility issues with Blizzard's updated action bar system
• Fixed compatibility with Blizzard's minimap layer system

