<\!-- SPDX-License-Identifier: Apache-2.0 Reference rendering of the pr-management-stats dashboard (see ../../../skills/pr-management-stats/export.md). Worked example over apache/airflow, 2026-06-09. Numbers are illustrative; the panel set + layout are the spec. -->

# 📊 Apache Airflow — PR Backlog Dashboard

Scope: apache/airflow · 500 open PRs · closed/merged since 2026-04-28 (6 wk) · viewer `@potiuk` · refreshed 2026-06-09 (post-cleanup)
✓ Effect of this session's cleanup: ready queue 236 → 217 (−19: 5 merged + 13 changes-requested stripped + 1 flipped), stale-ready (>4wk) 105 → 88 (−17).
⚠ The closed/merged velocity series hit GitHub's 1000-result Search cap — weeks 0–3 are authoritative, 4–5 truncated.
Total open
500
405 non-draft · 95 draft
Non-maintainer
373
contributor-authored (127 are maintainers' own)
Ready for review (non-maint.)
211
of 217 ready; 88 are >4 wk old
Drafts (author's court)
95
57 non-maintainer · 19% of open
Ready-for-review queue (211) split by review state — same colors as the "why waiting" chart below:
108
Never reviewed
(no maintainer look yet)
67
Discussed,
no decision
13
Changes requested
(author's court)
23
Approved
(awaiting merge)
What the numbers above mean (all counts are of currently-open PRs):
• Total open — 500: every open PR on apache/airflow (drafts + non-drafts, contributors + maintainers).
• Non-maintainer — 373: of those, the ones authored by contributors (not committers). The other 127 are maintainers' own PRs, which triage/review treat separately. This 373 is the work the triage + review pipeline actually serves.
• Ready for review (non-maint.) — 211: contributor PRs carrying the `ready for maintainer review` label — i.e. they cleared triage and are waiting on a maintainer to review. (6 maintainer-authored PRs also carry the label but are excluded — maintainers self-manage.)
• Drafts (author's court) — 95: open PRs in GitHub draft state — work-in-progress the author still owns; not awaiting maintainer action.
The 4 coloured cards break the 211 ready PRs down by what each is actually waiting for (same colours + the line chart further below): 108 never reviewed (no maintainer has looked yet — the real backlog), 67 discussed but no decision (a maintainer engaged but neither approved nor requested changes), 13 changes requested (really the author's court — mislabeled ready), 23 approved (review done, just awaiting a merge).

## 🚦 Triage funnel (mutually exclusive · 494 triage-scope PRs; the 6 maintainer-authored `ready` PRs are excluded — triage skips collaborator PRs)

211
Ready (queue, non-maint.)
15
Responded
34
Waiting (author silent)
139
Waiting for human maintainer comment
95
Drafts (author's court)
Every open non-maintainer PR sits in exactly one of these five mutually-exclusive states (left → right ≈ closest-to-merge → furthest):
• Ready (queue) — 211: carries the `ready for maintainer review` label → awaiting a maintainer's review. This is the bottleneck (see the split above).
• Responded — 15: a maintainer left review feedback and the author has since replied / pushed — back in the maintainer's court for a re-look.
• Waiting (author silent) — 34: a maintainer left feedback and the author has not responded for >7 days — the author's court; stale-ping candidates.
• Waiting for human maintainer comment — 139: open non-draft PRs with no `ready` label and no maintainer triage marker — no human maintainer has engaged yet. Not all neglected contributor work: 79 of 139 (57%) are maintainers' own PRs (triage skips collaborator PRs — they self-manage); only 60 are contributor PRs genuinely awaiting a first triage pass, most brand-new (76 <1 wk; 25 >4 wk). Real "needs first triage" ≈ 60, not 139.
• Drafts (author's court) — 95: PRs in GitHub draft state — work-in-progress the author owns, not awaiting maintainer action (either opened as draft, or triage converted them for failing CI / conflicts / staleness). They re-enter the funnel only when the author re-marks "Ready for review."

## 🔎 Why the ready-for-review queue (211) is actually waiting — non-maintainer PRs only (the 6 maintainer-authored ready PRs are excluded — triage skips collaborator PRs); by age

■ never reviewed (no formal review, no non-triage maintainer comment) ■ discussed, no decision ■ changes requested ■ approved (awaiting merge)
🔎 The headline finding: 108 of 211 non-maintainer ready PRs (51%) have never had a real maintainer look — and the red "never reviewed" line climbs steeply toward the right (newer PRs) — 36 + 34 + 31 of them are <8 wk old, while only 3–4 are >8 wk — i.e. the `ready` label is being applied faster than anyone reviews, so fresh PRs pile up unreviewed. Breakdown: never-reviewed 108 · discussed-no-decision 67 · approved-awaiting-merge 23 · changes-requested 13 (still mislabeled `ready` — these sit in other areas beyond the two cleaned this session, so a queue-wide bot would catch them all). The "review-bound" diagnosis is really two problems: a first-review gap (the 108) and a decision/merge gap (the 67 + 23). (The 6 maintainer-authored ready PRs are excluded — they self-manage and triage skips them.)

## 🤖 Workflow automation potential

Categorising every decision-point this session by whether the rule is deterministic (a GitHub Action could reproduce it exactly) or needs judgment (LLM/human):

Workflow step | Vol. | Determinism | CI-automatable?
--- | --- | --- | ---
Mark-ready gate (real-CI-green + mergeable + 0 unresolved + not changes-req) | 53 | Deterministic | YES — caught 13/53 false-positives by rule
CI-failing → draft + violations comment (check→category map) | 49 | Deterministic | YES
Conflict → rebase comment (`mergeable_state=dirty`) | 4 | Deterministic | YES
Changes-requested → strip `ready` + nudge (`reviewDecision`) | 13 | Deterministic | YES
Stale-draft detection (idle thresholds) | 5 | Deterministic | YES (flag only)
Workflow-approval safety scan (no workflow-file edits, no exfil patterns) | 9 | Semi | PARTIAL — scan auto, approve = judgment
Unresolved-thread engagement split (replied/pushed after marker) | 10 | Semi | PARTIAL
Stale-draft close decision | 5 | Judgment | NO — 3/5 kept (dependency / AIP / active first-timer)
Code-review correctness | 6 | Judgment | NO — caught a real "doesn't fix the bug" defect
Mentor reply | 1 | Judgment | NO

~80%
Fully deterministic
(124 of ~155 decision-points)
~12%
Semi-deterministic
(detection auto, action judgment)
~8%
Judgment-required
(review, mentor, close)

### Highest-value CI automations (in order)

# | GitHub Action | Why it wins
--- | --- | ---
1 | ready-label bot — auto add/remove `ready for maintainer review` on every push from: real CI green (not just bot checks) + mergeable + 0 unresolved threads + `reviewDecision ≠ CHANGES_REQUESTED` | The mark-ready gate is 100% deterministic yet humans get it wrong 25% of the time (the rollup-SUCCESS-but-real-CI-never-ran trap). A bot runs it continuously and never gets fooled — would have prevented all 13 false-positives + kept the 13 changes-requested out of the queue automatically.
2 | red-CI drafter — convert to draft + post the quality-violations comment when required checks fail | 49 PRs this session; pure check-name→category mapping.
3 | conflict / changes-requested sweeper — comment + relabel on `dirty` or `CHANGES_REQUESTED` | 17 PRs; trivially rule-based, keeps the queue honest about author-vs-maintainer court.
4 | stale flagger — label (not close) drafts idle > threshold | Detection is safe to automate; the close stays human (3/5 were wrongly closeable).

Keep human/LLM: code-review correctness, mentor replies, and close-vs-keep decisions — these are where the session's judgment actually changed outcomes (caught a non-fixing "fix", kept 3 PRs that rules would have closed, unblocked a stuck first-timer).

### Drafts vs closes per week — contributor PRs only (bot & backport PRs excluded; wk 0–3 reliable)

■ draft-conversions (`ConvertToDraft` events) ■ closed-unmerged. Bot-authored and backport PRs (base ≠ `main`) are removed — that stripped 76 of 203 closes (51 bot + 57 backport = release-branch housekeeping, not contributor triage) and 4 of 127 drafted PRs. wk-0 draft bump is partly this session; closes wk 4–5 truncated by the Search cap.

### Who does it — triage process vs author, and @potiuk's share (contributor PRs, 6-wk window)

Action | Total | By triage (maintainer acted) | By author (self) | @potiuk
--- | --- | --- | --- | ---
Draft-conversions | 173 | 125 (72%) | 48 (28%) | 90 — 52% of all · 72% of triage
Closes | 127 | 67 (53%) | 59 (46%) | 7 — 6% of all · 10% of triage

72%
of triage drafts by @potiuk
(one-maintainer-heavy → prime automation target)
10%
of triage closes by @potiuk
(closing is @kaxil-heavy, see below)

### Closing stats per person (contributor PRs closed by a maintainer ≠ author; n = 67)

Maintainer | Contributor PRs closed | Share |
--- | --- | --- | ---
@kaxil | 40 | 60% |
@potiuk | 7 | 10% |
@pierrejeambrun | 6 | 9% |
@bbovenzi | 5 | 7% |
@choo121600 | 3 | 4% |
@shahar1 | 2 | 3% |
@Lee-W / @jason810496 / @eladkal / @ashb | 1 each | ~1% |

Both triage actions are single-maintainer-concentrated, but different people: @potiuk does 72% of triage drafting, @kaxil does 60% of contributor-PR closing. Drafting is fully deterministic → automate it (red-CI drafter). Closing needs judgment (3/5 close candidates this session were wrongly closeable) → keep human, but the @kaxil concentration is a bus-factor worth spreading. Definitions: triage = actor ≠ author; author = self-action.

## 🔥 Pressure by area (refreshed)

# | Area | Score | Open PRs
--- | --- | --- | ---
1 | `area:task-sdk` | 173 | 106
2 | `area:providers` | 159 | 134
3 | `area:API` | 112 | 72
4 | `(no area)` | 67 | 63
5 | `area:dev-tools` | 63 | 47
6 | `area:UI` | 59 | 42
7 | `area:DAG-processing` | 56 | 40
8 | `area:Scheduler` | 51 | 45

## 📈 Closure velocity (wk 0–3, from prior snapshot)

Week ago | Merged | Closed | Bar (merged)
--- | --- | --- | ---
0 | 235 | 55 |
1 | 202 | 64 |
2 | 161 | 60 |
3 | 171 | 24 |

Avg 192 merged/wk · ~314 opened/wk. Inflow runs ahead of closes — but the exact net is cap-limited (see Trends caveat).

## 📉 Trends over time (last 6 weeks)

⚠ Data limit: GitHub's Search API caps results at 1000, so closes older than ~4 weeks are truncated. That makes the absolute backlog and net-flow for weeks 4–5 unreliable (they read artificially low). Weeks 0–3 below are authoritative. True historical trends need an uncapped daily snapshot job — itself a good automation (a tiny scheduled Action writing `open_count / ready_count / per-area` to a CSV would give exact week-over-week deltas the Search API cannot).

### PRs opened per week, by author class (reliable wk 0–3)

■ first-time ■ contributor ■ maintainer. Roughly ~48% maintainer-authored, ~43% contributor, ~9% first-timer — steady week over week. Contributor + first-timer inflow (~50%) is exactly the volume the triage automation serves.

### Merged per week (reliable wk 0–2; wk 3 partial)

### Open backlog at week-end (wk 0–3 only — 4–5 cap-distorted, omitted)

Even within the reliable window the backlog is climbing (330 → 500 across the cap-clean weeks). Note this slope is partly inflated by the same truncation (older closes missing); the honest read is "backlog is growing, magnitude needs a snapshot job to pin down." This is the strongest argument for the daily-snapshot Action above.

## 📋 Detailed — top areas (Total / Ready / Waiting / Untriaged / Draft)

Area | Total | Ready | Waiting | Untriaged | Draft
--- | --- | --- | --- | --- | ---
`area:providers` | 134 | 50 | 11 | 35 | 30
`area:task-sdk` | 106 | 41 | 9 | 38 | 18
`area:API` | 72 | 27 | 8 | 23 | 14
`(no area)` | 63 | 40 | 0 | 15 | 8
`area:dev-tools` | 47 | 11 | 1 | 22 | 13
`area:Scheduler` | 45 | 20 | 1 | 11 | 11
`area:UI` | 42 | 11 | 1 | 22 | 8
`area:DAG-processing` | 40 | 16 | 3 | 12 | 8

Bottom line: the queue is review-bound, not triage-bound (211 contributor PRs ready, 88 >4 wk; inflow ~+72/wk). The cleanup measurably shrank the ready queue by 19. ~80% of the triage workflow is deterministic and CI-automatable — the single highest-leverage move is a ready-label GitHub Action that runs the mark-ready gate continuously (humans mis-call it 25% of the time). Reserve human/LLM effort for code-review correctness, mentoring, and close-vs-keep — the ~8% where judgment changed outcomes this session.
Read-only stats — no mutations. Triage detection via the `Pull Request quality criteria` marker. Generated by Claude Code (Opus 4.8) for @potiuk.