diff --git a/app/models/__tests__/afl-wildcard-advancement.test.ts b/app/models/__tests__/afl-wildcard-advancement.test.ts index ee563c1..c07e50b 100644 --- a/app/models/__tests__/afl-wildcard-advancement.test.ts +++ b/app/models/__tests__/afl-wildcard-advancement.test.ts @@ -215,6 +215,14 @@ describe("AFL Wildcard Round advancement", () => { expect(row("ef2").participant2Id).toBe(seed(8)); }); + it("refuses to re-seed an Elimination Final that has already been played", async () => { + await winWildcard("wc1", seed(7)); + Object.assign(row("ef2"), { isComplete: true, winnerId: seed(6), loserId: seed(7) }); + + await expect(winWildcard("wc1", seed(10))).rejects.toThrow(/already has a recorded result/); + expect(row("ef2").participant2Id).toBe(seed(7)); + }); + it("leaves the bracket alone when the pairings are already right", async () => { await winWildcard("wc1", seed(7)); await winWildcard("wc2", seed(8)); diff --git a/app/models/playoff-match.ts b/app/models/playoff-match.ts index f2b5233..1b3a0f6 100644 --- a/app/models/playoff-match.ts +++ b/app/models/playoff-match.ts @@ -942,6 +942,15 @@ async function advanceAFLWinner( if (occupant !== null && !wildcardParticipants.has(occupant)) { throw new Error(`EF ${efMatch.matchNumber} participant2 already filled`); } + // Re-seeding a game that has already been played would rewrite who contested a + // recorded result. Surface that (this message is not one callers swallow) rather + // than quietly corrupting the bracket. + if (occupant !== null && (efMatch.isComplete || efMatch.winnerId)) { + throw new Error( + `Elimination Finals match ${efMatch.matchNumber} already has a recorded result, ` + + `so its Wildcard qualifier cannot be re-seeded — clear and regenerate the bracket` + ); + } // A Wildcard team in the wrong slot is a placement this result supersedes: a // corrected Wildcard winner, or one placed before the re-seeding rule existed. if (occupant !== null) slotsToClear.push(efMatch.id);