Fix double elimination with byes never finishing; hand-built brackets

Byes now cascade through the whole bracket (a slot nobody can fill is a bye or
a void), re-run on server start so stuck tournaments recover. New manual
bracket builder on the desk: pick round-1 pairings per match. Tests at 5-23
teams for both bracket types. Release 0.5.0.

Co-Authored-By: Claude Fable 5.1 <[email protected]>
Claude-Session: https://claude.ai/code/session_01MB7nCCAscYsb3zzkT6LHZi
This commit is contained in:
bkvargyasandClaude Fable 5.1 committed 2026-09-05 15:33:36 +00:00
1 parent a5222953dd
commit a4bee22d96
13 files changed
+214 -25

No files matched your search

+2 -11
View File
@@ -175,16 +175,7 @@ export function doubleElimination(seeded, { resetMatch = true } = {}) {
gf.resetMatch = reset.id;
matches.push(reset);
}
// Byes in WB R1 mean LB R1 gets a null loser -> treat as bye there too.
const index = Object.fromEntries(matches.map(m => [m.id, m]));
for (const m of wbByRound[0]) if (m.status === 'bye') {
const l = index[m.loserFeeds];
l[m.loserFeedsSide === 'A' ? 'teamA' : 'teamB'] = '__bye__';
}
for (const m of lb[0]) {
if (m.teamA === '__bye__' && m.teamB === '__bye__') { m.status = 'void'; }
else if (m.teamA === '__bye__') { m.teamA = null; m.pendingBye = 'A'; }
else if (m.teamB === '__bye__') { m.teamB = null; m.pendingBye = 'B'; }
}
// Byes cascade through the losers bracket (a bye has no loser; a void match has no winner);
// Tournament.settleByes() resolves them after generation and after every result.
return { matches, size: wb.size, wbRounds, lbRounds: lbRound };
}