MP: console-death freeze NOT REPRODUCIBLE + fix the latent game-listener-close bug (task #50)

Investigated the "console death froze peer replication" open question (2026-07-14)
with a direct 2-node repro (BT_REPL_LOG on a circling peer, affinity-pinned):

- Clean relay kill -> replicant kept circling smoothly through the kill, NO
  disconnect logged, node survived. Replication did NOT freeze.
- Deliberately STUCK console (scratchpad/btconsole_stuck.py: connect, start
  mission, then stop recv() while holding the socket OPEN = the exact
  "receive pad full -> close never seen" mode hypothesized) -> replicant kept
  moving the whole run. Replication did NOT freeze.

Conclusion: peer replication is INDEPENDENT of the console (pods replicate
peer-to-peer over the GAME socket; the console is a separate egg/mission/status
channel). The original freeze was a transient -- plausibly the same single-box
packet-jitter/CPU-contention artifact root-caused in 49d73dc -- or was fixed by
later MP work.

FIX (the one real bug found): L4NetworkManager::HostDisconnectedMessageHandler's
ConsoleHostType branch closed gameListenerSocket (the GAME listener) on a CONSOLE
disconnect -- a naming bug (the comment + commented-out OpenConnection intended a
CONSOLE re-listen, which CreateConsoleHost already does). Removed. Harmless to
established peer sockets (why a live match survives console loss) but it would
have blocked a NEW peer from joining after a console cycle. Verified: 2-node
still connects (All connections completed!) + the peer circles.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
arcattack
2026-07-15 15:52:35 -05:00
co-authored by Claude Opus 4.8
parent d1ce99402f
commit bc4d6e5597
3 changed files with 122 additions and 16 deletions
+18 -13
View File
@@ -558,19 +558,24 @@ register. ⚠ The audit also flags the damage-economy item as SELF-CONTRADICTOR
numbers no longer point at that code).
## Multiplayer (Phase 7 / P6)
- **OPEN: console death froze peer replication BOTH ways (2026-07-14) [T4 mechanism].** Live 2-node
session: the btconsole.py emulator process died mid-match (cause unknown — its recv loop only
caught socket.timeout; any OSError killed threads silently; NOW hardened + `-u` + console.log) and
peer↔peer update replication froze in BOTH directions at ~that moment (each node's replicant held a
frozen stale velocity; own sims + rendering fine). The engine NEVER logged a console disconnect —
though `CheckBuffers` recv==0 dispatches `HostDisconnectedMessage` and the loop keeps servicing
other hosts — so either the console host's receive pad was full (recv skipped → close never seen)
or the dispatch doesn't reach `HostDisconnectedMessageHandler` in the port (routing gap). ⚠ Also
found (unfired, latent): that handler's ConsoleHostType branch closes **`gameListenerSocket`** (the
GAME listener) where the comment says it re-posts a CONSOLE listen (L4NET.CPP:969) — suspect
`consoleListenerSocket` was intended. Diagnose on recurrence: console.log (death reason) +
whether `[repltrn]` velocities freeze at console death. Why peer replication depends on the
console connection at all is the core unknown.
- **✅ Console-death peer-replication freeze — NOT REPRODUCIBLE + the one real bug FIXED
(2026-07-15) [T2].** The 2026-07-14 report (btconsole.py died mid-match → peer↔peer replication
froze both ways) did NOT reproduce in the current build under EITHER failure mode, tested directly
(BT_REPL_LOG on a circling peer, affinity-pinned): (1) a clean relay kill — the replicant kept
circling smoothly through the kill, NO disconnect logged, node survived; (2) a deliberately STUCK
console (`scratchpad/btconsole_stuck.py` — connects, starts the mission, then stops recv()'ing while
holding the socket OPEN = the exact "receive pad full → close never seen" mode hypothesized) — the
replicant kept moving the entire run. So **peer replication is INDEPENDENT of the console**: the
pods replicate peer-to-peer over the GAME socket; the console is a separate egg/mission/status
channel. The original freeze was a transient (plausibly the same single-box packet-jitter /
CPU-contention artifact root-caused 2026-07-15, `49d73dc`) or was fixed by later MP work.
**The flagged latent bug IS real and is now FIXED:** `HostDisconnectedMessageHandler`'s
ConsoleHostType branch closed **`gameListenerSocket`** (the GAME listener) on a CONSOLE disconnect —
a naming bug; the comment + the commented-out `OpenConnection` intended a CONSOLE re-listen, which
`CreateConsoleHost()` already does. Removed (L4NET.CPP:969). Harmless to established peer sockets
(why a live match keeps replicating through console loss), but it would have blocked a NEW peer
from joining after a console cycle. Verified: 2-node still connects (`All connections completed!`)
+ the peer circles. Diag harness retained: `scratchpad/btconsole_stuck.py`.
- ✅ Cross-pod COMBAT — DONE (tasks #46/#47: replicant targeting + damage rerouted to the owning
master, full cross-pod kill verified). ✅ Replicant GAIT animation — DONE (task #50: replicant
derives speedDemand from the replicated velocity, full stand→walk→run lifecycle verified).