Skip to content

fix(scm): don't downgrade an UNSTABLE PR to blocked when CI is failing#2404

Open
abhay-codes07 wants to merge 1 commit into
AgentWrapper:mainfrom
abhay-codes07:fix/scm-mergeability-unstable-precedence
Open

fix(scm): don't downgrade an UNSTABLE PR to blocked when CI is failing#2404
abhay-codes07 wants to merge 1 commit into
AgentWrapper:mainfrom
abhay-codes07:fix/scm-mergeability-unstable-precedence

Conversation

@abhay-codes07

Copy link
Copy Markdown

Closes #2401.

What

The observer's mergeability derivation downgraded an UNSTABLE PR to blocked whenever CI was failing (or changes were requested), even though UNSTABLE means the PR is mergeable (it has a failing/pending non-required check; a required failure yields BLOCKED). Both mergeabilityObservation (adapters/scm/github) and its byte-identical twin mergeabilityFromProviderFacts (observe/scm) checked draft/CI/review and returned blocked before ever reaching the UNSTABLE branch at the bottom.

Why it's wrong

doc.go documents the priority order (first rule wins): BLOCKED (2) → UNSTABLE (3) → changes_requested (5) → CI failing (6). UNSTABLE must win over CI-failing and changes-requested. The sibling mergeabilityFromGraphQL (provider.go) already implements this — it switches on state first. Because an UNSTABLE PR's status rollup is FAILURE (→ ci = failing), the bottom UNSTABLE branch was effectively dead for the common case, and a genuinely mergeable PR was persisted as Mergeability = blocked.

Change

Move the UNSTABLE check above the draft/CI/review blockers in both functions, matching doc.go and the GraphQL sibling. Existing behavior is otherwise unchanged.

Tests

  • Added a regression test to each package (TestSCMMergeabilityUnstableNotDowngradedByBlockers, TestMergeabilityFromProviderFactsUnstableNotDowngraded) covering UNSTABLE + failing CI and UNSTABLE + changes-requested. Both fail before the change (blocked) and pass after (unstable).
  • go test ./internal/adapters/scm/github/... ./internal/observe/scm/... green; go vet and gofmt clean. -race left to CI (no 64-bit CGO locally).

cc @harshitsinghbhandari — followed doc.go's stated order and the GraphQL sibling; happy to adjust if a failing CI is intended to always read as blocked.

The observer mergeability derivation composes state in a documented priority
order (doc.go): DIRTY -> conflicting, BLOCKED -> blocked, UNSTABLE -> unstable,
then changes_requested / CI failing -> blocked. UNSTABLE (rule 3) is meant to win
over changes_requested (5) and CI failing (6): UNSTABLE means the PR IS mergeable
but has a failing/pending NON-required check (a required failure yields BLOCKED).

Both mergeabilityObservation (adapters/scm/github) and mergeabilityFromProviderFacts
(observe/scm) checked draft/CI/review and returned blocked before ever reaching the
UNSTABLE branch at the bottom. Because an UNSTABLE PR's status rollup is FAILURE
(so ci=failing), the UNSTABLE branch was effectively dead for the common case, and
a genuinely mergeable PR was persisted as Mergeability=blocked — contradicting the
package spec and the sibling mergeabilityFromGraphQL, which switches on state first.

Move the UNSTABLE check above the draft/CI/review blockers in both functions,
matching the spec and the GraphQL sibling. Adds a regression test to each package.
Copilot AI review requested due to automatic review settings July 4, 2026 06:28

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

bug(scm): UNSTABLE PR wrongly downgraded to blocked when CI is failing

2 participants