--- phase: 01-tournament-engine plan: 09 subsystem: api, tournament, financial tags: [tournament-lifecycle, multi-tournament, icm, chop, deal, malmuth-harville, monte-carlo, lobby] # Dependency graph requires: - phase: 01-tournament-engine/04 provides: Clock engine with registry, ticker, state machine - phase: 01-tournament-engine/06 provides: Financial engine with transactions, prize pool, payouts - phase: 01-tournament-engine/07 provides: Player management, rankings, buy-in flow - phase: 01-tournament-engine/08 provides: Seating engine with tables, balancing, break table provides: - Tournament lifecycle service (create, start, pause, resume, end, cancel, auto-close) - Multi-tournament manager with lobby view (MULTI-01, MULTI-02) - ICM calculator (exact Malmuth-Harville for <=10, Monte Carlo for 11+) - Chop/deal engine (ICM, chip chop, even chop, custom, partial chop) - Tournament state aggregation for WebSocket connect - Activity feed from audit trail - Tournament API routes with deal proposal workflow - Deal proposals migration (007_deal_proposals.sql) affects: [01-11, 01-12, 01-14, phase-02] # Tech tracking tech-stack: added: [] patterns: [tournament-scoped-state, template-first-creation, local-copy-semantics, proposal-confirm-workflow, icm-dispatcher-pattern] key-files: created: - internal/tournament/tournament.go - internal/tournament/state.go - internal/tournament/multi.go - internal/financial/icm.go - internal/financial/chop.go - internal/server/routes/tournaments.go - internal/store/migrations/007_deal_proposals.sql - internal/financial/icm_test.go - internal/financial/chop_test.go - internal/tournament/tournament_test.go - internal/tournament/integration_test.go modified: [] key-decisions: - "ICM dispatcher: exact Malmuth-Harville for <=10 players, Monte Carlo (100K iterations) for 11+" - "Deal proposal/confirm workflow: ProposeDeal returns preview, ConfirmDeal applies payouts" - "Full chop sets all players to 'deal' status and completes tournament; partial chop continues play" - "Integration tests use file-based DB with WAL mode for clock ticker goroutine compatibility" - "Tournament auto-close: 1 remaining = end, 0 remaining = cancel" patterns-established: - "Tournament-scoped state: all state (clock, players, tables, financials) keyed by tournament_id" - "Template-first creation: CreateFromTemplate loads expanded template, applies overrides, copies all refs" - "Proposal-confirm pattern: deal proposals are stored, reviewed, then confirmed or cancelled" - "ICM dispatcher pattern: CalculateICM auto-selects exact vs Monte Carlo based on player count" - "Activity feed: audit entries converted to human-readable ActivityEntry structs" requirements-completed: [MULTI-01, MULTI-02, FIN-11, SEAT-06] # Metrics duration: 25min completed: 2026-03-01 --- # Plan 09: Tournament Lifecycle + Multi-Tournament + Chop/Deal Summary **Full tournament lifecycle (create/start/pause/resume/end/cancel/auto-close) with multi-tournament lobby, ICM calculator (exact + Monte Carlo), and chop/deal engine supporting 5 deal types** ## Performance - **Duration:** ~25 min - **Started:** 2026-03-01T07:45:00Z - **Completed:** 2026-03-01T08:10:00Z - **Tasks:** 2 - **Files created:** 11 ## Accomplishments - Tournament lifecycle service with all state transitions, template-first creation with local copy semantics, and auto-close on last player standing - Multi-tournament manager enabling lobby view with independent state per tournament (clocks, financials, players, tables) - ICM calculator with exact Malmuth-Harville algorithm (<=10 players, <2ms) and Monte Carlo simulation (11+ players, 100K iterations, <25ms) - Chop/deal engine with 5 deal types (ICM, chip chop, even chop, custom, partial chop) and proposal/confirm workflow - 31 new tests across 4 test files: 12 ICM, 6 chop, 9 tournament unit, 4 integration ## Task Commits Each task was committed atomically: 1. **Task I1: Tournament lifecycle and multi-tournament management** - `75ccb6f` (feat) 2. **Task I2: ICM calculator, chop/deal engine, and comprehensive tests** - `2958449` (test) ## Files Created/Modified - `internal/tournament/tournament.go` - Tournament service: create from template, start, pause, resume, end, cancel, auto-close, list - `internal/tournament/state.go` - State aggregation for WebSocket snapshots and activity feed - `internal/tournament/multi.go` - Multi-tournament manager with lobby view, active tournament listing - `internal/financial/icm.go` - ICM calculator: exact Malmuth-Harville + Monte Carlo dispatcher - `internal/financial/chop.go` - Chop engine: 5 deal types, proposal/confirm workflow, position assignment - `internal/server/routes/tournaments.go` - Tournament API routes: CRUD, lifecycle, deal proposals - `internal/store/migrations/007_deal_proposals.sql` - Deal proposals table migration - `internal/financial/icm_test.go` - 12 ICM tests (exact, Monte Carlo, validation, performance, convergence) - `internal/financial/chop_test.go` - 6 chop/deal tests (all deal types, positions, tournament end) - `internal/tournament/tournament_test.go` - 9 tournament unit tests (template, start, auto-close, multi, state) - `internal/tournament/integration_test.go` - 4 integration tests (lifecycle, deal, cancel, pause/resume) ## Decisions Made - **ICM dispatcher pattern:** CalculateICM auto-selects exact for <=10 players (factorial complexity manageable) and Monte Carlo with 100K iterations for 11+ (converges to <2% deviation with equal stacks) - **Deal proposal/confirm workflow:** ProposeDeal calculates and stores proposal without applying; ConfirmDeal applies payouts as chop transactions -- matches the TD review flow from CONTEXT.md - **Full vs partial chop:** Full chop sets all players to 'deal' status and completes the tournament; partial chop applies partial payouts and lets tournament continue with remaining pool - **Integration test DB strategy:** In-memory DBs with libsql don't support cross-goroutine access; integration tests use file-based DB with WAL mode and busy_timeout for clock ticker compatibility - **Auto-close semantics:** CheckAutoClose called after every bust-out; 1 player remaining triggers EndTournament, 0 players triggers CancelTournament ## Deviations from Plan ### Auto-fixed Issues **1. [Rule 1 - Bug] Fixed in-memory DB cross-goroutine access in integration tests** - **Found during:** Task I2 (integration tests) - **Issue:** `setupTestDB` creates per-test in-memory DBs that aren't accessible from the clock ticker's background goroutine, causing "no such table" errors - **Fix:** Created `setupIntegrationDB` using file-based temp DB with WAL mode and busy_timeout=5000; added StopTicker call after StartTournament - **Files modified:** internal/tournament/integration_test.go - **Verification:** All 4 integration tests pass - **Committed in:** 2958449 **2. [Rule 1 - Bug] Fixed blind_levels notes NULL scan failure** - **Found during:** Task I2 (tournament tests) - **Issue:** blind_levels notes column could be NULL, causing scan into string to fail when loading template - **Fix:** Used sql.NullString for notes scanning in loadLevelsFromDB; added explicit empty string notes to seed data - **Files modified:** internal/tournament/tournament.go, internal/tournament/tournament_test.go - **Verification:** TestCreateFromTemplate passes - **Committed in:** 2958449 **3. [Rule 1 - Bug] Fixed payout_brackets column name mismatch** - **Found during:** Task I2 (tournament tests) - **Issue:** Test DDL used `payout_structure_id` but service queries use `structure_id` column name - **Fix:** Renamed column to `structure_id` in test DDL to match production schema - **Files modified:** internal/tournament/tournament_test.go - **Verification:** All tournament unit tests pass - **Committed in:** 2958449 --- **Total deviations:** 3 auto-fixed (3 Rule 1 bugs) **Impact on plan:** All auto-fixes necessary for test correctness. No scope creep. ## Issues Encountered - libsql PRAGMA handling: `PRAGMA journal_mode=WAL` returns a row, so `Exec` fails with "Execute returned rows" -- must use `QueryRow` with `Scan` instead. This is consistent with the decision logged in 01-02 about libsql PRAGMA inconsistency. ## User Setup Required None - no external service configuration required. ## Next Phase Readiness - Tournament lifecycle is complete and ready for wiring into the full server - Multi-tournament support enables lobby view for the frontend (Plan 11/14) - ICM and chop engines ready for frontend deal UI integration - API routes registered but need wiring into server.go router (will happen in final assembly plan) ## Self-Check: PASSED All 11 created files verified present. Both task commits (75ccb6f, 2958449) verified in git log. --- *Phase: 01-tournament-engine* *Completed: 2026-03-01*