Skip to content

fix(merge-gate): merge stacked PRs through merge-async - #17

Merged
lucasheriques merged 1 commit into
mainfrom
merge-gate-stacked-async
Oct 7, 2026
Merged

lucasheriques merged 1 commit into
mainfrom
merge-gate-stacked-async

Conversation

@lucasheriques

Copy link
Copy Markdown
Owner

Why

GitHub refuses gh pr merge for a PR in a native stack (gh-stack), so merge-gate --merge could not land any stack layer. The REST merge endpoint refuses too. Only merge-async works, as seen live on nagringa-dev/hubdeia #1 and #2.

What changed

  • GhGateGitHub.merge falls back to PUT pulls/{n}/merge-async when gh reports the stack error. It sends the head SHA the gate already pinned, polls the job, and still decides from the PR read-back.
  • A 4xx on the request or a failed job is merge-failed. A job that may still land (5xx, poll error, unknown status, timeout, or "merged" before the PR shows it) is merge-unverified.
  • opening-a-pr step 4 now says to wait on gh pr view before rerunning --merge after merge-unverified.

Scope

  • Covers trunk-based stack layers, the only ones the gate lets through (base-not-trunk refuses the rest).
  • Leaves out a test for the poll timeout. It would need a test-only knob or a ~60s wait.

Tradeoffs

  • Fallback, not always-async. merge-async has only been seen on stacked PRs, and the proven gh pr merge path stays the default. If GitHub rewords the error, the gate fails safe with merge-failed.

Blast Radius

Every agent merge runs through this. Verdict shape and exit codes are unchanged. The non-stacked path changes one detail string: the read-back-failed case now includes gh's stderr. This touches skills/poteto-mode/scripts/merge-gate/**, which the merge policy marks human-only, so it needs the owner's approval.

Verification

  • bun run test: 187 pass. New fake-gh CLI rows cover async success, multi-poll, merge-commit method, failed job, 409 head rejection, 502 request, poll error, unknown status, missing uuid, and a failed read-back.
  • bun run typecheck and bun scripts/check-port.ts are clean.

GitHub refuses `gh pr merge` for a PR in a native stack. When gh reports
that, merge-gate PUTs pulls/{n}/merge-async with the head SHA it already
verified, polls the job for up to ~60s, and still takes the verdict from
the PR read-back.

A 4xx on the request (head moved) or a failed job is merge-failed. A 5xx,
a garbled body, a poll error, an unknown status, a timeout, or a job that
reports merged before the PR does is merge-unverified (exit 1), because
GitHub may still merge it. opening-a-pr step 4 now says to wait on
gh pr view before rerunning --merge. Non-stacked merges keep the gh pr
merge path. The only text change there: the read-back-failed detail now
carries gh's stderr.

Tested: bun run test (187 pass), bun run typecheck, bun scripts/check-port.ts,
bun test ./scripts/check-port.test.ts. Fake-gh CLI cases cover the merge-async
paths above plus the merge-commit method for mergeCommitBranches heads.
@lucasheriques
lucasheriques merged commit e755880 into main Oct 7, 2026
1 check passed
@lucasheriques
lucasheriques deleted the merge-gate-stacked-async branch October 7, 2026 14:16
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.

1 participant