Skip to content

Cap the reconciler's new pull requests per run - #17

Merged
imanimanyara merged 3 commits into
mainfrom
feat/reconcile-rate-limit
Nov 2, 2026
Merged

imanimanyara merged 3 commits into
mainfrom
feat/reconcile-rate-limit

Conversation

@imanimanyara

Copy link
Copy Markdown
Member

Summary

The control plane works now (#15, #16) and is still dry-run, for one reason: volume.

Dry run across all ten accounts in policy.json, 2026-11-02:

account listed would open
laranail 85 64
simtabi 117 38
ichava 17 15
simbi-prjs-clt 16 1
brandgulp, mukoracms, simsange, tayariai, tusente, simbi-prjs-int 38 0
total 256 118

118 pull requests in the first scheduled run. Against the 773 in the week of 2026-09-30 that made
"fewer, fuller PRs" a rule, that is not a switch to flip blind — so it has stayed off, and the
Dependabot standard has stayed unenforced instead. The fix is not to accept the burst; it is to
make the switch safe.

The cap

policy.json gains max-new-per-run: 5 — at most five new pull requests per account per run.
--max-new N overrides it, --max-new 0 removes it. A scheduled week then opens at most five per
drifting account, and the estate converges over a few weeks instead of in one go.

Two details that matter more than the number:

  • A repository whose pull request is already open is still refreshed past the budget. Leaving a
    stale one open is worse than opening nothing, and the budget is about new ones.
  • A held-back repository reads deferred:rate-limit, never skipped:, and the summary states
    how many were deferred. skipped means a decision was taken about that repository; a budget says
    nothing about it. Without that distinction a capped run reads as a clean estate — which is exactly
    how the defects in fix(dependabot): the reconciler wrote nothing, and passed #15 and Rewrite a drifting Dependabot config with render, not check #16 hid for as long as they did.

Tests

Four new cases, and the three that can fail were proven red before the code existed: the budget
holds (1 create, 2 deferred from 3 drifting), deferring is not reported as skipping, an open pull
request is still refreshed past the budget, and 0 means no limit. Reverting the cap to a no-op
turns two of them red; 20 of 20 pass with it in place.

What this leaves you

gh variable set DEPENDABOT_RECONCILE_APPLY --repo simtabi/.github --body true now means at most
~20 pull requests a week across the four accounts that drift
, converging over roughly three
weeks, rather than 118 at once. Still your call, but it is a different decision from the one you
were being asked to make.

Going live was unsafe for one reason: volume. Measured 2026-11-02 with
a dry run across all ten accounts in policy.json, the first apply run
would have opened 118 pull requests across 256 repositories -- 64 in
laranail, 38 in simtabi, 15 in ichava, 1 in simbi-prjs-clt. Against the
773 pull requests in the week of 2026-09-30 that made "fewer, fuller
PRs" a rule, that is not a switch anyone should flip blind, so it has
stayed dry-run and the standard has stayed unenforced instead.

policy.json gains `max-new-per-run: 5`: at most five NEW pull requests
per account per run, overridable with --max-new, and 0 for no limit. A
scheduled week then opens at most five per drifting account and the
estate converges over a few weeks rather than in one burst.

Two details that matter more than the cap itself:

  A repository whose pull request is already open is still refreshed
  past the budget. Leaving a stale one open is worse than opening
  nothing, and the budget is about new ones.

  A repository held back reads `deferred:rate-limit`, never `skipped:`,
  and the summary says how many were deferred. `skipped` means a
  decision was taken about that repository; a budget says nothing about
  it. Without that distinction a capped run reads as a clean estate --
  which is exactly how the defects in #15 and #16 hid for as long as
  they did.

Four tests, proven red before green: the budget holds, deferring is not
skipping, an open pull request is still refreshed past it, and 0 means
no limit. Disabling the cap turns two of them red.
Copilot AI balanced review requested due to automatic review settings November 2, 2026 19:20

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Copilot was unable to review this pull request because the user who requested the review has insufficient remaining quota. Try requesting a review at a lower effort level.

The first placement checked the budget before doing any work, which is
cheaper and misreports. A repository that conforms, or whose pull
request is already up to date, came back `deferred:rate-limit` with
nobody having looked at it. The real laranail dry run showed it: 85
listed, 77 active, "63 deferred" -- when only 64 of the 77 drift at all.
A summary that inflates the backlog is the same class of defect as one
that hides it.

The budget is now an object passed into reconcile_repo and spent at the
one point a NEW pull request is decided, after every other branch has
returned. So `conforms`, `skipped:pr-up-to-date`,
`skipped:branch-without-open-pr` and the rest keep their own status, and
only a repository that would genuinely have had a pull request opened is
deferred.

test_the_budget_does_not_mislabel_a_repository_it_never_reached pins it:
two drifting repositories and one conforming, budget 1, and the
conforming one must read `conforms` with exactly one deferral.
Reinstating the early spend turns seven tests red, including that one.
The first placement checked it before the work, so a conforming repository read `deferred` with nobody having looked at it. laranail's real dry run showed 63 deferred where only 64 of 77 drift.
@imanimanyara
imanimanyara merged commit 3b75108 into main Nov 2, 2026
6 checks passed
@imanimanyara
imanimanyara deleted the feat/reconcile-rate-limit branch November 2, 2026 19:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants