MergeRequestsFinder ignores review_state when combined with a reviewer wildcard (ANY/NONE)
Summary
MergeRequestsFinder silently drops a positive review_state / review_states filter whenever a reviewer wildcard (reviewer_id: ANY / reviewer_id: NONE, or reviewerWildcardId in GraphQL) is also set. Only the wildcard applies, and the results are wrong.
Steps to reproduce
Run against the GraphQL API on gitlab.com (project gitlab-org/glql, open MRs, as of 2026-09-17):
query {
project(fullPath: "gitlab-org/glql") {
mergeRequests(state: opened, reviewerWildcardId: ANY, reviewState: APPROVED, first: 50) {
count
nodes { iid reviewers { nodes { username mergeRequestInteraction { reviewState } } } }
}
}
}Returned 8 MRs. None of them has a reviewer in APPROVED state (they are UNREVIEWED, REVIEWED or REVIEW_STARTED). The result is identical to reviewerWildcardId: ANY alone.
mergeRequests(state: opened, reviewerWildcardId: NONE, reviewState: APPROVED, first: 50)Returned 2 MRs that have no reviewers at all, which is impossible for an APPROVED review state.
The negated form is not affected: reviewerWildcardId: ANY, not: {reviewStates: UNREVIEWED} correctly excludes MRs with an unreviewed reviewer.
What is the current bug behavior?
review_state is ignored when combined with a reviewer wildcard. Only review_requested / no_review_requested is applied.
What is the expected correct behavior?
Either apply both filters (reviewer_id: ANY + review_state: X should return MRs with at least one reviewer in state X; reviewer_id: NONE + review_state: X should return nothing), or reject the combination with a validation error instead of returning wrong rows.
Root cause
In app/finders/merge_requests_finder.rb:
by_reviewerhandles the wildcards withitems.no_review_requested/items.review_requestedand never looks atparams.review_state. Only the named-reviewer branch passes it through (items.review_requested_to(params.reviewer, params.review_state)).by_review_statethen returns early because the wildcard setsreviewer_id:
def by_review_state(items)
return items unless params.review_state.present?
return items if params.reviewer_id? || params.reviewer_username?
items.review_states(params.review_state, params.ignored_reviewer)
endSo when a wildcard is present, neither method applies the state filter.
Context
Found while adding a reviewState filter to GLQL (glql!508 (merged)). GLQL now rejects the reviewer = any|none + reviewState pairing at compile time as a workaround. That rejection can be relaxed to a redundancy warning for any once this is fixed.