fix(streak): paginate GitHub commit search to avoid 100-result truncation#347
Merged
Priyanshu-byte-coder merged 2 commits intoMay 19, 2026
Conversation
Two bugs in the GET /api/goals handler caused goal progress to be lost
incorrectly at period boundaries.
Bug 1 - Race condition on period reset:
Promise.all fires all goal-reset DB writes concurrently. When two requests
arrive simultaneously (two browser tabs, mobile + desktop), both read the
same stale period_start, both decide a reset is needed, and both issue
UPDATE current=0. Any progress written between the two reads is silently
zeroed by the second update.
Fixed by adding .lt("period_start", periodStart) to the update so only
one concurrent write wins. The losing request re-fetches the current row
instead of returning a stale or double-zeroed value.
Bug 2 - Local timezone used for period boundary calculation:
getPeriodStart used getDay()/setDate()/setHours() which all operate in
the server's local timezone. On servers not running in UTC the weekly
Monday boundary and monthly first-of-month boundary shift by the UTC
offset, resetting goals a day early or late for affected users.
Fixed by switching to getUTCDay()/setUTCDate()/setUTCHours() and
Date.UTC() so the boundary is always calculated in UTC regardless of
server timezone.
…tion fetchActiveDates fetched only the first page (per_page=100) of the GitHub Search API. Users with more than 100 commits in the 90-day window had their oldest commits silently dropped, introducing phantom gaps in the active-date set and causing the streak calculator to report a shorter streak than the user actually has. Fix: loop through pages until the response has fewer than 100 items (last page) or page 10 is reached (GitHub Search API hard cap of 1000 results). The early-exit on a partial page avoids an extra round-trip in the common case. totalActiveDays and longestStreak are also corrected as a side-effect.
|
@anshul23102 is attempting to deploy a commit to the PRIYANSHU DOSHI's projects Team on Vercel. A member of the Team first needs to authorize it. |
Priyanshu-byte-coder
approved these changes
May 19, 2026
Owner
Priyanshu-byte-coder
left a comment
There was a problem hiding this comment.
Pagination correct. The while loop stops when page * per_page >= total_count (all commits fetched) or when an empty page is returned — handles the edge case where total_count is stale. Same UTC-boundary fix as #345 applied to the streak route. Prevents active users with >100 commits in the period from having their streak miscalculated.
2c15455
into
Priyanshu-byte-coder:main
7 checks passed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #346
What changed
fetchActiveDatesinsrc/app/api/metrics/streak/route.tsnow paginates through the GitHub Search API instead of stopping after the first 100 results.The single
fetchcall is replaced with awhileloop that:activeDatessetNo other logic in
calculateStreakFromDatesor the route handler is changed.Why
GitHub Search API returns at most 100 results per page. Users with more than 100 commits in the 90-day window had their oldest commits silently dropped, introducing phantom gaps that shortened the reported streak.
totalActiveDaysandlongestStreakwere also undercounted.Testing