Files
hdf5/.github/scripts
Scot BreitenfeldandH. Joe Lee daa1daf640 CI: fix reviewer-coordination edge cases — draft transitions, unrelated CODEOWNERS, explicit removals (#6465)
review-checklist.js previously tried to enforce a single load-balanced
reviewer per area by actively stripping anyone else who showed up, using a
checklist-comment-existence heuristic (isOpeningRace) to decide when it was
safe to do so. Walking through real PR timelines surfaced several cases
where that heuristic and that stripping behavior did the wrong thing:

- An old PR's first encounter with the bot (or one whose checklist comment
  was deleted) was misdiagnosed as a brand-new PR, forcibly reselecting a
  human-curated reviewer list.
- A CODEOWNER for areas this PR doesn't touch (e.g. a project lead added by
  hand for their judgment) was swept by the same logic as junk
  auto-assignment, with no protection for an existing approval.
- A reviewer who isn't an owner of any touched area was invisible in the
  checklist and untouched by any cleanup path either way.
- A PR that picked up reviewers while non-draft, then was converted to
  draft, had those reviewers wiped out by the next push — converted_to_draft
  isn't in this workflow's trigger list, so there's no event at the actual
  transition to distinguish "noise from this PR's creation" from "a real
  assignment from before it became a draft."
- A reviewer removed via the PR UI could be silently re-added by GitHub's
  own CODEOWNERS engine on a later push, since there was no memory of the
  removal across runs.

Redesign around one principle: the bot should never automatically strip a
reviewer who's already on the PR, manually added or auto-assigned, except
where the policy explicitly calls for it. Concretely:

- coordinateReviewers is now purely additive for non-draft PRs: chooseReviewers
  runs against the *real* existingRequested, so it naturally skips any area
  that already has someone and only fills gaps. This is idempotent and safe
  on every event, eliminating the need for the old race-detection heuristic
  entirely (isOpeningRace, the new-PR/synchronize distinction, and the
  post-request 15s delayed re-clear are all removed as dead weight).
- Pruning — used only where the bot still clears reviewers — is scoped to
  touchedAreaOwners (owners of areas this PR touches, plus catch-all "*"
  owners) instead of the repo-wide allCodeOwners, so a CODEOWNER for
  unrelated areas is never touched.
- Draft handling clears auto-assigned reviewers only at the literal
  opened/reopened-as-draft moment — the one point where "CODEOWNERS noise
  from this PR's creation" and "this PR's actual reviewer state" are
  mechanically the same thing. Every other event while draft leaves existing
  reviewers alone.
- An explicit review_request_removed persists that login to an exclusion
  list embedded as a second hidden marker in the checklist comment (the only
  durable storage available), and every run strips anyone in that list who
  reappears — covering GitHub re-assigning them on a later push. A direct
  review_requested for that exact login overrides the exclusion, since it's
  the strongest available signal that someone individually decided that
  person should be back right now.
- buildBody adds a catch-all "Additional reviewers" line for anyone
  requested who isn't an owner of any touched area, so they're visible and
  their approval is shown (informationally — it doesn't gate any area's
  sign-off), and accepts any owner's approval for an area's sign-off rather
  than only the specifically-assigned one's.

12 new tests cover the buildBody changes and the parseExcluded/serializeExcluded
round-trip; all existing pure-function tests are unchanged.

Co-authored-by: H. Joe Lee <hyoklee@hdfgroup.org>
2026-06-19 12:02:45 -05:00
..