Skip to content

Fix #1637: spawn open-PR collision guard counts merged PRs - #1673

Merged
amrmelsayed merged 17 commits into
mainfrom
builder/bugfix-1637
Sep 11, 2026
Merged

Fix #1637: spawn open-PR collision guard counts merged PRs#1673
amrmelsayed merged 17 commits into
mainfrom
builder/bugfix-1637

Conversation

@amrmelsayed

Copy link
Copy Markdown
Collaborator

Summary

afx spawn refused to spawn for an issue with "Found N open PR(s) referencing issue #X" when the referenced PRs were actually merged, forcing --force after manual verification. This filters the spawn collision guard to only count genuinely open PRs.

Fixes #1637

Root Cause

The spawn collision guard in checkBugfixCollisions (spawn-worktree.ts) calls the pr-search forge concept and treated every result as an open PR. PR #1619 (shipped in 3.3.3) deliberately changed pr-search to --state all so consult --type pr could find merged PRs (#759) — correct for consult, but the guard consumed the same concept and inherited merged/closed PRs into its "open" count. Compounding this, the github pr-search.sh emitted only number,headRefName,baseRefName with no state field, so the guard could not filter client-side.

Fix

  • github/pr-search.sh: add state to the --json fields (gh returns OPEN/MERGED/CLOSED).
  • gitlab/pr-search.sh: emit a normalized state, mapping glab's lowercase openedOPEN so the contract matches github's convention.
  • PrSearchItem contract: add optional state?: string, documented as normalized.
  • Spawn guard: filter to state === 'OPEN' before counting. A missing state (a stale project-local pr-search.sh override predating the field) is treated as open, preserving the conservative pre-fix behavior. --state all stays in the scripts — consult still needs merged PRs visible; the guard filters.

Test Plan

  • Regression test added — pairs both consumers: the spawn guard ignores merged/closed PRs (proven to fail without the filter), while the scripts keep merged PRs/MRs visible for consult.
  • Build passes
  • All tests pass

pr-search runs --state all (#759/#1619) so consult can find merged PRs,
but the spawn collision guard counted every result as an open PR —
refusing afx spawn when the referenced PRs were already merged.

- github/gitlab pr-search.sh now emit a normalized `state` field
  (OPEN/MERGED/CLOSED); gitlab maps glab's lowercase `opened` to OPEN.
- PrSearchItem gains optional `state`.
- The guard filters to state === 'OPEN' before counting; a missing state
  (stale pr-search.sh override) is treated as open, preserving pre-fix
  behavior. --state all stays in the scripts; consult is unaffected.
- Regression tests pair both consumers: guard ignores merged/closed,
  scripts keep merged MRs/PRs visible for consult.
Addresses non-blocking CMAP (claude) nits:
- gitlab/pr-search.sh captures glab output before piping to jq, so a failed
  glab surfaces instead of masquerading as an empty list (POSIX sh has no
  pipefail) — matching the #1645 convention in pr-list.sh.
- Guard predicate broadened from `state === undefined` to `!pr.state` so the
  gitlab jq's empty-string fallback is also treated as open (conservative),
  matching the documented intent. Adds a blank-state regression test.
…1645)

The capture-then-pipe shape from the previous commit hid `glab` from
extractExecutable's first-line heuristic (it skips the `out=` assignment and
lands on the `printf` builtin), so forge.test.ts's #1645 check resolved the
concept to a builtin. Add an explicit `# forge-executable: glab` declaration,
matching github/pr-list.sh's convention.
GitLab's MR state enum is opened/closed/merged/locked. `locked` is a transient
merging state that is still effectively open, so normalize it to OPEN alongside
`opened`. The spawn guard then counts a locked MR as a collision (recoverable
via --force) rather than silently skipping a live one. Pins the mapping in the
gitlab pr-search contract test.
…hItem

glab's `mr list --output json` emits GitLab-shaped fields (iid, source_branch,
target_branch), not the contract's number/headRefName/baseRefName, so the spawn
guard printed `PR #undefined` and consult's findPRForIssue couldn't resolve the
MR base branch on GitLab. Map them in the jq pass, matching the normalization
pattern already in gitlab/pr-list.sh and pr-view.sh. Marked UNVERIFIED per the
#920 convention (no live glab in the authoring/CI environment).
@amrmelsayed
amrmelsayed merged commit c88bc9c into main Sep 11, 2026
7 checks passed
@amrmelsayed
amrmelsayed deleted the builder/bugfix-1637 branch September 11, 2026 11:06
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.

afx spawn: open-PR collision guard counts merged PRs since #1619 widened pr-search to --state all

1 participant