Test Failure Debugging Runbook
When tests fail, follow this exact sequence. Do NOT skip steps or guess at root causes:
make test-summary: readsummary.json. Identify the FIRST failure (later ones are usually cancellation cascade from StopOnFail). Note theclassification(assertion/timeout/infrastructure/crash) andreproCommand.summary.jsonis always written, even on aborted runs ("aborted": true+abortReason).make test-events TEST=Class.Method: filterinfrastructure.jsonlfor events attributed to the failing test (jq filter ontest.displayName). Look at timing between events, whichphasefailed (connect, test body, artifacts, cleanup), and any error details.make test-container-log CONTAINER=server-0(orclient-0,steam-auth-shared,steam-auth-per-N): full lifecycle log for the container. Use the test window timestamps frommake test-eventsoutput to slice context around the failure.make test-infra-log: if the failure is infrastructure-related (server poisoned, capacity deadlock, timeout waiting for server), checkdiagnostics/infrastructure.jsonlfor resource lifecycle events (server create/evict/poison, capacity acquire/release, HTTP requests, session lifecycle) around the failure timestamp.- Read the actual test code and mod code before proposing a fix. Cross-reference the error with source.
make test-flaky: check if this test has failed before across runs. Flaky tests need different fixes than consistent failures.- Remote-host / SSH tunnel failures (only when
classificationisinfrastructureAND a host is remote — seehost_idin events): the SSH tunnel is a silent failure domain, so a dead tunnel surfaces downstream as a generic timeout/host_disconnected. To find the SSH-level cause:- Grep
diagnostics/infrastructure.jsonlforhost_disconnected,ssh_master_log,ssh_master_exited,tunnel_forward_failed(make test-infra-log, or grep the file directly —ssh_master_logis emitted at teardown on the coordinator, so it is not attributed to a single test and won't appear undermake test-events). - A
host_disconnectedwhosereasonnames a transport fault and which carries ansshMasterLogTailis the smoking gun for a mid-run drop; the tail holds ssh's own death line (e.g.Timeout, server not responding.). - Read
diagnostics/ssh-master-{host}.logfor the master's full-Eerror log. An empty master log on a poison is expected for an abrupt RST drop (the reset is caught by the exception classifier instead, not the log) — not itself a bug. - Healthy sequence:
ssh_preflight→ssh_master_ready→tunnel_forward_opened(×N) → … →ssh_master_exited(cleanexitCode 0). A non-zeroexitCode/stderronssh_master_exitedortunnel_forward_closedmeans a teardown step itself failed.
- Grep
Output locations: TestResults/latest.txt points to the current run directory. All artifacts are under TestResults/runs/{timestamp}_{sha}/.
Known benign log lines
Ignore these when triaging — they are not signals of test failure:
Timer: time has moved backwards!in anycontainer.log. Emitted by TigerVNC (common/rfb/Timer.cxx,Timer::getNextTimeout) when the container's wall clock jumps backwards by more than 1 second. Common on virtualized hosts (Docker Desktop on Mac/Windows, WSL2) where the VM clock is periodically resynced from the host. TigerVNC self-corrects (dueTime = now); the game, the mod, and the test infrastructure are unaffected. Cross-worker event correlation usesrun_ms, so wall-clock jumps inside a single container do not affect ordering either. Do not add in-container time-sync daemons to suppress this.