fix(server): pause periodic PR discovery without foreground clients#23852

open3
main
fix/issue-23702
opened18h agobyJJulius Marminge
View on GitHubTwo-way sync enabledPR last imported 18h ago

Problem

A headless Linux server kept discovering branch pull requests every minute after its client disconnected, spending GitHub quota without anyone using the client. Reproduced on current main with an active branch thread: listPullRequestsByHead continued after the browser left and no server sockets remained.

Change

Check the existing background activity policy before each periodic branch-discovery sweep. Discovery resumes on the next minute tick when foreground activity permits opportunistic work. Startup backfill and thread-event refreshes remain available to headless agents and scheduled tasks. The existing foreground and host/client power constraints apply; no new settings or persisted state are added.

Scope and approval

Fixes #23702

Triaged bug via the automated issue flow: #23702. This change only bounds recurring branch discovery. Existing PR-summary polling is unchanged.

Verification

  • Regression test against the baseline service: fails with 10 unwanted lookups in 10 simulated idle minutes. Patched service: 6/6 tests pass in ThreadPullRequestService.test.ts. The test also proves checkpoint-triggered discovery still runs without foreground demand.
  • Focused server typecheck passes. Targeted lint has only the existing unused layer warning; diff check passes.
  • Two independent diff reviews (Codex and Claude): MERGE. Proof audit: SUFFICIENT.
  • Real Linux dev server, isolated copied state and a local git fixture with a GitHub remote. Browser paired, then disconnected. The patched server remained alive and produced zero branch-discovery spans during 21:10:11–21:14:42 UTC, covering multiple minute ticks. A foreground activity RPC then resumed synchronization on the next tick, with a successful GitHub branch lookup.

Foreground positive control Ā· Proof matrix

Server-only change: visual matrix empty, screenshots and pixel diffs not applicable. Dev-watcher restarts are disclosed and excluded from the 271-second stable observation. Existing PR-summary requests continued during that interval; this evidence does not claim all idle GitHub traffic stops or attribute shared-account quota changes to this server. The original 450-thread/90-clone scale and quota-exhaustion state were not recreated. No platform-specific code changed; desktop/mobile shells and remote transports were not separately exercised.

Evidence captured at implementation head 29ce300674; the final merge from main changes only unrelated mobile dependencies. The audited server files are identical.

Models and harness: Codex gpt-6.1-sol and Claude claude-opus-5-5 through T3 Code.

Checks

All checks passed

Added 3 commits

  • test(server): reproduce idle branch pull request sweeps (#23702)1e1b2b9
  • fix(server): idle servers no longer sweep branch pull requests every minute (#23702)29ce300
  • Merge main into fix/issue-23702ab14184
Synced from GitHub

Approvability

Verdict: Approved at ab14184

Macroscope's review found this PR approvable — This focused bug fix pauses only the periodic pull-request discovery sweep when no foreground client or permitted background demand exists, while preserving initial backfill and event-driven refreshes. It adds targeted regression coverage and does not alter schemas, defaults, deployments, or security-sensitive code.

You can add or adjust custom eligibility rules. Learn more.

Synced from GitHub

Review in Change Stack →

No actionable comments were generated in the recent review. šŸŽ‰

ā„¹ļø Recent review info
āš™ļø Run configuration
šŸ“„ Commits

Reviewing files that changed from the base of the PR and between 2c8bdf6177159d8fcd12a897d7c9311f6eb93237 and ab1418478c65754a3637796ff61657c26aae2e56.

šŸ“’ Files selected for processing: 2
  • apps/server/src/orchestration-v2/ThreadPullRequestService.test.ts
  • apps/server/src/orchestration-v2/ThreadPullRequestService.ts

Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 5 remain after this review.

šŸ“ Walkthrough

The periodic pull-request sweep now checks BackgroundPolicy.shouldRunOpportunisticWork before proceeding. A regression test verifies that an idle interval does not trigger additional lookups, while a checkpoint event still triggers a lookup.

Changes: Pull-request discovery

Layer / File(s)Summary
Policy-gated periodic sweep
apps/server/src/orchestration-v2/ThreadPullRequestService.ts, apps/server/src/orchestration-v2/ThreadPullRequestService.test.ts
The service skips the periodic sweep when shouldRunOpportunisticWork is false. The test verifies that checkpoint events still trigger lookups and that no additional lookups occur during a ten-minute idle interval.

Priority: āž– Normal

Estimated code review effort: 2 (Simple) | ~10 minutes

Change: Bug fix Ā· Severity of issue fixed: Medium

Suggested reviewers: t3dotgg, brechard

Merge Risk: ⚪ Minimal · up to ab141

The change appears ready to merge after normal checks: idle periodic discovery is paused, while checkpoint-triggered discovery remains available.

Pre-merge checks: Passed 3 Ā· Failed 1

Failed Failed checks: 1 warning

Check nameStatusExplanationResolution
Linked Issues checkWarningThe change addresses #23702's recurring idle discovery requirement. ThreadPullRequestServiceV2 gates periodic sweeps on shouldRunOpportunisticWork, and the regression test covers idle minutes and …Honor a known source-control quota pause until its reset before retrying periodic discovery, and add a regression test that verifies no retry occurs during the pause.
Passed Passed checks: 3 passed
Check nameStatusExplanation
Title checkPassedThe title clearly summarizes the main change: periodic PR discovery pauses when no foreground clients are active.
Description checkPassedThe description covers the problem, change, scope and approval, and verification. It also states limitations and distinguishes recurring branch discovery from startup backfill, thread-event refreshes,…
Out of Scope Changes checkPassedThe service change and regression test relate directly to #23702's idle branch-discovery behavior. The supplied change summary shows no unrelated changes.
Full details: Description check

Explanation

The description covers the problem, change, scope and approval, and verification. It also states limitations and distinguishes recurring branch discovery from startup backfill, thread-event refreshes, and PR-summary polling.

Full details: Linked Issues check

Explanation

The change addresses #23702's recurring idle discovery requirement. ThreadPullRequestServiceV2 gates periodic sweeps on shouldRunOpportunisticWork, and the regression test covers idle minutes and checkpoint-triggered discovery. However, #23702 also requires a known quota pause to be honored until reset. The reviewed change does not add that behavior; BackgroundPolicy.shouldRunOpportunisticWork checks foreground activity and power constraints, not quota state. A paused provider can still be retried on a later sweep when opportunistic work is allowed.

Resolution

Honor a known source-control quota pause until its reset before retrying periodic discovery, and add a regression test that verifies no retry occurs during the pause.

✨ Finishing Touches
šŸ“ Generate docstrings
  • Commit to this branch
  • Create a new PR
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR

Comment @coderabbitai help to get the list of available commands.

Synced from GitHub

Thread transfer impact

āœ… Thread transfer remains within every enforced ceiling.

ProviderMetricMain baselineThis PRImpactPR ceiling
CodexTotal thread wire5.0 KiB5.0 KiBāˆ’7 B (āˆ’0.1%)6.8 KiBāœ…
CodexThread snapshot wire3.8 KiB3.8 KiB0 B (0.0%)4.9 KiBāœ…
CodexLive turn WebSocket wire1.2 KiB1.2 KiBāˆ’7 B (āˆ’0.6%)2.0 KiBāœ…
CodexLive turn WebSocket decoded20.9 KiB20.9 KiB0 B (0.0%)29.3 KiBāœ…
CodexLive turn messages220 (0.0%)8āœ…
ClaudeTotal thread wire5.0 KiB5.0 KiB+31 B (+0.6%)6.8 KiBāœ…
ClaudeThread snapshot wire3.8 KiB3.8 KiB0 B (0.0%)4.9 KiBāœ…
ClaudeLive turn WebSocket wire1.2 KiB1.2 KiB+31 B (+2.6%)2.0 KiBāœ…
ClaudeLive turn WebSocket decoded21.2 KiB21.2 KiB+41 B (+0.2%)29.3 KiBāœ…
ClaudeLive turn messages12+1 (+100.0%)8āœ…

Baseline: 2c8bdf6 Ā· PR result: ab14184 Ā· Source CI: success

Scenario and decoded snapshot size

10 historical turns, 5 command tools per turn, 878.9 KiB retained MCP result per historical turn, and a 1.05 MiB retained result in the measured turn.

  • Codex decoded thread snapshot: 108.5 KiB
  • Claude decoded thread snapshot: 108.8 KiB

Updated in place by a trusted workflow. PR artifacts are strictly validated and never executed.

The known quota pause already blocks requests locally before network I/O in GitHubRequestPolicy.ts and SourceControlRateLimit.ts. This PR stops the recurring idle sweep entirely, including re-entry during a known pause. Foreground local retries and warning stacks remain tracked in #19781, which the report explicitly separates. The linked-issue warning needs no additional change in this PR. All 28 current-head checks pass; CodeRabbit reports no actionable code comments, and Macroscope approved.