Skip to content

post-fix: preserve agent merges when the PR branch advances concurrently #1797

Open

Description

@ravelley

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

  1. The agent merges the target branch into the PR branch.
  2. Another writer pushes a PR commit that the agent has not incorporated, before the post-script fetch.
  3. The fetched remote tip is no longer an ancestor of the agent’s HEAD, so the new skip does not apply.
  4. 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

Activity

  1. fullsend-ai-triage commented on Oct 26, 2026

    @fullsend-ai-triage

    🤖 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

  2. fullsend-ai-triage commented on Oct 26, 2026

    @fullsend-ai-triage

    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:

    • Strategy: the choice between reconciling by merging the new remote tip into the agent's HEAD and failing closed without publishing is still open for maintainers. Either way, the agent's merge, its resolutions and the concurrent remote commit must stay in the published history.
    • Coverage: the test should include both signing modes and the GitLab reconstruction path, where SHA ancestry into HEAD can't be relied on.

    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:

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions