[EPIC - SEAT TAKEOVER] Player replacement: voluntary substitution and seat takeover #782
Replies: 2 comments
UX specThis comment captures the UX decisions for the player replacement feature, agreed through design review. 1. Opt-in toggle (seeking replacement)
2. Badge visual language
3. Non-member game view
4. Takeover confirm dialogTaking over a seat is irreversible and affects another player, so it warrants a confirm dialog (exception to the no-dialog pattern).
|
Design rationaleA few things worth calling out from the design review — places where we made deliberate choices or deviated from what you might expect. The opt-in toggle has no confirmation dialog. This might seem surprising given that it notifies your tablemates immediately, but the action itself is reversible — you can cancel at any time. Instead of a dialog, helper text next to the button does the job: it makes the consequence visible without adding friction. The one-way thing (the notification going out) is a social consequence, not a data consequence, so we treat it accordingly. Civil disorder seats don't get an "Open for replacement" badge. The CD badge already signals something is wrong with that seat. Adding a second badge would imply the two states are different things — for a newcomer this is maybe a bit tricky, but for a more advanced player (who will be recruiting players actively) perspective, they're the same: the seat is claimable. So we lean on the routing and simplicity instead. Both voluntary and CD seats end up on the same game-info nation list; the distinction is invisible to the person taking over, which is the right level of abstraction. Non-members don't enter the game view at all. The RFC described non-members seeing open seats inside the game. We moved this to game-info instead, which reuses an existing page and keeps privileged game data (chat, private press, etc.) completely out of reach. The map preview already renders the current board state, so newcomers get enough context to make an informed decision without us having to build a new "outsider" view of the game. The multi-seat picker isn't a separate screen. The RFC called out the multi-open-seat case as something to handle. By putting all replaceable nations as a list on game-info, the picker emerges naturally — each row has its own "Take over seat" button. No extra navigation step needed. The takeover confirm dialog is the one place we do add friction. Everything else in the flow avoids dialogs, but taking over a seat is irreversible and affects another real person. That combination earns a confirm step. It's a deliberate exception to the pattern, not an oversight. |
Uh oh!
There was an error while loading. Please reload this page.
Goal
Let a player be substituted out of an active game and replaced by another user
through a shareable link. A player can voluntarily mark their seat as seeking a
replacement and keep playing normally until someone takes over, and a seat
already in
civil_disorderbecomes claimable the same way. Discovery islink-only (never surfaced in Find Games), takeover is pure self-service with no
approval step, and anyone not already a member of the game can claim an open
seat.
Definition of done
self-service endpoint, and the rest of the table is notified when they opt in.
seeking_replacementand a derivedreplaceableflag are exposed through themember serializer and surfaced in the web UI: the current user can start or
cancel "looking for a substitute" on their own row, and an "Open for
replacement" badge (visually distinct from the civil-disorder badge) renders
on any replaceable seat.
and take over a replaceable seat through a confirm dialog, landing inside the
game on success — including the multi-open-seat picker case. This works for
both voluntary and civil-disorder seats, and in private games, without
exposing privileged member-only data to non-members.
created for the newcomer on the same nation (flags reset,
nmr_extensions_remainingreset to the game default), the outgoing member isretired via
replaced_by, the seat'sseeking_replacement/civil_disorderare cleared, the current-phase orders carry over to the newcomer as
re-openable (
orders_confirmed=False) while completed phase states stay on thepredecessor, the newcomer gains the game's chat history, and the table and the
departing player are notified. A loser in a double-claim race fails cleanly.
lookup treats a retired member (
replaced_byset) as a non-occupant, so anation can hold a retired + active member at once without anything
mis-resolving or raising
MultipleObjectsReturned.get_player_statskeeps aretired member's NMR/CD record but excludes retired members from
win/loss/total-games tallies.
CLAUDE.mdnote onthe replacement model are all in place.
Context
This RFC supersedes epic #690 and its sub-issues #691–#699, which should be
closed in its favour.
Settled design decisions: takeover creates a new member and retires the old one
(rather than reassigning
member.user) to preserve per-tenure reliability/statshistory and to use the
replaced_bychain as the seat's tenure lineage;voluntary
seeking_replacementis kept separate from the punitivecivil_disordervia a derived umbrellareplaceable; and "active member"everywhere means
replaced_by IS NULLin addition to the existingeliminated/kickedexclusions.The model groundwork —
Member.seeking_replacement,Member.replaced_by, andthe
replaceableproperty and serializer fields — has already merged (#700). Theremaining work is the active-member query/permission hardening, the
seek-replacement and take-over endpoints, non-member link access, and the
frontend opt-in/badge and takeover-via-link UI.
Sequencing: the leanest shippable milestone is voluntary replacement
end-to-end (opt-in toggle + takeover of a voluntary seat + its frontend).
Extending takeover to civil-disorder seats and hardening the link for
non-members of private games are deliberate follow-ups that can land after
voluntary works.
All reactions