Repository navigation
fix(pr-pipeline): delete a stopped lane run's branch when the issue re-runs - #11224
Conversation
…e-runs When a work-resolve-issue run starts on an issue, issue-prior now names the issue's lane branches left by earlier stopped runs: a branch whose run posted a lanes-App outcome marker, whose commits are all the lanes App's, and that has no pull request in any state. It spares the branch the run reuses, resumes or starts fresh past and every branch of the run itself, and decides from the reads it already makes. A new prune-lane-branches job in work-resolve-issue.yml, the lane's only contents: write, takes that list through issue-fields' shape check, drops the run's own, reuse and resume branches, re-reads every named branch in one GraphQL request, and deletes only one with no pull request, one updateRefs per branch at the tip it read. The stale-branch comment now says the next run deletes the branch. Closes #7948 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
|
claude-security-review reviewed No security findings in the incremental change since d22a582. critical-findings: 0 I read the two files in
The change widens no trust control and does not touch the kill switch, token scope, or merge holds. Nothing here spends anything beyond existing prepaid or subscription usage. |
|
claude-review reviewed Incremental review of the changes since d22a582:
I did not run the tests. The checks above come from reading the diff and the surrounding workflow and test code. Nothing here changes spend, so there is no cost hold. |
The run job that names the branches to prune runs the model, so a forged list could name a reuse or resume candidate, the stale branch, or a branch a person pushed to. issue-fields now re-derives the earlier-work check whenever a prune list is claimed and publishes only the names both lists hold. The prune job also keeps a branch an open pull request targets, and its log names a restore that works from GitHub's copy. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
The pr-verify verifier failed head What it wrote (32 lines)This pull request leaves the merge queue, and ci-status holds it out while it carries |
A plain fresh issue run skips the re-derive, so prior() returned 1 on the missing file and bash -e ended the publish step before checked=true. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Post-merge mutation testingKilled 4, survived 3, timeout 0, no coverage 0, invalid 0, not run 0.
Surviving mutants
The run's summary has the full report. |
Closes #7948
Summary
A work-resolve-issue run that stops after pushing leaves its lane branch behind, and a re-run on the same issue makes a new branch without touching the old one. Per the owner decision on #7948 (delete a stopped run's branch at the re-run when it has no pull request; keep it when one exists) and the recorded answers to the refinement's four questions, the next run on the issue now deletes those branches.
Departures from the spec:
updateRefsmutation pinned tobeforeOid(the tip the job read) instead of the spec's RESTDELETE. It is still one request per branch, and a branch pushed to after the read is not deleted.Fix
report-outcome.mjs: new purepruneBranches. With the model running or a branch reused,--find-priornames, as theprune-branchesstep output, every lane branch of the issue that meets all of these: its run posted a lanes-App outcome marker (a stopped run), every commit ahead of the default branch is the lanes App's, and it has no pull request in any state. It spares the branch the run reuses, resumes or starts fresh past, any unreported branch, and every attempt of the run itself (GITHUB_RUN_ID). It reports at most 20 per run and decides from the reads--find-prioralready makes.pr-run-activity-read.yml:prune-branchesgoes from the run job through the issue-fields job. There it must be at most 20 distinct lane branches of the issue, none of them the reuse or resume branch. Because the run job runs the model, issue-fields re-derives--find-priorwhenever a prune list is claimed, and publishes only the names both lists hold, asscan-prune-branches. A failed re-derive publishes none. This came from the independent security review.prior()returned 1 there, sobash -eended the step beforechecked=trueand every such run would stop.work-resolve-issue.yml: newprune-lane-branchesjob, after issue-prior (it needs the resolve-issue calls). It holds the lane's onlycontents: writegrant, withpull-requests: read, on its ownGITHUB_TOKEN, and runsprune-branches.mjsfrom the default-branch tip. Because the list came from the model's runner, the job treats it as a claim:associatedPullRequests(states: [OPEN, CLOSED, MERGED])).updateRefsper branch whosebeforeOidis the tip it read (the delete mutation the daily branch cleanup already uses).pr-run-activity.mdand the branch-cleanup section of theREADME.md.Verification
report-outcome.test.mjsfailed to load withoutpruneBranches. It now passes 326 of 326.prune-branches.test.mjscould not find its module. It now passes 8 of 8.callers.test.mjsrun against main's workflows failed 5 tests (issue-fields outputs, the prune job, the output list). It now passes 207 of 207.bash -ewith no re-derive file andCLAIMED=false: on d22a582 it exits 1 with no outputs; after the fix it exits 0 withchecked=trueand an emptyprune-branches, for an empty and a non-empty prune list. A new assertion also checks that the Node setup and the re-derive each run exactly when the step before them succeeded.pruneBranchesand in the prune job's read.prune-branches.test.mjsandpruneBranchescover this.work-resolve-issue.ymljob withcontents: write, one request per branch, and the read job's token is not widened.callers.test.mjsasserts the job's permissions, and that no other job of the lane holdscontents: write.write-issue,check-blockers,branch-cleanup,check-read-caller-keysand the other workflow-reading suites pass.actionlintandzizmorare clean on both workflows.Metrics
Per-run GitHub API call delta:
--find-prior(run job and issue-fields): +0 reads. The list comes from the matching-refs, compare, pulls and commit reads it already makes.--find-prioronce, which costs the existing reads again: about 4 plus 3 per lane branch of the issue. These are the same reads as the run job's, not a new per-item loop. Since the prune job then deletes those branches, the cost does not recur.prune-lane-branches: skipped with 0 calls when nothing is named. Otherwise it makes 1 GraphQL read plus kupdateRefswrites, where k ≤ 20 is the number of leftover branches it deletes. Each leftover branch is deleted once, so the writes do not recur. There is no per-item read loop.What this makes measurable: each delete logs its branch and tip in the job log. The issue's "Checks a person runs" item, the count of
work-resolve-issue/*branches with no pull request, should stop growing once this ships.Related
🤖 Generated with Claude Code