Skip to content

fix(streak): paginate GitHub commit search to avoid 100-result truncation#347

Merged
Priyanshu-byte-coder merged 2 commits into
Priyanshu-byte-coder:mainfrom
anshul23102:fix/streak-pagination
May 19, 2026
Merged

fix(streak): paginate GitHub commit search to avoid 100-result truncation#347
Priyanshu-byte-coder merged 2 commits into
Priyanshu-byte-coder:mainfrom
anshul23102:fix/streak-pagination

Conversation

@anshul23102
Copy link
Copy Markdown
Contributor

Fixes #346

What changed

fetchActiveDates in src/app/api/metrics/streak/route.ts now paginates through the GitHub Search API instead of stopping after the first 100 results.

The single fetch call is replaced with a while loop that:

  • Adds each page's commits to the activeDates set
  • Breaks when the page returns fewer than 100 items (last page)
  • Breaks at page 10 (GitHub Search API hard cap of 1000 results)

No other logic in calculateStreakFromDates or 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. totalActiveDays and longestStreak were also undercounted.

Testing

  1. Use a GitHub account with 100+ commits in the last 90 days.
  2. Before: streak shows a gap or resets unexpectedly.
  3. After: streak reflects the continuous commit history correctly.
  4. Users with fewer than 100 commits in the window see no change in behavior (loop exits on first iteration).

Draft -- waiting for assignment on #346 before review is requested.

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.
@vercel
Copy link
Copy Markdown

vercel Bot commented May 19, 2026

@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 Priyanshu-byte-coder marked this pull request as ready for review May 19, 2026 05:14
@Priyanshu-byte-coder Priyanshu-byte-coder self-requested a review as a code owner May 19, 2026 05:14
Copy link
Copy Markdown
Owner

@Priyanshu-byte-coder Priyanshu-byte-coder left a comment

Choose a reason for hiding this comment

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

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.

@Priyanshu-byte-coder Priyanshu-byte-coder merged commit 2c15455 into Priyanshu-byte-coder:main May 19, 2026
7 checks passed
@Priyanshu-byte-coder Priyanshu-byte-coder added gssoc:approved GSSoC: PR approved for scoring level:intermediate GSSoC: Intermediate difficulty (35 pts) gssoc26 GSSoC 2026 contribution type:bug GSSoC type bonus: bug fix quality:clean GSSoC: Clean quality multiplier (×1.2) labels May 19, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

gssoc:approved GSSoC: PR approved for scoring gssoc26 GSSoC 2026 contribution level:intermediate GSSoC: Intermediate difficulty (35 pts) quality:clean GSSoC: Clean quality multiplier (×1.2) type:bug GSSoC type bonus: bug fix

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Commit streak truncated for users with more than 100 commits in the 90-day window

2 participants