operator UI: a departed player no longer keeps their seat in the roster

Operator report: "if a player disconnects from the console, it leaves their name
up in the roster ... it should turn their seat back to empty."  I had not noticed
or fixed this -- the earlier review raised adjacent roster issues (lights mapped
through the untrimmed tag list after a trim) but not this one.

CAUSE.  The GUI only ever WROTE walk-up names into the table.  On a disconnect
the relay pops seat_info, the write-back loop hit `if not info: continue`, and
the cell kept the departed callsign for the rest of the session -- while the
pilot light beside it correctly said "waiting".  So the table and the light
disagreed and a free seat looked occupied.

Two changes, because the relay's two seat-clearing signals are NOT symmetric:

  * SessionMonitor now pops seat_info when a pilot goes idle from EITHER signal.
    "PLAYER n LEFT" is only printed inside the beacon-close branch gated on
    `if seat not in self.by_host` (the relay's own comment: "never claimed:
    player left"), so a player who was fully REGISTERED and then dropped
    produced only `game[...] dropped` -- the common case, and the one that left
    the name up.  Keying "seat is empty" off LEFT alone could never have worked.
  * _refresh_pod_status stashes the operator's configured callsign/mech PER
    OCCUPANCY when a seat fills, and restores it when the seat empties.
    Per-occupancy rather than once at egg load, so an edit the operator makes
    while a seat is empty is respected instead of being overwritten by a stale
    snapshot.

It restores the CONFIGURED PILOT, not a literal blank, deliberately: that cell is
editable and is what gets written to the egg on Save, so a placeholder like
"-- empty --" would end up in the mission file.  The "unoccupied" signal is the
grey `waiting` light beside it.

NOT CHANGED, and explained instead: a vacated seat is held for its player for 90s
(seat_reclaim) so a crash or a reconnect returns them to the same seat and mech.
Assignment skips claimed/reserved/reclaim-held seats, so a brand-new joiner in
that window gets the next free seat, or ROSTER FULL if there wasn't one; after 90s
the seat is fair game.  The operator said they were happy with players keeping
their seat/address, so this stays -- it is now documented in both docs rather than
silently removed.

VERIFIED: scratchpad/test_operator_roster.py (new, 14 checks) drives the REAL Qt
widget offscreen and feeds it the REAL relay log lines: a walk-up name appears;
after REGISTERED then `dropped` the light returns to waiting AND the seat shows
the configured pilot again; the seat is reusable by a different player and clears
for them too; the `PLAYER n LEFT` path clears it as well; an operator edit made
while the seat was empty survives an occupancy; and a neighbouring row is never
touched by another seat's traffic.  Other suites still pass (rearm 19/19, net
17/17); checkctx CLEAN.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
arcattack
2026-07-26 08:43:18 -05:00
co-authored by Claude Opus 5
parent ab5828a866
commit 3a694485bf
4 changed files with 207 additions and 12 deletions
+17 -4
View File
@@ -137,7 +137,20 @@ control link rather than restarting that relay.
- **`Public host`** is used only when exporting player scripts; it does not affect what the relay
binds or advertises.
## 7. Troubleshooting
## 7. When a player leaves
Their pilot light goes grey (**waiting**) and the seat's callsign reverts to whatever you had
configured for that row — so a free seat no longer looks occupied by a departed player.
**Their seat is held for them for 90 seconds.** That is deliberate: someone who crashes or gets
dropped comes straight back into the same seat with the same mech. During that window a *brand-new*
player is given the next free seat instead, or told the roster is full if there wasn't one. After 90
seconds the vacated seat is fair game for anybody.
So if a new arrival can't get in right after somebody left, wait a minute and have them retry — or
raise the seat count if you're simply out of seats.
## 8. Troubleshooting
| What you see | What it means | What to do |
|---|---|---|
@@ -162,7 +175,7 @@ diagnosable.
---
## 8. Match reports
## 9. Match reports
At the end of each clean round, every player's client **uploads its own match report to you
automatically** (relay mode only). They land in `matchlogs\` named by the sender's address. You do
@@ -175,7 +188,7 @@ for it explicitly when something went wrong on their end.
---
## 9. Local test instances
## 10. Local test instances
**Launch local instances** starts game clients on this machine against your own session — useful
for testing alone or filling a seat. **Stop games** closes them. In relay mode the session must
@@ -183,7 +196,7 @@ already be started, or a local instance has nothing to dial.
---
## 10. Which build everyone needs
## 11. Which build everyone needs
**All pods must run the same build as each other.** Build **4.11.554** changed what pods tell each
other about scores, so a mixed session shows disagreeing KILLS/DEATHS columns (nothing crashes —