diff --git a/app/models/scoring-calculator.ts b/app/models/scoring-calculator.ts index f5cb685..3b4cebe 100644 --- a/app/models/scoring-calculator.ts +++ b/app/models/scoring-calculator.ts @@ -1830,9 +1830,8 @@ export async function recalculateAffectedLeagues( // A match is included only when it is "notable": winner earned points this round OR // the loser is notifiable (eliminated / scored). A drafted winner that merely advanced // without earning points is NOT enough on its own. - // On any included match, the winning team's owner is shown in the embed (winnerUsername), - // but Discord-pinged only when they actually scored (winnerDiscordUserId gated on - // winnerScoreChanged) — advancing-only wins don't warrant a ping. + // winnerUsername (and winnerDiscordUserId) are only set when the winner actually scored — + // advancing through a non-scoring round does not warrant mentioning or pinging the owner. // Losers appear if their score changed or they were definitively eliminated (finalPosition // set, non-partial); losers who advance to another match (loserAdvances=true, e.g. NBA // 7v8 → PIR2) are correctly suppressed. @@ -1869,7 +1868,7 @@ export async function recalculateAffectedLeagues( .map((x) => ({ winnerName: x.m.winnerName ?? "", loserName: x.m.loserName ?? "", - winnerUsername: x.winnerOwnerId ? usernameByUserId.get(x.winnerOwnerId) : undefined, + winnerUsername: x.winnerScoreChanged && x.winnerOwnerId ? usernameByUserId.get(x.winnerOwnerId) : undefined, loserUsername: x.showLoser && x.loserOwnerId ? usernameByUserId.get(x.loserOwnerId) : undefined, winnerDiscordUserId: x.winnerScoreChanged && x.winnerOwnerId ? discordIdByUserId.get(x.winnerOwnerId) : undefined, loserDiscordUserId: x.showLoser && x.loserOwnerId ? discordIdByUserId.get(x.loserOwnerId) : undefined, diff --git a/app/services/__tests__/discord.test.ts b/app/services/__tests__/discord.test.ts index 45d97a3..af5585e 100644 --- a/app/services/__tests__/discord.test.ts +++ b/app/services/__tests__/discord.test.ts @@ -186,10 +186,10 @@ describe("sendStandingsUpdateNotification", () => { expect(desc).toContain("• **Sporting (christhrowsrocks)** def. Bodø/Glimt (apatel)"); }); - it("shows winner's owner even when winner only advanced (loser was eliminated)", async () => { - // Mirrors the Brazil/Japan scenario: Brazil advanced without earning points, - // Japan was eliminated. winnerUsername is shown in the embed; winnerDiscordUserId - // is left unset (no ping) because the winner did not score this round. + it("omits winner's manager when they only advanced without earning points", async () => { + // Brazil advances through a non-scoring round (R32 → R16 in World Cup). + // scoring-calculator.ts does not set winnerUsername for advancing-only winners, + // so only Japan's manager appears in the notification. await sendStandingsUpdateNotification({ webhookUrl: WEBHOOK_URL, seasonName: "Rumble League 2026", @@ -199,14 +199,15 @@ describe("sendStandingsUpdateNotification", () => { { winnerName: "Brazil", loserName: "Japan", - winnerUsername: "someManager", + // winnerUsername intentionally absent — Brazil advanced without scoring loserUsername: "ikyn", }, ], }); const desc = getDescription(); - expect(desc).toContain("• **Brazil (someManager)** def. Japan (ikyn)"); + expect(desc).toContain("• **Brazil** def. Japan (ikyn)"); + expect(desc).not.toContain("Brazil ("); }); it("omits scored matches where neither side has a username", async () => {