Problem
When self.base_commit is present (recorded at patch generation time), it's used as "parents": [base_commit] in the ADO Push API payload. The merge-base is by definition an ancestor of the target branch, so this is semantically correct.
However, if the target branch was force-pushed after Stage 1 ran, the merge-base SHA might no longer be reachable in ADO's history — the push would fail with a cryptic HTTP 400.
The existing fallback (resolving live target branch HEAD when base_commit is None) doesn't help here because base_commit is Some.
Suggested Fix
If the push fails with a 400 and base_commit was from Stage 1, retry by falling back to the live ADO refs API resolution (same as the None path).
Context
Low probability in practice — requires a force-push to the target branch between Stage 1 and Stage 2. But worth checking first if unexpected 400 errors appear in production.
Identified in PR #155 review.
Problem
When
self.base_commitis present (recorded at patch generation time), it's used as"parents": [base_commit]in the ADO Push API payload. The merge-base is by definition an ancestor of the target branch, so this is semantically correct.However, if the target branch was force-pushed after Stage 1 ran, the merge-base SHA might no longer be reachable in ADO's history — the push would fail with a cryptic HTTP 400.
The existing fallback (resolving live target branch HEAD when
base_commitisNone) doesn't help here becausebase_commitisSome.Suggested Fix
If the push fails with a 400 and
base_commitwas from Stage 1, retry by falling back to the live ADO refs API resolution (same as theNonepath).Context
Low probability in practice — requires a force-push to the target branch between Stage 1 and Stage 2. But worth checking first if unexpected 400 errors appear in production.
Identified in PR #155 review.