Skip to content

feat: the GitHub API is called sequentially per issue to fetch details β€” for repos with 100+ issues this creates a waterfall of 100+ serial API calls that hits the unauthenticated rate limit (60 req/hour) within the first analysis runΒ #93

Description

@prince-pokharna

πŸ› Problem Statement

IssueScope documents:

"Fetches issue details and performs AI analysis in parallel for high throughput."

However, the GitHub REST API /repos/{owner}/{repo}/issues/{number} returns full issue details (body, labels, comments count) within the list endpoint GET /repos/{owner}/{repo}/issues?per_page=100. If the implementation calls the detail endpoint separately for each issue after the list call, it creates a sequential waterfall:
GET /repos/owner/repo/issues β†’ 1 call (list, 100 items)
GET /repos/owner/repo/issues/1 β†’ 1 call
GET /repos/owner/repo/issues/2 β†’ 1 call
...
GET /repos/owner/repo/issues/100 β†’ 1 call
Total: 101 calls for a 100-issue repo

GitHub's unauthenticated rate limit is 60 requests/hour. A 100-issue analysis exhausts the entire hourly budget in a single run. Even with a GitHub token (5,000 req/hour), the serial nature means a 500-issue repo takes 500 sequential round trips.

πŸ’‘ Proposed Fix

1. Consume full issue data from the list endpoint β€” no separate detail calls needed

The list endpoint already returns body, labels, user, created_at, comments, and html_url. The only missing field is comments content (text). Batch-fetch comments separately only for issues with comments > 0:

// src/lib/github.ts

const GITHUB_API = 'https://api.github.com';

export async function fetchIssuesWithDetails(
  owner: string,
  repo: string,
  token?: string
): Promise<GitHubIssue[]> {
  const headers = token ? { Authorization: `Bearer ${token}` } : {};
  const allIssues: GitHubIssue[] = [];
  let page = 1;

  // Step 1: Paginate through issues β€” full body included in list response
  while (true) {
    const res = await fetch(
      `${GITHUB_API}/repos/${owner}/${repo}/issues?state=open&per_page=100&page=${page}`,
      { headers }
    );
    const batch: GitHubIssue[] = await res.json();
    if (batch.length === 0) break;
    allIssues.push(...batch);
    page++;
  }

  // Step 2: Fetch comments only for issues that have them β€” in parallel with concurrency cap
  const withComments = allIssues.filter(i => i.comments > 0);
  const commentResults = await Promise.allSettled(
    withComments.map(issue =>
      fetch(`${GITHUB_API}/repos/${owner}/${repo}/issues/${issue.number}/comments`, { headers })
        .then(r => r.json())
        .then(comments => ({ number: issue.number, comments }))
    )
  );

  // Merge comments into issues
  const commentMap = new Map(
    commentResults
      .filter(r => r.status === 'fulfilled')
      .map(r => [(r as PromiseFulfilledResult<any>).value.number, (r as PromiseFulfilledResult<any>).value.comments])
  );

  return allIssues.map(issue => ({
    ...issue,
    comments_data: commentMap.get(issue.number) ?? [],
  }));
}

2. Display a rate limit warning when no token is provided

if (!token && allIssues.length > 50) {
  showWarning(
    `Analyzing ${allIssues.length} issues without a GitHub token may hit the rate limit. ` +
    'Add a token in "Configure API Keys" to increase your limit to 5,000 req/hour.'
  );
}

πŸ“ Files to Modify

File Change
src/lib/github.ts Replace per-issue detail calls with list-first + batch comments pattern
src/components/ Add rate limit warning banner when token is absent and issue count > 50

Suggested labels: bug, performance, github-api

I would like to work on this. Could you please assign it to me?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions