Console: STAGING visibility + launch re-arm in launch-with-whoever mode

Field report (2026-07-23): with open seats the roster stays blue until
LAUNCH -- correct (loading cannot start before the roster is finalized,
and the LAUNCH press is what finalizes a partial roster) -- but the
operator lost all visibility into the post-launch staging, and worse,
the LAUNCH button's re-arm rode the "WAITING FOR OPERATOR" line that
only prints on a FULL-roster ACK, so in partial mode the button stayed
dead after round 1.

- The relay's 10s "launch HELD -- still loading: PLAYER n (k/m ready)"
  lines now surface as the status banner ("STAGING -- PLAYER 2 still
  loading (1/2 ready)") while the per-seat lights walk teal->green.
- "round RESET" re-arms the console (launched/ready/held cleared) so
  every round's LAUNCH works regardless of roster fullness.
- The standby banner explains the mode: seated players are STANDING BY,
  LAUNCH starts their loading, the mission fires itself at all-green.
- The seated count includes registered/ready players (it undercounted
  once pods advanced past blue).

Monitor states unit-tested (held -> launch -> clear -> reset -> re-arm).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
arcattack
2026-07-23 08:15:55 -05:00
co-authored by Claude Opus 4.8
parent 02a41f165f
commit 87ef6a85f9
+26 -3
View File
@@ -70,6 +70,9 @@ class SessionMonitor:
r"PLAYER (\d+) LEFT \(host \d+\) tag='([^']*)'")
RE_RELAY_READY = re.compile(
r"PLAYER (\d+) READY \(host \d+\) tag='([^']*)'")
RE_RELAY_HELD = re.compile(
r"launch HELD -- still loading: (.+) \((\d+)/(\d+) ready\)")
RE_RELAY_RESET = re.compile(r"round RESET")
RE_MESH_EGG = re.compile(r"\[([^\]]+)\] egg sent")
RE_MESH_RUN = re.compile(r"\[([^\]]+)\] RunMission #(\d+) sent")
@@ -82,6 +85,7 @@ class SessionMonitor:
self.launched = False
self.stats = ""
self.seat_info = {} # tag -> (callsign, mech) requests
self.held_status = None # "PLAYER 2, 3 (2/4 ready)" while staging
def host_tag(self, host_id):
i = host_id - 2 # hostIDs 2..N+1 in egg order
@@ -135,9 +139,24 @@ class SessionMonitor:
if tag and self.state.get(tag) != ST_IDLE:
self.state[tag] = ST_IDLE
changed = True
m = self.RE_RELAY_HELD.search(line)
if m:
self.held_status = "%s still loading (%s/%s ready)" % (
m.group(1), m.group(2), m.group(3))
changed = True
if self.RE_RELAY_RESET.search(line):
# BETWEEN ROUNDS: re-arm the console for the next launch. The
# old re-arm rode "WAITING FOR OPERATOR" which only prints on a
# FULL-roster ACK -- in launch-with-whoever mode the button
# stayed dead after round 1 (field report 2026-07-23).
self.launched = False
self.ready = False
self.held_status = None
changed = True
m = self.RE_RELAY_RUN.search(line)
if m and int(m.group(1)) >= 2:
self.launched = True
self.held_status = None
for t in self.state:
if self.state[t] == ST_REGISTERED:
self.state[t] = ST_LAUNCHED
@@ -755,21 +774,25 @@ class Operator(QMainWindow):
for tag, state in self.monitor.state.items():
parts.append('<span style="color:%s">⬤</span> %s <i>%s</i>'
% (ST_COLORS[state], tag, state))
seated = sum(1 for s in self.monitor.state.values() if s == ST_SEATED)
seated = sum(1 for s in self.monitor.state.values()
if s in (ST_SEATED, ST_REGISTERED, ST_READY))
ready_n = sum(1 for s in self.monitor.state.values() if s == ST_READY)
if self.monitor.launched:
head = "LAUNCHED — mission running"
if (self.console_proc and not self.end_btn.isEnabled()
and not getattr(self, "end_sent", False)):
self.end_btn.setEnabled(True)
elif self.monitor.held_status:
head = "STAGING — " + self.monitor.held_status
elif ready_n:
head = ("%d pod(s) LOADED+READY — LAUNCH starts them instantly"
% ready_n)
elif self.monitor.ready:
head = "ALL PODS READY — press LAUNCH MISSION"
elif seated:
head = ("%d player(s) seated — LAUNCH MISSION starts with "
"whoever is here" % seated)
head = ("%d player(s) seated (standing by) — LAUNCH starts "
"their loading; the mission fires itself when every "
"light is green" % seated)
elif self.monitor.relay_mode:
head = "eggs delivered: %d/%d" % (self.monitor.eggs,
len(self.monitor.tags))