Skip to content

✨ feat(review): spend review slots breadth-first on deep queues - #7528

Merged
clubanderson merged 1 commit into
v4from
feat/review-breadth-first
Sep 18, 2026
Merged

clubanderson merged 1 commit into
v4from
feat/review-breadth-first

Conversation

@clubanderson

Copy link
Copy Markdown
Member

Problem

PlanDispatch spends a fixed parallel-review budget in PR order, and an uncapped PR takes as many slots as it has missing perspectives:

limit := len(missing)
if limit > availableSlots { limit = availableSlots }

On a short queue that is exactly right - fanning every perspective out at once is the review swarm's designed behavior, and TestPlanDispatchStateMachine encodes it.

On a deep queue it inverts the intent. The head of the queue absorbs the entire budget, every PR behind it gets nothing that cycle, and adding reviewers buys more opinions on one PR instead of coverage across many. On a spoke with hundreds of open PRs the scarce resource is PRs looked at, not depth per PR.

It also bounds blast radius now that reviewers publish: uncapped, a single PR can collect five comments at once.

Change

Adds review.max_perspectives_per_pr - an opt-in cap on perspectives dispatched to one PR per cycle.

No coverage is lost. A perspective skipped this cycle is still missing next cycle (pendingMissingPerspectives) and gets dispatched then. The cap schedules depth rather than dropping it.

Zero means no cap, so every existing hive keeps exactly the behavior it has - the three tests that encode the current fan-out semantics pass unchanged. The cap stays subordinate to MaxParallelReviews, which still bounds total concurrency.

Tests

Three new tests, all passing:

  • TestDispatchSpendsSlotsDepthFirstByDefault - pins the status quo: uncapped, all three slots land on PR 🌱 Sync workflows from kubestellar/infra #1.
  • TestMaxPerspectivesPerPRSpreadsAcrossPRs - the same budget with the cap at 1 covers three distinct PRs once each.
  • TestMaxPerspectivesPerPRNeverExceedsSlotBudget - a cap above the slot budget cannot raise concurrency.

go build ./..., go vet ./pkg/review/ ./pkg/config/, and the full pkg/review suite are clean.

Companion

Pairs with #7527 (routing blocking verdicts to a human). Together: review more of the queue, and make the findings that need a person actually reach one.

PlanDispatch spends a fixed parallel-review budget in PR order, and an
uncapped PR takes as many slots as it has missing perspectives. On a short
queue that is exactly right - fanning every perspective out at once is the
review swarm's designed behavior. On a deep one it inverts the intent: the
head of the queue absorbs the entire budget, the PRs behind it get nothing
this cycle, and adding reviewers buys more opinions on one PR rather than
coverage across many. A spoke with hundreds of open PRs is the case where
that matters, because there the scarce thing is PRs looked at, not depth
per PR.

Add review.max_perspectives_per_pr, which caps perspectives dispatched to
one PR per cycle. It loses no coverage: a perspective skipped this cycle is
still missing next cycle and gets dispatched then, so the cap schedules
depth rather than dropping it. It also bounds how many comments a single PR
can collect at once, which starts to matter now that reviewers publish
their verdicts.

Zero means no cap, so every existing hive keeps the behavior it has. The
cap is subordinate to MaxParallelReviews, which still bounds total
concurrency.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Signed-off-by: Andrew Anderson <andy@clubanderson.com>
@kubestellar-prow kubestellar-prow Bot added dco-signoff: yes Indicates the PR's author has signed the DCO. size/L Denotes a PR that changes 100-499 lines, ignoring generated files. labels Sep 18, 2026
@clubanderson

Copy link
Copy Markdown
Member Author

/lgtm

@clubanderson

Copy link
Copy Markdown
Member Author

/approve

@kubestellar-prow

Copy link
Copy Markdown
Contributor

@clubanderson: you cannot LGTM your own PR.

Details

In response to this:

/lgtm

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository.

@kubestellar-prow

Copy link
Copy Markdown
Contributor

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: clubanderson

The full list of commands accepted by this bot can be found here.

The pull request process is described here

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@kubestellar-prow kubestellar-prow Bot added the approved Indicates a PR has been approved by an approver from all required OWNERS files. label Sep 18, 2026
@clubanderson
clubanderson merged commit 21c6482 into v4 Sep 18, 2026
54 of 57 checks passed
@kubestellar-prow
kubestellar-prow Bot deleted the feat/review-breadth-first branch September 18, 2026 03:18
@github-actions

Copy link
Copy Markdown
Contributor

Thank you for your contribution! Your PR has been merged.

We'd love to hear how your experience was: share feedback

clubanderson added a commit that referenced this pull request Sep 18, 2026
Carries v4 e74d45e..201c69c (v4.54.2, v4.55.0, v4.55.1) into v5,
including #7510 (cmd/hive domain extraction), #7532 (manager.go split),
#7527/#7528 (review routing + breadth-first slots), #7523 (token-access
audit backport of v5 #6303), #7515 (branch-protection facts on blocked
PR pills), #7535, #7539, #7520.

Resolution notes:
- cmd/hive, pkg/agent: declaration-level 3-way merge against base
  ff7630e; v5 seams (spokeStatePath, SetHubPushedDashboardURL,
  applyModeUnscheduledAlert, mutation boundary, runDuplicateSweepIfDue)
  preserved. F24 tombstone intact.
- pkg/github/client.go: v5 fetchPRs signature (RepoPRBreakdown) + v4
  BaseRef/prBaseRef; added Client.requiredStatusCheckContexts shim so
  v4's protection_facts.go compiles against v5, where the sweep lives in
  pkg/github/automerge.
- pkg/github/token_access_audit{,_test}.go: v4 side (its backport of
  v5's own #6303, now using testutil.Eventually).
- pkg/github/automerge/f3_trusted_merger_source_test.go: v4's
  f3ReadPackage path adjusted one level deeper for v5's subpackage.
- pkg/review/prompts.go: v4 routing instruction + mentionableAuthor
  added; v5's #6212 deletion of dead BuildPerspectivePrompts /
  BuildSequentialPrompt kept.
- pkg/agent tests: v4's normalizeModelName cases rewritten against v5's
  normalizeModelNameForBackend (v5 removed the wrapper in #5795).
- docs/knowledge-curator.md: v5 promotion-only body + v4's
  knowledge.git_sources section (code exists on v5). roadmap.md: v4
  rows. api-reference.md: v5 table, citations re-resolved (--fix).
- .github/workflows/v2-ci.yml: v5 UID-isolation step + v4's fuller
  audit-log step comment.

Refs #7463

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Signed-off-by: Andy Anderson <andy@clubanderson.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

approved Indicates a PR has been approved by an approver from all required OWNERS files. dco-signoff: yes Indicates the PR's author has signed the DCO. size/L Denotes a PR that changes 100-499 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant