280: MR creation not idempotent on resume — GitLab 409 when re-running after auto-merge failure #281

Merged
david merged 2 commits from feature/issue-280/mr-creation-not-idempotent-on-resume-gitlab-409-wh into main 2026-08-18 23:42:35 +00:00
Owner

Summary

Fixes #280: after #274's glab mr view --json bug aborted the mr stage during auto-merge polling (i.e. after the MR was already created), resuming re-ran createMr() and hit a duplicate-create error (GitLab 409, GitHub 422, Forgejo equivalent).

Fix (both parts, as requested)

  1. Idempotent createMr across resume

    • New optional findExistingMr() method on the MrClient interface (src/mr/types/mrClient.ts)
    • Implemented for all three bundled platforms: GitLab, GitHub, Forgejo
    • runMrStage checks findExistingMr() before calling createMr() and reuses an already-open MR/PR instead of creating a duplicate
    • Falls back to createMr() directly when a client doesn't implement findExistingMr (backward-compatible interface)
  2. Two-phase mr-result.json persistence

    • mr-result.json is now written immediately after createMr() succeeds, with autoMerge: { enabled: true, merged: false }, before auto-merge polling/merging begins
    • Rewritten once the merge actually completes
    • Resume detection (determineResumeStage.ts / isMrResultAutoMergeComplete) treats merged: false as an incomplete mr stage, so a crash during polling causes resume to skip straight to polling/merge instead of re-creating the MR/PR

Docs

  • New ADR-018
  • AGENTS.md, DESIGN.md, IMPLEMENTATION_PLAN.md updated to cross-reference the new idempotency behavior and two-phase artifact write

Acceptance criteria

  • Re-running createMr() for a branch with an already-open MR/PR reuses it instead of failing (GitLab 409 / GitHub 422 / Forgejo equivalent) — unit-tested per platform
  • MR-created state is durably recorded before auto-merge begins
  • Resume correctly detects "MR created, auto-merge pending" and proceeds directly to polling/merge
  • No schema-breaking change to mr-result.json; DESIGN.md/IMPLEMENTATION_PLAN.md/tests updated together
  • npm run lint, npm test (2030 tests), and npm run build all pass
  • Manual end-to-end verification (inject failure during auto-merge polling, resume, confirm no duplicate MR) — not yet performed, flagging for follow-up/reviewer awareness
  • #274 (the glab mr view --json bug that originally triggered this failure path)
## Summary Fixes #280: after #274's `glab mr view --json` bug aborted the `mr` stage during auto-merge polling (i.e. after the MR was already created), resuming re-ran `createMr()` and hit a duplicate-create error (GitLab `409`, GitHub `422`, Forgejo equivalent). ## Fix (both parts, as requested) 1. **Idempotent `createMr` across resume** - New optional `findExistingMr()` method on the `MrClient` interface (`src/mr/types/mrClient.ts`) - Implemented for all three bundled platforms: GitLab, GitHub, Forgejo - `runMrStage` checks `findExistingMr()` before calling `createMr()` and reuses an already-open MR/PR instead of creating a duplicate - Falls back to `createMr()` directly when a client doesn't implement `findExistingMr` (backward-compatible interface) 2. **Two-phase `mr-result.json` persistence** - `mr-result.json` is now written immediately after `createMr()` succeeds, with `autoMerge: { enabled: true, merged: false }`, *before* auto-merge polling/merging begins - Rewritten once the merge actually completes - Resume detection (`determineResumeStage.ts` / `isMrResultAutoMergeComplete`) treats `merged: false` as an **incomplete** mr stage, so a crash during polling causes resume to skip straight to polling/merge instead of re-creating the MR/PR ## Docs - New [ADR-018](docs/adr/018-mr-creation-idempotent-resume.md) - `AGENTS.md`, `DESIGN.md`, `IMPLEMENTATION_PLAN.md` updated to cross-reference the new idempotency behavior and two-phase artifact write ## Acceptance criteria - [x] Re-running `createMr()` for a branch with an already-open MR/PR reuses it instead of failing (GitLab 409 / GitHub 422 / Forgejo equivalent) — unit-tested per platform - [x] MR-created state is durably recorded before auto-merge begins - [x] Resume correctly detects "MR created, auto-merge pending" and proceeds directly to polling/merge - [x] No schema-breaking change to `mr-result.json`; `DESIGN.md`/`IMPLEMENTATION_PLAN.md`/tests updated together - [x] `npm run lint`, `npm test` (2030 tests), and `npm run build` all pass - [ ] Manual end-to-end verification (inject failure during auto-merge polling, resume, confirm no duplicate MR) — **not yet performed**, flagging for follow-up/reviewer awareness ## Related - #274 (the `glab mr view --json` bug that originally triggered this failure path)
david merged commit 5642832095 into main 2026-08-18 23:42:35 +00:00
david deleted branch feature/issue-280/mr-creation-not-idempotent-on-resume-gitlab-409-wh 2026-08-18 23:42:35 +00:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
david/pi-loop!281
No description provided.