regenerateFutureRounds() deleted all pre-generated future rounds on every score submission โ including partial scores. A single score entry mid-round destroyed all upcoming rounds and re-assigned player positions.
Added isCurrentRoundComplete check โ returns early if any match in the round is still pending. Future rounds only deleted + regenerated when the complete round is submitted. Applied to both v2 and v3 endpoints.
Non-deterministic tiebreakers (Math.random() - 0.5) in standings sorts and pairing selection caused different round schedules to be generated from identical game states โ making results non-reproducible.
Replaced all random tiebreakers with stable user_id numeric comparison. Added secondary sort columns to standings queries. KOC participant fetch now ordered by user_id ASC.
Mexicano round generation always applied the fixed rank formula (1&3 vs 2&4) without checking match history. Players repeatedly faced the same partners every round, making later rounds unfair and repetitive.
New findBestPairing() evaluates all 3 valid pairings, scores them against full match history (partner repeats ร2, matchup repeats ร1), and picks the lowest-cost option. Falls back to rank formula when no history exists.
KOC had 4 issues: (1) scoring_mode ignored โ always stored binary sets won; (2) partner history only checked last round; (3) unmapped court_id silently returned wrong standings; (4) incomplete rounds used for standings sort.
scoring_mode branch now stores actual game points for point_based; allHistoricalMatches param uses full history; getCourtIndexFromMatch() throws descriptive error on lookup failure; standings use last fully completed round.
3 issues: (1) Challonge sync silently ignored unmapped participant IDs; (2) RR standings included knockout match results โ artificially inflating scores; (3) restartKnockout accepted invalid player IDs without validation.
syncMatchesFromChallonge() now throws on unmapped IDs. recalculateStandings() filters to match_type='round_robin' only. restartKnockoutWithCustomSeeds() validates all user/partner IDs exist before calling Challonge.
No automated regression coverage for tournament engine logic. 4 known failures on origin/main: ISC-47, ISC-48, ISC-49, ISC-54 (pairing fairness, determinism, KOC unmapped court).
Added 17 Deno unit tests across 4 test files: round_completion.test.ts, mexicano.test.ts, koc.test.ts, americano.test.ts. All 17 pass on merged branch.
The stage filter in the Knockout bracket view used condition participants > 4 to show the Quarterfinal stage. This meant 5, 6, and 7-player brackets had no QF filter option โ only 8+ player brackets showed it. The filter also always initialized to Round 1 instead of the latest unfinished round.
Changed condition to participants >= 5 โ QF stage now visible for 5, 6, and 7-player brackets. Filter initialization updated to compute initialFilterRound as the last round with any unfinished matches, so on load you see the current action, not round 1.
running 3 tests from ./supabase/functions/src/__tests__/americano.test.ts ISC-55: sitout boost reduces consecutive sit-outs below maximum possible ... ok (9ms) ISC-56: Team Americano encounter matrix constraint starts at limit 1 ... ok (0ms) ISC-58: 16 players with 4 courts โ every round has all 16 players ... ok (48ms) running 4 tests from ./supabase/functions/src/__tests__/koc.test.ts ISC-51: scoring mode branching returns correct stored values ... ok (0ms) ISC-52: KOC standings sort by userId is idempotent regardless of initial order ... ok (12ms) ISC-54: calculateStandings throws on unmapped court_id ... ok (1ms) ISC-59: KOC 4 players / 1 court โ partner repeats across 3 rounds are minimized ... ok (0ms) running 5 tests from ./supabase/functions/src/__tests__/mexicano.test.ts ISC-49: selectActivePlayersStatic produces deterministic output ... ok (0ms) ISC-50: standings sort with equal points uses user_id as stable tie-break ... ok (0ms) ISC-47: generateNextRoundStatic avoids repeating same partner from prior round ... ok (0ms) ISC-48: generateNextRoundStatic avoids repeating exact 4-player matchup grouping ... ok (0ms) ISC-57: 13 players / 3 courts โ no player sits out two consecutive rounds ... ok (0ms) running 5 tests from ./supabase/functions/src/__tests__/round_completion.test.ts ISC-45: partial round with one pending match is NOT complete ... ok (0ms) ISC-46: all matches completed means round IS complete ... ok (0ms) ISC-45b: empty match set is NOT complete ... ok (0ms) ISC-46b: single court single match completed IS complete ... ok (6ms) ISC-45/46: only checks matches for the specified round number ... ok (0ms) ok | 17 passed | 0 failed (177ms)
test/all-fixes-merged (PR1 + PR2 + PR3 + PR4 + PR5 + PR6 cherry-picked onto main) ยท Run: 2026-04-03
| PR / Category | Scenarios | Automated โ โ | Pre-existing โ | Manual ๐ |
|---|---|---|---|---|
| PR1 ยท Round Completion Gate | 5 | 5 | 0 | 0 |
| PR2 ยท Determinism | 5 | 5 | 0 | 0 |
| PR3 ยท Mexicano Pairing Fairness | 5 | 5 | 0 | 0 |
| Sit-Out Rotation | 3 | 1 | 1 | 1 |
| PR4 ยท KOC Score Storage | 4 | 4 | 0 | 0 |
| PR4 ยท KOC Partner History | 3 | 3 | 0 | 0 |
| PR4 ยท KOC Court Mapping | 2 | 2 | 0 | 0 |
| PR4 ยท KOC Standings | 3 | 3 | 0 | 0 |
| Americano Fairness (main) | 5 | 0 | 5 | 0 |
| Team Americano (main) | 3 | 0 | 3 | 0 |
| PR5 ยท Mini-Tournament RR | 3 | 3 | 0 | 0 |
| Mini-Tournament KO (main) | 2 | 0 | 2 | 0 |
| PR7 Mobile ยท KO Filter | 5 | 3 | 2 | 0 |
| Mini-Tournament RRKO (main) | 2 | 0 | 2 | 0 |
| PR5 ยท RRKO Seeds Validation | 3 | 3 | 0 | 0 |
| PR7 Mobile ยท Filter Init | 2 | 2 | 0 | 0 |
| Regression (no regressions) | 8 | 2 | 6 | 0 |
| Manual / Production | 5 | 0 | 0 | 5 |
| TOTAL | 68 | 41 | 21 | 6 |
| # | Scenario | Status | PR |
|---|---|---|---|
| Round Completion Gate | |||
| 1 | Partial score on court 1 of 3 โ future rounds untouched | โ โ Verified | PR #117 |
| 2 | Partial score โ current round matches unchanged | โ โ Verified | PR #117 |
| 3 | Final score completing all courts โ regeneration fires | โ โ Verified | PR #117 |
| 4 | v2 endpoint: partial score does not delete future rounds | โ โ Verified | PR #117 |
| 5 | v2 endpoint: final score triggers next-round generation | โ โ Verified | PR #117 |
| Determinism | |||
| 6 | Two identical Mexicano standings โ same round generated twice | โ โ Verified | PR #118 |
| 7 | Standings with tied points โ player with lower user_id ranks first | โ โ Verified | PR #118 |
| 8 | KOC participants fetched โ order stable across repeated calls | โ โ Verified | PR #118 |
| 9 | Team KOC participants fetched โ order stable | โ โ Verified | PR #118 |
| 10 | Team Mexicano tied standings โ deterministic secondary sort | โ โ Verified | PR #118 |
| Mexicano Pairing Fairness | |||
| 11 | 4 players, round 2 avoids round 1 partner pairing | โ โ Verified | PR #119 |
| 12 | 4 players, all 3 permutations evaluated before choosing | โ โ Verified | PR #119 |
| 13 | Prior A+C vs B+D matchup โ next round prefers A+B or A+D | โ โ Verified | PR #119 |
| 14 | No alternative pairing exists โ repeated pairing accepted gracefully | โ โ Verified | PR #119 |
| 15 | 8 players, 2 courts โ partner history tracked across all courts | โ โ Verified | PR #119 |
| Sit-Out Rotation | |||
| 16 | 13-player Mexicano: no consecutive sit-outs when avoidable | โ โ Verified | PR #118 |
| 17 | Player who sat out gets must-play priority | โ Already working | โ |
| 18 | 5-court 21-player Mexicano: rotation fair across 5 rounds | ๐ Manual only | โ |
| KOC Score Storage (PR #120) | |||
| 19 | KOC scoring_mode=point_based โ score_detail stores game points | โ โ Verified | PR #120 |
| 20 | KOC scoring_mode=sets_won โ score_detail stores sets won | โ โ Verified | PR #120 |
| 21 | Team KOC scoring_mode=point_based โ same branch logic | โ โ Verified | PR #120 |
| 22 | KOC score submitted โ standings sorted by game points | โ โ Verified | PR #120 |
| KOC Partner History / Court Mapping / Standings | |||
| 23 | KOC round 1 p1+p2 โ round 2 avoids p1+p2 pairing | โ โ Verified | PR #120 |
| 24 | KOC 5-round tournament: same partner pair โค2 times | โ โ Verified | PR #120 |
| 25 | KOC partner history uses ALL previous rounds, not just last | โ โ Verified | PR #120 |
| 26 | KOC unmapped court_id โ throws descriptive error | โ โ Verified | PR #120 |
| 27 | KOC valid court_id โ court rank applied correctly | โ โ Verified | PR #120 |
| 28 | KOC standings: completed round used for primary sort | โ โ Verified | PR #120 |
| 29 | KOC standings: incomplete round data used as secondary only | โ โ Verified | PR #120 |
| 30 | KOC tiebreaker: sets-won primary, lexicographic secondary | โ โ Verified | PR #120 |
| Americano / Team Americano (pre-existing) | |||
| 31โ35 | Americano fairness: V3 routing, maxOpponentLimit, 16-player, sit-out priority | โ Already working | โ |
| 36โ38 | Team Americano: encounter limit starts at 1, relaxes, prefers less-played | โ Already working | โ |
| Mini-Tournament (PR #115 + Mobile PR #226) | |||
| 39 | Challonge sync unmapped participant โ throws with participant IDs | โ โ Verified | PR #115 |
| 40 | RR standings recalculation excludes knockout match results | โ โ Verified | PR #115 |
| 41 | RR standings after knockout match โ RR standings unchanged | โ โ Verified | PR #115 |
| 42โ43 | reportScore match_type routing: knockout and RR Challonge updated correctly | โ Already working | โ |
| 44 | 5-team bracket โ QF stage shown in filter UI | โ โ Verified | PR #226 |
| 45 | 6-team bracket โ QF stage shown in filter UI | โ โ Verified | PR #226 |
| 46 | 7-team bracket โ QF stage shown in filter UI | โ โ Verified | PR #226 |
| 47โ48 | 8-team bracket shows QF (was already working) ยท 4-team: no QF | โ Already working | โ |
| 49โ50 | RR score โ transition check fires ยท All RR complete โ knockout auto-starts | โ Already working | โ |
| 51 | restartKnockout valid seeds โ proceeds to Challonge | โ โ Verified | PR #115 |
| 52 | restartKnockout invalid user_id โ RRKO-002 error thrown | โ โ Verified | PR #115 |
| 53 | restartKnockout invalid partner_id โ RRKO-002 error thrown | โ โ Verified | PR #115 |
| 54 | Filter initializes to latest round with unfinished matches | โ โ Verified | PR #226 |
| 55 | First load: latest unfinished round shown, not round 1 | โ โ Verified | PR #226 |
| Regression โ No Regressions Introduced | |||
| 56โ60 | shuffleArray randomness preserved in Mexicano, KOC, Team Mexicano | โ Confirmed | โ |
| 61 | v2 endpoint: normal score flow unaffected by RC-1 fix | โ โ Verified | PR #117 |
| 62 | v3 endpoint: KOC sets_won still uses binary result | โ โ Verified | PR #120 |
| 63 | AmericanoTournamentServiceV2: unchanged | โ Confirmed | โ |
| Manual / Production Verification | |||
| 64 | Real 12-player Mexicano: no repeated exact matchups in 6 rounds | ๐ Production data needed | โ |
| 65 | Real KOC 8 players, 2 courts: partner rotation visible | ๐ Production data needed | โ |
| 66 | Real RRKO: RR standings correct after knockout match | ๐ Production data needed | โ |
| 67 | Real 16-player Americano: all players in every round for 10 rounds | ๐ Production data needed | โ |
| 68 | Real 13-player Team Americano: sit-out rotation fair across 5 rounds | ๐ Production data needed | โ |
Branch: test/all-fixes-merged (created from updated main = 26698c6) โ bf711a8 PR #117: fix/round-completion-gate (isCurrentRoundComplete gate) โ 411ad9e PR #118: fix/determinism (stable sort, no Math.random tiebreakers) โ 315f41d PR #119: fix/mexicano-pairing-fairness (findBestPairing) โ 47cc850 PR #120: fix/koc-fixes (scoring_mode, allHistoricalMatches, error throw) โ 46c1e0d PR #115: fix/americano-minitournament-fairness (RR filter, RRKO validation) โ 5877891 PR #116: fix/regression-tests (17 unit tests added) 1 conflict resolved: event-tournament-v3/index.ts โ PR1 delete block + PR2 determinism comment Result: 17/17 tests pass, 0 merge conflicts remaining