Appearance
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:
- Registration — players buy in.
- Play — hands deal.
- 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 → closedOne 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);
forceEndis the fast disposition.