promotional bannermobile promotional banner

Guild Mate

A guild bank donation tracker and goal management tool.

File Details

v0.4.5-bcc

  • R
  • Apr 12, 2026
  • 216.36 KB
  • 22
  • 2.5.5
  • Classic TBC

File Name

GuildMate-v0.4.5-bcc.zip

Supported Versions

  • 2.5.5

GuildMate

v0.4.5 (2026-04-12)

Full Changelog Previous Releases

  • v0.4.5: Comm hardening, broadcast fixes, slot-based enchants
    • Remove HELLO welcome dump; data propagates via real events or /gm sync
    • Fix donation double-counting (kill synthetics, heal on DB:Init)
    • Per-sender rate limit + strict version gate + schema write lock
    • Show addon version per member in officer roster
    • Slot-based enchanting recipe grouping (Helm/Shoulder/Cloak/...)
    • Category ordering for all professions matching in-game window
    • Scan UX: progress messages, session-scoped announcements, coalesced timers
    • Goal shown in grey for off-rank members with guild-wide progress
    • Fully-vendored libs so builds don't depend on CurseForge SVN
  • Show addon version per member in officer roster
    The indicator next to each member now distinguishes three states:
    - Green square + "v0.4.5" tag: addon, compatible version
    - Amber square + "v0.4.3" tag: addon, outdated (below MIN_COMPAT_VERSION)
    - Red square, no tag: no addon at all
    Hovering the square shows a tooltip with the exact version and
    the minimum required version when outdated. Makes it easy to see
    at a glance who needs to update after a breaking release.
  • Fix 5/5: Schema write lock prevents downgrade corruption
    Stamp MIN_COMPAT_VERSION into GuildMateDB.writeLock when a new-enough
    client initializes. If an older client later loads the same DB and
    its own version < writeLock.version, it enters read-only mode:
    - No bank scan (ProcessTransactionLog / RescanRecent)
    - No donation writes (AddDonationEvent, SetDonationTotal, SaveGoal,
    DeactivateAllGoals, SetMemberRank)
    - No profession / recipe writes (ScanSelf, ScanRecipes, ScanCraftRecipes)
    - No incoming data messages processed (HELLO still accepted so
    versions sync; everything else bails out)
    The user sees a clear chat warning on login:
    "GuildMate: this SavedVariables file was written by a newer
    version (v0.4.4). Running in READ-ONLY mode until you update."
    Prevents a guildie who downgrades their addon from silently
    poisoning schema they don't understand (recipe categories,
    donation event log, etc.).
  • Fix 4/5: Reject data from unknown senders, not just outdated ones
    IsSenderCompatible used to accept messages from senders we had no
    version record for. That opened a hole: a stale/bloated DB could
    propagate DONATION_BATCH to a newly-installed client and poison it
    before the handshake had a chance to complete.
    Now unknown senders are rejected. We fire an opportunistic HELLO
    (10s debounced) so they learn our version and we'll see theirs on
    their next broadcast. The sender will re-broadcast naturally on
    the next real event (bank open, goal edit, tradeskill) once the
    handshake completes.
    This makes the version gate strict: the ONLY way to land data in
    our DB is through a sender whose version we know and which meets
    MIN_COMPAT_VERSION.
  • Fix 3/5: Per-sender rate limit on incoming messages
    Outdated clients (e.g. pre-v0.4.1 still spamming DONATION_TOTAL every
    few seconds) can technically pass the version gate but still saturate
    our DB and UI. Add a sliding 60s window with per-command caps:
    DONATION_TOTAL / DONATION_BATCH: 6 per 60s
    DEPOSIT: 20 per 60s
    DEPOSIT_BATCH: 4 per 60s
    RECIPE_UPDATE / PROF_UPDATE: 3 per 60s
    GOAL / GOAL_UPDATE: 4 per 60s
    Caps are well above what a healthy client sends during normal
    operation (bank open = 1-2 messages, tradeskill open = 1 recipe
    update, goal edit = 1 goal broadcast). Only runaway senders get
    throttled. Over-cap messages drop silently unless /gm commtest
    debug logging is on.
  • Fix 2/5: Broadcast aggregated totals only when bank scan adds events
    ProcessTransactionLog called BroadcastKnownTotals unconditionally
    after every bank scan — even when no new events were found. Every
    member opening the bank triggered a full DONATION_BATCH blast to
    the whole guild for no change.
    Gated by changed now, matching BroadcastRecipes/BroadcastProfessions
    which already had proper change-detection.
  • Fix 1/5: Remove HELLO welcome dump
    Every HELLO received used to trigger a 5-50KB welcome dump:
    BroadcastGoal + BroadcastKnownTotals + BroadcastDonationLog +
    BroadcastProfessions + BroadcastRecipes per profession.
    In a guild with 7+ addon users this cascaded into hundreds of KB
    per login burst. HELLO now ONLY records the sender's version.
    Data propagates through real events (bank scans, goal edits,
    tradeskill opens). New users bootstrap via explicit /gm sync.
  • Make real donation log authoritative; heal bloated totals on reload
    Observed: one client's bloated DB (from legacy synthetic double-counting)
    propagates across the guild via DONATION_BATCH. Receiver has 413g of
    real log events but the aggregate says 832g — max-merge keeps the bloat.
    Three fixes:
    1. SetDonationTotal: if we have real events in donationLog for this
      member+period, the log is authoritative. Incoming aggregates that
      disagree are rejected rather than max-merged. Also actively heals
      stored totals that are higher than the real log sum (caused by old
      synthetic inflation). When we have no real events, accept the
      incoming aggregate as before.
    2. _RecomputePeriodTotal: same philosophy — when real events exist,
      overwrite stored total with the real sum. Previously max'd with
      the existing stored value, which made bloat permanent.
    3. DB:Init: on reload, iterate every (memberKey, periodKey) in the
      log and recompute. Heals existing bloated DBs even if their
      synthetic entries were already cleaned in a prior session.
      Auto-backup before touching anything; prints how many totals
      were healed.
  • Stop broadcast storm from HELLO loops and legacy clients
    Observed in the wild: 187 sent / 1292 received messages in a few
    minutes, with DONATION_TOTAL spamming every second. Three bugs:
    1. SetDonationTotal still created synthetic events for any gap
      between current and incoming total. When DONATION_BATCH arrived
      before DEPOSIT_BATCH (usual order), a synthetic was created and
      the later real events never removed it — perpetual growth on
      every HELLO round.
      Fix: drop synthetics entirely. Totals live in rec.records[pk],
      detail lives in donationLog. SetDonationTotal only max-merges
      the aggregate field. realLogSum still factors in so we never
      store less than the log says.
    2. Every incoming HELLO triggered a full data dump (DEPOSIT_BATCH
      ~5KB + DONATION_BATCH + GOAL + PROF_UPDATE + one RECIPE_UPDATE
      per profession). With multiple clients all forgetting each
      other (addonUsers flush) the dump cascaded into another HELLO
      round on the receiver side, cascading again.
      Fix: per-sender 5-minute debounce on the welcome dump. One HELLO
      = at most one dump per sender per 5 minutes. The HELLO reply
      itself keeps its existing guild-wide 10s debounce.
    3. Legacy DONATION_TOTAL (pre-v0.4.1) clients spam per-member
      totals every few seconds. We still accept the data but bump
      the UI refresh debounce from 0.5s to 2s so we don't churn
      layouts on every message.
  • Fix donation double-counting from synthetic event duplicates
    Root cause: on HELLO we broadcast both DEPOSIT_BATCH (individual
    events) and DONATION_BATCH (aggregated totals) for backward compat
    with old clients. SetDonationTotal unconditionally created a
    synthetic event for any gap between "current" and "newTotal",
    without checking whether the detailed log already contained real
    events covering that amount. When DONATION_BATCH arrived alongside
    or before DEPOSIT_BATCH, the log ended up with both the real events
    AND a synthetic for the same deposits.
    Two fixes:
    1. SetDonationTotal now computes the real (non-synthetic) log sum
      first. If realLogSum >= newTotal, the aggregate is redundant and
      no synthetic is created. Otherwise, synthetic covers only the
      uncovered portion (gap = newTotal - realLogSum), not the full
      current/newTotal delta.
    2. New CleanupSyntheticDonations() walks the log, groups events by
      (memberKey, periodKey), and removes synthetics in groups where
      the real event sum already covers (or exceeds) the max newTotal
      encoded in any synthetic id. Called on DB:Init() to heal
      existing duplicate-bloated DBs automatically. BackupDonations
      runs first so users can /gm restore if the heuristic over-cleans.