From 34f59eb301d96123e83422ffc004a0e1a7ae7c1c Mon Sep 17 00:00:00 2001 From: Justin Gasper Date: Mon, 24 Aug 2026 07:04:22 +1000 Subject: [PATCH] PM-5562: Preserve aggregate Marathon Match wins What was broken The previous PM-5562 follow-up made Development totals include aggregate wins for subtracks whose history had no placement data. QA still found that the profile totals for pops and wleite showed 76 instead of 152 and 2 instead of 36. Root cause Legacy Marathon Match history is partial but contains placement fields. The shared subtrack summary therefore treated those incomplete rows as the source of truth and replaced 76 and 34 valid aggregate wins with zero placement wins. The prior fix only covered histories with no placement fields at all. What was changed Keep an explicit aggregate wins value authoritative for Marathon Match while retaining placement-derived wins for modern tracks. This preserves the earlier Development deduplication and rating-only history fixes. Any added/updated tests Added a regression case modeled on the pops payload, proving that 76 aggregate Marathon Match wins survive a partial placement history with no first-place rows. The existing placement-history and Development aggregation tests remain passing. --- .../src/hooks/useFetchActiveTracks.spec.tsx | 32 +++++++++++++++++++ .../src/hooks/useFetchActiveTracks.tsx | 12 +++++-- 2 files changed, 41 insertions(+), 3 deletions(-) diff --git a/src/apps/profiles/src/hooks/useFetchActiveTracks.spec.tsx b/src/apps/profiles/src/hooks/useFetchActiveTracks.spec.tsx index e38686cc0..0623555e8 100644 --- a/src/apps/profiles/src/hooks/useFetchActiveTracks.spec.tsx +++ b/src/apps/profiles/src/hooks/useFetchActiveTracks.spec.tsx @@ -595,6 +595,38 @@ describe('getSubTrackSummaryStats', () => { wins: 2, }) }) + + it('keeps aggregate Marathon Match wins when legacy placement history is partial', () => { + const summaryStats = getSubTrackSummaryStats({ + challenges: 225, + name: 'MARATHON_MATCH', + submissions: { + submissions: 7, + }, + wins: 76, + } as MemberStats, [ + { + challengeId: 'legacy-mm-1', + challengeName: 'Legacy Marathon Match 1', + newRating: 1210, + placement: 122, + ratingDate: 1301961600000, + }, + { + challengeId: 'legacy-mm-2', + challengeName: 'Legacy Marathon Match 2', + newRating: 1218, + placement: 145, + ratingDate: 1302652800000, + }, + ]) + + expect(summaryStats) + .toEqual({ + submissions: 7, + wins: 76, + }) + }) }) describe('getTrackSummaryStats', () => { diff --git a/src/apps/profiles/src/hooks/useFetchActiveTracks.tsx b/src/apps/profiles/src/hooks/useFetchActiveTracks.tsx index 37f1adb46..e8a53610c 100644 --- a/src/apps/profiles/src/hooks/useFetchActiveTracks.tsx +++ b/src/apps/profiles/src/hooks/useFetchActiveTracks.tsx @@ -120,7 +120,8 @@ export const getSubTrackDisplaySubmissionCount = (subTrack?: MemberStats): numbe * Some unified stats rows currently include challenge/rating history while the * aggregate win or submission counters are stale, omitted, or left at zero. In * that case, placement-bearing history is used for wins and history/challenge - * count is used as the minimum visible submission count. + * count is used as the minimum visible submission count. Legacy Marathon Match + * history is partial, so its explicit aggregate win counter remains authoritative. * * @param {MemberStats | undefined} subTrack - The subtrack to summarize. * @param {StatsHistory[]} trackHistory - Optional history rows for the same subtrack. @@ -130,16 +131,21 @@ export const getSubTrackSummaryStats = ( subTrack?: MemberStats, trackHistory: StatsHistory[] = [], ): SubTrackSummaryStats => { - const statWins = getFiniteNumber(subTrack?.wins) ?? 0 + const aggregateWins = getFiniteNumber(subTrack?.wins) + const statWins = aggregateWins ?? 0 const historyWithPlacements = trackHistory .filter(history => getFiniteNumber(history.placement) !== undefined) const historyWins = historyWithPlacements.filter(history => history.placement === 1).length const displaySubmissions = getSubTrackDisplaySubmissionCount(subTrack) ?? 0 const historySubmissions = trackHistory.length + const hasAuthoritativeAggregateWins = subTrack?.name === 'MARATHON_MATCH' + && aggregateWins !== undefined return { submissions: Math.max(displaySubmissions, historySubmissions), - wins: historyWithPlacements.length > 0 ? historyWins : statWins, + wins: historyWithPlacements.length > 0 && !hasAuthoritativeAggregateWins + ? historyWins + : statWins, } }