Skip to content

Aged PRs

Cindy Zhang edited this page Aug 23, 2026 · 13 revisions

Aged PRs — the cleanup decision table

The queue is 146 non-draft open PRs; 68 were opened two or more weeks ago and 44 more than a month ago. Many are no longer relevant, and of the ones that are, some no longer work. This page is the decision table for clearing that backlog once, and then holding the line nightly.

Cindy, 2026-08-23: "I think many of them aren't relevant anymore and even if they were they might not work."

The governing rule is unchanged: we are goaled on good reviews, not on throughput. Closing a PR is a real cost to a real person. Every close is warm, names the reason, and leaves the door open.

The counts this table was built against

bucket n
team (eng/design), no changes-requested, idle ≥7d 1
changes-requested, idle ≥7d, any author 12
external, no changes-requested, opened ≥14d ago 56

Five of the twelve have the AUTHOR as the last speaker, and none of the twelve has ever been nudged. Both facts change what is owed — see below.

Track 1 — team PRs, mergeable, idle a week

Authors in .github/ENGOWNERS or .github/DESIGNOWNERS. They can merge themselves, so an open PR of theirs a week idle is abandoned rather than blocked.

Close it, warmly, with the reopen instruction. Say: reopen any time, and merge main first — a week-old branch usually needs it. If they wanted to keep working, draft is what draft is for.

Do NOT close a team PR that is idle but has an unanswered question on it, or whose CI is red for a reason we caused.

Track 2 — sitting on changes-requested

Measure silence from OUR last review, and count only author activity since: a commit, a comment, a review reply. CI runs, bot comments and base-branch churn are not responses.

state do
author spoke last WE are the silent party. Answer it. Never close.
under 2 days nothing
2+ days, never nudged one nudge, ever
7+ days AND already nudged AND no push close, warmly

The nudge is once per PR, not once per run. Read the comments before nudging; a daily nudge is harassment and is exactly what an unguarded cron does.

Nothing is eligible for closing on its first pass. Twelve PRs are sitting on changes-requested and not one has been nudged — so this cleanup's Track 2 action is seven nudges and five replies, and zero closes. The closes come a week later, to whoever has still not answered.

Track 3 — the aged pass, opened ≥14 days ago

56 PRs. This is the one that needs judgement, so it gets a cheap triage before any review effort. In this order — stop at the first that matches:

# test action
1 The problem is already fixed on main — someone else landed it, or the code it patches is gone close: "this landed as <sha>", credit the finding
2 Superseded by another PR R6d — this is a set. Review the winner first, then close naming it
3 The file it touches no longer exists, or the API it extends was removed close: the ground moved, with the commit that moved it
4 Conflicts with main and needs the author's judgement to resolve nudge once; close after a week of silence
5 Conflicts mechanically only (lockfile, both sides appended) fix it ourselves, then review — never bounce this back
6 Still applies, still wanted review it properly. Age is not a verdict
7 Still applies, and we do not want it that is a taste call → Rulings, not a unilateral close

Row 7 is the one to be honest about. "This is old" is not a reason to reject a change we would accept if it arrived today. If the only argument for closing is age, it is not an argument.

Row 1 is the most common and the cheapest to test, so it goes first: apply the diff to main and see whether it is a no-op, or check whether the symptom still reproduces. A PR fixing a bug that no longer exists closes in two minutes with no review at all.

What every close says

Four things, short, in this order:

  1. Thanks, by name, for the specific thing they found or built.
  2. Why it is closing — the concrete reason, not "stale". A commit, a superseding PR, a week of silence after a nudge.
  3. Reopening is welcome any time — and merge main first, since the branch has aged.
  4. Discord, for anything they would rather ask a person (R12e).

If the change is one we still want, say so, and say we may carry it ourselves with credit — then file it so the intent is not lost (R2g: file it in the same turn, or do not promise it).

Rate limit

No more than 10 closes in a day, and never a batch with one boilerplate body. A contributor watching several of their PRs close at once inside a minute learns the project is automated and hostile, whatever the words say. AKnassa alone has five in the changes-requested bucket.

Spread them, and write each one to its own PR.

After the cleanup

This runs once. Then the nightly holds the line with the same tests, on a much smaller flow — the ladder in Track 2 and the triage in Track 3 are already part of the sweep's standing instructions.

Clone this wiki locally