Skip to content

Foreign commits in a Merge run: merge them in, review them with a review Repair - #99

Merged
JacobStephens2 merged 2 commits into
mainfrom
issue-94
Sep 27, 2026
Merged

JacobStephens2 merged 2 commits into
mainfrom
issue-94

Conversation

@JacobStephens2

Copy link
Copy Markdown
Owner

Summary

In a Merge run, each round of the Repair loop now takes in Foreign commits first, and has them reviewed before they can be merged. A normal Run is unchanged.

 RepairLoop::run (per round)
+  if Merge run: take_in_foreign_commits
+    fetch origin/<branch>; nothing new → skip
+    count an upstream move (shared budget of 5 with Base branch moves)
+    log "merging new commit <sha> from origin/<branch>" per commit
+    merge (ff or merge commit, never rebase)
+      conflict → conflict Repair (origin/<branch> into <branch>)
+    review Repair: /thirdshift:code-review <own head>
   merge origin/<base>; conflict → conflict Repair
   push; watch CI
     green → base moved? go round
+            Merge run and origin/<branch> has new commits? go round
             else → return head
     red   → CI-fix Repair
  • The review Repair uses repair-<i> numbering, counts against the cap of 5 Repairs, and gets a Resume through Sessions::run like any session.
  • Its fixed point is the local head just before the Foreign commits were merged in. The agent fixes the findings it agrees with, puts the rest under "Unaddressed findings" marked as coming from their commits, and pushes.
  • Foreign commits that land during CI are caught before the merge is tried. Ones that land as the merge is tried send the Run through the existing failed-merge round.
  • thirdshift no longer pushes straight after a Repair session. The next round pushes, after merging, so a fix the agent couldn't push past a Foreign commit gets merged with it instead of failing the Run.
  • MAX_BASE_MOVES is now MAX_UPSTREAM_MOVES, shared by Base branch moves and Foreign-commit rounds. The failure message stays origin/<x> kept moving: merged it again 5 times.
  • Updated the Prompts and skills page (it now has a Review Repair and a Conflict Repair on Foreign commits) and the README (new section "Foreign commits in a Merge run").

Evidence

  • Before: a_merge_refused_because_the_head_moved_is_a_failed_run: a Foreign commit pushed during CI made the Self-merge fail with Head branch was modified, and the Run ended as a Failed run.
    After: new tests in tests/merge_run.rs, all passing (cargo test: every suite green, clippy clean):
    a_foreign_commit_pushed_during_ci_is_merged_in_reviewed_then_merged
    a_foreign_commit_that_lands_as_the_merge_is_tried_is_reviewed_then_merged
    a_foreign_commit_that_conflicts_with_local_work_gets_a_conflict_repair_then_a_review
    a_review_repair_whose_background_work_was_killed_gets_a_resume
    foreign_commits_that_keep_coming_spend_the_upstream_move_budget
    a_review_repair_counts_against_the_repair_cap
    a_run_without_merge_takes_no_foreign_commits_in
    prompts_page_shows_what_the_binary_sends
    

Merge Danger

Door: two-way

A binary change you can revert. Nothing persistent is migrated.

Blast Radius: Merge-runs

Only a Merge run fetches the Issue branch and starts review Repairs. The one change that also touches normal Runs is when thirdshift pushes after a Repair: it now pushes in the next round rather than straight away, and the existing tests cover that path.

Unaddressed findings

Standards

  • Twin Worktree methods (merge_new_commits / ensure_new_commits_merged beside the base-branch ones): kept. Callers name what they merge without building ref strings, and the shared private merge / ensure_merged / merged hold the logic.
  • "new commits" rather than "Foreign commit" in Worktree names: Worktree can't tell who made a commit, and the README fixes the stderr text as merging new commit.
  • Repeated Goal checks in the Repair loop: there are two, both on the one question "is this a Merge run?". A new abstraction wouldn't pay for itself.
  • count_upstream_move(upstream, why) data clump: upstream names the ref in the exhaustion error and why is the progress line, so they are different messages.
  • conflict_repair(issue, branch, branch, pr_url) repeats an argument: the first names the branch being merged from origin, the second the one being merged into. They happen to match for Foreign commits.

Spec

  • A Repair session may pull Foreign commits in itself, so they skip review: if its push is rejected, the agent might merge origin/<branch> on its own, and thirdshift then sees nothing new. Spotting that needs the Run to track which commits are its own, which is left as a follow-up. Telling the agent not to pull would change the prompts a normal Run sends.
  • Removing the push after Repair sessions was not asked for: it's needed, or a fix committed behind a Foreign commit fails the Run at the push before the fetch can merge it in. Behaviour otherwise stays the same because the next round pushes.
  • Extra progress line origin/<branch> has new commits; merging them in: kept, to match the origin/<base> moved …; merging it again line, which also marks a spent upstream move.
  • A Base branch move and Foreign commits in the same CI wait cost two upstream moves: both upstreams really did move, and each needs its own merge.
  • The fixed point includes the Run's commits that were not pushed yet: intended. They are the Run's own work, so only the Foreign commits get reviewed.

Closes #94

🤖 Generated with Claude Code

JacobStephens2 and others added 2 commits September 27, 2026 13:49
In a Merge run, each round of the Repair loop first fetches the Issue
branch from origin and merges any Foreign commits in, logging each one.
A conflict goes to a conflict Repair; a review Repair then runs
/thirdshift:code-review from the head the Run last knew as its own.
Foreign commits that arrive while CI runs send the Run round again
instead of on to the merge. Review Repairs count against the Repair cap
and Foreign-commit rounds against the round budget, shared with Base
branch moves. A normal Run is unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Name the shared budget for what it counts, upstream moves, and keep the
normal Run's "merged it again" message. Give the Issue branch's origin
ref one home in Worktree::upstream, and share the fixed-point lookup in
the tests.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@JacobStephens2
JacobStephens2 merged commit 8b5f908 into main Sep 27, 2026
13 checks passed
@JacobStephens2
JacobStephens2 deleted the issue-94 branch September 27, 2026 13:59
@JacobStephens2 JacobStephens2 mentioned this pull request Sep 27, 2026
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.

Foreign commits in a Merge run: merge them in, review them with a review Repair, then merge

1 participant