Gate-view pos-1 lockout: thread the acting ?seat through the GATE VIEW nav — TDD

The GATE VIEW buttons (navbar + room.html lapsed-cost) linked to room_gate
with no ?seat, so _viewer_current_slot fell back to owned[0] (pos 1). On the
gate view a CARTE multi-seat gamer acting at pos 2+ saw pos 1 wrongly flagged
me-current AND href-less — the one circle you could never switch back to.

Fix (option a): _role_select_context + _gate_context now both expose
current_slot; both GATE VIEW buttons append ?seat={{ current_slot }} on
page-room. The gate view's current now matches the table → pos 1 becomes
me-also (switch href) when acting elsewhere, the occupied seat correctly
carries no href. _gate_context computes current_slot once and reuses it for
gate_positions.

3 ITs in CarteTrayFollowsSelectedSeatTest (button carries acting seat;
default targets lowest owned; gate page re-carries seat + pos 1 is me-also).
911 epic+gameboard ITs green.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Disco DeDisco
2026-06-05 01:29:37 -04:00
parent 4c484cf25a
commit bedc489d7b
4 changed files with 47 additions and 5 deletions

View File

@@ -336,6 +336,7 @@ def _expire_lapsed_seats(room):
def _gate_context(room, user, seat_param=None):
_expire_reserved_slots(room)
current_slot = _viewer_current_slot(room, user, seat_param)
slots = room.gate_slots.order_by("slot_number")
pending_slot = slots.filter(status=GateSlot.RESERVED).first()
user_reserved_slot = None
@@ -390,9 +391,10 @@ def _gate_context(room, user, seat_param=None):
"carte_slots_claimed": carte_slots_claimed,
"carte_nvm_slot_number": carte_nvm_slot_number,
"carte_next_slot_number": carte_next_slot_number,
"gate_positions": _gate_positions(
room, user, _viewer_current_slot(room, user, seat_param)
),
# Acting seat — exposed so the gate page's own GATE VIEW re-click
# re-carries ?seat (keeps the seat-switch context across reloads).
"current_slot": current_slot,
"gate_positions": _gate_positions(room, user, current_slot),
"starter_roles": [],
}
@@ -486,6 +488,11 @@ def _role_select_context(room, user, seat_param=None):
role_select_deck_id = seat_w_deck.deck_variant_id
ctx = {
"card_stack_state": card_stack_state,
# The viewer's acting seat (?seat slot, else lowest owned). Threaded
# onto the GATE VIEW nav so the gate view's current matches the table
# — without it the gate view falls back to owned[0] (pos 1), locking
# pos 1 as a never-switchable me-current circle.
"current_slot": current_slot,
"equipped_deck_id": role_select_deck_id,
"starter_roles": starter_roles,
"assigned_seats": assigned_seats,