feat(merger): auto-rehome FF-recoverable orphan commits in contamination recovery

Follow-up to bf4428c00 (FF-only ref advance). After the prevention fix
new orphans can't form, but pre-fix orphans like f6358ce4 on
fusion/fn-5419 still need a path back onto the integration branch.

Adds an `orphan-our-advance` classification to contamination recovery:
a "unique" foreign commit whose Fusion-Task-Id trailer points at a
`done` task AND that is unreachable from refs/heads/<integrationBranch>
is treated as a stranded merger output.

For these, the executor attempts a fast-forward rehome onto the
integration branch via advanceIntegrationBranchRef (which still enforces
the FF-only invariant). When successful, the orphan sha is added to the
existing `shasToDrop` set so the same recovery pass that drops
already-upstream/misrouted commits also drops the now-upstream orphan.

Non-FF orphans (diverged from current integration tip) are refused.
Doing a cherry-pick onto the integration branch from inside automated
recovery would introduce conflict-resolution surface that's too high
blast radius for a never-event recovery path. The refusal log line
includes the exact `git cherry-pick <sha>` command an operator can run
manually.

Two new GitMutationType audit events:
  - merger:orphan-rehome-ff (successful FF rehome)
  - merger:orphan-rehome-refused (non-FF, manual cherry-pick required)

Tests in merger-orphan-rehome.test.ts cover classification (orphan,
not-done, already-reachable, no-trailer) and the rehome operation
(FF success advances the ref + emits the audit event; non-FF refusal
emits the hint and leaves the ref untouched).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
gsxdsm
2026-05-23 09:59:50 -07:00
parent bf4428c00c
commit ec1269fd84
5 changed files with 564 additions and 2 deletions

View File

@@ -220,6 +220,30 @@ export type GitMutationType =
* ```
*/
| "merge:integration-ref-advance"
/**
* Emitted when contamination recovery detects a foreign commit attributable
* to a `done` task that is not reachable from the integration branch — an
* orphan produced by a pre-fix non-FF ref advance. `merger:orphan-rehome-ff`
* fires after a successful fast-forward rehome; `merger:orphan-rehome-refused`
* fires when the orphan diverges from the integration tip and would require
* a cherry-pick (refused as too high-blast-radius for automated recovery).
*
* Metadata shape:
* ```ts
* {
* taskId: string;
* integrationBranch: string;
* orphanSha: string;
* integrationTipSha?: string;
* previousTipSha?: string;
* newTipSha?: string;
* reason?: "non-fast-forward";
* cherryPickHint?: string;
* }
* ```
*/
| "merger:orphan-rehome-ff"
| "merger:orphan-rehome-refused"
| "merge:audit-failure"
| "branch:auto-reclaim"
| "branch:auto-canonicalize-case"