From dda9d713f2691fe40ba9d2b2c2fd8e06b579e0da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?T=C3=82CHES?= Date: Sun, 15 Mar 2026 13:42:41 -0600 Subject: [PATCH] chore: remove dead code from branchless refactor (#510) Remove methods, fields, and comments left over after the branchless worktree architecture landed: - git-service.ts: delete isOnSliceBranch, getActiveSliceBranch, branchExists (private), discardUntrackedRuntimeFiles (private); update writeIntegrationBranch comment and remove --force flag - worktree.ts: delete isOnSliceBranch, getActiveSliceBranch exports; update module doc from "branch-per-slice" to "worktree utilities" - state.ts: remove activeBranch computation (always null) - types.ts: remove GSDState.activeBranch field - templates/state.md: remove "Slice Branch" line - auto.ts, guided-flow.ts: update "branch-per-slice" comments - Tests updated to match Co-authored-by: Claude Opus 4.6 (1M context) --- src/resources/extensions/gsd/auto.ts | 2 +- src/resources/extensions/gsd/git-service.ts | 52 ++----------------- src/resources/extensions/gsd/guided-flow.ts | 2 +- src/resources/extensions/gsd/state.ts | 13 ++--- .../extensions/gsd/templates/state.md | 1 - .../extensions/gsd/tests/git-service.test.ts | 12 +---- .../gsd/tests/worktree-integration.test.ts | 6 +-- .../extensions/gsd/tests/worktree.test.ts | 8 --- src/resources/extensions/gsd/types.ts | 1 - src/resources/extensions/gsd/worktree.ts | 32 ++---------- 10 files changed, 20 insertions(+), 109 deletions(-) diff --git a/src/resources/extensions/gsd/auto.ts b/src/resources/extensions/gsd/auto.ts index aef0fb752..a65c16ae3 100644 --- a/src/resources/extensions/gsd/auto.ts +++ b/src/resources/extensions/gsd/auto.ts @@ -553,7 +553,7 @@ export async function startAuto( return; } - // Ensure git repo exists — GSD needs it for branch-per-slice + // Ensure git repo exists — GSD needs it for worktree isolation try { execSync("git rev-parse --git-dir", { cwd: base, stdio: "pipe" }); } catch { diff --git a/src/resources/extensions/gsd/git-service.ts b/src/resources/extensions/gsd/git-service.ts index 9dd22eede..966ef6d3e 100644 --- a/src/resources/extensions/gsd/git-service.ts +++ b/src/resources/extensions/gsd/git-service.ts @@ -132,13 +132,11 @@ export function readIntegrationBranch(basePath: string, milestoneId: string): st * Persist the integration branch for a milestone. * * Called when auto-mode starts on a milestone. Records the branch the user - * was on at that point, so that slice branches merge back to it instead of - * the repo's default branch. Idempotent when the branch matches; updates - * the record when the user starts from a different branch. + * was on at that point, so the milestone worktree merges back to the correct + * branch. Idempotent when the branch matches; updates the record when the + * user starts from a different branch. * - * The file is committed immediately so it survives branch switches — the - * pre-switch auto-commit excludes `.gsd/` to avoid merge conflicts, and - * uncommitted `.gsd/` files are discarded during checkout. + * The file is committed immediately so the metadata is persisted in git. */ export function writeIntegrationBranch(basePath: string, milestoneId: string, branch: string): void { // Don't record slice branches as the integration target @@ -167,7 +165,7 @@ export function writeIntegrationBranch(basePath: string, milestoneId: string, br // Commit immediately so the metadata is persisted in git. try { - runGit(basePath, ["add", "--force", metaFile]); + runGit(basePath, ["add", metaFile]); runGit(basePath, ["commit", "--no-verify", "-F", "-"], { input: `chore(${milestoneId}): record integration branch`, }); @@ -404,48 +402,8 @@ export class GitServiceImpl { } /** True if currently on a GSD slice branch. */ - isOnSliceBranch(): boolean { - const current = this.getCurrentBranch(); - return SLICE_BRANCH_RE.test(current); - } - - /** Returns the slice branch name if on one, null otherwise. */ - getActiveSliceBranch(): string | null { - try { - const current = this.getCurrentBranch(); - return SLICE_BRANCH_RE.test(current) ? current : null; - } catch { - return null; - } - } - // ─── Branch Lifecycle ────────────────────────────────────────────────── - /** - * Check if a local branch exists. Native libgit2 when available, execSync fallback. - */ - private branchExists(branch: string): boolean { - return nativeBranchExists(this.basePath, branch); - } - - /** - * Remove untracked runtime files from the working tree. - * - * Complements `git checkout -- .gsd/` (which only handles tracked files). - * Runtime files can end up untracked after a cleanup commit removes them - * from the current branch's HEAD — but the target branch may still have - * them committed. Without this step, `git checkout` fails with: - * "The following untracked working tree files would be overwritten by checkout" - * - * `git clean -fdx` is safe here because: - * - Only removes *untracked* files (tracked files are untouched) - * - Targets only the specific runtime paths listed in RUNTIME_EXCLUSION_PATHS - * - These files are always regenerated by GSD on the next run - */ - private discardUntrackedRuntimeFiles(): void { - this.git(["clean", "-fdx", "--", ...RUNTIME_EXCLUSION_PATHS], { allowFailure: true }); - } - // ─── S05 Features ───────────────────────────────────────────────────── /** diff --git a/src/resources/extensions/gsd/guided-flow.ts b/src/resources/extensions/gsd/guided-flow.ts index fddd76d6f..4d6dbd33c 100644 --- a/src/resources/extensions/gsd/guided-flow.ts +++ b/src/resources/extensions/gsd/guided-flow.ts @@ -700,7 +700,7 @@ export async function showSmartEntry( ): Promise { const stepMode = options?.step; - // ── Ensure git repo exists — GSD needs it for branch-per-slice ────── + // ── Ensure git repo exists — GSD needs it for worktree isolation ────── try { execSync("git rev-parse --git-dir", { cwd: basePath, stdio: "pipe" }); } catch { diff --git a/src/resources/extensions/gsd/state.ts b/src/resources/extensions/gsd/state.ts index 6d15b1c5b..0cc4b6bc5 100644 --- a/src/resources/extensions/gsd/state.ts +++ b/src/resources/extensions/gsd/state.ts @@ -29,7 +29,7 @@ import { resolveGsdRootFile, gsdRoot, } from './paths.js'; -import { getActiveSliceBranch } from './worktree.js'; + import { milestoneIdSort, findMilestoneIds } from './guided-flow.js'; import { nativeBatchParseGsdFiles, type BatchParsedFile } from './native-parser-bridge.js'; @@ -438,8 +438,6 @@ async function _deriveStateImpl(basePath: string): Promise { }; } - const activeBranch = getActiveSliceBranch(basePath); - // Check if the slice has a plan const planFile = resolveSliceFile(basePath, activeMilestone.id, activeSlice.id, "PLAN"); const slicePlanContent = planFile ? await cachedLoadFile(planFile) : null; @@ -453,7 +451,7 @@ async function _deriveStateImpl(basePath: string): Promise { recentDecisions: [], blockers: [], nextAction: `Plan slice ${activeSlice.id} (${activeSlice.title}).`, - activeBranch: activeBranch ?? undefined, + registry, requirements, progress: { @@ -480,7 +478,7 @@ async function _deriveStateImpl(basePath: string): Promise { recentDecisions: [], blockers: [], nextAction: `All tasks done in ${activeSlice.id}. Write slice summary and complete slice.`, - activeBranch: activeBranch ?? undefined, + registry, requirements, progress: { @@ -501,7 +499,7 @@ async function _deriveStateImpl(basePath: string): Promise { recentDecisions: [], blockers: [], nextAction: `Slice ${activeSlice.id} has a plan file but no tasks. Add tasks to the plan.`, - activeBranch: activeBranch ?? undefined, + registry, requirements, progress: { @@ -547,7 +545,7 @@ async function _deriveStateImpl(basePath: string): Promise { recentDecisions: [], blockers: [`Task ${blockerTaskId} discovered a blocker requiring slice replan`], nextAction: `Task ${blockerTaskId} reported blocker_discovered. Replan slice ${activeSlice.id} before continuing.`, - activeBranch: activeBranch ?? undefined, + activeWorkspace: undefined, registry, requirements, @@ -578,7 +576,6 @@ async function _deriveStateImpl(basePath: string): Promise { nextAction: hasInterrupted ? `Resume interrupted work on ${activeTask.id}: ${activeTask.title} in slice ${activeSlice.id}. Read continue.md first.` : `Execute ${activeTask.id}: ${activeTask.title} in slice ${activeSlice.id}.`, - activeBranch: activeBranch ?? undefined, registry, requirements, progress: { diff --git a/src/resources/extensions/gsd/templates/state.md b/src/resources/extensions/gsd/templates/state.md index 35c000b1c..76ce20ee7 100644 --- a/src/resources/extensions/gsd/templates/state.md +++ b/src/resources/extensions/gsd/templates/state.md @@ -4,7 +4,6 @@ **Active Slice:** {{sliceId}}: {{sliceTitle}} **Active Task:** {{taskId}}: {{taskTitle}} **Phase:** {{phase}} -**Slice Branch:** {{activeBranch}} **Active Workspace:** {{activeWorkspace}} **Next Action:** {{nextAction}} **Last Updated:** {{date}} diff --git a/src/resources/extensions/gsd/tests/git-service.test.ts b/src/resources/extensions/gsd/tests/git-service.test.ts index eaba65c7c..51989d732 100644 --- a/src/resources/extensions/gsd/tests/git-service.test.ts +++ b/src/resources/extensions/gsd/tests/git-service.test.ts @@ -533,7 +533,7 @@ async function main(): Promise { return dir; } - // ─── getCurrentBranch / isOnSliceBranch / getActiveSliceBranch ───────── + // ─── getCurrentBranch ──────────────────────────────────────────────── console.log("\n=== Branch queries ==="); @@ -541,21 +541,13 @@ async function main(): Promise { const repo = initBranchTestRepo(); const svc = new GitServiceImpl(repo); - // On main assertEq(svc.getCurrentBranch(), "main", "getCurrentBranch returns main on main branch"); - assertEq(svc.isOnSliceBranch(), false, "isOnSliceBranch returns false on main"); - assertEq(svc.getActiveSliceBranch(), null, "getActiveSliceBranch returns null on main"); - // Create and checkout a slice branch manually run("git checkout -b gsd/M001/S01", repo); assertEq(svc.getCurrentBranch(), "gsd/M001/S01", "getCurrentBranch returns slice branch name"); - assertEq(svc.isOnSliceBranch(), true, "isOnSliceBranch returns true on slice branch"); - assertEq(svc.getActiveSliceBranch(), "gsd/M001/S01", "getActiveSliceBranch returns branch name on slice branch"); - // Non-slice feature branch run("git checkout -b feature/foo", repo); - assertEq(svc.isOnSliceBranch(), false, "isOnSliceBranch returns false on non-slice branch"); - assertEq(svc.getActiveSliceBranch(), null, "getActiveSliceBranch returns null on non-slice branch"); + assertEq(svc.getCurrentBranch(), "feature/foo", "getCurrentBranch returns feature branch name"); rmSync(repo, { recursive: true, force: true }); } diff --git a/src/resources/extensions/gsd/tests/worktree-integration.test.ts b/src/resources/extensions/gsd/tests/worktree-integration.test.ts index 2d4bcdb4a..5d153eec1 100644 --- a/src/resources/extensions/gsd/tests/worktree-integration.test.ts +++ b/src/resources/extensions/gsd/tests/worktree-integration.test.ts @@ -24,9 +24,8 @@ import { getCurrentBranch, getMainBranch, getSliceBranchName, - isOnSliceBranch, - getActiveSliceBranch, autoCommitCurrentBranch, + SLICE_BRANCH_RE, } from "../worktree.ts"; import { deriveState } from "../state.ts"; @@ -109,8 +108,7 @@ async function main(): Promise { const sliceBranch = getSliceBranchName("M001", "S01", "alpha"); run(`git checkout -b ${sliceBranch}`, wt.path); assertEq(getCurrentBranch(wt.path), "gsd/alpha/M001/S01", "worktree-namespaced slice branch"); - assertTrue(isOnSliceBranch(wt.path), "isOnSliceBranch returns true"); - assertEq(getActiveSliceBranch(wt.path), "gsd/alpha/M001/S01", "getActiveSliceBranch returns namespaced branch"); + assertTrue(SLICE_BRANCH_RE.test(getCurrentBranch(wt.path)), "slice branch regex matches namespaced branch"); // ── Do work on slice branch, then merge to worktree branch ───────────────── diff --git a/src/resources/extensions/gsd/tests/worktree.test.ts b/src/resources/extensions/gsd/tests/worktree.test.ts index f2ac55d9b..a84570ea5 100644 --- a/src/resources/extensions/gsd/tests/worktree.test.ts +++ b/src/resources/extensions/gsd/tests/worktree.test.ts @@ -7,11 +7,9 @@ import { autoCommitCurrentBranch, captureIntegrationBranch, detectWorktreeName, - getActiveSliceBranch, getCurrentBranch, getMainBranch, getSliceBranchName, - isOnSliceBranch, parseSliceBranch, setActiveMilestoneId, SLICE_BRANCH_RE, @@ -37,12 +35,6 @@ run('git commit -m "chore: init"', base); async function main(): Promise { - console.log("\n=== getActiveSliceBranch on main ==="); - assertEq(getActiveSliceBranch(base), null, "getActiveSliceBranch returns null on main"); - - console.log("\n=== isOnSliceBranch on main ==="); - assertEq(isOnSliceBranch(base), false, "isOnSliceBranch returns false on main"); - console.log("\n=== autoCommitCurrentBranch ==="); // Clean — should return null const cleanResult = autoCommitCurrentBranch(base, "execute-task", "M001/S01/T01"); diff --git a/src/resources/extensions/gsd/types.ts b/src/resources/extensions/gsd/types.ts index e394b90b3..c119a7393 100644 --- a/src/resources/extensions/gsd/types.ts +++ b/src/resources/extensions/gsd/types.ts @@ -175,7 +175,6 @@ export interface GSDState { recentDecisions: string[]; blockers: string[]; nextAction: string; - activeBranch?: string; activeWorkspace?: string; registry: MilestoneRegistryEntry[]; requirements?: RequirementCounts; diff --git a/src/resources/extensions/gsd/worktree.ts b/src/resources/extensions/gsd/worktree.ts index a215657a5..6ab512c71 100644 --- a/src/resources/extensions/gsd/worktree.ts +++ b/src/resources/extensions/gsd/worktree.ts @@ -1,13 +1,11 @@ /** - * GSD Slice Branch Management — Thin Facade + * GSD Worktree Utilities * - * Simple branch-per-slice workflow. No worktrees, no registry. - * Runtime state (metrics, activity, lock, STATE.md) is gitignored - * so branch switches are clean. + * Pure utility functions for worktree name detection, legacy branch name + * parsing, and integration branch capture. * - * All git-mutation functions delegate to GitServiceImpl from git-service.ts. * Pure utility functions (detectWorktreeName, getSliceBranchName, parseSliceBranch, - * SLICE_BRANCH_RE) remain standalone. + * SLICE_BRANCH_RE) remain standalone for backwards compatibility. * * Branchless architecture: all work commits sequentially on the milestone branch. * Pure utility functions (detectWorktreeName, getSliceBranchName, parseSliceBranch, @@ -147,26 +145,4 @@ export function autoCommitCurrentBranch( return getService(basePath).autoCommit(unitType, unitId); } -// ─── Query Functions (delegate to GitServiceImpl) ────────────────────────── -/** - * Check if we're currently on a slice branch (not main). - * Handles both plain (gsd/M001/S01) and worktree-namespaced (gsd/wt/M001/S01) branches. - */ -export function isOnSliceBranch(basePath: string): boolean { - const current = getCurrentBranch(basePath); - return SLICE_BRANCH_RE.test(current); -} - -/** - * Get the active slice branch name, or null if on main. - * Handles both plain and worktree-namespaced branch patterns. - */ -export function getActiveSliceBranch(basePath: string): string | null { - try { - const current = getCurrentBranch(basePath); - return SLICE_BRANCH_RE.test(current) ? current : null; - } catch { - return null; - } -}