Authored by Opus 4.8 (Claude Code). Session de8830c3-8d1b-47f8-90db-bd236c8b9bd2.
Related: #12190
Related: #12186
PR + Discussion sync scanned the entire corpus every run — the dominant driver of the rising GitHub rate-limit hits (issues were already delta-gated; PRs/Discussions were not). The pullRequests and discussions GraphQL connections have no server-side since filter (only issues does), but both already order UPDATED_AT DESC. This adds a client-side cutoff: stop paginating once a batch's oldest item predates the cached high-water mark (max updatedAt across metadata.pulls / metadata.discussions). A clean-slate run (lastSync === null) or an empty cache still traverses the full history — consistent with the issue delta + sealed-chunk model (archived items stay put; only new/changed items re-bucket).
FAIR-band: over-target — sole active implementer (@neo-gpt rate-limited, @neo-gemini benched per current project state) + operator-directed lane (epic #12186 P1).
Evidence: L1 (unit: cutoff stops pagination at the high-water mark — 2 new tests, 208 green) → L1 required (no runtime-only ACs; the win is fewer GraphQL page-fetches, asserted via query-call count). No residuals for the delta.
Deltas from ticket (if any)
This PR delivers the substantive half of #12190 — the PR + Discussion delta cutoffs, which are the dominant rate-limit driver. Two items from #12190's body are intentionally not pursued here, with rationale:
- Discussion query-cost reduction (the
replies(first:$maxReplies) nesting): unnecessary post-delta. Once the discussion sync fetches only changed discussions (a handful of pages, not the full corpus), the per-page nesting cost is marginal. Reducing it would add continuation-query complexity (like the issue timeline) for negligible gain.
- Shared rate-limit governance (lifting the low-remaining guard out of IssueSyncer): low-urgency post-delta. With both syncers delta-gated, PR/Discussion runs are cheap; the guard gap is a robustness nicety, not a driver. Easy follow-up if the reviewer deems it worth a dedicated lane.
Related: #12190 (not Resolves) so the operator decides whether the delta suffices to close it or to keep it open for the optional governance item.
Test Evidence
npm run test-unit -- test/playwright/unit/ai/services/github-workflow/ → 208 passed (2 new, 0 regressions).
- New tests (
PullRequestSyncer.spec + DiscussionSyncer.spec): a 3-page stub where page 2's oldest item predates the cached high-water mark → the sync issues exactly 2 GraphQL calls (page 3 never requested). Pre-fix this would be 3 (full-corpus scan). Existing tests (empty/clean-slate metadata → cutoff 0 → full fetch) are unaffected.
node --check on all touched source files; pre-commit whitespace/shorthand hooks green.
Post-Merge Validation
Authored by Opus 4.8 (Claude Code). Session de8830c3-8d1b-47f8-90db-bd236c8b9bd2.
Related: #12190 Related: #12186
PR + Discussion sync scanned the entire corpus every run — the dominant driver of the rising GitHub rate-limit hits (issues were already delta-gated; PRs/Discussions were not). The
pullRequestsanddiscussionsGraphQL connections have no server-sidesincefilter (onlyissuesdoes), but both already orderUPDATED_AT DESC. This adds a client-side cutoff: stop paginating once a batch's oldest item predates the cached high-water mark (maxupdatedAtacrossmetadata.pulls/metadata.discussions). A clean-slate run (lastSync === null) or an empty cache still traverses the full history — consistent with the issue delta + sealed-chunk model (archived items stay put; only new/changed items re-bucket).FAIR-band: over-target — sole active implementer (@neo-gpt rate-limited, @neo-gemini benched per current project state) + operator-directed lane (epic #12186 P1).
Evidence: L1 (unit: cutoff stops pagination at the high-water mark — 2 new tests, 208 green) → L1 required (no runtime-only ACs; the win is fewer GraphQL page-fetches, asserted via query-call count). No residuals for the delta.
Deltas from ticket (if any)
This PR delivers the substantive half of #12190 — the PR + Discussion delta cutoffs, which are the dominant rate-limit driver. Two items from #12190's body are intentionally not pursued here, with rationale:
replies(first:$maxReplies)nesting): unnecessary post-delta. Once the discussion sync fetches only changed discussions (a handful of pages, not the full corpus), the per-page nesting cost is marginal. Reducing it would add continuation-query complexity (like the issue timeline) for negligible gain.Related: #12190(notResolves) so the operator decides whether the delta suffices to close it or to keep it open for the optional governance item.Test Evidence
npm run test-unit -- test/playwright/unit/ai/services/github-workflow/→ 208 passed (2 new, 0 regressions).PullRequestSyncer.spec+DiscussionSyncer.spec): a 3-page stub where page 2's oldest item predates the cached high-water mark → the sync issues exactly 2 GraphQL calls (page 3 never requested). Pre-fix this would be 3 (full-corpus scan). Existing tests (empty/clean-slate metadata → cutoff 0 → full fetch) are unaffected.node --checkon all touched source files; pre-commit whitespace/shorthand hooks green.Post-Merge Validation
lastSync === null) still traverses the full PR/Discussion history — the eventual v8.1.0 re-bucket re-sync must not be truncated by the cutoff.