console review round 2: six must-fixes from the adversarial pass (one of its fixes corrected)

The 4-dimension review of 4736cba..820caf8 returned 14 surviving findings.  All
six must-fixes plus the four deferables are in; one of the review's own
prescriptions was wrong and is fixed differently (below).

THE REAPER, FINAL DOCTRINE (blocker + major).  Rev 2 -- "reap anything silent in
the staging window" -- was still wrong twice over: a pad sends exactly ONE
message in its life (the egg ACK, L4NET.CPP:1259) and is then silent FOREVER, so
any manual-launch hold >180s reaped every healthy ACKed pad and force-relaunched
their clients; and a REGISTERED game conn is quiet on TCP while loading, so with
BT_RELAY_TCP_ONLY=1 (or blocked UDP) the reaper _abort_round()ed the whole night
every ~3 minutes blaming a healthy player.  The rule is now: an app-level
deadline is valid only while a RESPONSE IS OWED.  Only egg-sent-never-ACKed pads
are reaped, with the debt clock starting at EGG SEND (a pad that sat through a
long held-egg wait gets its full window -- an edge neither review round caught);
game conns are never reaped at all.  Half-open ghosts are TCP keepalive's job
(~130s, faster than the deadline anyway).

RE-ARM GUARDED ON EVERY CHANNEL (major).  The launch_at guard lived only on the
LAUNCH-press path; the ctl `rearm` command, stdin, and the always-lit GUI button
reached _rearm_for_new_round unconditionally -- one press mid-mission zeroed the
counters, permanently killing the mission clock AND making End Mission print "no
mission is running": an unstoppable round, the exact class this feature exists
to eliminate.  Now refused (loudly) while a mission is running or a pair is in
flight, and the button greys while launched.  THE REVIEW'S OWN FIX WAS WRONG
here: it prescribed refusing on `launches_sent >= 2`, but that stays 2 after a
FINISHED round -- applying it verbatim resurrected the original dead-LAUNCH
wedge, caught immediately by the regression suite.  "Running" is
`launches_sent >= 2 AND not stop_sent`.

RE-ARM RE-KEYS SEATS (major).  It restored the template roster but left
seat_beacons/seat_prefs keyed by the trimmed round's positional ids, so round
2's trim minted a departed player's tag into the egg and trimmed a present
player's out, shifting every callsign/mech a slot.  The re-key block is factored
out of _maybe_reset_round (_rekey_seats_to_roster) and shared.

RESTART SESSION NO LONGER BAKES A WALK-UP'S NAME INTO THE EGG (major).
_stop_session and _start_session now restore the stashed configured
callsign/mech into the cells BEFORE _collect_egg can snapshot them
(_restore_seat_defaults); previously the departed name went into the egg (name=
plus rasterized bitmaps) and was then re-captured as the seat's permanent
"configured default".

LATE REMOTE OPERATOR GETS A ROSTER (major).  The only line the GUI can adopt
tags from was printed once at relay startup and aged out of the 400-line control
history in ~33 minutes of stats chatter -- AUTH now re-issues the live roster
line ahead of the replay, so a remote operator connecting at any point gets
pilot lights and a working LAUNCH button.

DEFERABLES, all four: _drop_game blames the tag stashed AT REGISTRATION (the
live-roster resolve named the wrong tag for a trimmed-round conn dying after a
re-arm restore -- and the tag-trusting GUI would clear the wrong seat); an
operator-BLANKED callsign cell now restores (empty string is a real configured
value; the falsy skip left the departed name up and re-captured it); a returning
player displaces their own half-open registered ghost (same IP, no mission
running) instead of eating ROSTER FULL until keepalive fires; udp_spoofed now
rides the [relay-stats] line when non-zero and the warn set is capped at 256.

VERIFIED: rearm suite grown to 25 checks (ACKed pad never reaped however silent;
never-ACKed pad reaped; game conns never reaped; the egg-send debt clock; re-arm
refused mid-mission, allowed after round end) -- plus net 17/17, roster 22/22,
checkctx CLEAN.  Live rig: mid-mission `rearm` refused with the message and the
mission survived; End Mission -> re-arm -> full re-seat -> second mission
launched.  One bounded artifact observed and documented: each waiting pod
bounces once (identity resync) after an explicit re-arm.

Docs rewritten to the final doctrine (context/operator-console.md reaper +
re-arm + roster-replay + udp_spoofed sections; OPERATOR_GUIDE + tooltip now say
re-arm is between-rounds-only and warn about the one-bounce resync).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
arcattack
2026-07-26 10:11:07 -05:00
co-authored by Claude Opus 5
parent 820caf8765
commit c9e561d9ba
5 changed files with 260 additions and 95 deletions
+41 -5
View File
@@ -511,7 +511,8 @@ class Operator(QMainWindow):
"Clear the finished round's state and re-open the launcher, "
"keeping everyone who is already connected. "
"Use this if LAUNCH looks dead after a round instead of "
"restarting the session.")
"restarting the session. Between rounds only: refused while "
"a mission is running or a launch is firing.")
self.rearm_btn.clicked.connect(self._rearm_round)
self.rearm_btn.setEnabled(False)
self.launch_local_btn = QPushButton("Launch local instances")
@@ -817,12 +818,35 @@ class Operator(QMainWindow):
# ------------------------------------------------------------- session --
def _restore_seat_defaults(self):
"""Write every stashed configured (callsign, mech) back into its row and
clear the stash. MUST run before anything snapshots or saves the table:
Restart Session used to _collect_egg() with a departed walk-up's name
still in the cell, baking it into the next session's egg (name= AND the
rasterized bitmaps) and then re-capturing it as the seat's 'configured
default' -- the reported roster bug returning through the egg file
(review 2026-07-26)."""
for tag, (callsign, mech) in list(self._seat_defaults.items()):
for r in range(self.table.rowCount()):
item = self.table.item(r, 0)
if item is None or item.text().strip() != tag:
continue
cell = self.table.item(r, 1)
if callsign is not None and cell is not None:
cell.setText(callsign)
combo = self.table.cellWidget(r, 2)
if mech is not None and combo is not None:
combo.setCurrentText(mech)
break
self._seat_defaults.clear()
def _start_session(self):
self.end_sent = False
# A session stopped while a seat was OCCUPIED leaves its stash entry
# behind (the seat never emptied, so it was never popped); a new
# session must not restore last session's snapshot.
self._seat_defaults.clear()
# behind (the seat never emptied, so it was never popped). Write those
# configured values BACK into the cells before _collect_egg can bake a
# walk-up's name into the egg, then start clean.
self._restore_seat_defaults()
relay_host = self.f_relayhost.text().strip()
if (self.mode.currentIndex() == 0 and relay_host
and relay_host.lower() not in ("localhost", "127.0.0.1")):
@@ -916,6 +940,7 @@ class Operator(QMainWindow):
self.pod_status.setText("remote link closed")
def _stop_session(self):
self._restore_seat_defaults() # departed walk-up names must not outlive the session
if getattr(self, "remote_link", None):
link = self.remote_link
self.remote_link = None # closed-signal becomes a no-op
@@ -1130,8 +1155,16 @@ class Operator(QMainWindow):
callsign, mech = info
else:
# Empty: restore the configured pilot and forget the stash, so
# the next player to take this seat re-snapshots.
# the next player to take this seat re-snapshots. Restore on
# `is not None`: an operator-BLANKED cell is a real configured
# value, and skipping it as falsy left the departed name up and
# then re-captured it as the default (review 2026-07-26).
callsign, mech = self._seat_defaults.pop(tag, (None, None))
if callsign is not None and cell is not None and cell.text() != callsign:
cell.setText(callsign)
if mech is not None and combo is not None and combo.currentText() != mech:
combo.setCurrentText(mech)
continue
if callsign and cell is not None and cell.text() != callsign:
cell.setText(callsign)
if mech and combo is not None and combo.currentText() != mech:
@@ -1145,6 +1178,9 @@ class Operator(QMainWindow):
(self.monitor.ready or (self.monitor.relay_mode and seated > 0))
and not self.monitor.launched
and have_relay)
# Re-arm is refused by the relay mid-mission/mid-pair; grey it too so the
# button beside END MISSION does not invite the press (review 2026-07-26).
self.rearm_btn.setEnabled(have_relay and not self.monitor.launched)
if self.monitor.stats:
self.stats_label.setText(self.monitor.stats)