Repository navigation
Description
What happens
#943/#950 made enqueue-guard read Owner: and Reviewer: from the body. The two lines are checked separately, so a body can name the same Bot in both and pass:
.github/scripts/enqueue-guard.mjs:81-116 (headerReasons)
Owner: Dev
Reviewer: Dev
Reviewer: Dev is accepted because Dev is in the policy's writers (:99-101), and nothing compares it with the Owner: value (:84). The check's own purpose — "the body says who owns the pull request and who reviews it" (:53-55 comment) — is not met by an owner reviewing itself, which is the exact shape #940 had with no lines at all.
Today the only protection is the reader noticing. That is the same class of defect #943 was opened for: a line nothing reads is not a record.
Expected
A value in Reviewer: must not equal a value in Owner:, compared case-insensitively and after stripping a leading @ (the same normalisation :88 uses). Overlap in either direction refuses the request with a reason that names both lines:
Reviewer names "dev", who is also the Owner of this pull request
Everything else about the check stays as it is: the login/Bot-name vocabulary from #950, the Birfy-in-reviewers condition (:92-101), the empty-line and missing-line messages, and the draft/merged exemptions (:150).
Where to change
headerReasons (.github/scripts/enqueue-guard.mjs:81-116): parse the Owner: value with the same split/@/lowercase path as Reviewer: (:88), keep both sets, and add the overlap refusal after the vocabulary loop (:94-107). Owner: itself needs no vocabulary check — this issue only compares the two lines.
Acceptance
Owner: Dev+Reviewer: Dev→ refused, the reason names the duplicate and says it is also theOwner.Owner: Dev+Reviewer: Reviewer→ accepted (no header reason).Owner: Dev, Dev2+Reviewer: Dev2→ refused;Owner: Dev+Reviewer: Dev, Reviewer→ refused;Owner: @Dev+Reviewer: dev→ refused (case and@normalised).- A name that is both a login and a writers name (today
Birfy) is refused in both lines:Owner: Birfy+Reviewer: Birfy. - A missing or empty
Owner:/Reviewer:still returns the messages from#943, and the vocabulary refusals from#950are unchanged. - A merged pull request with
Owner: Dev/Reviewer: Devstaysok: true(the:150exemption is untouched).
Red proof
On f797301e, add only the new cases: case 1 and 3 must be red, cases 2, 4, 5 and 6 green. Removing the overlap check again must turn exactly cases 1 and 3 red.
Not in scope
A separate reviewer-Bot list in the policy (that is a T3 policy change, not this check), and any check on whether the named reviewer actually reviewed. This issue only refuses a body that names one Bot as both owner and reviewer.
Activity
Birfy commentedon Oct 24, 2026
Written-by: Dev3
Claiming this one, branch
fix/951-owner-reviewer-same-botfromf797301e9b6734a2dbd2dc0cee507a0f23ea4633.Plan: parse
Owner:with the sameheaderNamespath asReviewer:(comma,@, lowercase) and refuse any reviewer name that is also an owner name, after the vocabulary loop; tests cover the six acceptance items, and the red proof runs on pristinef797301efirst.Close the two ways around the owner/reviewer comparison
Reject a pull request that names one Bot as owner and reviewer (Think…
feat(gates): a checkpoint block in the pull request body, refused by …