From fbeee4ed15b9fd358d530220f6f4283e6335bfe2 Mon Sep 17 00:00:00 2001 From: Chris Parsons <438676+chrisparsons83@users.noreply.github.com> Date: Sun, 5 Apr 2026 15:11:43 -0700 Subject: [PATCH] Refactor playoff event processing and improve code clarity (#261) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Remove redundant processPlayoffEvent loop from finalize-bracket action All bracket rounds are already processed (with scoring and Discord notifications) as each match winner is set via set-winner/set-round-winners. By the time the Finalize button is clicked, placements are current and standings are up to date. The re-processing loop was firing recalculations and Discord notifications once per round needlessly. The finalize action now only assigns 0 points to non-bracket participants, marks the event complete, and runs one final standings recalculation. https://claude.ai/code/session_01RhQS6FQRh6iYtVNaryCEf5 * Fix stale comment in finalize-bracket action The template is now fetched only as a validity guard, not for round order iteration (which was removed in the previous commit). https://claude.ai/code/session_01RhQS6FQRh6iYtVNaryCEf5 * Fix complete-round redundant Discord/recalculation and stale comment complete-round was calling processPlayoffEvent without skipRecalculate, firing recalculateAffectedLeagues and Discord even though each match winner had already triggered those side effects via set-winner. Add skipRecalculate: true to match the autoCompleteRoundIfDone pattern. Also fix autoCompleteRoundIfDone comment which incorrectly said "non-bracket eliminations are recorded" — that's a separate step in finalize-bracket; processPlayoffEvent records bracket round placements. https://claude.ai/code/session_01RhQS6FQRh6iYtVNaryCEf5 --------- Co-authored-by: Claude --- ...sons.$id.events.$eventId.bracket.server.ts | 23 +++++-------------- 1 file changed, 6 insertions(+), 17 deletions(-) diff --git a/app/routes/admin.sports-seasons.$id.events.$eventId.bracket.server.ts b/app/routes/admin.sports-seasons.$id.events.$eventId.bracket.server.ts index 88d3ccd..21ae56c 100644 --- a/app/routes/admin.sports-seasons.$id.events.$eventId.bracket.server.ts +++ b/app/routes/admin.sports-seasons.$id.events.$eventId.bracket.server.ts @@ -212,7 +212,7 @@ export async function action({ request, params }: Route.ActionArgs) { /** * Auto-complete a round when every match in it is marked complete. * Updates scoringEvents.playoffRound and calls processPlayoffEvent so that - * non-bracket eliminations are recorded and probabilities are refreshed. + * round placements are recorded and probabilities are refreshed. * This replaces the manual "Complete Round" button. * * skipRecalculate=true because the caller already sent a Discord notification @@ -552,8 +552,10 @@ export async function action({ request, params }: Route.ActionArgs) { }; } - // Process playoff event to update participant results - await processPlayoffEvent(params.eventId); + // Process playoff event to update participant results. + // skipRecalculate=true: match winners were already set via set-winner/set-round-winners, + // which triggered recalculateAffectedLeagues and Discord per match. No need to re-fire. + await processPlayoffEvent(params.eventId, undefined, { skipRecalculate: true }); return { success: `${round} completed and placements calculated successfully`, @@ -690,7 +692,7 @@ export async function action({ request, params }: Route.ActionArgs) { return { error: "No bracket exists for this event" }; } - // Get template to determine round order + // Verify the event has a valid bracket template configured const template = event.bracketTemplateId ? getBracketTemplate(event.bracketTemplateId) : null; if (!template) { return { error: "Bracket template not found" }; @@ -712,20 +714,7 @@ export async function action({ request, params }: Route.ActionArgs) { matches.flatMap((m) => [m.participant1Id, m.participant2Id].filter(Boolean)) ); - // Process all rounds in order const db = database(); - for (const round of template.rounds) { - const roundMatches = matches.filter((m) => m.round === round.name); - if (roundMatches.length === 0) continue; - - // Set playoffRound and process this round - await db - .update(schema.scoringEvents) - .set({ playoffRound: round.name, updatedAt: new Date() }) - .where(eq(schema.scoringEvents.id, params.eventId)); - - await processPlayoffEvent(params.eventId, db); - } // Assign 0 points to participants not in the bracket (Q20) for (const participant of allParticipants) {