A task reopened by task_verify failed is redispatched onto its old, already-merged branch with no prompt pointer to the verification evidence; the worker re-submits the merged work - #1976
Merged
Conversation
…ilures in the prompt (bd-8ssxap) A task reopened by `task_verify failed` had its worktree already torn down by `:await_verification`'s CleanupWorktree hook, leaving only a branch ref whose commits were already merged into main. Redispatch reused that stale branch as-is (Worktree.create's "already exists" fallback just checks it out), so the worker had nothing new to add and could submit an empty PR. Worktree.reset_if_merged/3 now checks both a live worktree directory and a surviving branch ref: if the branch's tip is already an ancestor of the current origin/<base>, it force-resets (or force-moves) it to that tip before Dispatch.create/3 runs, so redispatch always starts from current upstream. Dispatch calls this before provisioning. PromptBuilder also now puts verification_outcome/verification_evidence front and center in the work prompt when the prior round's merged fix failed verification, so the worker knows to do new work rather than resubmit what already landed. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…t a resumed/dirty worktree (bd-8ssxap) reset_if_merged/3 only trusted `merge-base --is-ancestor`, which never holds after a squash merge (this repo's default GitHub merge method) — the old branch tip is never an ancestor of the new squash commit on main, so the exact bd-96mn8i redispatch-onto-stale-branch bug still reproduced. Add an explicit `force: true` option, driven from `task.verification_outcome == :failed` in Dispatch, so a squash-merged branch is caught even though ancestry says otherwise. Guard the destructive side: `reset --hard` now refuses to run on a worktree with uncommitted changes (has_uncommitted?/1), and Dispatch skips the reset entirely on any `resume` — resume exists to preserve a stopped worker's committed and uncommitted state, and force-driven resets must never destroy that. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…credo disable placement (bd-8ssxap) verification_outcome stays :failed for the whole re-work round (it only clears once the next PR merges), so a naive `force? or ancestor?` reset in reset_if_merged/4 would also wipe round-2 commits made after the first, legitimate reset. force: true now only resets when the branch's tree content is still identical to the base tip (git diff --quiet), not merely whenever the task's verification_outcome is :failed. Also move resuming?/1 and its comment above the credo:disable-for-next-line so it again sits directly on maybe_provision_worktree, restoring the cyclomatic-complexity suppression credo needs there. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
… tree equality (bd-8ssxap) git diff --quiet ref branch only matches right after the squash lands; any later unrelated merge into base makes the trees diverge even though the branch still contributes nothing, so the stale branch was wrongly kept — reintroducing the incident on a busy fleet. git merge-tree --write-tree ref branch compares what merging would produce against base's own tree, which stays a match regardless of how much base has since moved on, while a genuine new commit on the branch still diverges and is kept. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…ened-by-task-verify-failed
ryanrborn
deleted the
bugfix/1959-task-reopened-by-task-verify-failed
branch
September 22, 2026 18:39
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.
Summary
A task reopened by
task_verify failedwas redispatched onto its old,already-merged branch with no new commits, which produced an empty PR
(#1957 for bd-96mn8i) instead of new work fixing the reported defect.
Dispatch.maybe_provision_worktree/2now runsWorktree.reset_if_merged/4before
create/3. When the task's last verification outcome was:failed,it forces a reset even though this repo's default GitHub merge method
(squash) means the old branch tip is never a git-ancestor of
main— plainmerge-base ancestry alone never catches that case.
git merge-tree --write-tree <ref> <branch>producing the same tree as
<ref>itself — i.e. merging the branch inwould change nothing. This correctly fires right after a squash lands
(any number of squashed commits), keeps firing even after unrelated PRs
land on
mainafterward, and stops firing the moment new work iscommitted on the branch (so a later redispatch in the same re-work round,
while
verification_outcomeis still:failed, doesn't throw away thatnew work).
opts[:resume]) skips the reset entirely, and a liveworktree with uncommitted changes is never hard-reset even under
force: true— both guard againstarb resumelosing in-progress work.verification_evidencesection rightafter Acceptance, under a heading stating the merged fix failed in
production, whenever
verification_outcome == :failed.Went through 3 rounds of internal review; round 3's finding was that the
prior tree-equality check (
git diff --quiet ref branch) only matchedimmediately after the squash landed — once anything else merged into
main, the trees diverged and the stale branch was wrongly kept again.Switched to
git merge-tree --write-tree, which is robust tomainadvancing.
Test plan
mix testonworktree_test.exs,dispatch_test.exs,prompt_builder_test.exs— 249 tests, 0 failures.mix format --check-formattedon touched files — clean.mix credoon touched lib files — no issues.mix test(umbrellamix precommit) — failures are pre-existing,unrelated
ProvisioningTest(hardcoded worktree path assertions) andarbiter_cli(live dev workspace not named "default") failures,reproduced independently of this change.
2-commit branch onto
main, then push an unrelated commit tomainbefore redispatching —
force: truestill resets.a later redispatch while
verification_outcomeis still:failed.References
bd-8ssxap
Closes #1959