Skip to content

PR auto-merge always fails: GraphQL mutations use non-existent MergeMethod type #206

Closed

Description

@lbacik

Problem

With PR_AUTO_MERGE=true (introduced in #185), auto-merge never succeeds. GitHub rejects both mutations before execution because they declare the variable with a type that does not exist in its GraphQL schema:

auto-merge failed: GitHub GraphQL request was rejected: MergeMethod isn't a defined input type (on $mergeMethod)

Observed in a real run (agent-simple-rpg-engine, issue #24, attempt 2026-10-11T14:53:26.424648Z, outcome complete), event auto_merge_failed in agent_output.json at 2026-10-11T15:00:34Z. The PR (lbacik/simple-rpg-engine#45) was opened but had to be merged by hand.

Because _maybe_auto_merge never raises, the attempt still ends complete and the failure only appears as a WARNING event and in the result comment.

Root cause

simple_coding_agent/github_tracker.py declares $mergeMethod: MergeMethod! in both:

  • enable_auto_merge (line ~550, EnableAutoMerge mutation)
  • merge_pull_request (line ~573, MergePullRequest mutation)

GitHub's enum is named PullRequestMergeMethod (values MERGE, SQUASH, REBASE). Verified by introspection:

gh api graphql -f query='{ a: __type(name:"MergeMethod"){name} b: __type(name:"PullRequestMergeMethod"){name enumValues{name}} }'
# => {"data":{"a":null,"b":{"name":"PullRequestMergeMethod","enumValues":[{"name":"MERGE"},{"name":"SQUASH"},{"name":"REBASE"}]}}}

The existing tests in tests/test_github_tracker.py assert only on transport.variables and never check the query text, so the bad type went unnoticed.

Proposed fix

-            mutation EnableAutoMerge($pullRequestId: ID!, $mergeMethod: MergeMethod!) {
+            mutation EnableAutoMerge($pullRequestId: ID!, $mergeMethod: PullRequestMergeMethod!) {
-            mutation MergePullRequest($pullRequestId: ID!, $mergeMethod: MergeMethod!) {
+            mutation MergePullRequest($pullRequestId: ID!, $mergeMethod: PullRequestMergeMethod!) {

Also update the _graphql_merge_method docstring (line ~737), which refers to GitHub's MergeMethod enum.

Tests

  • Add assertions that both mutations declare $mergeMethod: PullRequestMergeMethod! (e.g. check transport.queries[0]), so a wrong type name fails a unit test rather than a live run.

Related, to verify while fixing: direct-merge fallback on unprotected branches

When the base branch has no protection rule and the PR is already mergeable, GitHub typically refuses enablePullRequestAutoMerge with a message like Pull request is in clean status rather than one containing mergeable. _is_already_mergeable (simple_coding_agent/publication.py ~438) matches only on "mergeable", so in that case the code would skip _merge_directly and report auto_merge_failed again, just with a different message.

The target repo above (lbacik/simple-rpg-engine, main not protected, allow_auto_merge: true) is exactly this case. This hasn't been verified live because the type error fails first. Suggested change: also treat clean status (and possibly unstable status) as "mergeable now", and add a unit test that uses that error text.

Acceptance criteria

  • Both mutations use PullRequestMergeMethod!; a unit test pins the declared type.
  • On a repo with an unprotected base branch, a complete attempt with PR_AUTO_MERGE=true ends with the PR merged (pull_request_merged event), not auto_merge_failed.
  • On a repo with branch protection and required checks, auto-merge is enabled (auto_merge_enabled event).

🤖 Generated with Claude Code

Activity

  1. lbacik commented on Oct 11, 2026

    @lbacik
    OwnerAuthor

    This was generated by AI during triage.

    Agent Brief

    Category: bug
    Summary: Auto-merge GraphQL mutations declare a non-existent MergeMethod type, and the direct-merge fallback misses GitHub's "clean status" refusal

    Current behavior:
    With PR_AUTO_MERGE enabled, every merge attempt is rejected by GitHub before execution: MergeMethod isn't a defined input type (on $mergeMethod). Both GitHub tracker operations that take a merge method — enable_auto_merge() (the enablePullRequestAutoMerge mutation) and merge_pull_request() (the mergePullRequest mutation) — declare $mergeMethod: MergeMethod!. GitHub's enum is actually PullRequestMergeMethod (values MERGE, SQUASH, REBASE; confirmed by schema introspection during triage). Existing unit tests only assert on the GraphQL variables, never on the declared variable type, so they pass while every live call fails. The attempt still ends complete, with an auto_merge_failed WARNING event and auto-merge failed: … in the result comment.

    Once the type is fixed, a second defect surfaces: when the base branch has no protection rule and the PR is already mergeable, GitHub refuses enablePullRequestAutoMerge with a message like Pull request is in clean status. The "already mergeable" classifier used by the publication auto-merge step (_is_already_mergeable) only matches the substring mergeable, so this refusal falls through to auto_merge_failed instead of the direct-merge fallback. (Not yet observed live — the type error fails first.)

    Desired behavior:

    • Both mutations declare $mergeMethod: PullRequestMergeMethod!. The helper that maps the operator merge method (_graphql_merge_method) and its docstring refer to PullRequestMergeMethod.
    • When enabling auto-merge is refused because the PR is already mergeable, the publisher merges directly (existing _merge_directly path → pull_request_merged event, result merged). This includes refusals whose text says the PR is in clean status or unstable status (case-insensitive), as well as the existing already mergeable wording.
    • All other behavior per ADR 0004 and the Auto-merge entry in CONTEXT.md is unchanged: native auto-merge first, a merge failure never raises and never changes the complete outcome.

    Key interfaces:

    • GitHubGraphQLTransport.enable_auto_merge(repository, pull_request, merge_method) and .merge_pull_request(...): only the declared GraphQL variable type changes; signatures and variables stay the same.
    • _is_already_mergeable(error) -> bool in the publication module: widen what counts as "mergeable now".

    Acceptance criteria:

    • A unit test asserts that the query sent by enable_auto_merge declares $mergeMethod: PullRequestMergeMethod! (e.g. via transport.queries[0]), and fails if the type is MergeMethod.
    • The same assertion holds for merge_pull_request.
    • No GraphQL query in the codebase declares a variable of type MergeMethod.
    • A publication test: enable_auto_merge raises an error containing Pull request is in clean status → merge_pull_request is called with the configured method, a pull_request_merged event is logged, and the merge result is merged (not auto-merge failed).
    • Equivalent test (or parametrized case) for unstable status.
    • The existing behavior is still covered: successful enable → auto_merge_enabled; already mergeable → direct merge; an unrelated error → auto_merge_failed with the attempt still complete.
    • The full test suite passes.

    Out of scope:

    • Live verification against real repositories (unprotected lbacik/simple-rpg-engine → pull_request_merged; protected repo with required checks → auto_merge_enabled). The maintainer will do this after merge.
    • Classifying refusals by querying mergeStateStatus instead of matching error text.
    • Any change to PR_AUTO_MERGE / PR_MERGE_METHOD configuration, the agent-auto-merge label opt-in, or ADR 0004.
  2. added
    ready-for-agentFully specified implementation issue ready for an unattended agent
    and removed on Oct 11, 2026
  3. self-assigned this
    on Oct 11, 2026
  4. lbacik commented on Oct 11, 2026

    @lbacik
    OwnerAuthor

    Agent Attempt Result: complete

    Branch: agent/issue-206
    PR: #207

    Evidence

    • Check command: UV_PROJECT_ENVIRONMENT=/home/agent/venv-py311 uv run --python 3.11 --extra dev ruff check && UV_PROJECT_ENVIRONMENT=/home/agent/venv-py311 uv run --python 3.11 --extra dev pytest && UV_PROJECT_ENVIRONMENT=/home/agent/venv-py313 uv run --python 3.13 --extra dev pytest → exit code 0
    • Review cycles: 0/2
    • Review findings: all clear

    Details

    Claude SDK completed the implementation workflow.

  5. removed
    ready-for-agentFully specified implementation issue ready for an unattended agent
    on Oct 11, 2026
  6. removed their assignment
    on Oct 11, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions