Abort the resume when label or comment reads fail#50
Merged
Conversation
The squash-merge fan-out retargeted every updated child PR onto the target branch and only afterwards pushed the new heads, batched into a single non-atomic push together with the merged-branch deletion. If the push failed (e.g. someone pushed to a child mid-run, rejecting the plain push) or a pr edit died partway through the loop, set -e aborted the run with PRs already retargeted but their heads stale - and unlike the conflict-resume path there is no label to re-trigger the action, so nothing ever repaired them. Apply the ordering the resume path already uses: push the updated heads first, then flip the bases, and delete the merged branch last (deleting a PR's base branch closes the PR, so every child must be off it first). A failed push now leaves the PRs untouched on their old base. The unit test captures the run transcript and asserts the push -> retarget -> delete order; it fails against the previous code. Also corrects the README: pushes are plain, not forced, and branch deletion is its own final step. 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_01JHvKryT4QUpHYdNq9YEQxX
…g-check-3njvdx # Conflicts: # README.md
Since #40 the conflict comment's fast-forward step reads `git merge --ff-only origin/<branch>`, which assert_conflict_comment_merges picks up with its `^git merge` grep, so the extracted commands never match the expected conflict merges. Skip the --ff-only line when extracting. Also trim the new comments in the fan-out push/retarget/delete sequence. 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_01JHvKryT4QUpHYdNq9YEQxX
The fix for the --ff-only line breaking assert_conflict_comment_merges moved to a separate PR; the e2e job here stays red until that lands and main is merged back in. 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_01JHvKryT4QUpHYdNq9YEQxX
A head branch can carry several PRs (one per base), so gh calls keyed by branch name can comment, label, or retarget the wrong one. Every gh call that acts on a specific PR now uses the PR number: the fan-out carries number/branch pairs from gh pr list, and the conflict-resolved run gets PR_NUMBER from the event payload via action.yml. The payload also already carries the PR's base branch, so the resume takes it from a new PR_BASE variable instead of querying the API; the resume test's gh mock no longer answers baseRefName queries, so a reintroduced lookup fails loudly. 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_01JHvKryT4QUpHYdNq9YEQxX
…ber-addressing-3njvdx
pr_has_conflict_label swallowed gh failures as "no label", so a transient API error made the resume silently skip a labeled PR, and a failed comments fetch in read_state_marker read as "no marker", which made the caller abandon the resume and drop the conflict label for good. Both now abort the run instead; the label stays on, so the next push retries. 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_01JHvKryT4QUpHYdNq9YEQxX
ec963ed to
8e565f3
Compare
Phlogistique
commented
Jun 11, 2026
Phlogistique
commented
Jun 11, 2026
Phlogistique
added a commit
that referenced
this pull request
Jun 11, 2026
`read_state_marker` accepted a marker from *any* comment, so on a public repo anyone able to comment could plant one; if its `base=` matched, the resume would merge an attacker-chosen commit (fork-pushed objects are reachable by hash in the repo network) into the branch and push it with the action's token. Benign variant: a quote-reply of an old conflict comment resurrects a stale marker, since HTML comments survive quoting and the newest marker wins. Fix: filter comments to `viewerDidAuthor` — those posted with the same token the action runs under — which needs no configured identity. The resume test's gh mock rejects comment queries without that filter. Caveat: if the repo switches tokens (e.g. `GITHUB_TOKEN` → App) while a PR sits in conflict, the old marker is no longer "ours" and the resume takes the safe abandon path. Also rejects markers with missing fields instead of passing empty values to git (a marker missing `squash=` used to crash on `update-ref` and strand the PR under the label); new scenario E covers it. Stacked on #50 (same function). 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_01JHvKryT4QUpHYdNq9YEQxX --- _Generated by [Claude Code](https://claude.ai/code/session_01JHvKryT4QUpHYdNq9YEQxX)_ --------- Co-authored-by: Claude <noreply@anthropic.com> Co-authored-by: github-actions <github-actions@github.com>
Phlogistique
added a commit
that referenced
this pull request
Jun 11, 2026
Hit on #50 today: after the retarget to main, GitHub kept comparing against the deleted parent branch tip and showed a 323-line diff for a 14-line change. A push to the head branch eventually got it to recompute. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Phlogistique
pushed a commit
that referenced
this pull request
Jun 11, 2026
Trunk meanwhile absorbed most of this PR (#42 reordered main(), #50 hardened the label and comment reads), so what remains is the has_sibling_conflicts fix plus a new one of the same kind: list_child_prs failures were swallowed by the process substitutions consuming it, so a failed listing read as 'no children' and let main() delete the merged branch under the children it never saw. Callers now capture the output and die on failure. https://claude.ai/code/session_01STkeSJ7cLrmrNn4aTDYkwH
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
pr_has_conflict_labelswallowed gh failures as "no label", so a transient API error made the resume silently skip a labeled PR. Worse, a failed comments fetch inread_state_markerread as "no marker", which made the caller abandon the resume and drop the conflict label for good — a dead end. Both now abort the run instead; the label stays on, so the next push retries.Stacked on #45; #51 builds on this.
🤖 Generated with Claude Code
https://claude.ai/code/session_01JHvKryT4QUpHYdNq9YEQxX
Generated by Claude Code