Repository navigation
Add per-reviewer response time - #32
Merged
hy0ug0 merged 3 commits intoOct 9, 2026
Merged
Conversation
hy0ug0
force-pushed
the
hugocontrerasperso/ori-100-add-per-reviewer-response-time
branch
from
October 9, 2026 21:08
642661a to
52e2fb0
Compare
For each reviewer, the time from a review request (to them or one of their teams) to their next review or conversation comment. A team request goes to the first member who responds; draft time is excluded; a re-request after a response starts a new round; removed requests and requests still pending give no sample. The rules live in server/analysis/reviewer-response.ts, with tests built from real timelines. Each PR now carries its review requests and removals, normalized to the requested reviewer (user, bot or team; null when GitHub hides it). The requester is not fetched. A PR with more than 50 events is served as partial and never cached. The extra connection made 50-PR batches time out on the busiest nodejs/node and microsoft/vscode PRs, so batches drop to 25 at the same cost per PR. The PR cache moves to version 6. The reviewer table gets sortable "Response p50" and "p90" columns, with the sample count next to p50 and p90 dimmed under 5 samples. The CSV export carries both, in minutes, and the sample count. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
hy0ug0
force-pushed
the
hugocontrerasperso/ori-100-add-per-reviewer-response-time
branch
from
October 9, 2026 21:11
52e2fb0 to
95d6663
Compare
When the review continuation fails, the PR keeps only its inline reviews, so an unfetched review could be an earlier response than a fetched comment. PullRequest.reviews now carries pageInfo.hasNextPage, true only for such a partial PR, which is never cached, so the cache version stays at 6. Reviewer response time drops samples after the last fetched review, as it does after the last fetched comment or event. First response had the same blind spot: a PR whose only fetched response comes after the last fetched review is now undetermined. The code and README also say that team requests go to the first qualifying responder, without a membership check, and that requested bots give samples when bots are included. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Each column header now holds a native button for sorting, with a visible focus ring, and the header carries aria-sort. The info icons are buttons too: their tooltip opens on hover and on keyboard focus, closes on Escape, and screen readers read it as the button's description. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
hy0ug0
deleted the
hugocontrerasperso/ori-100-add-per-reviewer-response-time
branch
October 9, 2026 21:35
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Each reviewer row gets the time from a review request to that reviewer's response, as p50 and p90. A response is a submitted review or a conversation comment. The rules live in
server/analysis/reviewer-response.ts, a pure module:Choices the issue left open:
actor, so the two can't be mixed up. No metric needs the requester yet.Team.members, theread:orgscope and extra query cost, and the token can't see private teams.Fetching and the model:
ReviewerTablegets sortable "Response p50" and "p90" columns. Nulls sort last in both directions and show "–". The sample count sits in small muted text before p50 (n=7 19h 8m). With fewer than 5 samples, p90 is dimmed (gray-500 against the gray-900 of the other response values), and the header tooltip and the cell title say why. The CSV export adds p50 and p90 in minutes and the sample count.Every sortable header now holds a native
<button>with a visible focus ring, and the<th>carriesaria-sort(ascending, descending or none). A pseudo-element keeps the whole cell clickable, as before. The info icons are buttons too: their tooltip opens on hover and on keyboard focus and closes on Escape, and screen readers read it as the button's description.Evidence
Tests.
bun run checkandbun run testpass (222 tests).reviewer-response.test.tsencodes six real timelines:The first four cases are anonymized timelines from a private repository.
To check that the tests catch broken rules, I broke one rule at a time. Each of these failed tests: no seen set (2 fail), the clock starting at a request made during draft (2 fail), a re-request resetting the start (1 fails), no horizon (2 fail), no individual precedence (13 fail). Dropping the events-before-responses tie-break failed nothing, so I removed it. Events go into the list first and the sort is stable, which gives the same order.
Regression tests for a failed review continuation, from the review: a request at 10:00, a fetched review at 10:30, an unfetched review at 11:00 and a fetched comment at 13:00. Reviewer response time now drops the 3 h sample instead of reporting it, and first response is undetermined. Turning the review horizon off fails both tests.
Live run. Server on :3100 with a fresh cache, client on :5300. A run on a private repository (216 PRs in 9 batches of 25, complete, 12 GitHub requests, 6.1 s cold) was also cross-checked against its REST timelines.
Hand checks against
gh api repos/{repo}/issues/{n}/timeline(REST, separate from the GraphQL path):UI. Checked in Chrome at 1280 px, light and dark, and at 390 px:
aria-sortfollows. Tab moves to "About Response p50", which shows the tooltip and is described by its text. Clicking the header padding still sorts. The accessibility tree names each column header by its label alone ("Total", not "Total About Total").Merge Danger
Door: two-way
Reverting restores the old fragment and
PULL_REQUEST_CACHE_VERSION = 5. Version 6 entries are then ignored, and the version 5 entries left on disk can be read again.Blast Radius: fetching
Closes ORI-100
🤖 Generated with Claude Code