claude/wimbledon-qp-scoring-bug-xevhlf #127

Merged
chrisp merged 3 commits from claude/wimbledon-qp-scoring-bug-xevhlf into main 2026-07-03 21:40:12 +00:00
2 changed files with 25 additions and 25 deletions
Showing only changes of commit 83e41e9cf1 - Show all commits

View file

@ -675,35 +675,35 @@ describe("sendDraftOrderNotification", () => {
});
});
// The caller now supplies each entry's rank in the FULL season field. This helper
// mirrors the production ranking (qualifying-points-discord.server.ts): sort by
// qpTotal desc, competition ranking with ties sharing the lower rank, so existing
// tests keep asserting ranks derived from qpTotal.
function withRanks<T extends { qpTotal: number }>(entries: T[]) {
const sorted = [...entries].toSorted((a, b) => b.qpTotal - a.qpTotal);
const rankByTotal = new Map<number, number>();
let prevTotal = Number.NaN;
let prevRank = 0;
sorted.forEach((e, i) => {
const rank = i > 0 && Math.abs(e.qpTotal - prevTotal) < 0.001 ? prevRank : i + 1;
rankByTotal.set(e.qpTotal, rank);
prevTotal = e.qpTotal;
prevRank = rank;
});
const countByTotal = new Map<number, number>();
for (const e of entries) countByTotal.set(e.qpTotal, (countByTotal.get(e.qpTotal) ?? 0) + 1);
return entries.map((e) => ({
...e,
globalRank: rankByTotal.get(e.qpTotal) ?? 0,
globalRankTied: (countByTotal.get(e.qpTotal) ?? 0) > 1,
}));
}
describe("sendQualifyingPointsUpdateNotification", () => {
beforeEach(() => {
vi.stubGlobal("fetch", mockFetch(204));
});
// The caller now supplies each entry's rank in the FULL season field. This helper
// mirrors the production ranking (qualifying-points-discord.server.ts): sort by
// qpTotal desc, competition ranking with ties sharing the lower rank, so existing
// tests keep asserting ranks derived from qpTotal.
function withRanks<T extends { qpTotal: number }>(entries: T[]) {
const sorted = [...entries].sort((a, b) => b.qpTotal - a.qpTotal);
const rankByTotal = new Map<number, number>();
let prevTotal = Number.NaN;
let prevRank = 0;
sorted.forEach((e, i) => {
const rank = i > 0 && Math.abs(e.qpTotal - prevTotal) < 0.001 ? prevRank : i + 1;
rankByTotal.set(e.qpTotal, rank);
prevTotal = e.qpTotal;
prevRank = rank;
});
const countByTotal = new Map<number, number>();
for (const e of entries) countByTotal.set(e.qpTotal, (countByTotal.get(e.qpTotal) ?? 0) + 1);
return entries.map((e) => ({
...e,
globalRank: rankByTotal.get(e.qpTotal) ?? 0,
globalRankTied: (countByTotal.get(e.qpTotal) ?? 0) > 1,
}));
}
const BASE_ENTRIES = withRanks([
{ participantName: "Novak Djokovic", qpEarned: 20, qpTotal: 45, ownerUsername: "alex" },
{ participantName: "Carlos Alcaraz", qpEarned: 14, qpTotal: 34, ownerUsername: "chris" },

View file

@ -102,7 +102,7 @@ export async function notifyQualifyingPointsUpdate(
// ahead therefore render as T9, not T1 among just the two of them.
const rankedField = [...qpTotalById.entries()]
.map(([id, total]) => ({ id, total }))
.sort((a, b) => b.total - a.total);
.toSorted((a, b) => b.total - a.total);
const globalRankById = new Map<string, number>();
let prevTotal = Number.NaN;
let prevRank = 0;