Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
7905f7d
Nudge authors waiting on pull requests
trask Jul 20, 2026
7a3c379
Address review comments from Copilot: make author nudges race-safe
trask Jul 20, 2026
ba2d8d5
Address review comments from Copilot: align author nudge state
trask Jul 20, 2026
e9c8e48
Require clean Copilot review before PR routing
trask Jul 20, 2026
75c2f33
Address review comments from Copilot: gate human routing
trask Jul 20, 2026
1891917
Address review comment from Copilot: evaluate latest review
trask Jul 20, 2026
e1201f9
Address review comment from Copilot: use re-review mutation
trask Jul 20, 2026
4847c62
Consolidate pull request dashboard delivery
trask Jul 21, 2026
1506167
Address review comment from Copilot: prepare nudges in accepted state
trask Jul 21, 2026
cf27daf
Address review comment from Copilot: retry same-head reviews
trask Jul 21, 2026
45163ef
Address review comment from Copilot: prefer current-head reviews
trask Jul 21, 2026
ad37657
Address review comment from Copilot: validate nudges before writes
trask Jul 21, 2026
77554e7
Merge remote-tracking branch 'upstream/main' into combine-dashboard-d…
trask Jul 21, 2026
c978b53
Address review comments from Copilot: drain publisher work
trask Jul 21, 2026
59ee4ed
Allow author reminders after route resets
trask Jul 21, 2026
85b53dd
Simplify author-nudge delivery to match the Copilot re-review path
trask Jul 21, 2026
7bd5db4
Consolidate dashboard delivery paths
trask Jul 21, 2026
55ec573
Address review comment from copilot-pull-request-reviewer: drain queu…
trask Jul 21, 2026
1cfaa29
Improve author reminder comment wording
trask Jul 21, 2026
d3a588e
Clarify author reminder routes PR back to reviewers automatically
trask Jul 21, 2026
094da49
Let authors and approvers route a PR to reviewers
trask Jul 21, 2026
8f442f1
Refine dashboard status comment override wording
trask Jul 21, 2026
5723470
Address review comment from copilot-pull-request-reviewer: don't let …
trask Jul 21, 2026
100db7c
Address review comment from copilot-pull-request-reviewer: remove unu…
trask Jul 21, 2026
8302647
Address review comment from copilot-pull-request-reviewer: gate the o…
trask Jul 21, 2026
2073c2d
Address review comment from copilot-pull-request-reviewer: refresh on…
trask Jul 21, 2026
e030282
Scope clean-Copilot-review gate to configured base branches
trask Jul 21, 2026
6501e4b
Address review comment from copilot-pull-request-reviewer: log traceb…
trask Jul 21, 2026
a56fc29
Address review comment from copilot-pull-request-reviewer: keep autho…
trask Jul 21, 2026
319f372
Address review comment from copilot-pull-request-reviewer: read PR he…
trask Jul 21, 2026
5297b33
Address review comment from copilot-pull-request-reviewer: trust only…
trask Jul 21, 2026
0374971
Address review comment from copilot-pull-request-reviewer: deliver al…
trask Jul 21, 2026
81ea32a
Address dashboard override review findings
trask Jul 21, 2026
c738ca6
Address review comment from copilot-pull-request-reviewer: restore pr…
trask Jul 22, 2026
7617f23
Address review comments from copilot-pull-request-reviewer: validate …
trask Jul 22, 2026
11532ec
Address review comment from copilot-pull-request-reviewer: validate c…
trask Jul 22, 2026
3322e56
Address review comment from copilot-pull-request-reviewer: preserve c…
trask Jul 22, 2026
60f767f
Address review comment from copilot-pull-request-reviewer: order requ…
trask Jul 22, 2026
1a11f91
Address review comment from copilot-pull-request-reviewer: persist nu…
trask Jul 22, 2026
77189fc
Address review comment from copilot-pull-request-reviewer: accept nor…
trask Jul 22, 2026
790702c
Address review comment from copilot-pull-request-reviewer: validate o…
trask Jul 22, 2026
b957422
Address review comment from copilot-pull-request-reviewer: advertise …
trask Jul 22, 2026
f206e0a
Address review comment from copilot-pull-request-reviewer: validate P…
trask Jul 22, 2026
698a912
Address review comment from copilot-pull-request-reviewer: revalidate…
trask Jul 22, 2026
20d62b7
Address review comment from copilot-pull-request-reviewer: report gat…
trask Jul 22, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
97 changes: 72 additions & 25 deletions .github/scripts/pull-request-dashboard/RATIONALE.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,10 @@ the implementation understandable and operationally cheap.
- Target repositories only need GitHub App access and an entry in
`repositories.json`.
- The top-level workflow resolves target repositories, then calls a reusable
per-repository workflow for each target. The per-repository workflow runs the
update, notification, and publishing jobs top to bottom for one repository, so
one repository's update failure does not block publishing or notifications for
repositories whose updates succeeded.
per-repository workflow for each target. The per-repository workflow separates
read-only calculation from a repository-wide publisher, so one repository's
update failure does not block delivery for repositories whose updates
succeeded.
- The top-level repository matrix runs one repository at a time. Backfills do
not benefit enough from cross-repository parallelism to justify extra
aggregate API and LLM demand.
Expand Down Expand Up @@ -43,6 +43,14 @@ the implementation understandable and operationally cheap.
- Concurrency bounds pending jobs per target; it does not debounce webhook
delivery or workflow dispatch. Different repositories and PRs can still run
independently, and every accepted webhook still creates a workflow run.
- Publishers use one concurrency group per target repository. GitHub preserves
the running publisher but may replace an older pending publisher with a newer
one even when `cancel-in-progress` is false. This is safe because accepted
work lives on the state branch and every surviving publisher drains
repository-wide work rather than serving only its triggering invocation.
- The top-level hourly health check treats a replaced pending publisher as
successful. Matrix failures take precedence over cancellation, so genuine
update or delivery failures still open the failure issue.

## GitHub Actions Instead Of Netlify For Scheduled Backfills

Expand Down Expand Up @@ -82,8 +90,8 @@ the implementation understandable and operationally cheap.
queue. Incrementing the implementation revision snapshots all open PRs, then
hourly runs update at most 50 queued comments until the rollout completes.
Dashboard refreshes atomically queue comments only when their persisted result
changes; targeted refreshes update immediately and leave no completed PR
pending in the rollout queue.
changes. Every publisher drains up to 50 queued comments, so a newer publisher
also delivers work left by an older pending publisher that GitHub replaced.
- Selected PRs are processed one at a time through the same single-PR merge path
as targeted refreshes. Each accepted PR update pushes structured state before
the next selected PR is processed.
Expand All @@ -106,9 +114,9 @@ the implementation understandable and operationally cheap.
- A selected PR failure is recorded outside dashboard state, advances the
cursor, and does not stop later selected PRs. The backfill still exits nonzero
while any open PR is still recorded as having failed processing, keeping
scheduled failure reporting active. Publish and notification jobs consume
only accepted state, so untrusted PR content cannot deny service to the rest
of the repository.
scheduled failure reporting active. The publisher consumes only accepted
state, so untrusted PR content cannot deny service to the rest of the
repository.
- The cursor deliberately does not rely on PR `updatedAt`; prior testing showed
`updatedAt` is not a safe freshness key for every comment, review-comment, or
thread event the dashboard needs.
Expand Down Expand Up @@ -167,6 +175,40 @@ the implementation understandable and operationally cheap.
respond to a dashboard action. Pending required checks affect the CI column
but do not change who owns the next action.

## Copilot Review Gate

- `require_clean_copilot_review_branches` is a final safety net applied only when a PR
would otherwise route to reviewers or maintainers — that is, after the author
has addressed the actionable discussions. It is not a routing input while the
author still owns actions.
- The setting lists the base branches to gate rather than a single on/off
switch, because automatic Copilot review is itself configured per branch
(often only the default branch). Gating a branch with no automatic review
would park every ready PR on the copilot route waiting for a review that never
runs, so only branches with automatic review are listed and PRs targeting
other branches route normally.
- Copilot findings normally return a PR to the author through ordinary
discussion routing: an inline finding is an unresolved review thread, and an
actionable one routes the PR to "waiting on author." In that common path the
gate never fires and no re-review is requested.
- The gate's re-request path is deliberately narrow: it triggers when the
current head has no Copilot review yet (a push made the prior review stale) or
the author resolved Copilot's threads without a code change. Re-requesting the
same head is intentional — it asks Copilot to re-review after the author
responded, mirroring a human review cycle. Copilot's answer either clears the
gate or produces fresh actionable threads that route the PR back to the
author, so re-requesting an unchanged commit is self-correcting rather than a
re-request loop.
- "Clean" means no inline comments on the current head, counted from the
review, not from the classifier's actionability judgment. Accepted
limitation: if Copilot leaves comments the classifier treats as
non-actionable while they stay unresolved, routing sits at reviewers but the
gate holds the PR on the copilot route and re-requests until Copilot returns a
comment-free review or the author pushes. The strict count is intentional —
the gate is a conservative "Copilot had nothing to say about this exact code"
check, and folding in classifier judgment could let a real-but-non-actionable
comment slip a PR to humans.

## Live PR Status Comments

- Feedback totals in the live comment count the canonical author-action links
Expand Down Expand Up @@ -261,32 +303,37 @@ the implementation understandable and operationally cheap.
- Slack notification state is PR-granular. It does not track notification
history separately for each assignee.
- When notification state is first created, existing approver-routed PRs may
receive initial notifications on a later targeted refresh. Avoiding that
bootstrap case would require storing separate seen-but-not-notified state.
receive initial notifications from a later publisher. Avoiding that bootstrap
case would require storing separate seen-but-not-notified state.
- When a mapped assignee is added after a PR was already notified during the
same waiting period, that assignee may wait until the next follow-up cadence
instead of receiving an immediate initial notification.
- Scheduled runs send only due follow-up reminders. Targeted PR refreshes send
only the triggering PR's initial notification. This keeps webhook-driven
refreshes from sweeping unrelated PR reminders while preserving the hourly
reminder pass.
- Every publisher evaluates all accepted repository state for eligible initial
and follow-up notifications. The sent-notification ledger and weekday
24-hour follow-up cadence bound delivery. Repository-wide evaluation ensures
that a newer publisher drains Slack work whose older pending publisher GitHub
replaced.
- Slack notifications are sent only for dashboard state that has already been
accepted on the state branch. A newer dashboard update can land after the
notification job checks out state, so a notification can be slightly late
publisher checks out state, so a notification can be slightly late
relative to the newest state.
- The notification job preserves just-written notification state across normal
- The publisher preserves just-written notification state across normal
state-branch CAS retries. If Slack delivery succeeds and every state-branch
push attempt is rejected, a later run can send the same notification again.
Recording state before sending Slack would avoid that duplicate window, but
could instead record notifications that were never delivered.

## Publishing

- Dashboard publishing is serialized per target repository.
- Each publish job fetches the accepted state branch while holding the publish
slot, lists the target repository's current open PRs, renders markdown from
`dashboard-state.json`, and publishes the issue body.
- Publish jobs are superseded by newer publish jobs for the same repository;
only the newest queued publish needs to render the latest accepted state.
- If another update advances the state branch while a publish job is already
editing the issue, the live issue can briefly lag until the next publish job.
- Dashboard publishing is serialized per target repository. The publisher owns
target-repository writes for status comments, author reminders, Copilot
re-review requests, Slack notifications, and the dashboard issue.
- Each publisher fetches accepted state while holding the publish slot and
drains repository-wide pending work. Status comments are bounded to 50 per
publisher; author reminders and Copilot requests use explicit durable
ledgers; Slack eligibility is reconstructed from accepted dashboard and
notification state.
- The dashboard issue is rendered from `dashboard-state.json` and the target
repository's current open PR list after delivery. If another update advances
the state branch while a publisher is already working, external views can
briefly lag until the next publisher.
Loading