Skip to content

fix(ab-3238): switch drift integration from merge to rebase - #472

Merged
PolyphonyRequiem merged 1 commit into
mainfrom
fix/ab-3238-rebase-strategy
May 19, 2026
Merged

fix(ab-3238): switch drift integration from merge to rebase#472
PolyphonyRequiem merged 1 commit into
mainfrom
fix/ab-3238-rebase-strategy

Conversation

@PolyphonyRequiem

Copy link
Copy Markdown
Owner

PR #471 (just merged) shipped AB#3238 using git merge --no-ff origin/<target> as the drift-integration strategy. Per user feedback, the feature PR's Commits tab should show clean linear history — not an extra integration merge commit sitting on top of the feature work. Switching to git rebase + git push --force-with-lease.

Why rebase (vs merge)

  • Feature PRs are squash-merged into main (per cloudvault config), so preserving upstream MG-merge SHAs on the feature branch adds nothing — they're discarded at squash anyway.
  • Rebase keeps the PR's Commits tab focused on the work the feature actually did; reviewer sees upstream drift as ancestor history, not as a sibling merge commit.
  • Force-with-lease (refusing if origin advanced since our fetch) + the existing feature_branch_diverged gate make force-push safe given polyphony's branch model (SDLC run is sole writer of the feature branch).

What changed

Script (integrate-target-drift.ps1):

  • git merge --no-ffgit rebase origin/<target>
  • git push origin <feature>git push --force-with-lease=refs/heads/<feature>:<expected-sha> origin HEAD:refs/heads/<feature>. The expected SHA is captured BEFORE rebase to defeat lease-weakening from background fetches (rubber-duck Q2).
  • Conflict abort: git merge --abort (guarded by MERGE_HEAD) → git rebase --abort (guarded by Test-RebaseInProgress, which checks BOTH rebase-merge and rebase-apply dirs via git rev-parse --git-path).
  • New pre-flight Test-WorktreeBlocked rejects with new error code worktree_dirty if any in-progress merge/rebase/cherry-pick/revert OR uncommitted changes are detected (rubber-duck Q6).
  • Edge case: rebase no-op (HEAD didn't move despite behind_by>0) exits success without force-push.
  • Initial-push path: if origin/ doesn't exist yet, falls back to git push --set-upstream (no lease — nothing to overwrite).
  • Envelope: new strategy: 'rebase', old_head_sha, new_head_sha fields. Dropped merge_commit_sha (rebase has no single integration SHA).
  • error_code value merge_conflict retained for workflow-route + lint contract compatibility. The semantic meaning is "drift integration conflicted"; only the operator-instructions in the conflict-gate prompt change.

Workflow (feature-pr.yaml):

  • version: 2.4.9 → 2.4.10
  • Agent comment updated: rebase rationale, force-with-lease safety argument.
  • Conflict-gate operator instructions: full rebase recipe with explicit git rev-parse refs/remotes/origin/<feature> for the lease, rebase --continue loop, force-with-lease push.
  • Failed-gate prompt: documents new worktree_dirty cause + updated push_failed (lease-refused) semantics.

Tests (integrate-target-drift.Tests.ps1):

  • Clean-drift: now asserts strategy='rebase', new_head_sha != old_head_sha, origin/<feature> HEAD landed on new_head_sha (force-with-lease verified end-to-end).
  • Conflict: asserts neither rebase-merge nor rebase-apply dir remains after abort.
  • New Worktree dirty context.
  • Envelope-contract updated for new field set.
  • 6/6 pass.

Validation

  • Invoke-Pester .\.conductor\registry\tests\integrate-target-drift.Tests.ps1 → 6 passed, 0 failed.
  • Invoke-Pester .\.conductor\registry\tests\lint-feature-pr.Tests.ps1 → 28/29 passed. The remaining failure (missing-ado-remediation-route) is pre-existing on main and unrelated.

Rubber-duck adoption

  • Q1 (rebase vs --rebase-merges): plain rebase — preserves feature-PR review clarity; MG merge trail already exists in ADO PR history.
  • Q2 (force-with-lease syntax): explicit --force-with-lease=refs/heads/<feature>:<expected-sha> + HEAD:refs/heads/<feature> push refspec.
  • Q3 (rebase-detection): Test-Path (git rev-parse --git-path rebase-merge) OR rebase-apply (different rebase modes use different dirs).
  • Q4 (operator instructions): included git fetch origin <target> <feature> pre-step + explicit lease.
  • Q5 (divergence gate): kept (more critical with force-push than with merge).
  • Q6 (pre-checks): added in-progress merge/rebase/cherry-pick/revert + uncommitted-changes guard up front.

Closes the user-feedback gap on PR #471.

PR #471 shipped AB#3238 with git merge --no-ff origin/<target> as the
drift-integration strategy. User feedback: clean linear feature-PR
history is preferred over preserving the upstream MG-merge SHA chain;
the extra integration merge commit polluted the PR's Commits tab.

This change:

* Script (integrate-target-drift.ps1): replaces git merge --no-ff  with git rebase origin/<target>, replaces git push origin <feature>  with git push --force-with-lease=<feature>:<expected-sha> (the  expected SHA is captured BEFORE rebase to defeat lease-weakening from  background fetches).
* Conflict path: replaces git merge --abort (guarded by MERGE_HEAD)  with git rebase --abort (guarded by Test-RebaseInProgress, which  checks both 
ebase-merge and 
ebase-apply dirs via  git rev-parse --git-path).
* New pre-flight: Test-WorktreeBlocked refuses to proceed if any  in-progress merge/rebase/cherry-pick/revert OR uncommitted changes  are detected, surfaced as new error_code worktree_dirty.
* New envelope fields: strategy: 'rebase', old_head_sha,
ew_head_sha.  Dropped merge_commit_sha (rebase has no single integration SHA).
* Edge case: rebase-no-op (HEAD didn't move despite behind_by>0) exits  success without force-push.
* Initial-push path: if origin/<feature> doesn't exist yet, falls back  to git push --set-upstream (no lease — nothing to overwrite).
* error_code value merge_conflict retained for workflow-route  compatibility (semantic meaning is still 'drift integration  conflicted'); only the operator-instructions in the conflict gate  prompt change (rebase + force-with-lease, not merge + plain push).
* Workflow YAML: version 2.4.9 -> 2.4.10. Updates agent comment,  conflict-gate operator instructions (full rebase/continue/force-push  recipe with explicit git rev-parse refs/remotes/origin/<feature> for  the lease), failed-gate prompt (documents new worktree_dirty and  updated push_failed semantics).
* Tests: clean-drift test asserts strategy='rebase', new_head_sha != old_head_sha, and verifies the force-pushed SHA landed on origin/<feature>. Conflict test asserts no rebase-merge or rebase-apply dir remains after abort. New worktree_dirty test. Envelope-contract test updated for new field set. 6/6 pass.

Lint (lint-feature-pr.ps1) contract unchanged — routes still check  �rror_code == 'merge_conflict', gate names + entry-point invariant  preserved. 28/29 lint tests pass (1 pre-existing missing-ado-remediation-route failure unrelated to this change).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@PolyphonyRequiem
PolyphonyRequiem merged commit 6d07b9c into main May 19, 2026
1 check failed
@PolyphonyRequiem
PolyphonyRequiem deleted the fix/ab-3238-rebase-strategy branch May 19, 2026 13:56
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.

1 participant