## 1. Type system updates - [x] 1.1 Add `betMatched: boolean` field to `PlayerSeat` interface in `src/lib/types/player.ts` - [x] 1.2 Add `lastAggressorIndex: number` field to `GameState` interface in `src/lib/types/game-state.ts` - [x] 1.3 Define `SidePot` interface with `amount` and `eligiblePlayerIds` fields - [x] 1.4 Add `sidePots: SidePot[]` field to `GameState` interface ## 2. State initialization & reset - [x] 2.1 Update `createInitialState` to initialize new fields (`betMatched`, `lastAggressorIndex`, `sidePots`) - [x] 2.2 Update `startNewHand` to reset all per-round fields including new fields - [x] 2.3 Update `postBlinds` to set `betMatched` correctly for SB and BB players ## 3. Action function rewrites - [x] 3.1 Rewrite `applyCheck` to set `betMatched = true` without modifying `currentBet` or chips - [x] 3.2 Rewrite `applyCall` to use `state.currentBet - player.currentBet` for call amount with correct chip deduction - [x] 3.3 Rewrite `applyRaise` to update `lastAggressorIndex`, reset other players' `betMatched`, and enforce minimum raise - [x] 3.4 Rewrite `applyFold` to correctly mark player as folded and advance turn - [x] 3.5 Rewrite `applyAllIn` to handle partial all-in raises and update `lastAggressorIndex` if applicable - [x] 3.6 Add `validateAction` call at the start of each action function with early return on invalid actions ## 4. Validation fixes - [x] 4.1 Fix fold validation to always permit folding (remove pre-flop restriction) - [x] 4.2 Fix raise validation to correctly calculate minimum raise based on `lastRaiseAmount` - [x] 4.3 Add validation for all-in actions that don't constitute a full raise ## 5. Betting round completion rewrite - [x] 5.1 Implement `isRoundComplete` function with last-aggressor tracking logic - [x] 5.2 Rewrite `completeBettingRound` to use `betMatched` flag and exclude all-in players from match check - [x] 5.3 Implement BB option: allow BB to check pre-flop when no raises occurred - [x] 5.4 Ensure `currentTurn` advances correctly after round completion ## 6. Side pot implementation - [x] 6.1 Implement `calculatePots` function to compute main pot and side pots from player bets - [x] 6.2 Integrate side pot calculation into all-in action handling - [x] 6.3 Update `awardPot` to distribute main pot and all side pots correctly - [x] 6.4 Fix remainder chip distribution (award leftover chips to first winner) - [x] 6.5 Update showdown logic to determine winners for each pot based on eligibility ## 7. Turn advancement fixes - [x] 7.1 Rewrite `advanceTurn` to skip folded and all-in players correctly - [x] 7.2 Ensure turn advancement respects dealer position and betting round start position - [x] 7.3 Handle edge case where no active players remain for turn advancement ## 8. Game loop rewrite (+page.svelte) - [x] 8.1 Add `aiActing: boolean` state flag to disable controls during AI turns - [x] 8.2 Replace `processGame` with unified `processTurn` state machine function - [x] 8.3 Ensure all state transitions apply returned state atomically (no discarding) - [x] 8.4 Convert AI turn timing from nested setTimeout to sequential promise chain - [x] 8.5 Add guard clause in `handleAction` to reject actions when `aiActing` is true - [x] 8.6 Update BetControls component to accept and respond to `disabled` prop ## 9. Bug fixes discovered during playtesting - [x] 9.1 Fix deadlock: `completeBettingRound` sets `currentTurn` to first active player instead of hardcoded `dealerPosition + 1` - [x] 9.2 Simplify `processTurn` to use corrected `currentTurn` directly after round completion ## 10. Testing & verification - [ ] 10.1 Test pre-flop betting round with all action combinations (check, call, raise, fold) - [ ] 10.2 Test single all-in scenario verifies correct main pot and side pot creation - [ ] 10.3 Test multiple all-ins at different levels verifies correct multi-side pot distribution - [ ] 10.4 Test BB option pre-flop (BB checks when no raises) - [ ] 10.5 Test full hand flow from deal through showdown with no state corruption - [ ] 10.6 Test race condition prevention (rapid human clicks during AI turn are rejected)