From efae19b89cff69b1b5194c6ed42cd1201ff87c57 Mon Sep 17 00:00:00 2001 From: Thomas Lively Date: Fri, 6 Nov 2026 18:39:25 -0800 Subject: [PATCH] Add logging to the review assignment script This will give us more visibility into the results to make sure it's working as expected and to fine tune the logic if we want. --- scripts/assign_reviewer.py | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/scripts/assign_reviewer.py b/scripts/assign_reviewer.py index e1cfe54abee..92c836c18ec 100755 --- a/scripts/assign_reviewer.py +++ b/scripts/assign_reviewer.py @@ -34,9 +34,15 @@ # Accumulated exponentially decayed review load per reviewer. review_load: dict[str, float] = {} +# Number of review-requested PRs per reviewer. +review_count: dict[str, int] = {} + # Accumulated exponentially decayed authored-PR load per reviewer. authored_load: dict[str, float] = {} +# Number of authored PRs per reviewer. +authored_count: dict[str, int] = {} + # Most recent review-request timestamp per reviewer, used for tie-breaking. last_assigned: dict[str, float] = {} @@ -155,6 +161,7 @@ def accumulate_pr_activity(pr: dict, reviewer_set: set[str]) -> None: if author in reviewer_set: age = max(0.0, now - active_at) authored_load[author] += w_pr * math.exp(-DECAY_RATE * age) + authored_count[author] += 1 # Track which reviewers have reviewed or approved so we can ignore removed # unreviewed requests and drop PENDING_REVIEW_MULTIPLIER on approved PRs. @@ -194,6 +201,7 @@ def accumulate_pr_activity(pr: dict, reviewer_set: set[str]) -> None: mult = PENDING_REVIEW_MULTIPLIER if is_pending else 1.0 age = max(0.0, now - assign_ts) review_load[r] += mult * w_pr * math.exp(-DECAY_RATE * age) + review_count[r] += 1 # Load per-reviewer weight overrides from REVIEWER_WEIGHTS (JSON object mapping @@ -275,7 +283,9 @@ def main() -> None: return review_load.update(dict.fromkeys(reviewers, 0.0)) + review_count.update(dict.fromkeys(reviewers, 0)) authored_load.update(dict.fromkeys(reviewers, 0.0)) + authored_count.update(dict.fromkeys(reviewers, 0)) last_assigned.update(dict.fromkeys(reviewers, 0.0)) for pr in repo_data['recentPRs']['nodes']: if not pr['isDraft'] and pr['number'] != pr_number: @@ -286,7 +296,7 @@ def main() -> None: for r in eligible } # Break ties by least-recently-assigned reviewer, then team member order. - chosen = min( + ranked = sorted( eligible, key=lambda r: ( round(scores[r], 6), @@ -294,6 +304,14 @@ def main() -> None: reviewers.index(r), ), ) + print('Candidate reviewers:') + for r in ranked: + print( + f' {r}: score={scores[r]:.2f} ' + f'(review_requests={review_count[r]}, review_load={review_load[r]:.2f}, ' + f'authored={authored_count[r]}, authored_load={authored_load[r]:.2f})', + ) + chosen = ranked[0] print(f'Selected reviewer for PR #{pr_number}: {chosen}') gh_api([