Skip to content
[OPEN_POKER]

Pro Poker Bot Architecture: Resilience and Evaluation

JJoão Carvalho||12 min read

A pro poker bot is an evaluated service, not a big strategy function. It reconnects without guessing, discards stale work, degrades safely when dependencies fail, and can prove which policy produced every action. The strategic ceiling matters, but unattended operation is won by recovery, observability, and disciplined releases.

Poker bot architecture series: Part 3 of 3. Build the reliable core in Basic Poker Bot Architecture, then add equity and replay testing with Advanced Poker Bot Architecture. Budget the runtime with Poker Bot Cost in 2026.

What separates a pro poker bot from an advanced one?

A pro poker bot treats every component as fallible and every strategy change as an experiment. The advanced bot can calculate equity and adapt to opponents. The pro bot can lose its connection during that calculation, recover the authoritative table state, reject the now-stale result, choose a safe fallback, and leave an audit trail that explains the sequence.

The difference shows up in ownership. One supervisor owns the session state machine. A turn coordinator owns deadlines and cancellation. Policy workers own computation but can't write to the socket. A guard owns executable actions. Telemetry observes the path without changing it. Release tooling decides which signed, versioned policy receives traffic.

ConcernAdvanced implementationPro implementation
ReconnectOpen socket againBounded backoff, resync, snapshot rebuild
Decision timeoutFunction timeoutPer-stage budget and cancellation
Model failureCatch exceptionCircuit breaker, fallback tier, incident signal
Strategy testReplay and A/B resultShadow policy, paired evaluation, promotion gate
LoggingDecision JSONCorrelated event, trace, metric, and artifact versions
DeploymentRestart processHealth checks, canary, rollback, state compatibility

More infrastructure isn't automatically professional. Every added system needs a failure it prevents and a metric that proves it works.

How should reconnect and resynchronization work?

Reconnect should rebuild from server truth before strategy resumes. Keep the last table_id and highest processed table_seq. After opening the socket with the same API key, send resync_request with those values when a table session may still exist. Apply replayed events in sequence, then replace derived table state from the fresh snapshot.

Open Poker holds a disconnected seat for 120 seconds. That's a recovery window, not a sleep target. Retry quickly with bounded exponential backoff and jitter, because simultaneous clients reconnecting on fixed intervals can create a thundering herd. The bot lifecycle guide documents the seat window, and the WebSocket protocol defines resync_request, resync_response, and table_state.

import asyncio
import random
 
 
async def reconnect_forever(connect_and_run):
    attempt = 0
    while True:
        try:
            await connect_and_run()
            attempt = 0
        except asyncio.CancelledError:
            raise
        except Exception as exc:
            cap = min(8.0, 0.25 * (2 ** attempt))
            delay = random.uniform(0.0, cap)
            record_disconnect(type(exc).__name__, delay)
            await asyncio.sleep(delay)
            attempt = min(attempt + 1, 6)

Sequence handling must be idempotent. Ignore an event whose table_seq is at or below the last applied sequence. If a new sequence jumps ahead, request resync instead of filling the gap with assumptions. The snapshot is authoritative; the event log supplies history needed by the opponent model.

How do deadline budgets stop stale actions?

Deadline budgets split one turn into measured stages and reserve time for validation and network delivery. Open Poker currently allows 120 seconds before an automatic check or fold, but a pro bot shouldn't consume that whole window. A hanging model call blocks useful recovery and reduces hands per hour.

Set an internal service objective based on your runtime. One reasonable target is a 2-second decision budget for ordinary rules or model calls, divided into 100 ms for normalization and features, 1,500 ms for policy work, 100 ms for validation, and 300 ms of delivery reserve. The platform timeout remains an outer safety net.

import asyncio
from dataclasses import dataclass
 
 
@dataclass(frozen=True)
class ActiveTurn:
    hand_id: str
    turn_token: str
 
 
async def decide_with_budget(snapshot, policy, active_turn):
    try:
        intent = await asyncio.wait_for(policy(snapshot), timeout=1.5)
    except (TimeoutError, ValueError, RuntimeError) as exc:
        metric("policy_fallback_total", reason=type(exc).__name__)
        intent = safe_fallback(snapshot)
 
    if ActiveTurn(snapshot.hand_id, snapshot.turn_token) != active_turn():
        metric("stale_decision_total")
        return None
    return guard(intent, snapshot)

Cancellation must propagate. Python's asyncio.wait_for cancels overdue work, but synchronous CPU code won't yield to the event loop. Run heavy simulations in a worker process or use a bounded native implementation. Python's asyncio task documentation explains cancellation behavior. Test it with an intentionally hung policy, not just a fast unit fixture.

How should failure isolation and fallbacks work?

Failure isolation keeps optional intelligence from taking down mandatory play. Put remote models, large equity simulations, opponent storage, and analytics exporters behind narrow interfaces with timeouts. The session loop and legal-action guard must remain available when all four are down.

Use a fallback ladder, ordered by cost and dependency:

  1. Primary learned or model-assisted policy.
  2. Local range-and-equity policy with a short compute budget.
  3. Deterministic position and price rules.
  4. Check when legal, otherwise fold.

Each descent increments a labeled metric and appears in the decision record. A circuit breaker should stop calling a failing remote service after a threshold, wait through a cooldown, then probe with limited requests. Retrying the same model three times inside one turn is usually worse than falling back once; it compounds latency and can multiply charges.

The guard stays after the ladder. A fallback can still contain a bug. Validate action membership, clamp raise-to amounts to the server's current minimum and maximum, require current hand_id and token, and generate a fresh client_action_id. The timeout debugging guide covers common async and model failure paths.

What observability does a pro poker bot need?

A pro poker bot needs correlated logs, metrics, and traces at decision granularity. Use hand_id as the poker correlation key and client_action_id as the action-delivery key. Add session ID, table ID, turn token hash, policy version, feature schema version, model version, prompt version, range version, and code revision.

Don't record private credentials or send raw hole cards to broad third-party telemetry. Hole cards are necessary in protected decision logs and replay fixtures, but access and retention should be deliberate. Logs used for public dashboards should aggregate or redact them.

The core service-level indicators are:

SignalUseful breakdown
Decision latency histogrampolicy, street, fallback tier
Action rejection counterserver reason and policy version
Reconnect and resync countercause and recovery result
Sequence-gap countertable and client revision
Fallback counterdependency and exception class
Stale-decision counterpolicy and elapsed time
Hands completedpolicy version and session
bb/100 estimatepolicy, opponent cohort, confidence interval

Prefer histograms to average latency. One 40-second model call vanishes inside a low mean but can still cause a stale response. OpenTelemetry's metrics specification and trace specification provide vendor-neutral concepts. You don't need a large observability stack on day one, but preserve stable names and units so dashboards don't become archaeology.

How do shadow policies and counterfactual evaluation work?

A shadow policy sees the same immutable snapshot as the active policy but can't send an action. Record its proposed action, size, confidence, latency, and features next to the live decision. This tests integration and behavioral difference without risking chips or protocol correctness.

Shadow results aren't direct win-rate evidence. If the shadow chooses a fold while the active policy calls, the rest of the observed hand follows the call branch. You can't pretend the shadow's fold caused the later result. Use shadowing to measure action agreement, latency, schema errors, and coverage. Use a simulator, solver comparison, or off-policy method for counterfactual value.

For local game research, OpenSpiel includes algorithms and environments for imperfect-information games. Its 2019 paper explains the framework's evaluation goals. For live changes, combine shadow checks with replay suites and a canary cohort.

A useful promotion report includes:

  • action agreement by street and position;
  • large sizing disagreements;
  • schema and legality failure rates;
  • p50, p95, and p99 latency;
  • behavior metrics such as VPIP, PFR, and river call rate;
  • paired simulation result with uncertainty;
  • live canary result with opponent cohort and hand count.

We don't promote a policy because its explanations sound smarter. We promote it because the behavior moved in the intended direction while correctness and latency gates stayed green.

How should policy releases and rollback work?

Policy releases should be immutable, versioned, and reversible. Package code revision, feature schema, range data, prompt text, model identifier, evaluator version, and configuration into one release manifest. The decision log stores the manifest ID, so any hand can be replayed under the exact policy that acted.

Use a release path with explicit gates:

  1. Unit and property tests pass, including legal-action invariants.
  2. Recorded hand replays produce reviewed diffs.
  3. Long simulation shows no memory or latency regression.
  4. Shadow mode passes schema, coverage, and latency gates.
  5. A small live canary receives the new version.
  6. Automated rollback watches rejection, fallback, stale-decision, and crash thresholds.
  7. Strategy performance is reviewed only after enough hands accumulate.

Operational rollback should be fast and independent of poker variance. One illegal-action spike can roll back immediately. A bb/100 dip usually can't, because short samples are noisy. Separate hard health gates from slow performance gates.

State compatibility deserves special attention. If a new opponent model changes stored feature names, either migrate the data or version the reader. A rollback that can't read yesterday's state isn't a rollback. We prefer append-only raw observations with derived features rebuilt by version. Storage costs more, but strategy changes stop corrupting history.

How do you measure poker performance without fooling yourself?

Measure poker performance with uncertainty, controlled comparisons, and behavior diagnostics. Report big blinds per 100 hands with the sample size and a confidence interval. Segment by policy version, table size, position, and opponent cohort. Raw season chips matter for competition, but they aren't a stable comparison between runs with different buy-ins or blind exposure.

Short samples lie. A bot can win several all-ins while consistently taking negative-expectation lines. Track showdown and all-in diagnostics, but don't mistake an adjusted metric for ground truth either. Opponent models drift, multiway pots complicate estimates, and live policies change the data they later learn from.

Use three evidence sources:

EvidenceBest useMain limitation
Deterministic replayRegression and explanationKnown hands only
Paired simulationPolicy comparison under controlled dealsSimulator mismatch
Live bot arenaProtocol, operations, real opponent mixHigh variance and drift

Set the experiment question before looking at results. “Reduce river calls with equity below price by 30% without raising timeout fallbacks” is testable. “Make the bot more GTO” isn't. The zero-to-leaderboard plan is useful for iteration cadence, while stack management covers risk measures that chip totals alone miss.

What does the production runbook need?

The production runbook needs specific actions for authentication failures, reconnect loops, resync gaps, action rejection spikes, model outages, slow decisions, corrupted state, low balance, and season transitions. Each alert should name an owner action, a safe fallback, and the evidence needed before returning to normal.

For example, a model outage shouldn't page someone merely because one call failed. The circuit breaker opens, the local policy takes over, and an alert fires if the fallback rate stays above a threshold for a sustained window. An action rejection spike is different: switch to the deterministic fallback or stop rejoining until the protocol mismatch is understood.

Test the runbook with fault injection. Kill the network during a turn. Return duplicate events. Delay the policy beyond its budget. Make the model return malformed JSON. Restart the process between hand_start and your_turn. A document that hasn't survived a rehearsal is only a guess.

Cost is also an operational constraint. Bound model calls per hand, token input, simulation CPU, log retention, and reconnect attempts. The poker bot cost guide gives a planning model. A strategy that earns a tiny simulated edge but needs an unbounded remote call isn't ready for unattended play.

FAQ

What is a pro poker bot architecture?

It's a resilient, observable, versioned service around a poker policy. It includes authoritative resync, deadline cancellation, fallback tiers, action guards, shadow evaluation, release gates, and an incident runbook.

How should a poker bot recover after disconnecting?

Reconnect with bounded jitter, use the same identity, send resync_request with the current table and last processed sequence, apply replayed events idempotently, then rebuild from the authoritative snapshot before acting.

What should happen when the AI model times out?

Cancel the request, record the timeout, and move down a local fallback ladder. Before sending, confirm the active hand and turn token still match. Never send a late model result.

Can shadow mode prove a new policy wins?

No. Shadow mode proves that the policy runs, returns valid output, meets latency targets, and differs in known ways. Use controlled simulation and live canaries for performance evidence.

When should a poker bot roll back automatically?

Roll back on hard operational failures such as action rejection spikes, crashes, stale-decision spikes, schema failures, or excessive fallbacks. Strategy results need slower review because poker variance makes short windows unreliable.

The pro move isn't adding another model. It's making the current one replaceable, observable, and safe under failure. Register through the Open Poker quickstart, run the first fault-injection drill, and see whether your bot can lose every optional dependency without losing control of the table.

Keep Reading