From c9e302da37fe5cfc38cf83ebabb37e4ac89d5ed1 Mon Sep 17 00:00:00 2001 From: indifferentketchup Date: Sat, 30 May 2026 22:19:53 +0000 Subject: [PATCH] fix(coder): no-upstream branch alone no longer flags a session at-risk MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Session worktree branches (session-) never get an upstream, so the original atRisk rule (unpushed !== 0) flagged every worktree-backed session as at-risk on delete — even pristine ones — forcing a Stash/Force confirm on each. Gate the unpushed arm behind hasUpstream (unpushed !== -1) so the no-upstream sentinel can't trigger it: atRisk = dirty || unmerged > 0 || (hasUpstream && unpushed > 0). No protection is lost — any genuinely unsafe local commit also shows as unmerged > 0 — and the unpushed > 0 arm stays correct for P1.5's pushable worktree branches. unpushed is still reported (-1 = local-only) as informational. Follow-up to 3a26563. Co-Authored-By: Claude Opus 4.8 (1M context) --- apps/coder/src/services/worktrees.ts | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/apps/coder/src/services/worktrees.ts b/apps/coder/src/services/worktrees.ts index 820635a..aad7ead 100644 --- a/apps/coder/src/services/worktrees.ts +++ b/apps/coder/src/services/worktrees.ts @@ -196,7 +196,7 @@ export interface RiskReport { dirty: boolean; // uncommitted working-tree changes (incl. untracked) unpushed: number; // commits ahead of upstream, or -1 if no upstream is set unmerged: number; // commits on this branch not in the project default branch - atRisk: boolean; // dirty || unpushed !== 0 || unmerged > 0 || git error + atRisk: boolean; // dirty || unmerged > 0 || (upstream && unpushed > 0) || git error error?: string; // populated on a git failure; presence forces atRisk } @@ -308,7 +308,13 @@ export async function checkWorktreeWorkAtRisk( if (rl.exitCode === 0) unmerged = parseInt(rl.stdout.trim() || '0', 10) || 0; } - const atRisk = dirty || unpushed !== 0 || unmerged > 0; + // unpushed only contributes when an upstream actually exists. Session branches + // (session-) never have one (unpushed === -1), and any real local-only work + // there already surfaces as unmerged > 0 — so the no-upstream case adds no + // protection, only friction (it flagged every pristine worktree-backed session). + // The unpushed > 0 arm stays forward-compatible with P1.5 pushable branches. + const hasUpstream = unpushed !== -1; + const atRisk = dirty || unmerged > 0 || (hasUpstream && unpushed > 0); return { worktreePath, branch, dirty, unpushed, unmerged, atRisk }; }