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 bychangednow, 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:- 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. - _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. - 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.
- SetDonationTotal: if we have real events in donationLog for this
- 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:- 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. - 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. - 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.
- SetDonationTotal still created synthetic events for any gap
- 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:- 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. - 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.
- SetDonationTotal now computes the real (non-synthetic) log sum

