File Details
v0.1.1
- R
- Jun 13, 2026
- 129.12 KB
- 4
- 12.0.5
- Retail
File Name
MythicPlusPartyShuffle-v0.1.1.zip
Supported Versions
- 12.0.5
Mythic+ Party Shuffle
v0.1.1 (2026-06-13)
Full Changelog Previous Releases
- feat(join): host-identity addressing + realm normalization
Join events by the host's Name-Realm (whisper-hub target), with realm
normalization (display name -> whisper slug) and a bundled US realm list
(Data/USRealms.lua). Archives the join-by-host-identity change and folds its
specs into main. Also reword the event-moderation localization requirement so
SHALL is on the first line (OpenSpec --strict gate); all 15 specs validate, 99
Lua tests pass.
Co-Authored-By: Claude Opus 4.6 (1M context) noreply@anthropic.com - chore(release): set CurseForge project id (1573831) for packager uploads
Co-Authored-By: Claude Opus 4.6 (1M context) noreply@anthropic.com - docs(roadmap): join by host identity + realm selection strategy
Co-Authored-By: Claude Opus 4.6 (1M context) noreply@anthropic.com - fix(comm): retry whisper spoke resync so cross-faction reconnect recovers groups
A whisper spoke sent JOIN/ROSTER_REQ once at login, fire-and-forget. For a
cross-faction participant the whisper routes through the shared WoW Community,
whose data is not loaded yet at PLAYER_LOGIN, so that single resync was dropped
and the spoke never got the hub's ROSTER/SHUFFLE back — the group vanished on
relog. (Cross-realm same-faction worked because the whisper is direct.)
The spoke now retries JOIN + ROSTER_REQ on a bounded backoff (8 attempts, 3s
apart) until the hub answers, marked by the hub's ROSTER, then stops — mirroring
the channel _probeChannel confirmation loop. Reset on join/close.
+1 test (77 total green). Main whisper-transport spec gains the retry scenario.
Co-Authored-By: Claude Opus 4.8 noreply@anthropic.com - feat(comm): WHISPER hub-and-spoke transport for cross-realm events
Add a second transport beside the realm-local CHANNEL so an organizer and
participants on different realms (same faction) can run an event with the
existing click-Join UX — no group, no community, reusing the envelope,
serialize/compress/encode pipeline, src:seq de-dup, and every message type.- Pure helpers selectTransport / parseOrganizer (lua-test covered)
- Organizer = HUB: channel-independent whisper fan-out to remote spokes,
bounded; spoke = SPOKE: whispers only the hub - Hybrid events (local on channel + remote on whisper); de-dup reconciles
- Resilient reconnect: hub persists its participant roster and re-whispers a
rejoin CREATE on reload; spoke re-whispers JOIN/ROSTER_REQ to the persisted
hub. Covers hub-reload, spoke-reload, and both. - UI + /mpps join
[Organizer-Realm] + enUS/frFR strings - 16 new tests in comm-whisper.test.lua (76 total green)
Specs synced to main (whisper-transport new; comm-protocol + event-reconnect
modified). OpenSpec change archived under
openspec/changes/archive/2026-06-12-whisper-hub-transport.
Co-Authored-By: Claude Opus 4.8 noreply@anthropic.com
- docs(roadmap): community + WHISPER hub solves cross-faction/realm (confirmed in-game)
Tested: addon WHISPER by Name-Realm crosses realms with no community; crosses
faction when both share a WoW Community. Adopt a whisper hub-and-spoke transport
with the community as enabler+addressing (C_Club.SendMessage is protected; read
APIs are not). Supersedes guild-relay / RAID / Bnet. Records the join UX and
transport selection (CHANNEL locally, WHISPER hub for remote spokes).
Co-Authored-By: Claude Opus 4.6 (1M context) noreply@anthropic.com - docs(openspec): sync kick/close specs to main and archive change
Sync the event-kick-and-close delta specs into the main specs and move
the completed change into the archive:- new capability spec event-moderation (organizer KICK/CLOSE, forced exit,
persisted-state cleanup, localized feedback) - comm-protocol: KICK/CLOSE added to the supported envelope types and the
organizer-authority requirement (no protocol version bump) - event-window: organizer-only per-row kick controls, Leave -> End event
Implementation, tests, and the change planning artifacts already landed in
the previous commit; this archives the change now that all tasks are done.
Co-Authored-By: Claude Fable 5 noreply@anthropic.com
- new capability spec event-moderation (organizer KICK/CLOSE, forced exit,
- feat(comm): event persistence/auto-reconnect + organizer kick/close
Two features landed together (parallel work sessions on the same tree).
Reconnect after /reload or relog (openspec: event-reconnect-persistence,
archived):- Active event (code, role, organizer meta incl. visibility) persisted in
MPPSDB at create/join, cleared at leave; scoped to the persisting character - PLAYER_LOGIN auto-reconnect: participants ride the existing late-joiner
resync; the organizer re-broadcasts CREATE with a rejoin flag and
participants answer with a fresh JOIN (roster never persisted). The
ROSTER_REQ re-announce never carries the flag (anti JOIN-storm) - Last shuffle restored from persisted history and re-broadcast with current
visibility; ROSTER_REQ answers now include the current SHUFFLE so reloaded
participants and late joiners get groups immediately - Debug fake roster persisted and re-injected while debug is on
- Localized reconnect notice (en/fr); 18 offline harness tests
- Main specs synced: new event-reconnect spec, comm-protocol updated
Organizer moderation (openspec: event-kick-and-close, in progress): - KICK and CLOSE organizer-only message types; kick button per registrant
row and End event button with confirmation popup - Localized notices (en/fr); 11 offline harness tests
59/59 offline tests pass.
Co-Authored-By: Claude Fable 5 noreply@anthropic.com
- Active event (code, role, organizer meta incl. visibility) persisted in
- fix(comm): gate sends on confirmed channel membership; persist debug flag
Root cause of the all-day "messages don't cross" flakiness, caught live
with both clients' debug logs: right after a /reload the chat system
reports a cached, non-zero channel index while the server is still
re-establishing the join (observed: sends at "channel ready, index 6"
landed 14s before the server's own "[player] joined channel" notice).
Addon messages sent in that window are silently discarded server-side,
so GetChannelName(...) ~= 0 is NOT proof of membership.- Queue all envelopes until membership is positively confirmed: a tiny
"P" probe is sent every 0.5s and the queue flushes when the server
echoes it back to us (or on the YOU_JOINED/YOU_CHANGED notice,
whichever comes first). Probes never decode as envelopes, so any
client drops them safely. - Persist Comm.debug in MPPSDB: the flag silently resetting to off on
every reload is what kept this bug undiagnosable — the receiving side
always looked silent.
Co-Authored-By: Claude Fable 5 noreply@anthropic.com
- Queue all envelopes until membership is positively confirmed: a tiny
- docs(roadmap): mark quality/visibility shipped, 2-client smoke test done, publishing items
- feat(groups): quality indicators, organizer visibility toggle, i18n scaffold
Ports two web-app capabilities to the group view (openspec change
group-quality-and-visibility, archived):- Core/GroupQuality.lua: pure per-group facts (tank/heal/dps counts,
completeness, Bloodlust/Battle-Rez coverage, rounded avg ilvl,
keystone min-max/spread with warn-don't-block threshold 4), classified
via SpecDetails, harness-tested on handcrafted and DevFixture rosters. - Event window: quality line under each group header, role icons with
class-colored names (atlas markup, text fallback), masked
"groups hidden by the organizer" view for participants, organizer-only
Show/Hide groups button. - Comm: VISIBILITY message (organizer-only, existing src:seq dedup),
arePartiesVisible default-hidden in CREATE meta, visibility re-broadcast
after ROSTER replies for late-joiner convergence; organizer fake-roster
injection now pushes a ROSTER snapshot so participants resolve fake names. - Locales/enUS + frFR: MPPS.L string table with missing-key passthrough;
all new user-facing strings go through it. - Delta specs synced to main specs; lua-tests extended (30 green).
Co-Authored-By: Claude Fable 5 noreply@anthropic.com
- Core/GroupQuality.lua: pure per-group facts (tank/heal/dps counts,
- fix(comm): seed seq from server clock, case-insensitive event codes, ping probe
Two silent-drop bugs found in two-account testing plus the tooling that
found them:- Comm.seq restarted at 0 on /reload while peers' src:seq dedup sets
survived, so every message from a reloaded client was discarded as a
duplicate unless the peer happened to recreate the event. Seed the
sequence from GetServerTime() so a new session always resumes above
the previous one. - Event codes were compared case-sensitively while WoW channel names
are case-insensitive: REALTEST and realtest shared a channel but
dropped each other's envelopes. Normalize codes to uppercase in
OpenChannel and log the mismatch drop in debug mode. - /mpps ping [p|w Name-Realm]: raw C_ChatInfo probes (own prefix,
passive listener) to test the Blizzard delivery layer independently
of AceComm when comm "does not work".
Co-Authored-By: Claude Fable 5 noreply@anthropic.com
- Comm.seq restarted at 0 on /reload while peers' src:seq dedup sets
- docs(roadmap): add event discovery/browser + cross-faction relay for discovery
Event browser (list active events without a code): guild events via GUILD
beacons, faction events via a shared MPPSLOBBY channel. No relay needed
same-faction (direct lobby); cross-faction discovery uses the same guildmate
relay as comm (one online same-faction relay bridges all non-guild joiners of
that faction).
Co-Authored-By: Claude Opus 4.6 (1M context) noreply@anthropic.com - chore: use pseudonym Rothkill for author attribution
Set .toc Author and LICENSE copyright to the handle Rothkill instead of the
real name.
Co-Authored-By: Claude Opus 4.6 (1M context) noreply@anthropic.com - chore(release): add MIT license and BigWigs packager workflow
LICENSE (MIT). .github/workflows/release.yml runs the BigWigs packager on
version tags (v*): builds from .pkgmeta, substitutes @project-version@, uploads
to CurseForge (needs CF_API_KEY secret + X-Curse-Project-ID in the .toc) and
creates a GitHub release.
Co-Authored-By: Claude Opus 4.6 (1M context) noreply@anthropic.com - docs(roadmap): no-raid principle reshapes cross-faction; add publishing + contest section
Cross-faction transports re-ranked by 'works without a group' (the app exists to
avoid grouping people while organizing): GUILD / Bnet / guildmate-relay kept;
RAID rejected; Communities are a lobby not a transport (no club addon API) with
a whisper-lift question to verify. Add CurseForge 'Addon Trials' contest facts
(July 5 deadline, Midnight-only, votes-decide) and a publishing checklist.
Co-Authored-By: Claude Opus 4.6 (1M context) noreply@anthropic.com - docs(roadmap): event lifecycle, presence, minimap icon, raid-grid + drag-drop, web feature-parity matrix
Co-Authored-By: Claude Opus 4.6 (1M context) noreply@anthropic.com - fix(comm): deliver addon messages over the custom channel
Two bugs prevented any cross-client sync over CHANNEL:- _dispatchSend targeted the channel NAME; SendAddonMessage's CHANNEL
distribution needs the NUMERIC channel index (GetChannelName). Resolve and
send to the index; re-queue until it resolves. - The MPPS prefix was never registered for inbound delivery (AceComm's
RegisterComm did not do it reliably here), so CHAT_MSG_ADDON never fired for
our traffic. Register it explicitly via C_ChatInfo.RegisterAddonMessagePrefix.
Also make the post-join flush robust: poll GetChannelName instead of relying on
a single CHAT_MSG_CHANNEL_NOTICE subtype (YOU_JOINED vs YOU_CHANGED), and add
debug-gated send/recv/handle traces. Verified live: two same-realm clients now
sync the roster over the event channel.
Co-Authored-By: Claude Opus 4.6 (1M context) noreply@anthropic.com
- _dispatchSend targeted the channel NAME; SendAddonMessage's CHANNEL
- docs: add roadmap with pending ideas and cross-faction transport decisions
Co-Authored-By: Claude Opus 4.6 (1M context) noreply@anthropic.com - chore(openspec): archive completed changes, fold deltas into main specs
Archive addon-comm-protocol, ui-event-roster-live, shuffle-and-group-view and
dev-roster-fixture-harness; their delta specs are merged into openspec/specs/
(7 specs, all validating --strict). Remaining unchecked tasks were in-game
manual verifications only; implementation and offline Lua tests are complete.
Reword one dev-roster-fixture requirement so SHALL appears on the first line
(OpenSpec validation gate).
Co-Authored-By: Claude Opus 4.6 (1M context) noreply@anthropic.com - feat(dev): synthetic roster fixture + offline Lua test harness
Core/DevFixture.lua: pure, seedable synthetic roster generator producing entries
in the exact Roster:GetSelfEntry() wire shape, coherent with SpecDetails. Loads
both in-game and standalone (no WoW API calls).
/mpps fakeroster [n]: debug-gated in-game injection into Comm.roster (local only,
never broadcast) so the organizer can Shuffle against a full synthetic roster.
scripts/lua-tests/: Node + fengari harness (npm test:lua) running shuffle,
fixture and anti-repetition invariants outside WoW. 13 tests passing.
Includes the OpenSpec change dev-roster-fixture-harness.
Co-Authored-By: Claude Opus 4.6 (1M context) noreply@anthropic.com - feat(shuffle): port party shuffle algorithm + group view
Port PartyService.shuffleGroups to Core/Shuffle.lua: standard and DPS-only
modes, Tank->Heal->BR->BL->balanced CAC/DIST priority, leftover distribution,
global swap optimization, and anti-repetition over the last 3 shuffles persisted
in MPPSDB.shuffleHistory (keyed by event code, registrants keyed by Name-Realm).
Add Core/SpecDetails.lua (spec-id -> role/bloodLust/battleRez, ported from the
backend) so the shuffle can tell melee (CAC) from ranged (DIST); Roster entries
gain specId. The keystone window and item-level balancing are ported but gated
behind opts.useKeystone / opts.useItemLevel, both OFF by default, so the default
shuffle is role priority + anti-repetition only and never errors on absent data.
Event window gains an organizer-only Shuffle button (computes, records history,
broadcasts SHUFFLE) and a Registrants / My group / All groups view that joins the
broadcast assignments against the live roster and updates live on SHUFFLE.
Plan:- New Core/SpecDetails.lua and Core/Shuffle.lua, loaded after Roster in the .toc
- Roster.lua: add specId to the self-entry
- UI/EventWindow.lua: Shuffle button + group result view with view tabs
- README: step 4 done; keystone/item-level optional and off by default
Co-Authored-By: Claude Opus 4.6 (1M context) noreply@anthropic.com
- docs(openspec): propose shuffle-and-group-view change
Port PartyService.shuffleGroups to Lua with an organizer Shuffle button and a
my-group / all-groups view. Keystone window and item-level balancing are ported
but optional and OFF by default; default shuffle is role priority + anti-repetition.
Co-Authored-By: Claude Opus 4.6 (1M context) noreply@anthropic.com - chore(dev): add Lua 5.1 syntax check via luaparse
Node-based, reproducible across machines (npm install).npm run lint:lua
parses Core/ and UI/ in Lua 5.1 mode to catch syntax errors before loading the
addon in-game (syntax only — not WoW globals or runtime behavior).
node_modules is gitignored; package.json/scripts/node_modules/openspec are
excluded from the packaged addon via .pkgmeta ignore.
Co-Authored-By: Claude Opus 4.6 (1M context) noreply@anthropic.com - feat(ui): event window + live roster wired on comm
Replace the empty scaffolding frame with a functional main window: create /
join / leave controls and a live registrant list that re-renders on every
JOIN/LEAVE/ROSTER/CREATE from the comm layer (single source of truth: it reads
Comm.roster directly, no UI-side copy).
Add Core/Roster.lua with MPPS.Roster:GetSelfEntry() — name/class/spec/role/ilvl
plus reserved keystone/Bloodlust/Battle-Rez fields (basic, class-derived; deep
detection deferred). The detected entry replaces the devSelfEntry stub in the
join/create flow. The organizer is seeded into the local roster on create since
the comm layer suppresses self-echo.
Implements OpenSpec change ui-event-roster-live (roster-detection, event-window).
In-game smoke tests (tasks 6.x) require a WoW client.
Co-Authored-By: Claude Opus 4.6 (1M context) noreply@anthropic.com - docs(openspec): propose ui-event-roster-live change
Add the OpenSpec change for the event window + live roster: create/join/leave
controls, basic self-entry detection (name/class/spec/role/ilvl plus reserved
keystone/Bloodlust/Battle-Rez fields), and a real-time registrant list wired on
the Comm layer (JOIN/LEAVE/ROSTER/CREATE).
Artifacts: proposal, design, specs (roster-detection, event-window), tasks.
Consumes Core/Comm.lua as-is; no comm-protocol changes.
Co-Authored-By: Claude Opus 4.6 (1M context) noreply@anthropic.com - chore(dev): add fetch-libs script and dev setup docs
Libs/ is git-ignored (packager fetches them at build). scripts/fetch-libs.ps1
downloads Ace3 + LibDeflate into Libs/ for a raw dev checkout. README dev
section updated with fetch-libs, junction setup, and /mpps subcommands.
Co-Authored-By: Claude Opus 4.6 (1M context) noreply@anthropic.com - feat(comm): peer-to-peer event protocol over custom channel
Backend-less sync over a custom chat channel named MPPS: wire envelope,
serialize/compress/encode pipeline (AceSerializer + LibDeflate), chunking and
throttling via AceComm, inbound de-dup, organizer authority, late-joiner roster
resync. CREATE/JOIN/LEAVE/SHUFFLE/ROSTER_REQ/ROSTER message types.
Wires the embedded libs into the .toc and inits Comm at PLAYER_LOGIN. Adds
/mpps debug subcommands (status, test, create, join, leave, debug) to exercise
the protocol in-game.
Includes the OpenSpec change addon-comm-protocol (proposal, design, spec, tasks).
Co-Authored-By: Claude Opus 4.6 (1M context) noreply@anthropic.com - chore: init OpenSpec, ignore regenerable .claude tooling
Co-Authored-By: Claude Opus 4.6 (1M context) noreply@anthropic.com - fix(toc): target interface 120005 (WoW 12.0) and normalize line endings
Addon was flagged INCOMPATIBLE on the 12.0 client; bump Interface to match.
Add .gitattributes to force LF in the repo.
Co-Authored-By: Claude Opus 4.6 (1M context) noreply@anthropic.com - chore: scaffold addon repo (step 1)
- .toc manifest (SavedVariables MPPSDB, packager version token)
- Core/init.lua: namespace, SavedVariables bootstrap, /mpps slash command, empty main frame
- .pkgmeta with Ace3 + LibDeflate externals (fetched at package time)
- .gitignore, README
Co-Authored-By: Claude Opus 4.6 (1M context) noreply@anthropic.com

