promotional bannermobile promotional banner

Mythic+ Party Shuffle

Create an event, let players join in-game, and shuffle everyone into balanced Mythic+ groups.

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
  • 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
  • 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
  • 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
  • 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
  • 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
  • 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