Repository navigation
post-fix: preserve agent merges when the PR branch advances concurrently #1797
Description
Background
Follow-up to #1793 and #1323. The ancestry skip fixes unnecessary replay when the fetched remote PR tip is already contained in the agent’s HEAD.
A related edge case appears to remain when the PR branch advances while the agent is working. This scenario is based on code review; we do not have an observed workflow failure or an executed reproduction of this specific race.
Potential failure
- The agent merges the target branch into the PR branch.
- Another writer pushes a PR commit that the agent has not incorporated, before the post-script fetch.
- The fetched remote tip is no longer an ancestor of the agent’s HEAD, so the new skip does not apply.
- The post-script falls through to ordinary rebase. That can drop the agent’s merge, replay target-side commits, and either inflate the PR diff or reintroduce resolved conflicts.
The original merge-only failures establish the replay risk, but are not examples of this concurrent-update scenario.
Expected behavior
Reconcile concurrent updates without silently flattening the agent’s merge, losing its resolutions, or dropping remote commits. If safe reconciliation is not possible, stop without publishing. Keep this separate from the ancestry-skip fix in #1793; the appropriate reconciliation strategy needs investigation.
Validation
- First reproduce locally: agent merges the target, then a non-conflicting remote PR commit arrives before the fetch.
- Verify that the target’s original tip and the concurrent remote commit remain ancestors of the published result, with only expected changes in the PR diff.
- Cover preservation of manual merge resolutions/edits, both signing modes, and affected GitLab reconstruction behavior.
Relevant replay path:
agents/scripts/post-fix.src.sh
Lines 1118 to 1132 in a72dadd
| if [ "${SKIP_REMOTE_REBASE}" = "false" ] \ | |
| && git merge-base --is-ancestor "origin/${BRANCH}" HEAD 2>/dev/null; then | |
| SKIP_REMOTE_REBASE=true | |
| echo "origin/${BRANCH} is already an ancestor of local HEAD — skipping rebase onto origin/${BRANCH} (push is a fast-forward)" | |
| fi | |
| if [ "${SKIP_REMOTE_REBASE}" = "false" ]; then | |
| echo "Rebasing local ${BRANCH} onto origin/${BRANCH}..." | |
| REBASE_OUTPUT="$(git rebase "origin/${BRANCH}" 2>&1)" && REBASE_RC=0 || REBASE_RC=$? | |
| if [ "${REBASE_RC}" -ne 0 ]; then | |
| print_sanitized_gha_log "${REBASE_OUTPUT}" | |
| git rebase --abort 2>/dev/null || true | |
| post_fail_to_pr push-rejected \ | |
| "Could not rebase local '${BRANCH}' onto origin/${BRANCH}: the remote branch has commits that conflict with the agent's changes. Resolve the conflict on the PR/MR and re-run /fs-fix. | |
| ${REBASE_OUTPUT}" | |
| fi |
Metadata
Metadata
Assignees
Labels
Type
Projects
- StatusShow more project fieldsTodo
Activity
fullsend-ai-triage commentedon Oct 26, 2026
🤖 Finished Triage · ✅ Success · Started 7:02 PM UTC · Completed 7:04 PM UTC
Commit:
f589f2e· View workflow run →Runtime: claude · Model: sonnet → claude-sonnet-5-5 · Effort: high · Cost: $0.18
fullsend-ai-triage commentedon Oct 26, 2026
Thanks for the detailed write-up. This is currently blocked on the open PR that adds the ancestry skip (#1793, which closes #1323). The edge case you describe, where the fetched remote tip is no longer an ancestor of HEAD so the skip doesn't apply, depends on that logic. It isn't in the main branch yet, and any reconciliation change would edit the same skip-decision block in the post-fix script, its generated counterpart and the tests. Landing that PR first gives a stable baseline and avoids conflicting work. That PR doesn't fix this issue, so this one stays open and separate.
Once #1793 merges, the next step is the local reproduction you outlined: the agent merges the target, then a non-conflicting remote PR commit arrives before the fetch. Two points are worth settling then:
Since no failure has been observed in a real run, the reproduction should also confirm the race is reachable in practice before a fix is designed.
Blocked by: