Skip to content

bug(pr_merge): GitLab adapter returns merged:false eagerly while the merge is actually completing — race breaks /nextwave post-flight #424

@bakeb7j0

Description

@bakeb7j0

Summary

mcp__sdlc-server__pr_merge returned {ok: true, enrolled: true, merged: false, pr_state: "OPEN"} for an MR that was actually merged on the GitLab side moments later. The eager-return-before-merge-complete behavior surfaces as a stale state to the caller and breaks downstream logic that branches on merged.

Environment

  • Where observed: /wavemachine Wave 1 Flight 1 post-flight merge of !69 (feature/76-foundation-pgvector-depskahuna/74-pluggable-vector-stores) on analogicdev/internal/tools/wellofsouls, 2026-05-06
  • Project: GitLab, merge_trains_enabled: false, merge_method: merge

Steps to Reproduce

  1. Open MR with green CI on a GitLab project where merge_method: merge.
  2. Call mcp__sdlc-server__pr_merge({number: <iid>}).
  3. Observe response shape:
    {"ok": true, "number": 69, "enrolled": true, "merged": false, "merge_method": "direct_squash", "queue": {"enabled": false, "position": null, "enforced": false}, "pr_state": "OPEN", "url": "...", "warnings": [], "queue_fallback": false}
  4. Query MR state via glab api projects/:id/merge_requests/69 immediately after — state: "merged". The merge had already completed by the time the next API call landed.

Expected Behavior

For a merge-queue-disabled GitLab repo (no enrollment delay), pr_merge should block until the merge actually completes and return {merged: true, pr_state: "MERGED"}. Or, if the eager-return shape is intentional (e.g. for queue-enabled paths), the caller needs a clear way to distinguish "queued, not yet merged" from "merge in flight, will land".

The same call shape on !68 (the parallel MR in the same flight, merged moments earlier) correctly returned merged: true with a merge_commit_sha. So the eager-false is non-deterministic — likely a race between the merge call and GitLab's state-update propagation.

Actual Behavior

  • merged: false returned despite GitLab side completing the merge.
  • Caller sees pr_state: "OPEN" and may incorrectly treat the merge as failed/pending.
  • A subsequent glab api query confirms the merge actually happened.

Severity

severity::moderate/nextwave's post-flight Prime branches on the response. In my run it correctly handled !69 because I cross-checked via glab api and saw the merged state. Without that cross-check, the orchestrator would have hung waiting for a "second" merge that already happened.

Workaround

After pr_merge, query glab api projects/:id/merge_requests/<iid> | jq .state to verify actual state. If state: "merged", treat as success regardless of the response's merged field.

Acceptance Criteria

  • On merge-queue-disabled GitLab repos, pr_merge blocks until merge completes (or until a sane timeout). Response is deterministic — merged: true + merge_commit_sha populated, OR merged: false with a clear enrolled-but-not-yet-landed state distinguishable from failed-to-merge.
  • Add a regression test: GitLab fixture with merge_method=merge, no train, MR with green CI — pr_merge returns merged: true.
  • Document the response-shape contract for queue-enabled vs queue-disabled vs merge-train projects in the tool description.

Dependencies

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions