Skip to content

Cross Cohort Performance metrics - #88

Open
Vayras wants to merge 1 commit into
mainfrom
feat/cross-cohort-score-fields
Open

Cross Cohort Performance metrics#88
Vayras wants to merge 1 commit into
mainfrom
feat/cross-cohort-score-fields

Conversation

@Vayras

@Vayras Vayras commented Jul 30, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • Adds attendedWeeks, totalWeeks, scorePercent, attendancePercent, avgScore to GetCohortScoresResponseDto
  • Computed per-cohort inside the existing loop in ScoresService.getUserScores (backs GET /scores/me and GET /scores/user/:userId), no schema/migration changes
  • Enables cross-cohort performance comparisons per user without the client recomputing percentages

Test plan

  • tsc --noEmit passes
  • Manually hit GET /scores/me for a user in multiple cohorts and confirm the new fields, including zero-denominator cohorts (no weeks / no scored weeks yet)

🤖 Generated with Claude Code

@Vayras Vayras changed the title Add attendance/score-rate fields to per-cohort scores response Cross Cohort Performance metrics Jul 31, 2026
@Vayras
Vayras marked this pull request as ready for review July 31, 2026 07:02
@Vayras
Vayras requested a review from theanmolsharma July 31, 2026 07:02
Comment thread src/scores/scores.service.ts Outdated
`${c.cohortType}_S${c.seasonNumber}`,
new CrossCohortPerformanceEntryDto({
scoreReceived: c.totalScore,
totalScore: c.maxTotalScore,

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

totalScore here means the opposite of everywhere else in the module.

In this DTO, totalScore is being set to the max possible score (c.maxTotalScore), while the earned total goes into scoreReceived. But everywhere else in this file — GetCohortScoresResponseDto, LeaderboardEntryDto, WeeklyScoretotalScore means points earned and maxTotalScore is the ceiling.

A consumer reading entry.totalScore will almost certainly treat it as the earned score and render the ceiling instead — a silent data bug that's hard to spot.

Can we rename the field to match the rest of the module (e.g. scoreReceived / maxScore) so the same name doesn't mean two different things? If the API contract is already fixed externally, let's at least document it explicitly on the DTO.

Comment thread src/scores/scores.service.ts Outdated
}
}

const totalWeeks = cohort.weeks.length;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

totalWeeks counts non-scoring weeks, which deflates attendancePercent and avgScore.

totalWeeks is every week on the cohort — including ORIENTATION / GRADUATION and any week the user has no attendance record for. But attendedWeeks is derived from weeklyScores, which are only pushed when an attendance record exists (if (attendance)), and scorePercent's denominator (cohortMaxTotalScore) is likewise summed only over weeks with records.

So within the same object we're mixing two denominators: scorePercent is over attended/recorded weeks, while attendancePercent and avgScore are over all calendar weeks. This also differs from LeaderboardEntryDto, which uses user.attendances.length for maxAttendance.

Is counting orientation/graduation weeks in the denominator intended? If not, filtering cohort.weeks to scoreable week types (or using the count of weeks with attendance records) would keep the three metrics consistent.

Comment thread src/scores/scores.controller.ts Outdated
ApiExtraModels(CrossCohortPerformanceEntryDto),
ApiOkResponse({
description:
'Map of "<cohortType>_S<season>" to { scoreReceived, totalScore }',

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Response description is out of date — the entry now also returns attendedWeeks and totalWeeks, but the description still lists only two fields. Quick fix:

Suggested change
'Map of "<cohortType>_S<season>" to { scoreReceived, totalScore }',
'Map of "<cohortType>_S<season>" to { scoreReceived, totalScore, attendedWeeks, totalWeeks }',

@Vayras
Vayras force-pushed the feat/cross-cohort-score-fields branch from 902e154 to dcf50a9 Compare July 31, 2026 11:17
Co-authored-by: Cursor <cursoragent@cursor.com>
@Vayras
Vayras force-pushed the feat/cross-cohort-score-fields branch from 1759ca1 to 3c86b21 Compare July 31, 2026 11:20
@Vayras
Vayras requested a review from theanmolsharma July 31, 2026 11:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants