fix(FN-2855): scope task diff base to baseCommitSha when branch is null

When a dependency task merges and its branch is deleted, self-healing nulls
the dependent task's baseBranch. Both resolveDiffBase (dashboard) and
resolveTaskDiffBaseRef (merger) defaulted to "main" in that case, widening
the diff range to merge-base(HEAD, main) and surfacing unrelated history —
e.g. FN-2855 reported 108 changed files instead of 16. Skip the merge-base
step when baseBranch is unset and a baseCommitSha is recorded; fall back to
"main" only for legacy tasks lacking both hints.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
gsxdsm
2026-04-28 07:44:04 -07:00
parent 0c241b017f
commit 479f25d50f
3 changed files with 59 additions and 20 deletions

View File

@@ -1287,26 +1287,33 @@ export async function resolveTaskDiffBaseRef({
baseBranch,
baseCommitSha,
}: DiffBaseResolutionInput): Promise<string | undefined> {
const resolvedBaseBranch = baseBranch?.trim() || "main";
// When baseBranch was nulled (e.g., upstream dep merged and its branch was
// deleted) but a task-scoped baseCommitSha is still recorded, skip the
// merge-base step so we don't widen the diff range to merge-base(HEAD, main)
// and surface unrelated history. Only fall back to "main" when neither hint
// is available (legacy tasks).
const resolvedBaseBranch = baseBranch?.trim() || (baseCommitSha ? undefined : "main");
const quotedHeadRef = quoteArg(headRef);
let mergeBase: string | undefined;
try {
if (resolvedBaseBranch) {
try {
const { stdout } = await execAsync(`git merge-base ${quotedHeadRef} ${quoteArg(resolvedBaseBranch)}`, {
cwd,
encoding: "utf-8",
});
mergeBase = stdout.trim() || undefined;
try {
const { stdout } = await execAsync(`git merge-base ${quotedHeadRef} ${quoteArg(resolvedBaseBranch)}`, {
cwd,
encoding: "utf-8",
});
mergeBase = stdout.trim() || undefined;
} catch {
const { stdout } = await execAsync(`git merge-base ${quotedHeadRef} ${quoteArg(`origin/${resolvedBaseBranch}`)}`, {
cwd,
encoding: "utf-8",
});
mergeBase = stdout.trim() || undefined;
}
} catch {
const { stdout } = await execAsync(`git merge-base ${quotedHeadRef} ${quoteArg(`origin/${resolvedBaseBranch}`)}`, {
cwd,
encoding: "utf-8",
});
mergeBase = stdout.trim() || undefined;
// Base branch may not exist locally/remotely.
}
} catch {
// Base branch may not exist locally/remotely.
}
// Same guard as dashboard routes: when merge-base === headRef, the range