File Details
v1.0.0
- R
- Apr 29, 2026
- 298.96 KB
- 8
- 12.0.5
- Retail
File Name
GOBIGnINTERRUPT-v1.0.0.zip
Supported Versions
- 12.0.5
GOBIGnINTERRUPT
v1.0.0 (2026-04-29)
Full Changelog Previous Releases
- v1.0.0 — non-addon peer coverage + presence badge
Peer presence detection- CDComm tracks peerSeen[name] on inbound addon messages, lastQueryAt on
Q broadcast. M.PeerHasAddon(unit) returns true/false/nil after a 5s grace. - M.DumpPeerPresence + /gbi peers slash command for diagnostic visibility.
- Brain.Reset wipes peerSeen so dungeon entry re-queries fresh.
"No addon" badge - Bar.lua: per-row red "?" font string anchored left of the unit name,
refreshed on the existing 0.5s tick. - UnitOverlay.lua: per-host frame badge with dark plate, anchored INSIDE
the host TOPLEFT offset by ICON_SIZE/2 so it clears the leader-crown
area without colliding with role icons or the cooldown strip.
Aura-duration back-calculation - Evidence computes castedAt from aura.expirationTime - aura.duration,
laundered via tostring->tonumber + double-pcalled comparison so
12.0.5 secret-tagged numeric fields fail closed instead of throwing. - Brain.OnCast accepts castedAt 5th param; back-dates startedAt when
within effDur of now (non-peer paths only). Non-addon peer CDs now
show accurate remaining time instead of "full duration from when
polling first saw the buff".
CastTracker taint cleanup - Early IsSecret(castGUID) check skips the string.match recovery for
tagged casts, eliminating the "match failed" debug-log spam. - Single concise "skip: tagged cast on partyN (Evidence will catch
via aura)" line replaces three verbose lines per cast.
Data_Cooldowns audit (~30 new entries) - Warrior: Ravager, Bladestorm (Arms+Fury), Champion's Spear,
Demoralizing Shout - DK: Empower Rune Weapon, Dancing Rune Weapon, Lichborne, AMZ
- DH: Soul Carver, Immolation Aura
- Druid: Tranquility, Innervate, Incarnation (all 4 specs)
- Evoker: Rewind, Tip the Scales
- Hunter: A Murder of Crows, Double Tap
- Mage: Cold Snap, Evocation
- Monk: Revival, Celestial Brew, Dampen Harm
- Paladin: Holy Avenger, Aura Mastery
- Priest: Vampiric Embrace, Apotheosis, Symbol of Hope, Rapture
- Rogue: Cold Blood, Killing Spree
- Shaman: Earth/Fire/Storm Elemental, Healing Tide, Spirit Link
- Warlock: Dark Soul (Misery + Instability), Summon Infernal
Co-Authored-By: Claude Opus 4.7 (1M context) noreply@anthropic.com
- CDComm tracks peerSeen[name] on inbound addon messages, lastQueryAt on
- Remove CombatLog.lua — CLEU is protected for unsigned addons in 12.0.5
User got ADDON_ACTION_FORBIDDEN at addon load:
AddOn 'GOBIGnINTERRUPT' tried to call the protected function
'GOBIGnINTERRUPT_CLEUFrame:RegisterEvent()'.
The earlier research suggesting CLEU was usable was wrong on this
specific path: Blizzard now blocks UNSIGNED addons from registering
COMBAT_LOG_EVENT_UNFILTERED at all. (Details and other large addons
in the prior comparison may be on a different policy tier or older
installations didn't hit this.)
Reverts the v0.5.0-beta CLEU module entirely. Brain's peer-priority
guard (state.fromPeer + 5s lockout for local detections) is kept —
still useful for the remaining detection paths (UNIT_SPELLCAST,
UNIT_AURA, polling, CDComm).
Co-Authored-By: Claude Opus 4.7 (1M context) noreply@anthropic.com - CLEU-based party CD detection + peer-priority dedup
New CombatLog.lua: registers COMBAT_LOG_EVENT_UNFILTERED and routes
SPELL_CAST_SUCCESS from friendly party members into Brain.OnCast.
Catches gaps the existing paths miss:
* Pure interrupts (Pummel, Mind Freeze) - no buff to poll
* Instant CDs without auras (Touch of Death, Wake of Ashes)
* Spells whose buff name differs from cast name
* Locale-independent (spellID, not name)
GUID -> unit cache flushed on roster updates. Pet sources skipped.
Class filter applied. Default DB.combatLog.enabled = true.
Brain peer-priority guard: once a peer broadcasts a U message
(arriving with their actual talented duration), local detections
(CLEU / CastTracker / UNIT_AURA) ignore that (unit, spellID) for
the next 5s. Prevents the "guess" duration from overwriting the
authoritative peer-reported one. state.fromPeer flag tracks origin.
Co-Authored-By: Claude Opus 4.7 (1M context) noreply@anthropic.com - Follow-up audit fixes: Inspect nil-guard, cooldownsMode sync, StackTracker reset
- CastTracker.lua:108 — defensive nil-guard on GBI.Inspect for the
GetSpecByGUID call (matches the pattern used in Data_Cooldowns). - MinimapIcon.lua + Slash.lua: legacy unitOverlay.enabled toggle
replaced with show.cooldownsMode toggle. Avoids drift between the
two fields after the v5 schema migration. - StackTracker.Reset() added; Brain.Reset now calls it so stack
counters drop on zone change / explicit reset. - TalentSync intentionally NOT reset on zone change — its data is
player-keyed talent IDs that persist across zones; spec-change
broadcasts handle the only legitimate invalidation case.
Co-Authored-By: Claude Opus 4.7 (1M context) noreply@anthropic.com
- CastTracker.lua:108 — defensive nil-guard on GBI.Inspect for the
- Audit fixes: drop dead Purify nil, BW alias, glow leaks, schema migration
- Data_Cooldowns: removed
[527] = nilline that was deleting the
Priest Purify entry above. Purify is back in the DB. - Data_Cooldowns: removed bogus auraAliases = { "Aspect of the Wild" }
from Bestial Wrath; the buff name is just "Bestial Wrath". - Bar.lua PopulatePlaceholders prune + TestInterruptFill cleanup
now both call hideGlow() before table.remove so glow textures
don't leak when icons are pruned. - App schema migrated v4 -> v5: legacy DB.show.cooldownBar +
DB.unitOverlay.enabled fields are read once, written into
DB.show.cooldownsMode, then cleared. No more drift. - CastTracker: defensive nil-guards on GBI.Taint.SafeSpellID +
SafeGUID for cases where Taint module fails to load.
Tag-only release; CurseForge push held until verified.
Co-Authored-By: Claude Opus 4.7 (1M context) noreply@anthropic.com
- Data_Cooldowns: removed
- Bar.Reset clears icon list in-place (was orphaning bar.iconList)
The interrupt bar's progBar.iconList is set ONCE at row creation
to point at self.icons[unit]. Bar.Reset was reassigning that slot
to a fresh{}on every zone change / Brain.Reset, so the bar's
iconList kept pointing at the dropped old table. Subsequent casts
landed in the new table but the bar's OnUpdate kept iterating the
orphan -> bar appeared dead.
Fix: clear the existing list in-place (list[i] = nilfrom
length down to 1) so the table identity is preserved across
resets. Also clean any active overlay glow on the way out.
Reproducer: enter a M+ instance, get a CD, exit / re-enter, cast
something. Pre-fix the bar wouldn't update; post-fix the new cast
animates correctly.
Co-Authored-By: Claude Opus 4.7 (1M context) noreply@anthropic.com - Read notInterruptible at correct position (8th return)
- Two crash fixes
- Brain.OnCast bails for stackingResource spells (calls FlashCast
instead). Was setting endsAt + scheduling a CD timer that later
crashed onmath.abs(nil - endsAt)once SetStacks nil'd endsAt.
Reproducer: any peer broadcasts U for Void Meta -> receiver throws. - StackTracker.scanUnit checks IsSecret on aura.spellId before
indexing auraIndex, and pcalls the index for defense in depth.
Reproducer: enemy aura with secret-tagged spellId scanned by the
player's HELPFUL loop -> 1940 throws/run.
Co-Authored-By: Claude Opus 4.7 (1M context) noreply@anthropic.com
- Brain.OnCast bails for stackingResource spells (calls FlashCast
- Layout pass + interrupt bar restore + fixes
- Options panel left-margin alignment fixed: Glow checkbox no
longer indents off cdModeDD; Overlay slider stack drops the
24px inset; Test/5s preview buttons moved BELOW the slider
stack (no right-edge clipping); Bar appearance header now
anchors to testBtn at the same left margin. - Overlay section gets a "Overlay" header above its sub-controls
for visual separation. - Interrupt bar restored to the original layout per user request:
bar fills the right portion of the row at icon-tall height,
icons ride the moving fill edge as the CD ticks down. Reverts
the v0.4.0-beta grid+thin-strip experiment. - TestInterruptFill now schedules a cleanup after the test duration
ends, so test-cast icons don't linger as ready-glowing forever. - Profiles: auto-create a "Default" profile on PLAYER_LOGIN
capturing current settings; M.List always includes "Default"
defensively so the dropdown is never empty. - Zenith (1249625): re-classified to MONK Windwalker (spec=2),
60s, 2 charges. Was incorrectly added as Ret Paladin. - Rogue: Deathmark (360194, Assa, 120s) + Shroud of Concealment
(114018, all specs, 360s, utility) — added in earlier work,
now part of this release.
Co-Authored-By: Claude Opus 4.7 (1M context) noreply@anthropic.com
- Options panel left-margin alignment fixed: Glow checkbox no
- Split Options into Settings subcategories
The main GOBIGnINTERRUPT panel was getting unwieldy. Spell Database
and Profiles are now their own canvas-layout subcategories under
GOBIGnINTERRUPT in the AddOns settings tree.- New makeSubPanel(name, subtitle) helper: builds a scrollable
Settings subpanel and registers it with the parent category. - Spell Database section moved to its own subcategory.
- Profiles section moved to its own subcategory.
- Main panel keeps General + Bars + Overlay + Sounds (still scrolls
but much shorter and aligned).
Co-Authored-By: Claude Opus 4.7 (1M context) noreply@anthropic.com
- New makeSubPanel(name, subtitle) helper: builds a scrollable
- Profile manager: save / switch / import / export
New Profiles.lua module:- GBI.Profiles.Save(name) snapshot current settings into named slot
- GBI.Profiles.Load(name) swap current settings with named slot;
the UI prompts to /reload to apply - GBI.Profiles.Delete(name)
- GBI.Profiles.Export(name) serialize to "GBINT:" text
- GBI.Profiles.Import(name, str) parse text into a new profile slot
DB schema:
DB.profiles[name] = snapshot table (deep copy minus profiles +
activeProfile + transient fields like context)
DB.activeProfile = string
Options panel adds a Profiles section at the bottom with a
dropdown of saved profiles, name input + Save/Delete buttons, and
an import/export edit box. Loading a profile pops a "reload now?"
dialog since most settings need a refresh to apply.
Serialization is plain Lua-table-to-string with sandboxed
loadstring on import (setfenv to , so no globals reachable).
Co-Authored-By: Claude Opus 4.7 (1M context) noreply@anthropic.com
- Engine active only in 5-man parties (size 2-5, not raid)
- Interrupt bar: grid layout like cooldowns + thin progress strip below
- Unify show/hide: single Cooldowns dropdown + drop showAlways
- New DB.show.cooldownsMode = "off" | "bar" | "overlay" replaces
the old DB.show.cooldownBar checkbox + DB.unitOverlay.enabled
pair, which interacted in 3 confusing ways. - Options panel now has a single "Cooldowns display" dropdown
(Bar window / Party-frame overlay / Off). The legacy "Show CDs
on party frames" checkbox is gone. Mirroring keeps back-compat
for any code still reading the old fields. - Engine no longer context-gates ("show outside dungeons"
removed). Tracking happens whenever the addon's master enable
is on; the show toggles do all visibility work. Removes the
perceived conflict where a context flip overrode user toggles.
Co-Authored-By: Claude Opus 4.7 (1M context) noreply@anthropic.com
- New DB.show.cooldownsMode = "off" | "bar" | "overlay" replaces
- Late-join CD sync (Q query) + class stuns/CC additions
- Placeholders render at full color/alpha (per user preference)
- Stack-resource spells: glow at threshold, flash on cast, no fake CD swipe
Void Metamorphosis (and any future stackingResource spell) was
showing a 2h cooldown swipe because SetStacks set endsAt to
GetTime()+9999. Fix:- Brain.SetStacks no longer sets endsAt; the field stays nil so
CooldownFrameTemplate has nothing to swipe. - Bar.OnCDStart + UnitOverlay.OnCDStart detect stackCount and
switch to stack-mode rendering: SetCooldown(0,0) + glow when
count reaches stackThreshold. - CastTracker bypasses Brain.OnCast for stackingResource spells
(no CD timer to track) and instead calls Brain.FlashCast(unit,
spellID) which sets flashUntil = now+2s. Bar/Overlay treat
flashUntil > now as a forced glow ("just cast" indicator). - expireIcons clears the flash glow when its 2s window ends.
Stack reset is automatic - StackTracker observes the buff drop
on UNIT_AURA / poll and pushes count=0 into Brain.SetStacks.
Co-Authored-By: Claude Opus 4.7 (1M context) noreply@anthropic.com
- Brain.SetStacks no longer sets endsAt; the field stays nil so
- Bar.Show: cooldownBar=false now hides overlay too (showAlways respect)
- Fix CD sync bug + correct several base CD values
- Brain.OnCast now accepts an overrideDuration; the peer-comm
receive path passes the sender's broadcast duration verbatim
instead of recomputing via local TalentSync. Avoids double
talent-CDR application when both sender and receiver had
partial/conflicting talent data, which is why CDs weren't
syncing correctly. - Player Broadcast now sends the actually-applied effDur (post
TalentSync) so receivers see the player's real CD.
Data fixes per in-game observation: - Takedown (1250646): 90 -> 60
- Fortifying Brew (115203): 120 -> 240
Survival of the Fittest (264735) is a 2-charge spell — the
charges already track live via C_Spell.GetSpellCharges on the
caster, broadcast in U;sid;dur;ch;chMax. Display shows X/2.
Co-Authored-By: Claude Opus 4.7 (1M context) noreply@anthropic.com
- Brain.OnCast now accepts an overrideDuration; the peer-comm
- Per-window UI toggles (interrupts bar / cooldowns bar / overlay)
Two new checkboxes in /gbi config General section:
* Show Interrupts bar
* Show Cooldowns bar / overlay
Both default on. Off = the bar/overlay is hidden but tracking,
peer broadcast, and receiving still work. Useful for "headless"
mode (broadcast-only) or hiding one window while keeping the other.
Bar.M.Show is now the single source of truth for visibility
decisions; RefreshLayout just delegates. Show toggles + the
existing unitOverlay.enabled flag interact in 4 combinations:
cooldownBar=on, overlay=off → cooldown bar window
cooldownBar=on, overlay=on → unit-frame overlay (bar hidden)
cooldownBar=off → both hidden regardless of overlay
Co-Authored-By: Claude Opus 4.7 (1M context) noreply@anthropic.com - Drop Voidfall from DB (not needed)
- Devourer DH: wire Void Metamorphosis aura (1225789) + add Voidfall (1256301)
- Stack-resource tracking infrastructure (Void Meta etc.)
Some 12.0.5 abilities don't have a traditional cooldown - they
unlock when the player accumulates N stacks of a charging aura.
Devourer DH's Void Metamorphosis (1217605, threshold 50) is the
canonical case ("Cooldown: n/a" on Wowhead).- New StackTracker.lua: builds an aura-id -> spell-id index from
cdEntry.stackingResource = { auraID, threshold }. Listens to
UNIT_AURA on player + party + polls C_UnitAuras every 0.5s. - New CDComm message K;<sid>;<count> for peer broadcast of stack
counts. Throttled - only sent when the value actually changes. - Brain.SetStacks(unit, sid, n, threshold) synthesizes a state
entry with stackCount/stackThreshold so the bar/overlay can
render. - Bar + UnitOverlay show "n/total" overlay when stack data is
present; falls back to "ch" charge display otherwise.
Devourer Meta's stackingResource auraID is currently 0 (placeholder)
- the aura ID needs to be supplied once observed in-game via the
/run scan we asked the user to perform.
Co-Authored-By: Claude Opus 4.7 (1M context) noreply@anthropic.com
- New StackTracker.lua: builds an aura-id -> spell-id index from
- Add Void Metamorphosis (1217605) - Devourer DH dynamic CD
- Dynamic CD support: detect runtime CDR + peer D delta messages
For spells whose remaining cooldown shrinks during the cooldown
window (Devourer DH Metamorphosis reduced by ability usage,
charge-per-cast reductions, etc.), peer broadcast keeps everyone
in sync.- New CDComm message: D;<spellID>;<remaining>
- Brain.UpdateRemaining(unit, sid, sec) - applies an inbound delta
by shortening the existing entry's endsAt and re-rendering the
bar/overlay. Ignores noise (<0.5s diff). - SPELL_UPDATE_COOLDOWN listener on the local player polls every
active tracked spell; if the engine reports a shorter remaining
than we expect, locally update + broadcast D (throttled to 1/sec
per spell). - Works for any spell with dynamic CDR - no per-spell DB flag
needed. The poll is generic.
Co-Authored-By: Claude Opus 4.7 (1M context) noreply@anthropic.com
- Peer-comm enhancements: spec / interrupt / charges / talent CDR
- CDComm protocol extended (back-compat: receivers tolerate missing
trailing fields):- U;sid;dur[;charges;chargesMax] cast announcement
- S;specID spec announcement
- I self-interrupt landed
- T;node,node,... active talent node IDs
All outgoing messages gated by GBI.Taint.IsSecret to never leak
tagged values to the addon channel.
- Inspect.SetSpecForUnit lets CDComm S messages preempt the slow
NotifyInspect cycle for units running the addon. - KickCounter.AttributePeer credits the sender directly when their
CDComm I message arrives; suppresses temporal-attrib race for
~0.5s afterwards. Self-attribution now broadcasts I so peers
credit us instead of running their own heuristic. - Bar + UnitOverlay show a charge-count overlay (NumberFontNormalSmall,
bottom-right of icon) when state.charges/chargesMax > 1.
Brain reads C_Spell.GetSpellCharges on local-player casts and
includes the count in the U broadcast. - New TalentSync.lua: each instance reads its own active talent
nodes via C_Traits and broadcasts them as T messages. AdjustCD
applies registered CDR rules per-unit so a talented Hunter sees
Aspect of the Turtle at 150s while an untalented one sees 180s.
Seed list of 5 well-known reductions; extensible at runtime.
All four features fall back to existing behavior when the peer
isn't running the addon - no impact on non-addon party members.
Co-Authored-By: Claude Opus 4.7 (1M context) noreply@anthropic.com
- CDComm protocol extended (back-compat: receivers tolerate missing
- Aura aliases + interrupt-pull only fires for interruptible casts
- AuraMap: entries can declare auraAliases = { "name1", ... } for
spells whose buff name differs from cast name. build() registers
each alias under the same class. Lookup function unchanged -
unknown names still miss cleanly. - Interrupt.lua: onStart_inner now probes UnitCastingInfo's
notInterruptible flag (tag-safe boolean check via laundered_bool)
and skips the alert + sound when the cast can't be interrupted.
Boss casts and uninterruptible channels no longer trigger spam.
Co-Authored-By: Claude Opus 4.7 (1M context) noreply@anthropic.com
- AuraMap: entries can declare auraAliases = { "name1", ... } for
- Tidy remaining audit items (#3, #4, #9, #10)
- Constants.lua adds K.IsCooldownBarCategory(cat); Bar + Overlay
use it instead of the duplicated chain of category != X checks (#3). - Drop empty M.OnAllReady stub from Bar.lua + the call site in
Brain.lua. Sound was already fired by Brain.fireAllReady directly;
the stub never did anything (#4). - Options.rebuildList early-returns if neither GBI.IterCooldowns
nor GBI.Cooldowns is loaded yet (defensive against load-order
races) (#9). - Bar instance Hide() now clears any active overlay-glow state on
its icons so glows don't leak when the engine flips off mid-glow
and back on later (#10).
Co-Authored-By: Claude Opus 4.7 (1M context) noreply@anthropic.com
- Constants.lua adds K.IsCooldownBarCategory(cat); Bar + Overlay
- Cooldown sort modes + interrupts always-tracked + audit cleanup
- New sort modes for cooldown bar + unit overlay:
- "By remaining CD" (default) — current behavior
- "Offensive first" — BIGCD/OFFENSIVE > DEFENSIVE > UTILITY
- "Defensive first" — DEFENSIVE > BIGCD/OFFENSIVE > UTILITY
Within each bucket: live by endsAt, then placeholders.
Setting in /gbi config under Bar appearance, applies to both
Cooldowns bar and party-frame overlay (DB.cdSort).
- Interrupts are now ALWAYS tracked internally even if the user
unticks them in the Spell DB. GBI.GetCooldown ignores the
disabled flag for K.CAT_INTERRUPT spells, so the Interrupts
bar + KickCounter keep working regardless. - Audit cleanup #5: dropped vestigial DB.interrupt.mode/ratio
fields from ensureCfg + slash + comments. /gbi int now uses
"delay <seconds>" instead of "ratio/fixed". - Audit cleanup #6: rewrote Evidence.lua header to match its
current implementation (UNIT_AURA + polling + CDComm
redundancy) instead of "Phase 1 stub" boilerplate.
Co-Authored-By: Claude Opus 4.7 (1M context) noreply@anthropic.com
- New sort modes for cooldown bar + unit overlay:
- Audit fixes: orphan placeholders + dispatch nil-guard
- PopulatePlaceholders (Bar + UnitOverlay) now ALWAYS prunes
stale icons - whether placeholder or live - if the spell ID
is no longer in the expected set (user disabled it, spec
changed). Previously a disabled spell that was actively on
cooldown left the icon orphaned forever. - Pruning also runs when the placeholders feature is toggled
off mid-session, so existing dim icons disappear cleanly.
Add step is gated by the feature flag; prune step always runs. - Bar.dispatch checks GBI.UnitOverlay isn't nil before indexing
ov[fnName] - falls back to barCD if the module isn't loaded.
Per audit findings #1, #2, #8 (high/medium severity).
Co-Authored-By: Claude Opus 4.7 (1M context) noreply@anthropic.com
- PopulatePlaceholders (Bar + UnitOverlay) now ALWAYS prunes
- Cooldown bar + overlay: same as interrupts (no glow on ready, no re-dim)
- Interrupt bar: don't re-dim after first detection (only placeholders dim)
- Interrupt bar: dim icons when ready (not glow); position placeholders
- When an interrupt CD ends, the icon stays visible but dims to
alpha 0.4 + desaturated (matching the placeholder look). Live
cast un-dims it. Cooldown bar still glows on ready (unchanged). - Bar OnUpdate now positions placeholder/ready icons at the
"frac=0 / ready end" of the bar so they're visible without
needing endsAt.
Co-Authored-By: Claude Opus 4.7 (1M context) noreply@anthropic.com
- When an interrupt CD ends, the icon stays visible but dims to
- CDComm: default ON when DB.comm.enabled is unset (existing savedvars)
- CDComm: verbose tracing on broadcast + receive paths
- Spec-aware placeholders: use GetSpecialization for player; prune wrong-spec icons
Fixes overlay/bar showing OTHER specs' icons greyed out:- SpellsForUnit now uses GetSpecialization() directly when unit
is "player" - the local API is always correct, no need to wait
for GBI.Inspect to populate the player's GUID->spec cache. - PopulatePlaceholders (both Bar and UnitOverlay) now PRUNES
existing placeholder entries that aren't in the current
expected-spell set. Previously, when inspect was permissive
initially (unknown spec -> show all class spells) and later
resolved the actual spec, the wrong-spec icons stayed.
Co-Authored-By: Claude Opus 4.7 (1M context) noreply@anthropic.com
- SpellsForUnit now uses GetSpecialization() directly when unit
- IterCooldowns honors disabled list; UI bypasses with true flag
Disabled spells were still showing as overlay placeholders because
GBI.IterCooldowns merged built-in + custom but never consulted
DB.spellDb.disabled. SpellsForUnit (used by placeholder code) and
all other runtime callers now get only the active subset.
The Spell DB UI in /gbi config calls IterCooldowns(true) so it
can display + manage disabled entries (otherwise unticking a
spell would make it disappear from the list).
Co-Authored-By: Claude Opus 4.7 (1M context) noreply@anthropic.com - Spell DB category filter + DH Devourer + burst offensive-only
- Spell DB tab now has a third dropdown: All / Offensive /
Defensive / Interrupt / Utility/Dispel. Filters the list with
class+spec for fine-grained DB management. - DEMONHUNTER spec list extended with "Devourer" (spec 1480) -
was missing from the spec dropdown. - Burst-ready trigger now only considers OFFENSIVE big CDs
(CAT_BIGCD, CAT_OFFENSIVE). Defensives in seenBig or
allReadyList are filtered out so the cd_ready sound fires
strictly on offensive readiness.
Co-Authored-By: Claude Opus 4.7 (1M context) noreply@anthropic.com
- Spell DB tab now has a third dropdown: All / Offensive /
- Spell DB: add spec sub-filter dropdown next to class
- Spec-aware placeholder pre-population (default on)
Bars and unit overlays now pre-populate with dim/desaturated icons
for every CD a party member's class+spec could use - regardless of
whether it's been observed yet. When the spell is actually cast,
the placeholder converts to a live icon (un-dim, alpha 1.0,
cooldown swipe runs). When ready: glow as before.- GBI.SpellsForUnit(unit) - iterates the merged DB filtered by
class+spec, permissive on unknown spec. - Bar.PopulatePlaceholders + UnitOverlay.PopulatePlaceholders
create dim icons for matching spells (interrupt-only on the
Interrupts bar; defensives + big DPS elsewhere). - OnCDStart finds existing entries by spellID first; placeholder
-> live conversion on first observed cast. - relayout sort: live entries first (by endsAt), placeholders
trailing (by spellID). - Triggered on Show() + INSPECT_READY + PLAYER_SPECIALIZATION_CHANGED
- GROUP_ROSTER_UPDATE.
- Default DB.placeholders.enabled = true.
Inspired by InterruptTrack's IT.GetSpellsForUnit (IT_Core.lua:778).
Co-Authored-By: Claude Opus 4.7 (1M context) noreply@anthropic.com
- GBI.SpellsForUnit(unit) - iterates the merged DB filtered by
- Peer-to-peer CD sharing (default on)
New CDComm.lua module: each addon instance broadcasts its own
observed casts to the party/raid via C_ChatInfo.SendAddonMessage
on prefix "GBINT". Receivers parse and call Brain.OnCast for the
sender's party unit, painting their CD as if locally observed.
Solves the 12.0.5 remote-PC redaction problem cleanly: where
local UNIT_SPELLCAST and UNIT_AURA fail for foreign party
members, the data arrives instead via the addon channel from
their own (unredacted) instance. Both ends must run GBINT.
Wire format: U;<spellID>;<duration>
Channel: RAID if in raid, else PARTY.
Inspired by InterruptTrack's prefix-based protocol (see
InterruptTrack.lua:185, 4050, 3683-3715). Default enabled; toggle
via DB.comm.enabled.
Hooked into Brain.OnCast: broadcasts every player cast that
already passed CastTracker's filters. Not broadcasted for unit
~= "player" (so we don't echo received messages back).
Co-Authored-By: Claude Opus 4.7 (1M context) noreply@anthropic.com - Spell DB tab: per-class spell list + custom add
- Add 20 missing tracked CDs from InterruptTrack DB
Cross-referenced our Data_Cooldowns vs InterruptTrack's IT_Core
spell data; added 16 entries we were missing plus 4 commonly-
tracked extras.
Defensives: Fiery Brand, Metamorphosis (Veng), Last Resort,
Berserk (Guardian), Ironbark, Time Dilation, Life Cocoon,
Divine Hymn, Guardian Spirit, Ascendance (Resto), Die by the
Sword, Enraged Regeneration, Alter Time, Ice Cold,
Blessing of Spellwarding.
Big DPS: Takedown (12.0.5 SV Hunter), Invoke Niuzao,
Shadow Dance, Avenging Crusader.
Interrupt: Axe Toss (Felguard pet, Demo Lock).
Skipped racials (Stoneform, Shadowmeld, Feign Death) and one
duplicate (19647 Spell Lock — already covered by 119910).
Co-Authored-By: Claude Opus 4.7 (1M context) noreply@anthropic.com - Hide interrupt-bar rows for classes/specs without an interrupt
- Visual-settings audit: interrupt grow-direction live + exposed
- applyScale for progressBar bars now re-applies SetReverseFill
according to effGrowDir() so changing the dropdown reflects on
the existing bars without /reload. - Re-add Grow direction dropdown to the Interrupts window in
/gbi config (next to the Bar width slider). Was hidden after
the bar-width refactor.
Other visual settings audited - all wire correctly through their
refresh path:- overlay side/offsets/iconSize/iconGap -> UnitOverlay.Refresh
- cooldowns iconSize/iconsPerRow/growDir -> ApplyAllBars
- glow toggle -> expireIcons reads glowEnabled() each tick
- lock anchor -> applyLocked + RefreshLocked
Co-Authored-By: Claude Opus 4.7 (1M context) noreply@anthropic.com
- applyScale for progressBar bars now re-applies SetReverseFill
- Interrupt bar: grow direction now flips fill side + icon tracking
The grow-direction control on the Interrupts window was previously
ignored - bars always tick down right-to-left. Now:- RIGHT (default): fill anchored at left edge of bar; as time
passes the right edge of fill moves leftward. Icons track that
moving edge (sliding left). - LEFT: SetReverseFill(true) so fill is anchored at the right
edge; as time passes the LEFT edge of fill moves rightward.
Icons anchored CENTER -> bar.RIGHT and slide right toward the
bar's right end.
Note: re-add the grow-direction dropdown to the Interrupts window
in Options if you want it controllable from /gbi config (it's
currently hidden because makeBarControls' isProgressBar branch
shows bar-width instead).
Co-Authored-By: Claude Opus 4.7 (1M context) noreply@anthropic.com
- RIGHT (default): fill anchored at left edge of bar; as time
- Container width = icon row width (not n*(size+gap))
Off-by-one: previous formula counted a trailing gap after the
last icon, so increasing the spacing slider grew the test-mode
green background past the actual icon row. Use the precise span
n*size + (n-1)*gap.
Co-Authored-By: Claude Opus 4.7 (1M context) noreply@anthropic.com - Centralized secret-value detection via issecretvalue
WoW exposes issecretvalue as a global in 12.0.5 (used by OmniReborn,
InterruptTrack, Kicker as the canonical detection helper). Adopting
the same pattern:- GBI.Taint.IsSecret(v) - true if v is secret-tagged. Falls back
to a pcall probe if the global isn't available. - GBI.Taint.SafeString2(v) - returns v only if non-tagged string.
- SafeSpellID now uses IsSecret for the up-front gate.
- AuraMap.LookupByName uses SafeString2 to reject tagged names
cleanly before any table access.
Eliminates the throw class entirely instead of catching them
one by one with reactive pcalls.
Co-Authored-By: Claude Opus 4.7 (1M context) noreply@anthropic.com
- GBI.Taint.IsSecret(v) - true if v is secret-tagged. Falls back
- Pcall AuraMap.LookupByName lookup; drop GUID :sub in log
- Kicker-style cross-attribution for interrupt counter
Inspired by /Kicker/Modules/Interrupt.lua and verified compatible
with InterruptTrack's pattern. Sidesteps 12.0.5 spellID redaction
on remote-PC parties:- Track timestamp of every UNIT_SPELLCAST_SUCCEEDED per friendly
unit (player/partyN/partypetN). Spell ID isn't needed - only
the unit token, which is never tagged. - Listen to UNIT_SPELLCAST_INTERRUPTED on enemy units (target,
focus, bossN, nameplateN). - When an enemy cast is interrupted, attribute the kick to the
party member whose UNIT_SPELLCAST_SUCCEEDED fired in the last
0.5s. Most recent wins. - Existing per-spell counter (player's own kicks via spellID
match) still works in parallel; cross-attrib runs alongside.
This finally lets the counter increment for party members on the
remote-PC scenario where event spell IDs are unusable.
Co-Authored-By: Claude Opus 4.7 (1M context) noreply@anthropic.com
- Track timestamp of every UNIT_SPELLCAST_SUCCEEDED per friendly
- Persist tracked-CD icons for the run; glow when ready
Once a CD is detected (via cast event or aura poll), the icon now
stays on the bar and on the unit-frame overlay for the rest of
the run. expireIcons no longer removes them; instead it adds an
ActionButton overlay glow when the CD is ready and clears the
glow when a new cast resets endsAt. Brain.Reset (zone change /
new dungeon) still flushes everything via Bar.Reset for a clean
slate.
Resolves the "icons fade away" complaint from in-game testing -
the addon now functions as a persistent run-long readiness board.
Co-Authored-By: Claude Opus 4.7 (1M context) noreply@anthropic.com - Route poller through fire() for dedup against UNIT_AURA path
- Aura polling fallback for redaction-walled party CDs
On the user's remote-PC dual-box configuration, both
UNIT_SPELLCAST_* and UNIT_AURA events are silent for partyN.
Bypass the event wall by directly calling C_UnitAuras.GetAuraDataByIndex
every 0.75s on each party member, comparing aura names against the
AuraMap byNameClass index, and firing Brain.OnCast for newly-seen
aura names. Re-detection allowed after a 5s gap so refreshed CDs
re-fire.
Co-Authored-By: Claude Opus 4.7 (1M context) noreply@anthropic.com - Aura name fallback for remote-PC party CD detection
UNIT_SPELLCAST_SUCCEEDED is silent for remote-PC party members in
12.0.5 and the existing UNIT_AURA path's aura.spellId can be
unlaunderable. OmniReborn and MiniCC both solve this with a
spell-NAME fallback - aura.name is plain text and never tagged.- AuraMap now also indexes Data_Cooldowns by name+class
(byNameClass[name][CLASS_TOKEN] -> spellID), with a
LookupByName(name, classToken) helper. - Evidence.lua tries spellId first; on miss, pcalls aura.name and
consults AuraMap.LookupByName. Same downstream fire path as the
spellId case, with Brain dedup preventing double-fires. - Verbose Debug logging at every step so we can see exactly what
UNIT_AURA delivers per cast.
Co-Authored-By: Claude Opus 4.7 (1M context) noreply@anthropic.com
- AuraMap now also indexes Data_Cooldowns by name+class
- Launder castGUID via string.format before regex; log match failures
- Recovery now always sets spellID, even for non-DB spells
Previously the castGUID recovery only set spellID if the recovered
ID was in our CD database — so any party-member spell whose ID
wasn't tracked would silently fall through to "cannot resolve",
even when we'd successfully extracted the correct ID. The user
saw e.g. party2's Aimed Shot (19434) parsed correctly but logged
as unresolvable.
Now recovery sets spellID unconditionally on a successful parse;
the downstream "not in CD database" branch handles the actual
miss with proper logging.
Co-Authored-By: Claude Opus 4.7 (1M context) noreply@anthropic.com - Sturdier laundering: dual-path tostring + string.format("%d")
Logs from a remote-PC dual-box show party member rawSpellIDs are
losing the launder despite tostring printing the digits ("19434"
shows in the log but tonumber returns nil). Try a second pass with
string.format("%d", x) - C-level integer conversion, output is
plain Lua, tonumber strips any residual taint. Also pcall the0 comparison in SafeSpellID since arithmetic comparisons on
tagged numbers can throw.
Co-Authored-By: Claude Opus 4.7 (1M context) noreply@anthropic.com - Log skip when spellID can't be resolved (silent returns)
- Harden GBI.GetCooldown against secret-tagged spellIDs
The remote-PC scenario shows that even after laundering through
tostring -> tonumber, the resulting number can still be secret-
tagged (engine appears to track propagation through arithmetic on
some classes of values). type(spellID) returns "number" on tagged
numbers so the existing gate doesn't catch it.
Single-chokepoint fix: GBI.GetCooldown now pcalls the table index.
A tainted key just misses cleanly instead of throwing. KickCounter
.isInterruptSpell now uses GBI.GetCooldown instead of direct
GBI.Cooldowns indexing so it inherits the protection.
Resolves the recurrence at KickCounter.lua:33 reported on remote
PC after the prior launder-only fix.
Co-Authored-By: Claude Opus 4.7 (1M context) noreply@anthropic.com - Workflow: grant contents:write so packager can create GitHub releases
- Simplify .pkgmeta: drop license-output + manual-changelog + empty externals
- Remote-PC party CD tracking fixes (12.0.5 secret-value hardening)
- KickCounter.lua: launder UNIT_SPELLCAST_SUCCEEDED's arg3 spellID
through GBI.Taint.SafeSpellID before any table-key indexing.
Mirrors the pattern already used in CastTracker.lua. Without this,
remote-PC party members trigger "secret value" Lua errors at
GBI.Cooldowns[spellID] lookup. - CastTracker.lua: wrap the castGUID:match recovery call in pcall.
castGUID strings can also be secret-tagged on remote-PC party
members; the method-call index would throw before. Now falls back
silently if the string is tagged. - Bar.lua: ensure the unit-frame overlay is re-shown whenever a CD
is dispatched to it. The overlay'svisibleflag could be flipped
off by App.UpdateContext (e.g. context=world) hiding the engine
even though the user explicitly opted into the overlay. Calling
ov.Show() before painting is idempotent and keeps the display
honoring DB.unitOverlay.enabled regardless of engine state.
Diagnosed by debug-handoff session on a remote-PC dual-box setup
where party members are genuinely "remote" and trigger taint
enforcement that the original-PC dual-box did not.
Co-Authored-By: Claude Opus 4.7 (1M context) noreply@anthropic.com
- KickCounter.lua: launder UNIT_SPELLCAST_SUCCEEDED's arg3 spellID
- Burst-ready quality gates (A + B + C)
Refuses to fire the cd_ready sound on trivial bursts. The latch
still re-arms on all-ready, but the actual sound only fires when
ALL three gates pass:
A) effective set has >= 3 spells (no fire from a one-spell
observation in auto mode)
B) peak simultaneous-on-CD count during the burst was >= 2
(no fire when only one spell ever overlapped)
C) burst window has been open for >= 30s (no instant on/off
re-fires from a brief recast)
Tracks burstStartAt + burstPeakInFlight, recomputed at every cast
of a tracked spell. Both reset on M.Reset and after each fire/skip
decision. Gate-failures log at Debug level for tuning.
Co-Authored-By: Claude Opus 4.7 (1M context) noreply@anthropic.com - Drop dead bar.text writes (no font template -> SetText errors)
- Overlay icon spacing slider (0..20 px)
ICON_GAP is now read from DB.unitOverlay.iconGap (default 2)
instead of being a hardcoded local. New slider in /gbi config
under the overlay icon-size slider; live-applies via UnitOverlay
.Refresh which re-relayouts every container.
Co-Authored-By: Claude Opus 4.7 (1M context) noreply@anthropic.com - Interrupt row: drop duplicate seconds text + fix ready-stick
- OnCDReady on the Interrupts window no longer hides the icon -
it just sets endsAt to "now" so the next expireIcons tick
flips the entry into the ready/glowing state. Previously the
Brain's CD-ready timer fired Hide() unconditionally, undoing
the persistence we'd added. - Removed the bar's own seconds-remaining fontstring (the icon's
CooldownFrameTemplate already shows the countdown). Avoids a
duplicate number rendering on the far right of the bar.
Co-Authored-By: Claude Opus 4.7 (1M context) noreply@anthropic.com
- OnCDReady on the Interrupts window no longer hides the icon -
- Interrupt row polish: name strip, ready-glow, hide empty rows
- Name strip is now a separate area on the LEFT of the bar, right-
aligned against the bar's left edge. Bar starts at NAME_WIDTH px
in from the row's left. - When a spell goes off CD on the Interrupts window, the icon now
PERSISTS at the bar's leftmost (frac=0) edge with an Action-
Button glow effect, indicating the player is ready to interrupt.
On next cast the glow clears and the icon rides the fill edge
right-to-left again. - OnCDStart now reuses the existing entry by spellID (so the same
ready-glowing icon transitions back into a ticking CD without
creating a duplicate). - refreshNames hides empty party slots entirely and repacks the
visible rows + shrinks the panel height to fit.
Co-Authored-By: Claude Opus 4.7 (1M context) noreply@anthropic.com
- Name strip is now a separate area on the LEFT of the bar, right-
- Interrupt name overlays bar + always visible
Name fontstring is now anchored to row.progBar's LEFT (overlaying
the bar) instead of sitting in its own strip above. Row height
collapses back to icon-tall. applyLocked no longer hides the name- it stays visible regardless of lock state since locking should
just dim chrome, not strip identification.
Co-Authored-By: Claude Opus 4.7 (1M context) noreply@anthropic.com
- it stays visible regardless of lock state since locking should
- Interrupt row: name above bar, icons ride the fill edge
- Row layout reshaped: name strip (14 px, BLACK OUTLINE for class
color legibility) sits above the bar; bar fills bottom portion
at icon-tall height. - Bar fill color switched to neutral teal-blue so it never collides
with class-color names. - Each visible icon now rides its own fill edge: position recomputed
every frame as(remaining/total) * barWidthfrom the bar's left
edge. As the CD ticks down, icons slide leftward with the fill. - Default per-icon layout (LEFT/RIGHT grow + per-row wrap) is now
bypassed for the Interrupts window since the bar OnUpdate owns
icon positioning.
Co-Authored-By: Claude Opus 4.7 (1M context) noreply@anthropic.com
- Row layout reshaped: name strip (14 px, BLACK OUTLINE for class
- Interrupt bar fixes: tick-down fill + fixed panel width
- Row-wide progress bar now ticks DOWN: full at cast, empties to
zero at ready. Previously grew from 0 -> max which looked like
"no bar visible" right after cast. SetValue now feeds remaining
seconds against (0, total). - Interrupts window panel width is fixed (DB.bars.interrupts.barWidth,
default 220 px) instead of being multiplied by icons-per-row.
Icons just stack inside the bar area; bar always spans the same
visual length regardless of how many CDs are active. - Options panel now shows a "Bar width" slider for the Interrupts
window, and the icons-per-row + grow direction controls only for
the Cooldowns window. Avoids the confusion of icons-per-row
affecting an interrupts bar where the bar IS the row.
Co-Authored-By: Claude Opus 4.7 (1M context) noreply@anthropic.com
- Row-wide progress bar now ticks DOWN: full at cast, empties to
- Visual interrupt test (button + slash)
GBI.Bar.TestInterruptFill schedules a fake 15s Pummel CD on every
party slot so row layout, progress bars, scaling, and grow direction
can be tuned without a live M+ pull. Wired in two places:- /gbi test interrupt - now fills the bar in addition to firing
the interrupt-alert sound (previous behaviour kept). - "Test interrupts (15s)" button in /gbi config beside the
Bar appearance header.
Co-Authored-By: Claude Opus 4.7 (1M context) noreply@anthropic.com
- /gbi test interrupt - now fills the bar in addition to firing
- Initial public release setup

