promotional bannermobile promotional banner

Cerebro

Modern EPGP & Loot Distribution with native RCLootCouncil & Mythic+ integration.

File Details

v0.10.29

  • R
  • Mar 20, 2026
  • 5.77 MB
  • 110
  • 12.0.1+1
  • Retail

File Name

Cerebro-v0.10.29.zip

Supported Versions

  • 12.0.1
  • 11.2.7

Cerebro

v0.10.29 (2026-03-20)

Full Changelog

  • Merge pull request #35 from Shezzannn/feature/guild-roster-sync-dashboard
    feat(standings): Guild Roster Sync Dashboard with all PR review fixes
  • chore: Bump version to 0.10.29
    Guild Roster Sync Dashboard: combat guard on guild scan and heartbeat UI refresh; LWW sentinel for auto-discovered players; semver version comparison; cached online-member lookup; DRY sync health helper; correct no_addon (red) / unknown (gray) colors; stale addonStatus pruning; config hash convergence fix (sync.lastUpdate excluded, fixes 25/25 to 1/25 every-5-min bounce)
  • fix(standings): apply all 13 PR #35 review fixes
    Critical:
    • Fix 1: Add InCombatLockdown() guard in HandleHeartbeat addon-state refresh timer;
      add PLAYER_REGEN_ENABLED post-combat flush in CommunicationV2
    • Fix 2: Add not InCombatLockdown() guard before DiscoverFullGuildRoster in
      GROUP_ROSTER_UPDATE (prevents mid-boss DB writes + RecalculateAllPR)
    • Fix 3: Correct comment GUILD_ROSTER_UPDATE -> GROUP_ROSTER_UPDATE
    • Fix 4: Remove duplicate INACTIVE_THRESHOLD local; expose as
      CommunicationV2.INACTIVE_THRESHOLD module constant
    • Fix 5: DiscoverFullGuildRoster creates Pending+lastUpdate=0 stubs (LWW sentinel)
      instead of Core+real timestamp to prevent auto-discovery winning over officer data
      Important:
    • Fix 6: Add CommunicationV2:CompareVersions() semver helper; replace all
      lexicographic v < maxVersion comparisons in GetAddonState + ShowSyncHealthTooltip
    • Fix 7: Add CommunicationV2:GetOnlineGuildMembers() with 10s TTL cache;
      replaces O(N) guild scan per standings row in GetAddonState
    • Fix 8: Add StandingsFrame:ComputeSyncHealth() DRY helper; refactor Draw()
      and Refresh() to call it instead of duplicating the sync-pct block
    • Fix 9: Split no_addon (red, online+no addon) from unknown (dim gray,
      offline/indeterminate) in GetAddonStateColor per design intent
      Minor:
    • Fix 10: Prune addonStatus entries older than 7 days in InitSyncState
    • Fix 11: Add GetMaxAddonVersion() with _cachedMaxVersion cache; invalidate on HB
    • Fix 12: Anchor _dev pattern to end of string (_dev$) everywhere
    • Fix 13: Remove tools/inspect_pb.ps1 (unrelated debug utility)
  • chore(tasks): add PR #35 fix task tracker and implementation plan
    13 fixes across Core.lua, CommunicationV2.lua, StandingsFrame.lua:
    • Critical: combat guards, LWW safety, class on restore
    • Important: semver helper, guild lookup cache, sync health DRY, color split
    • Minor: addonStatus pruning, version cache, _dev anchor, ps1 removal
  • fix(standings): resolve 4 bugs found in deep-dive PR review
    Bug 1 (StandingsFrame.lua:184) — broken WoW color code
    GetAddonStateTooltip used |cfffe8<000 for the outdated state label.
    The < is not valid hex; WoW ignores the color and renders as plain
    text. Fixed to |cfffe8700 (matching the tooltip row color).
    Bug 2 (Core.lua:728) — DiscoverFullGuildRoster skips Pending stubs
    Race condition: GROUP_ROSTER_UPDATE fires immediately on login and
    DiscoverGuildGroupMembers creates Pending stubs (lastUpdate=0) for
    all raid members. The 10s login timer then fires DiscoverFullGuildRoster,
    which skipped anyone already in players — including those fresh stubs.
    Result: visible-rank raiders stayed Pending, defeating the feature's
    primary purpose. Fix: detect the sentinel (status=Pending, lastUpdate=0)
    and upgrade stubs to Core, preserving ep/gp/class from the stub.
    Bug 3 (StandingsFrame.lua:407) — Restore creates classless record
    ShowRemovedPlayersPopup Restore path created the new Core record
    without a class field. Fixed: look up class from guild roster before
    creating the record (same pattern as MergeRosterData/Admit to Core).
    Bug 4 (StandingsFrame.lua:1104) — _removedPlayersLabel shows "0 removed"
    After the last purged/blocked player is restored/unblocked, Refresh()
    kept updating the label text to "| 0 removed" with no way to hide it
    short of closing the window. Fixed: clear the label text to "" when
    count == 0 so the widget takes no visual space.
    Luacheck: 0 warnings / 0 errors in 2 files
  • fix(sync): exclude sync.lastUpdate from config hash computation
    sync.lastUpdate is a merge-metadata LWW timestamp stored inside
    config.sync. ComputeConfigHash()'s recursive serializer was including
    it, causing two officers with identical settings but different save
    timestamps to compute permanently different config hashes — the
    ping-pong loop seen in debug logs (0b565077 vs 690de2b8 vs c0583603).
    Fix: add EXCLUDED_NESTED_KEYS = inside the
    serialize() closure so LWW timestamps are never part of the content
    hash, regardless of which config section contains them.
    Luacheck: 0 warnings / 0 errors
    validate_docs.py: all checks passed
  • fix(standings): sync bar now requires both roster AND config hash match
    Previously only rosterHash was checked, causing 100% (9/9) to display
    even when configHash diverged on 6 of 9 peers. Now a peer is only
    counted as fully synced when both hashes match. The tooltip detailed
    breakdown (roster vs config separately) is unchanged for diagnostics.
  • fix(standings): apply Offline steel blue-gray to guild rank column
    no_addon and unknown states now both use {0.45, 0.50, 0.62} in
    GetAddonStateColor, matching the tooltip Offline color. Red (no_addon)
    and dim gray (unknown) are consolidated since both represent offline.
  • fix(standings): improve Offline tooltip color readability
    Changed from near-black (0.28, 0.28, 0.28) to steel blue-gray (0.45, 0.50, 0.62).
    Readable against dark tooltip background, cool tone suggests 'disconnected',
    clearly distinct from the warm neutral gray of Inactive.
  • feat(standings): rewrite addon compliance tooltip counts
    • Compliance now scoped to visible guild roster (visibleRanks filtered,
      excluding purged/blocked) instead of raw addonStatus table
    • Self (local officer) now counted in 'Synced & current'
    • Replaced 'No addon detected' with 'Offline' bucket (dimmer gray):
      synced = in addonStatus, recent, current version
      outdated = in addonStatus, recent, old version
      inactive = in addonStatus, >90s ago (darker gray)
      offline = never in addonStatus at all (darkest gray, 0.28)
    • Total now matches visible standings player count
    • Sync: 100% label turns green in both Draw() and Refresh()"
  • feat(standings): split sync bar into two separate hover zones
    • ShowSyncHealthTooltip: removed the inline removed-players list
    • ShowRemovedPlayersTooltip: new fn showing only purged/blocked names
    • Draw(): sync bar is now two InteractiveLabels:
      'Sync: X% (N/M)' -> hover = hash/compliance/epoch stats
      'N removed' -> hover = removed players list, click = popup
    • Refresh(): updates both labels independently"
  • fix(standings): include self in tooltip peer counts
    ShowSyncHealthTooltip had its own peerHashes loop that also omitted
    self, showing 3/3 peers instead of 4/4 when 4 officers were online.
    Adds +1 to rMatch and cMatch after the loop (self never differs).
  • fix(standings): remove blank spacer between filter row and table
    The spacer Label was invisible before the sync health bar was added.
    Once the bar caused the filter row to wrap to two lines, the spacer
    became a visible blank gap between the search bar and column headers.
  • fix(standings): include self in sync peer count
    peerHashes only contains other players' heartbeats — the local officer
    is never in it. Was showing 3/3 when 4 officers were online. Now adds
    +1 to both syncedPeers and totalPeers after the loop so the local
    player is always counted as synced (self-check already returns 'synced').
  • fix(standings): self red color and stale sync bar
    • GetAddonState: short-circuit to 'synced' for local player — HandleHeartbeat
      self-excludes so the local officer never had an addonStatus entry, causing
      them to fall through to the guild online check and return 'no_addon' (red)
    • Refresh(): update _syncHealthLabel text with live peerHashes data on every
      call — the label was created once in Draw() and never updated, causing the
      sync percentage to stay stale until a tab reopen"
  • fix(standings): sync dashboard bug fixes
    • addonStatus keys now normalized to full Name-Realm before write
      (AceComm passes short name on same-realm; lookup was always missing)
      → fixes all rank colors showing red (no_addon)
    • Removed Players popup: added ScrollFrame container so 10+ entries
      scroll instead of overflowing
    • Removed Players popup: fixed 350px height keeps AceGUI close button
      always visible regardless of entry count
    • Removed Players popup: added duplicate guard (self._removedPlayersPopup)
      so re-clicking closes old popup before opening new one"
  • feat(standings): guild roster sync dashboard
    • Auto-discover all visible-rank guild members on login (DiscoverFullGuildRoster,
      10s delay, 60s throttle). Purge/block lists take absolute priority. Core
      status assigned directly (visibleRanks IS the admission gate).
    • Guild rank text color now encodes 5-state addon compliance for officers:
      green=synced, yellow=outdated, dark gray=inactive, red=no addon, dim=unknown.
      Raiders continue to see the original binary green/gray color.
    • Sync health bar added to filter row top-right of Standings (officer-only).
      Shows 'Sync: X% (N/M) | N removed'. Hover reveals per-hash breakdown,
      addon compliance counts, epoch, last HB age, and named purged/blocked players.
    • Clicking the 'N removed' label opens a Removed Players popup with
      per-row Restore/Unblock buttons (RBAC-gated, audit-logged).
    • Real-time UI reactivity: state-change detection in HandleHeartbeat
      triggers a 1s debounced RefreshAllUI() — no window reopen needed.
    • addonStatus stored in syncStateV2 (NOT players) — hash-immune by design.
    • _dev version suffixes excluded from max version computation."