Skip to content

Fix reviewer checkout after merged PR branch deletion - #71210

Merged
pelikhan merged 3 commits into
mainfrom
pelikhan-jubilant-chainsaw
Oct 22, 2026
Merged

pelikhan merged 3 commits into
mainfrom
pelikhan-jubilant-chainsaw

Conversation

@pelikhan

Copy link
Copy Markdown
Collaborator

Summary

Fix the shared PR checkout race behind failures in Test Quality Sentinel, PR Code Quality Reviewer, Design Decision Gate, Ponytail Reviewer, and Matt Pocock Skills Reviewer. The same-repository pull_request fast path fetched the source branch by name; merging the PR and deleting that branch before the agent started made checkout fail.

  • Fetch +refs/pull/<number>/head:refs/remotes/origin/pr-head for same-repository PR events, matching the retained-head checkout already used for forks and other PR events. Reset the local source-named branch to the fetched PR head so stale local branches cannot select the wrong commit.
  • Preserve shallow/full-history behavior, trusted-actor checks, actual checked-out-head baseline exports, and intentional closed/merged-event workflows. The remote source branch is not recreated. Existing safe-output lifecycle checks still skip obsolete effects after closure.
  • Keep genuine checkout/authentication/network errors fatal. If even the retained PR ref disappears, the existing live-state-confirmed invalidation path remains separate from ordinary failures and never permits running on the previous checkout.
  • Document the behavior and add isolated real-Git regressions for deleted source branches, stale local refs/payload SHAs, and open/closed payloads in shallow and full clones.

The latest main already contained #70141's lifecycle classification, but that deliberately failed the checkout step and did not remove the branch-name fetch race. No duplicated reviewer workflow patches or generated lock changes are needed.

Validation

  • npm exec --no -- vitest run checkout_pr_branch.test.cjs checkout_pr_branch_z3.test.cjs: 201 passed; optional Z3 execution skipped because Z3 is unavailable.
  • make fmt-cjs and make lint-cjs: passed.
  • PATH="/opt/homebrew/bin:$PATH" make agent-report-progress: passed, including build, TypeScript checks, JavaScript lint, and all 200 checkout tests. No Go files changed; impacted Go tests were correctly skipped. Two existing catch-property lint warnings remain unchanged.
  • Read-only security gate: all ten safety questions passed, no vulnerabilities found.
  • No workflow dispatch or rerun performed.

Representative observed failure: https://github.com/github/gh-aw/actions/runs/39829351695 (PR #71195 source branch deleted after merge).

Fetch the retained pull-request head ref for same-repository PR events instead of relying on a source branch that can disappear while queued. Reset the local branch from the fetched head, preserve lifecycle/error handling, and cover deleted refs with isolated real Git regressions.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot AI max review requested due to automatic review settings October 22, 2026 19:25
@pelikhan

Copy link
Copy Markdown
Collaborator Author

/matt

@pelikhan

Copy link
Copy Markdown
Collaborator Author

/review

@github-actions

github-actions Bot commented Oct 22, 2026 •

Copy link
Copy Markdown
Contributor

✅ PR Code Quality Reviewer completed the code quality review.

🔎 Code quality review by PR Code Quality Reviewer

@github-actions

github-actions Bot commented Oct 22, 2026 •

Copy link
Copy Markdown
Contributor

🧠 Matt Pocock Skills Reviewer has completed the skills-based review. ✅

🧠 Reviewed using Matt Pocock's skills by Matt Pocock Skills Reviewer

Record the runtime RS-05a ref-isolation boundary and dated regression evidence without adding a compiler threat rule or changing checkout provenance policy.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Skills-Based Review 🧠

Applied /diagnosing-bugs and /codebase-design (via pr-triage: bug_fix). The root-cause fix is sound — switching from git fetch origin <branchName> to the retained refs/pull/<number>/head ref correctly eliminates the race where a merged PR's source branch is deleted before the agent checks it out, and the fix is backed by a strong new real-Git integration test covering open/closed payload states and shallow/full clones.

📋 Key Themes & Highlights

Key Themes

  • Doc placement: the new paragraph explaining retained-ref checkout behavior sits under "Disabling the PR Branch Checkout", which is about an unrelated opt-out flag.
  • Minor duplication: the origin/pr-head checkout target literal isn't derived from the existing PR_HEAD_BASE_REF constant, so the two could drift.

Positive Highlights

  • ✅ /diagnosing-bugs: root cause (branch-name fetch racing against branch deletion) is fixed at the source, not papered over — the retained PR ref survives deletion.
  • ✅ /tdd: the new it.each integration test exercises real git repos (not just mocks) across open/closed × shallow/full, directly reproducing the reported failure mode (PR #71195 run).
  • ✅ Error classification between "missing-ref invalidation" and genuine auth/permission/network failures is preserved and still tested.
  • ✅ Existing tests were updated consistently rather than left stale.

Both findings above are minor (non-blocking) and left as inline suggestions; approving since there are no correctness or test-coverage gaps.

🧠 Reviewed using Matt Pocock's skills by Matt Pocock Skills Reviewer · copilot · sonnet50 · ~82 AIC · ⌖ ~17 AIC · ⊞ 10.2K
Comment /matt to run again

Comment thread docs/src/content/docs/reference/checkout.md
Comment thread actions/setup/js/checkout_pr_branch.cjs Outdated

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Skills-Based Review 🧠

Applied /diagnosing-bugs and /codebase-design — no blocking issues. Only observations.

📋 Key Themes & Highlights

Key Themes

  • Root-cause fix: switching to the retained refs/pull/<n>/head ref (instead of the branch name) directly addresses the race condition rather than masking it, and the fix is applied symmetrically in both the fast-path and fallback branches.
  • Minor duplication (/codebase-design): after this change, the fast-path (isFork === false & !isClosed) and fallback branches in checkout_pr_branch.cjs (around lines 469-540) both now do fetchPRHead([...PR_HEAD_BASE_REF]) → git checkout -B branchName origin/pr-head → exportPRHeadBaseline(...). The only remaining differences are how branchName/commitCount are derived and the log strings. This could be extracted into a shared helper (e.g. checkoutRetainedPRHead({ prNumber, branchName, commitCount })) to reduce the chance the two paths drift again in a future fix — not blocking, just a deepening opportunity since the two paths are converging.
  • Excellent regression coverage (/tdd / /diagnosing-bugs): the new it.each real-Git test (open/closed × shallow/full) actually deletes the remote branch and asserts the exact failure that was observed in production (https://github.com/github/gh-aw/actions/runs/39829351695), then verifies the fix resolves it end-to-end rather than only at the mock level. This is a strong example of reproducing before fixing.
  • Docs updated appropriately: checkout.md now explains that the local branch name is kept but the remote branch is not recreated, which matches the implementation.

Positive Highlights

  • ✅ Real-Git regression test directly reproduces the reported production failure mode (deleted branch + stale local ref) rather than relying only on mocks.
  • ✅ Shallow/full-history behavior, trusted-actor checks, and lifecycle-invalidation semantics are explicitly preserved and covered by both an old and a new regression test.
  • ✅ Symmetry: the same-repo fast path now matches the retained-ref strategy already used by the fork/pull_request_target path, removing a special case that was the actual source of the bug.

No actionable blocking issues found; the minor duplication note above is optional follow-up, not a requirement for merge.

🧠 Reviewed using Matt Pocock's skills by Matt Pocock Skills Reviewer · copilot · sonnet50 · ~77 AIC · ⌖ ~16 AIC · ⊞ 10.2K
Comment /matt to run again

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Verdict

No actionable blocking issues found in the changed lines. The retained PR-head ref fetch and forced local branch reset address the reported deleted-source-branch race while preserving checkout failure handling and baseline export behavior. Review was static; repository tests were not run.

🔎 Code quality review by PR Code Quality Reviewer · copilot · gpt50 · ~7 AIC · ⌖ ~1 AIC · ⊞ 1.6K
Comment /review to run again

Comment thread actions/setup/js/checkout_pr_branch.cjs Outdated

core.info(`Checking out branch: ${branchName}`);
await exec.exec("git", ["checkout", branchName]);
await exec.exec("git", ["checkout", "-B", branchName, "origin/pr-head"]);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This checkout can create an unintended upstream for the local branch because origin/pr-head is a remote-tracking start point, so a later plain git push may target a stray pr-head branch rather than the PR source branch.

💡 Prevent accidental pushes to the synthetic refUse git checkout -B --no-track <branchName> origin/pr-head (and apply the same option in the fallback path) so the synthetic retained ref is only a checkout source and never becomes the branch's push target.

Separate checkout lifecycle behavior from the opt-out reference and use PR_HEAD_BASE_REF as the checkout source in both paths.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@pelikhan

Copy link
Copy Markdown
Collaborator Author

Regarding #71210 (comment): The requested Matt review completed, and both actionable inline suggestions have been accepted and addressed. No additional code change is needed for the command itself, and I did not dispatch or rerun a workflow.

@pelikhan

Copy link
Copy Markdown
Collaborator Author

Regarding #71210 (comment): The review feedback has been evaluated and the documentation-placement and shared-ref suggestions have been addressed. No code change is needed for the command itself, and this batch does not dispatch or rerun a workflow.

@pelikhan

Copy link
Copy Markdown
Collaborator Author

Regarding #71210 (comment): Accepted both inline suggestions from this completed review: the checkout behavior documentation now has its own section and both checkout paths use the shared ref constant. The completion notification itself requires no code change.

@pelikhan

Copy link
Copy Markdown
Collaborator Author

Regarding #71210 (comment): This status comment has since changed to review completion and requires no code change. I addressed the concrete shared-ref duplication, but deferred the optional larger checkout-helper extraction to keep this race fix narrowly scoped.

@pelikhan
pelikhan merged commit 3619e5c into main Oct 22, 2026
32 checks passed
@pelikhan
pelikhan deleted the pelikhan-jubilant-chainsaw branch October 22, 2026 20:02

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

A verified ref-name collision can still make checkout fail after a successful fetch.

1 open issue
What changed in this PR

Updates the shared PR checkout helper to use retained PR-head refs, addressing queued reviewer failures after merged source branches are deleted.

Changes:

  • Fetches the retained PR head for same-repository events and resets the local source-named branch.
  • Adds real-Git regressions covering deleted branches, stale refs and payload SHAs, and shallow/full clones.
  • Documents checkout behavior and its separation from safe-output lifecycle checks.
File Description
specs/​compiler-threat-detection-spec.md Maps retained-head checkout to runtime ref-isolation requirements.
specs/​compiler-threat-detection-changelog.md Records version 1.0.67 and the checkout mapping audit.
docs/​src/​content/​docs/​reference/​checkout.md Explains checkout after source-branch deletion.
actions/​setup/​js/​checkout_pr_branch.test.cjs Updates command assertions and adds deleted-branch regressions.
actions/​setup/​js/​checkout_pr_branch.cjs Switches same-repository checkout to the retained PR ref.

Review effort: Max

Comment thread actions/setup/js/checkout_pr_branch.cjs Outdated
@github-actions

Copy link
Copy Markdown
Contributor

🎉 This pull request is included in a new release.

Release: v0.93.1

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.

2 participants