Skip to content

Tournament Resolution ​

Stage 3 of a Sit-n-Go's lifecycle — completion: a tournament concludes, the winner is paid, and the results page shows the final standings.

The three stages:

  1. Registration — players buy in.
  2. Play — hands deal.
  3. Resolution — this page.

Prediction markets on tournaments are in development.

The resolution chain ​

A tournament reaches ended either naturally (players bust down to a lone survivor) or via an operator forceEnd (for wedged/abandoned tables). Both paths run the same flow:

playing → ended → settling → closed
   │
   ├─ elimination_order written to table_players (position 1 = winner)
   └─ onPlayingEnded():
        └─ payout → payout_intents → bank /api/withdraw → withdrawFor (on-chain) → confirmed → closed

One source of truth for the winner ​

The payout reads the winner from the authoritative DB table_players.elimination_order (readAuthoritativeStandings()), the same source the /tournaments/:id/results endpoint serves. It never reads the orchestrator's in-memory standings — which can drift from the DB on a reconstructed forceEnd and would otherwise pay the wrong player.

onPlayingEnded is shared by both end paths ​

The payout dispatch lives in onPlayingEnded, so both the natural bust-down and the operator forceEnd run the identical settlement — a force-ended tournament pays out exactly like one that concludes on its own.

The results page ​

TournamentResults (rendered at /table/[id] for a concluded tournament) reads the durable results — standings by finishing place, per-position prize, on-chain paid status. It's the loudest surface in the app by design.

Operator disposition ​

POST /admin/force-end-tournament { tableId } (service-key) ends a wedged tournament by current engine stack (deepest = winner) and runs the full resolution. Valid only from playing.

Known residuals ​

  • The natural bust-driven conclusion works but is slow (blind erosion); forceEnd is the fast disposition.