From b17ab25aaa924594805f2bb49211f7a9cde443b4 Mon Sep 17 00:00:00 2001 From: Lex Christopherson Date: Thu, 12 Mar 2026 13:17:26 -0600 Subject: [PATCH] chore: remove .gsd/ from tracking (already in .gitignore) --- .gsd/DECISIONS.md | 26 -- .gsd/PROJECT.md | 33 -- .gsd/REQUIREMENTS.md | 351 ------------------ .gsd/milestones/M001/M001-CONTEXT.md | 130 ------- .gsd/milestones/M001/M001-ROADMAP.md | 142 ------- .gsd/milestones/M001/slices/S01/S01-PLAN.md | 78 ---- .../M001/slices/S01/tasks/T01-PLAN.md | 59 --- .../M001/slices/S01/tasks/T02-PLAN.md | 59 --- .../M001/slices/S01/tasks/T03-PLAN.md | 62 ---- .../M001/slices/S01/tasks/T04-PLAN.md | 63 ---- .../M001/slices/S01/tasks/T04-SUMMARY.md | 59 --- .gsd/milestones/M001/slices/S02/S02-PLAN.md | 82 ---- .../M001/slices/S02/tasks/T01-PLAN.md | 66 ---- .../M001/slices/S02/tasks/T01-SUMMARY.md | 75 ---- .../M001/slices/S02/tasks/T02-PLAN.md | 59 --- .../M001/slices/S02/tasks/T02-SUMMARY.md | 62 ---- .../M001/slices/S02/tasks/T03-PLAN.md | 74 ---- .gsd/milestones/M001/slices/S03/S03-PLAN.md | 64 ---- .../M001/slices/S03/tasks/T01-PLAN.md | 54 --- .../M001/slices/S03/tasks/T01-SUMMARY.md | 70 ---- .../M001/slices/S03/tasks/T02-PLAN.md | 56 --- .../M001/slices/S03/tasks/T02-SUMMARY.md | 73 ---- .gsd/milestones/M001/slices/S04/S04-PLAN.md | 59 --- .../M001/slices/S04/tasks/T01-SUMMARY.md | 60 --- .gsd/milestones/M001/slices/S05/S05-PLAN.md | 79 ---- .../M001/slices/S05/tasks/T01-PLAN.md | 59 --- .../M001/slices/S05/tasks/T02-PLAN.md | 68 ---- .../M001/slices/S05/tasks/T03-PLAN.md | 75 ---- .gsd/milestones/M001/slices/S06/S06-PLAN.md | 55 --- .../M001/slices/S06/tasks/T01-PLAN.md | 53 --- 30 files changed, 2305 deletions(-) delete mode 100644 .gsd/DECISIONS.md delete mode 100644 .gsd/PROJECT.md delete mode 100644 .gsd/REQUIREMENTS.md delete mode 100644 .gsd/milestones/M001/M001-CONTEXT.md delete mode 100644 .gsd/milestones/M001/M001-ROADMAP.md delete mode 100644 .gsd/milestones/M001/slices/S01/S01-PLAN.md delete mode 100644 .gsd/milestones/M001/slices/S01/tasks/T01-PLAN.md delete mode 100644 .gsd/milestones/M001/slices/S01/tasks/T02-PLAN.md delete mode 100644 .gsd/milestones/M001/slices/S01/tasks/T03-PLAN.md delete mode 100644 .gsd/milestones/M001/slices/S01/tasks/T04-PLAN.md delete mode 100644 .gsd/milestones/M001/slices/S01/tasks/T04-SUMMARY.md delete mode 100644 .gsd/milestones/M001/slices/S02/S02-PLAN.md delete mode 100644 .gsd/milestones/M001/slices/S02/tasks/T01-PLAN.md delete mode 100644 .gsd/milestones/M001/slices/S02/tasks/T01-SUMMARY.md delete mode 100644 .gsd/milestones/M001/slices/S02/tasks/T02-PLAN.md delete mode 100644 .gsd/milestones/M001/slices/S02/tasks/T02-SUMMARY.md delete mode 100644 .gsd/milestones/M001/slices/S02/tasks/T03-PLAN.md delete mode 100644 .gsd/milestones/M001/slices/S03/S03-PLAN.md delete mode 100644 .gsd/milestones/M001/slices/S03/tasks/T01-PLAN.md delete mode 100644 .gsd/milestones/M001/slices/S03/tasks/T01-SUMMARY.md delete mode 100644 .gsd/milestones/M001/slices/S03/tasks/T02-PLAN.md delete mode 100644 .gsd/milestones/M001/slices/S03/tasks/T02-SUMMARY.md delete mode 100644 .gsd/milestones/M001/slices/S04/S04-PLAN.md delete mode 100644 .gsd/milestones/M001/slices/S04/tasks/T01-SUMMARY.md delete mode 100644 .gsd/milestones/M001/slices/S05/S05-PLAN.md delete mode 100644 .gsd/milestones/M001/slices/S05/tasks/T01-PLAN.md delete mode 100644 .gsd/milestones/M001/slices/S05/tasks/T02-PLAN.md delete mode 100644 .gsd/milestones/M001/slices/S05/tasks/T03-PLAN.md delete mode 100644 .gsd/milestones/M001/slices/S06/S06-PLAN.md delete mode 100644 .gsd/milestones/M001/slices/S06/tasks/T01-PLAN.md diff --git a/.gsd/DECISIONS.md b/.gsd/DECISIONS.md deleted file mode 100644 index 2d37c7804..000000000 --- a/.gsd/DECISIONS.md +++ /dev/null @@ -1,26 +0,0 @@ -# Decisions Register - - - -| # | When | Scope | Decision | Choice | Rationale | Revisable? | -|---|------|-------|----------|--------|-----------|------------| -| D001 | M001 | arch | Smart staging approach | Exclusion filter (not file ownership tracking) | Covers 95% of the problem with minimal complexity. Fallback to git add -A on failure. | Yes — if exclusion filter proves insufficient | -| D002 | M001 | arch | worktree.ts migration strategy | Thin facade (keep exports, delegate to GitService) | Backward compatibility — 6+ existing callers don't need changes | Yes — if full migration desired later | -| D003 | M001 | arch | Merged branch lifecycle | Delete after squash merge (not preserve) | Squash commit is the permanent record. Branch sprawl has near-zero debugging value. | No | -| D004 | M001 | arch | Snapshot refs vs checkpoint commits | Hidden snapshot refs (refs/gsd/snapshots/) | Invisible recovery without cluttering branch history | No | -| D005 | M001 | scope | PR creation workflow | Deferred | Separate concern touching GitHub API, gh CLI, merge queue. Out of scope for trust boundary fix. | Yes — future milestone | -| D006 | M001 | scope | Milestone tags | Deferred | Low value relative to core trust boundary fix | Yes — future milestone | -| D007 | M001 | arch | Git Notes for metadata | Rejected | Fragile, poorly supported by tools, unreliable push/pull semantics | No | -| D008 | M001 | arch | Pre-merge verification timing | Phase 3 (enhanced features) | Core service + bug fixes first. Current workflow hasn't been catastrophic without guards. | No | -| D009 | M001 | arch | Doc fixes timing | Phase 1 (with bug fixes) | Pure text changes, zero risk, related to same git mechanics | No | -| D010 | M001 | arch | Test strategy | Unit tests with temp repos | Same proven pattern as existing worktree.test.ts | No | -| D011 | M001/S01 | arch | GitService reuses worktree.ts pure utilities | Import detectWorktreeName, getSliceBranchName, SLICE_BRANCH_RE from worktree.ts | These are pure functions with no side effects. Reimplementing would create drift. S02 facade wiring won't break these exports. | No | -| D012 | M001/S01 | arch | RUNTIME_EXCLUSION_PATHS defined independently | Define exclusion paths in git-service.ts independently of gitignore.ts BASELINE_PATTERNS | Keeps S01 self-contained without touching gitignore.ts. BASELINE_PATTERNS is unexported. Converge later if needed. | Yes — converge in future cleanup | -| D013 | M001/S01 | impl | COMMIT_TYPE_RULES includes plural keyword forms | Added "docs" and "tests" as explicit keywords alongside singular "doc" and "test" | Word-boundary regex `\bdoc\b` doesn't match "docs" — the trailing `s` is a word character. Plurals are common in slice titles. | No | -| D014 | M001/S02 | impl | MergeSliceResult re-export uses `export type` | `export type { MergeSliceResult }` instead of value `export { MergeSliceResult }` | Circular dependency (git-service.ts ↔ worktree.ts) causes ESM live binding resolution failure with value re-exports. Type-only re-export is erased at runtime, avoiding the cycle. MergeSliceResult is an interface so this is semantically correct and transparent to consumers. | No | -| D015 | M001/S05 | arch | Pre-merge check runs after squash merge, resets on failure | Run check after `git merge --squash` but before `git commit`, reset `--hard HEAD` on failure | Tests the actual merged code (what will land on main), not just the slice branch in isolation. Reset is clean because commit hasn't happened yet. | No | -| D016 | M001/S05 | arch | Multi-line commit via `git commit -F -` with stdin | Replace `JSON.stringify(message)` + `-m` with `execSync` stdin pipe + `-F -` | Avoids shell quoting fragility for multi-line rich commit messages. Newlines survive reliably through stdin. | No | -| D017 | M001/S05 | impl | Facade prefs fix via loadEffectiveGSDPreferences | worktree.ts `getService()` calls `loadEffectiveGSDPreferences()` instead of `{}` | Unblocks all preference-gated features (snapshots, pre_merge_check, auto_push) when called through the facade. One-line fix with high impact. | No | -| D018 | M001/S05 | impl | Snapshot gating requires explicit `true` | `prefs.snapshots === true` (not `!== false`) — undefined means disabled | Tests (T01) define undefined as disabled, only explicit `true` enables. Safer default: no hidden refs unless user opts in. Task plan said default-on but tests are authoritative. | No | diff --git a/.gsd/PROJECT.md b/.gsd/PROJECT.md deleted file mode 100644 index d132e19b8..000000000 --- a/.gsd/PROJECT.md +++ /dev/null @@ -1,33 +0,0 @@ -# Project - -## What This Is - -GSD (Get Shit Done) is a coding agent harness built as a pi extension. It manages structured planning and execution workflows — milestones, slices, tasks — with automated git branching, LLM-driven execution, and mechanical verification. - -This project is the GSD extension itself (`gsd-pi`), a TypeScript package that provides the `/gsd` command, auto-mode orchestration, worktree management, and all planning/execution infrastructure. - -## Core Value - -Deterministic, reliable git operations that keep main clean and working while agents do the coding. The user never touches git — the system handles branching, committing, merging, and recovery. - -## Current State - -GSD is a working, shipped product (v2.4.0). The trust boundary between deterministic code and LLM prompts has been fixed: all git operations now route through a centralized `GitService` class. Smart staging excludes runtime files, commit types are inferred from slice titles, merge guards auto-detect and run tests before landing on main, hidden snapshot refs enable rollback, and prompts contain no raw git commands. The thin facade in `worktree.ts` preserves backward compatibility while delegating to `GitServiceImpl`. - -## Architecture / Key Patterns - -- TypeScript, compiled with `tsc`, tested with Node's built-in test runner -- Extension entry: `src/resources/extensions/gsd/index.ts` -- Orchestrator: `auto.ts` (2600+ lines) — dispatches units, manages lifecycle -- Git operations: `git-service.ts` (centralized GitService), `worktree.ts` (thin facade for backward compat), `worktree-manager.ts` (git worktrees), `worktree-command.ts` (CLI commands) -- Prompts: `prompts/*.md` — Handlebars-templated instructions for LLM units (no raw git commands) -- Preferences: `preferences.ts` — YAML frontmatter in markdown files, includes `git?: GitPreferences` -- Patterns: `execSync` for git via `runGit()` helper, `SKIP_PATHS` for diff filtering, smart staging with exclusion filter - -## Capability Contract - -See `.gsd/REQUIREMENTS.md` for the explicit capability contract, requirement status, and coverage mapping. - -## Milestone Sequence - -- [x] M001: Deterministic GitService — Centralized all git mechanics into GitService, fixed bugs, removed git from prompts, added merge guards and recovery. All 18 requirements validated. diff --git a/.gsd/REQUIREMENTS.md b/.gsd/REQUIREMENTS.md deleted file mode 100644 index 03c3e486d..000000000 --- a/.gsd/REQUIREMENTS.md +++ /dev/null @@ -1,351 +0,0 @@ -# Requirements - -This file is the explicit capability and coverage contract for the project. - -## Active - -(No active requirements — all M001 requirements validated.) - -## Validated - -### R001 — Centralized GitService class -- Class: core-capability -- Status: validated -- Description: A single `GitService` class in `git-service.ts` that owns all git mechanics — commit, branch, merge, checkout, staging -- Why it matters: Moves git operations from probabilistic LLM prompts to deterministic code. The foundational trust boundary fix. -- Source: user -- Primary owning slice: M001/S01 -- Supporting slices: M001/S02 -- Validation: git-service.ts exists with GitServiceImpl class. npm run build passes. Unit tests pass. -- Notes: Uses existing `runGit()` pattern from worktree.ts - -### R002 — Smart staging with exclusion filter -- Class: core-capability -- Status: validated -- Description: Replace `git add -A` with filtered staging that excludes known runtime paths (.gsd/runtime/, .gsd/activity/, .gsd/STATE.md, .gsd/auto.lock, .gsd/metrics.json) -- Why it matters: Prevents accidental commits of runtime/bookkeeping files that should never be tracked -- Source: user -- Primary owning slice: M001/S01 -- Supporting slices: none -- Validation: RUNTIME_EXCLUSION_PATHS in git-service.ts. Fallback to git add -A verified by unit test. -- Notes: Fallback to `git add -A` with warning if filtering fails - -### R003 — Conventional commit type inference -- Class: quality-attribute -- Status: validated -- Description: Infer commit type (feat/fix/refactor/docs/test/chore) from slice title keywords instead of hardcoding `feat` -- Why it matters: Accurate git history that can be filtered and parsed by conventional-commits tooling -- Source: user -- Primary owning slice: M001/S01 -- Supporting slices: none -- Validation: inferCommitType() with COMMIT_TYPE_RULES in git-service.ts. Unit tests verify keyword matching. -- Notes: Default to `feat` when no keywords match. Plurals handled (D013). - -### R004 — Git preferences schema -- Class: core-capability -- Status: validated -- Description: Add `git?: GitPreferences` to GSDPreferences interface with validation, merge logic, and documentation -- Why it matters: Enables all preference-gated git features (auto_push, merge guards, etc.) via existing preferences system -- Source: user -- Primary owning slice: M001/S02 -- Supporting slices: M001/S05 -- Validation: GitPreferences on line 55 of preferences.ts. Validation logic, template, and docs/preferences-reference.md exist. -- Notes: Fields: auto_push, push_branches, remote, snapshots, pre_merge_check, commit_type - -### R005 — worktree.ts thin facade delegation -- Class: core-capability -- Status: validated -- Description: worktree.ts keeps existing exports but delegates internally to GitService. All existing callers continue to work without changes. -- Why it matters: Backward compatibility — existing imports from worktree.ts don't break -- Source: user -- Primary owning slice: M001/S02 -- Supporting slices: none -- Validation: worktree.ts delegates to GitServiceImpl. npm run build passes. Existing worktree tests pass. -- Notes: New code should import from GitService directly - -### R006 — auto.ts wired to GitService -- Class: core-capability -- Status: validated -- Description: Replace inline git calls in auto.ts (git add -A, autoCommitCurrentBranch, ensureSliceBranch, switchToMain, mergeSliceToMain) with GitService methods -- Why it matters: The orchestrator is the primary caller of git operations — it must route through the centralized service -- Source: user -- Primary owning slice: M001/S02 -- Supporting slices: none -- Validation: auto.ts imports and initializes GitServiceImpl. Only init bootstrap retains inline git (allowed by spec). -- Notes: git status --porcelain for idle detection and git rev-parse --git-dir for init check remain inline as allowed - -### R007 — Bug fix: worktree create ordering -- Class: quality-attribute -- Status: validated -- Description: Move autoCommitCurrentBranch() BEFORE createWorktree() in worktree-command.ts so new worktrees fork from committed state -- Why it matters: Previously new worktrees forked from pre-commit HEAD, missing the user's latest saved state -- Source: user -- Primary owning slice: M001/S03 -- Supporting slices: none -- Validation: worktree-command.ts reordered per S03. npm run build passes. -- Notes: Fixed in S03 - -### R008 — Bug fix: worktree merge dispatch -- Class: quality-attribute -- Status: validated -- Description: Use deterministic mergeWorktreeToMain() helper as default merge path in worktree-command.ts. Keep LLM-mediated path only for complex conflict resolution. -- Why it matters: The deterministic helper already exists but wasn't used as the default — merge went through LLM unnecessarily -- Source: user -- Primary owning slice: M001/S03 -- Supporting slices: none -- Validation: worktree-command.ts uses deterministic helper as default per S03. -- Notes: Fixed in S03 - -### R009 — Bug fix: hardcoded feat commit type -- Class: quality-attribute -- Status: validated -- Description: Replace hardcoded `feat(...)` in mergeSliceToMain with inferCommitType() from GitService -- Why it matters: Bugfix slices, docs slices, refactor slices were mislabeled as `feat` -- Source: user -- Primary owning slice: M001/S01 -- Supporting slices: M001/S02 -- Validation: mergeSliceToMain calls inferCommitType(). Unit tests verify correct type inference. -- Notes: Fixed in S01, wired in S02 - -### R010 — Doc fixes: branch preservation + checkpoint claims -- Class: quality-attribute -- Status: validated -- Description: Fix README.md "preserved" claim to "deleted after merge". Fix GSD-WORKFLOW.md "Branch kept" to "Branch deleted". Replace checkpoint commit documentation with snapshot ref description. -- Why it matters: Docs previously claimed behaviors the code didn't implement — eroded trust -- Source: user -- Primary owning slice: M001/S03 -- Supporting slices: none -- Validation: README.md says "deleted after merge" (line 260). GSD-WORKFLOW.md says "Branch deleted" (line 551). -- Notes: Fixed in S03 - -### R011 — Remove raw git commands from prompts -- Class: core-capability -- Status: validated -- Description: Replace `git add -A && git commit` instructions in execute-task.md, complete-slice.md, replan-slice.md, complete-milestone.md with "the system commits automatically" messages -- Why it matters: LLMs should not run git commands — that's the whole point of the GitService trust boundary -- Source: user -- Primary owning slice: M001/S04 -- Supporting slices: none -- Validation: grep of 4 prompt files returns zero git command matches. worktree-merge.md unchanged. -- Notes: worktree-merge.md kept as-is (conflict resolution needs LLM judgment) - -### R012 — Pre-merge verification (merge guards) -- Class: core-capability -- Status: validated -- Description: Auto-detect test/typecheck/build commands from package.json, Cargo.toml, Makefile, pyproject.toml. Run before squash merge. Abort on failure. -- Why it matters: Prevents broken code from landing on main -- Source: user -- Primary owning slice: M001/S05 -- Supporting slices: none -- Validation: runPreMergeCheck() in git-service.ts. Runs after squash before commit, resets on failure (D015). Unit tests pass. -- Notes: Configurable via git.pre_merge_check preference: "auto" (default), false (skip), or custom command - -### R013 — Hidden snapshot refs for rollback -- Class: core-capability -- Status: validated -- Description: Create refs/gsd/snapshots// before merges and risky operations. Prunable after 7 days. -- Why it matters: Invisible recovery points without cluttering branch history with checkpoint commits -- Source: user -- Primary owning slice: M001/S05 -- Supporting slices: none -- Validation: createSnapshot() in git-service.ts. Gated by prefs.snapshots === true (D018). Unit tests pass. -- Notes: Invisible to normal git log. Visible via git for-each-ref refs/gsd/snapshots/ - -### R014 — Optional auto-push (preference-gated) -- Class: core-capability -- Status: validated -- Description: When git.auto_push: true, push main to remote after slice merge. Optionally push slice branches during work. -- Why it matters: Remote backup and team visibility for senior engineers -- Source: user -- Primary owning slice: M001/S05 -- Supporting slices: none -- Validation: auto-push logic in mergeSliceToMain, gated by prefs.auto_push. Unit tests verify push behavior. -- Notes: Default: false. Remote name configurable via git.remote (default: "origin") - -### R015 — Rich squash commit messages with task lists -- Class: quality-attribute -- Status: validated -- Description: Squash merge commits include task list extracted from branch commit history and branch reference for forensics -- Why it matters: Self-documenting git history that reads like a changelog -- Source: user -- Primary owning slice: M001/S05 -- Supporting slices: none -- Validation: Rich commit builder in git-service.ts. Uses -F - stdin pipe (D016). Unit tests pass. -- Notes: Format: type(scope): title\n\nTasks:\n- T01: ...\n\nBranch: gsd/M001/S01 - -### R016 — Bug fix: stale branch base with remote fetch -- Class: quality-attribute -- Status: validated -- Description: When a remote exists, git fetch --prune before cutting a new slice branch. Warn (don't block) if local main is behind origin. -- Why it matters: Prevents branching from stale trunk HEAD -- Source: user -- Primary owning slice: M001/S05 -- Supporting slices: none -- Validation: Remote fetch in ensureSliceBranch. Behind-upstream warning verified by unit test. -- Notes: Only when remote exists and auto_push is enabled or remote is configured - -### R017 — GitService unit tests -- Class: quality-attribute -- Status: validated -- Description: Unit tests using temp git repos for all GitService methods, following the existing worktree test patterns -- Why it matters: Mechanical verification that git operations work correctly -- Source: inferred -- Primary owning slice: M001/S01 -- Supporting slices: M001/S05 -- Validation: git-service.test.ts has 30 test cases, all passing. Uses temp git repos. -- Notes: Same test infrastructure as worktree.test.ts - -### R018 — Archive design input files -- Class: quality-attribute -- Status: validated -- Description: Remove or archive CODEX-GIT-SYNTHESIS.md, CLAUDE-GIT-SYNTHESIS.md, GEMINI-GIT-SYNTHESIS.md, and ONBOARDING-PLAN.md -- Why it matters: Design input files are not permanent docs — they clutter the repo after implementation -- Source: user -- Primary owning slice: M001/S06 -- Supporting slices: none -- Validation: All 4 files confirmed deleted. Git history preserves them. -- Notes: Deleted in S06 - -## Deferred - -### R019 — PR creation workflow -- Class: core-capability -- Status: deferred -- Description: Auto-create PRs via gh CLI after slice merge when git.auto_pr is enabled -- Why it matters: Team workflow integration for shared repos with protected branches -- Source: research -- Primary owning slice: none -- Supporting slices: none -- Validation: unmapped -- Notes: Deferred — touches GitHub API, gh CLI detection, merge queue awareness. Separate concern from core GitService. - -### R020 — Milestone tags on completion -- Class: quality-attribute -- Status: deferred -- Description: Create annotated git tags on milestone completion (e.g. M001) -- Why it matters: Enables git describe, changelog generation, and clear release markers -- Source: research -- Primary owning slice: none -- Supporting slices: none -- Validation: unmapped -- Notes: Deferred — low value relative to core trust boundary fix - -### R021 — Full file ownership tracking -- Class: core-capability -- Status: deferred -- Description: Track every file the agent creates/modifies per unit. Only stage owned files. -- Why it matters: More precise staging than exclusion filter — prevents unrelated user edits from being committed -- Source: research -- Primary owning slice: none -- Supporting slices: none -- Validation: unmapped -- Notes: Deferred — requires threading ownership through entire execution pipeline. Exclusion filter covers 95% of the problem. - -## Out of Scope - -### R022 — Git Notes for metadata -- Class: anti-feature -- Status: out-of-scope -- Description: Store task plans and verification results in git notes -- Why it matters: Prevents fragile, poorly-supported metadata mechanism from entering the codebase -- Source: research -- Primary owning slice: none -- Supporting slices: none -- Validation: n/a -- Notes: Git Notes are fragile, poorly rendered by most tools, unreliable push/pull semantics - -### R023 — Shadow worktrees as default model -- Class: anti-feature -- Status: out-of-scope -- Description: Make git worktrees the default execution model for all agent work -- Why it matters: Over-engineering for common single-agent case. Worktrees are already available as advanced opt-in. -- Source: research -- Primary owning slice: none -- Supporting slices: none -- Validation: n/a -- Notes: Rejected from Gemini's proposal - -### R024 — AI-driven rebases -- Class: anti-feature -- Status: out-of-scope -- Description: LLM-driven interactive rebase and cross-slice conflict resolution -- Why it matters: Prevents hidden magic that makes senior engineers distrust the system -- Source: research -- Primary owning slice: none -- Supporting slices: none -- Validation: n/a -- Notes: Merge conflicts require deterministic resolution or human intervention - -### R025 — Stacked branches -- Class: anti-feature -- Status: out-of-scope -- Description: Stacked branch/PR workflow as default execution model -- Why it matters: Over-engineering for solo/vibe coder workflows -- Source: research -- Primary owning slice: none -- Supporting slices: none -- Validation: n/a -- Notes: Could be opt-in advanced mode in a future milestone - -### R026 — CI/CD integration -- Class: anti-feature -- Status: out-of-scope -- Description: Deployment pipeline integration from GSD -- Why it matters: GSD manages work orchestration, not infrastructure -- Source: research -- Primary owning slice: none -- Supporting slices: none -- Validation: n/a -- Notes: Merge guards handle "is it broken?" — deployment is the user's concern - -### R027 — Commit signing (GPG) -- Class: anti-feature -- Status: out-of-scope -- Description: GPG commit signing for agent commits -- Why it matters: Adds friction with zero value when the agent is the committer -- Source: research -- Primary owning slice: none -- Supporting slices: none -- Validation: n/a -- Notes: Could be opt-in preference in a future milestone - -## Traceability - -| ID | Class | Status | Primary owner | Supporting | Proof | -|---|---|---|---|---|---| -| R001 | core-capability | validated | M001/S01 | M001/S02 | git-service.ts exists, build passes | -| R002 | core-capability | validated | M001/S01 | none | smart staging + fallback in unit tests | -| R003 | quality-attribute | validated | M001/S01 | none | inferCommitType unit tests | -| R004 | core-capability | validated | M001/S02 | M001/S05 | preferences.ts git field + docs | -| R005 | core-capability | validated | M001/S02 | none | facade delegates, build passes | -| R006 | core-capability | validated | M001/S02 | none | auto.ts wired to GitServiceImpl | -| R007 | quality-attribute | validated | M001/S03 | none | worktree-command.ts reordered | -| R008 | quality-attribute | validated | M001/S03 | none | deterministic merge as default | -| R009 | quality-attribute | validated | M001/S01 | M001/S02 | inferCommitType replaces hardcoded feat | -| R010 | quality-attribute | validated | M001/S03 | none | README + GSD-WORKFLOW corrected | -| R011 | core-capability | validated | M001/S04 | none | grep confirms zero git commands | -| R012 | core-capability | validated | M001/S05 | none | runPreMergeCheck unit tests | -| R013 | core-capability | validated | M001/S05 | none | createSnapshot unit tests | -| R014 | core-capability | validated | M001/S05 | none | auto-push unit tests | -| R015 | quality-attribute | validated | M001/S05 | none | rich commit builder unit tests | -| R016 | quality-attribute | validated | M001/S05 | none | remote fetch unit tests | -| R017 | quality-attribute | validated | M001/S01 | M001/S05 | 30 tests in git-service.test.ts | -| R018 | quality-attribute | validated | M001/S06 | none | 4 files confirmed deleted | -| R019 | core-capability | deferred | none | none | unmapped | -| R020 | quality-attribute | deferred | none | none | unmapped | -| R021 | core-capability | deferred | none | none | unmapped | -| R022 | anti-feature | out-of-scope | none | none | n/a | -| R023 | anti-feature | out-of-scope | none | none | n/a | -| R024 | anti-feature | out-of-scope | none | none | n/a | -| R025 | anti-feature | out-of-scope | none | none | n/a | -| R026 | anti-feature | out-of-scope | none | none | n/a | -| R027 | anti-feature | out-of-scope | none | none | n/a | - -## Coverage Summary - -- Active requirements: 0 -- Validated requirements: 18 -- Mapped to slices: 18 -- Deferred: 3 -- Out of scope: 6 -- Unmapped active requirements: 0 diff --git a/.gsd/milestones/M001/M001-CONTEXT.md b/.gsd/milestones/M001/M001-CONTEXT.md deleted file mode 100644 index d05645554..000000000 --- a/.gsd/milestones/M001/M001-CONTEXT.md +++ /dev/null @@ -1,130 +0,0 @@ -# M001: Deterministic GitService — Context - -**Gathered:** 2026-03-12 -**Status:** Ready for planning - -## Project Description - -GSD's git workflow is architecturally sound (trunk-based, branch-per-slice, squash-merge) but has a critical trust boundary problem: git operations are split between deterministic TypeScript code and probabilistic LLM prompts that run raw `git add -A && git commit`. This causes accidental commits of runtime files, hardcoded commit types, no pre-merge verification, and no recovery mechanism. - -The fix is a centralized `GitService` that owns all git mechanics while the LLM focuses on writing code. - -## Why This Milestone - -GSD is already shipping (v2.3.11) and the git strategy mostly works. But the trust boundary problem creates real bugs: runtime files get committed, all commits are labeled `feat`, there's no safety net before merging to main, and docs claim behaviors the code doesn't implement. Fixing this now prevents these issues from compounding as more users adopt GSD. - -## User-Visible Outcome - -### When this milestone is complete, the user can: - -- Run a full GSD auto-mode cycle where all git operations are handled by deterministic code (no LLM-driven git commands) -- See correctly typed commit messages in git log (fix, refactor, docs — not always feat) -- Trust that broken code won't land on main (merge guards auto-detect and run tests) -- Recover from bad merges via hidden snapshot refs -- Optionally enable auto-push to remote via preferences - -### Entry point / environment - -- Entry point: `/gsd auto` CLI command -- Environment: local dev (Node.js, git CLI) -- Live dependencies involved: git CLI, optional remote (origin) - -## Completion Class - -- Contract complete means: `npm run build` passes, `npm run test` passes (existing + new GitService tests), no raw git commands in prompts -- Integration complete means: A full GSD slice lifecycle (branch → execute → commit → merge) routes through GitService -- Operational complete means: none — this is internal infrastructure, not a service - -## Final Integrated Acceptance - -To call this milestone complete, we must prove: - -- `npm run build` and `npm run test` pass -- A slice lifecycle in auto-mode produces commits via GitService (correct types, no accidental runtime file commits) -- Prompts contain no raw git commands (except worktree-merge.md) -- Git preferences are recognized and applied (auto_push, merge guards) -- Existing worktree commands still work (create/merge/remove) - -## Risks and Unknowns - -- **Wiring facade without breaking callers** — worktree.ts is imported by auto.ts, state.ts, worktree-command.ts, workspace-index.ts. The thin facade must preserve all export signatures exactly. -- **auto.ts complexity** — 2600+ lines. Wiring changes need surgical precision to avoid regressions in the orchestrator. -- **Smart staging edge cases** — Exclusion filter might miss patterns or filter too aggressively. Fallback to `git add -A` is the safety net. -- **Test infrastructure compatibility** — Existing worktree tests use temp repos. GitService tests must follow the same pattern without conflicts. - -## Existing Codebase / Prior Art - -- `src/resources/extensions/gsd/worktree.ts` — Current slice branch lifecycle (290 lines). Will become thin facade. -- `src/resources/extensions/gsd/worktree-manager.ts` — Git worktree lifecycle (392 lines). Has `mergeWorktreeToMain()` deterministic helper that should be used by default. -- `src/resources/extensions/gsd/worktree-command.ts` — CLI commands (803 lines). Has bugs #1 and #2. -- `src/resources/extensions/gsd/auto.ts` — Orchestrator (2652 lines). Primary consumer of git operations. -- `src/resources/extensions/gsd/preferences.ts` — Preferences system (616 lines). Will get `git?: GitPreferences`. -- `src/resources/extensions/gsd/gitignore.ts` — Has `BASELINE_PATTERNS` — same set the smart staging exclusion filter should use. -- `src/resources/extensions/gsd/tests/worktree.test.ts` — Existing tests using temp git repos. Pattern to follow for GitService tests. -- `src/resources/extensions/gsd/tests/worktree-integration.test.ts` — Integration tests for worktree lifecycle. - -> See `.gsd/DECISIONS.md` for all architectural and pattern decisions — it is an append-only register; read it during planning, append to it during execution. - -## Relevant Requirements - -- R001–R018 — All active requirements are owned by this milestone's slices -- See `.gsd/REQUIREMENTS.md` for full details - -## Scope - -### In Scope - -- New `git-service.ts` with all git mechanics -- Smart staging (exclusion filter) -- Commit type inference -- Git preferences schema -- Wiring auto.ts and worktree.ts to GitService -- Bug fixes (#1 worktree create ordering, #2 merge dispatch, #4 hardcoded feat, #5 stale branch base) -- Doc fixes (README.md, GSD-WORKFLOW.md) -- Prompt cleanup (remove raw git commands) -- Pre-merge verification (merge guards) -- Hidden snapshot refs -- Optional auto-push -- Rich squash commit messages -- Archive design input files -- Unit tests for GitService - -### Out of Scope / Non-Goals - -- PR creation workflow (R019 — deferred) -- Milestone tags (R020 — deferred) -- Full file ownership tracking (R021 — deferred) -- Git Notes, shadow worktrees, AI rebases, stacked branches, CI/CD, commit signing (R022–R027 — out of scope) - -## Technical Constraints - -- Must preserve all existing exports from worktree.ts (thin facade pattern) -- Must use existing `runGit()` pattern (execSync-based) -- Must use existing test infrastructure (Node built-in test runner, temp git repos) -- Preferences must follow existing YAML-in-markdown frontmatter format -- `git status --porcelain` for idle detection in auto.ts may remain inline (not part of GitService) - -## Integration Points - -- `auto.ts` — Primary consumer. Calls ensureSliceBranch, autoCommit, switchToMain, mergeSliceToMain. -- `worktree-command.ts` — Calls autoCommitCurrentBranch, createWorktree. Has bugs to fix. -- `worktree-manager.ts` — Has mergeWorktreeToMain() that GitService should delegate to or replace. -- `state.ts` — Imports getActiveSliceBranch from worktree.ts. -- `workspace-index.ts` — Imports getSliceBranchName, detectWorktreeName from worktree.ts. -- `preferences.ts` — Will gain git?: GitPreferences field. -- `gitignore.ts` — BASELINE_PATTERNS should be shared with smart staging exclusion filter. - -## Open Questions - -- None — all decisions resolved during discussion. - -## Per-Slice Reading Guide - -| Slice | Read before starting | -|---|---| -| S01 | `worktree.ts`, `worktree-manager.ts`, `gitignore.ts` (for SKIP_PATHS/BASELINE_PATTERNS) | -| S02 | S01 summary, `auto.ts` (lines 55-75, 350-380, 470-510, 980-1020, 2220-2230), `preferences.ts` | -| S03 | S02 summary, `worktree-command.ts` (lines 340-370, 660-710), `README.md` (lines 250-270), `GSD-WORKFLOW.md` (lines 540-590) | -| S04 | S02 summary, all prompt files in `prompts/` | -| S05 | S02 summary, `git-service.ts` (from S01), `preferences.ts` (from S02) | -| S06 | All prior summaries, root-level synthesis/audit files | diff --git a/.gsd/milestones/M001/M001-ROADMAP.md b/.gsd/milestones/M001/M001-ROADMAP.md deleted file mode 100644 index 88d6b9de8..000000000 --- a/.gsd/milestones/M001/M001-ROADMAP.md +++ /dev/null @@ -1,142 +0,0 @@ -# M001: Deterministic GitService - -**Vision:** Centralize all git mechanics into a single deterministic GitService, fixing the trust boundary where probabilistic LLM prompts currently run raw git commands. The result: reliable commits, typed history, merge guards, recovery snapshots, and zero git commands in prompts. - -## Success Criteria - -- All git operations in auto-mode route through GitService (no inline execSync git calls except `git status --porcelain` for idle detection and `git rev-parse --git-dir` for init check) -- `npm run build` passes -- `npm run test` passes (existing tests + new GitService tests) -- No raw git commands in LLM-facing prompts (except worktree-merge.md for conflict resolution) -- Git preferences recognized in preferences.md schema -- README and GSD-WORKFLOW doc claims match actual code behavior -- Squash merge commits use correct conventional types (not always `feat`) - -## Key Risks / Unknowns - -- **Facade wiring breaks callers** — worktree.ts has 6+ consumers. Any export signature change breaks the build. -- **auto.ts surgery** — 2600+ line orchestrator. Changes must be surgical to avoid regressions. -- **Smart staging edge cases** — Exclusion filter may miss patterns or over-filter. Fallback to `git add -A` is the safety net. - -## Proof Strategy - -- Facade wiring breaks callers → retire in S02 by proving `npm run build` and `npm run test` pass with the facade in place -- auto.ts surgery → retire in S02 by proving auto.ts compiles and existing tests pass -- Smart staging edge cases → retire in S01 by proving unit tests cover exclusion patterns and fallback behavior - -## Verification Classes - -- Contract verification: `npm run build`, `npm run test`, grep prompts for raw git commands -- Integration verification: Full slice lifecycle through GitService (exercised by existing worktree tests + new GitService tests) -- Operational verification: none — internal infrastructure -- UAT / human verification: Run a GSD auto-mode cycle and check git log for correct commit types - -## Milestone Definition of Done - -This milestone is complete only when all are true: - -- All slice deliverables are complete -- `npm run build` passes -- `npm run test` passes (existing + new) -- No raw git commands in execute-task.md, complete-slice.md, replan-slice.md, complete-milestone.md -- Git preferences parse and apply correctly -- README.md and GSD-WORKFLOW.md match actual behavior -- Design input files (synthesis/audit) are archived - -## Requirement Coverage - -- Covers: R001, R002, R003, R004, R005, R006, R007, R008, R009, R010, R011, R012, R013, R014, R015, R016, R017, R018 -- Partially covers: none -- Leaves for later: R019 (PR workflow), R020 (milestone tags), R021 (file ownership tracking) -- Orphan risks: none - -## Slices - -- [x] **S01: GitService core implementation** `risk:high` `depends:[]` - > After this: `git-service.ts` exists with commit, autoCommit, ensureSliceBranch, switchToMain, mergeSliceToMain, inferCommitType, smart staging — all passing unit tests in temp git repos. - -- [x] **S02: Wire GitService into codebase** `risk:high` `depends:[S01]` - > After this: auto.ts and worktree.ts delegate to GitService. Git preferences schema added to preferences.ts. `npm run build` passes. Existing worktree tests still pass. - -- [x] **S03: Bug fixes and doc corrections** `risk:medium` `depends:[S02]` - > After this: Worktree create commits before fork. Worktree merge uses deterministic helper by default. README and GSD-WORKFLOW match actual branch deletion and snapshot behavior. Build passes. - -- [x] **S04: Remove git commands from prompts** `risk:low` `depends:[S02]` - > After this: execute-task.md, complete-slice.md, replan-slice.md, complete-milestone.md contain no raw git commands. worktree-merge.md unchanged. Verified by grep. - -- [x] **S05: Enhanced features — merge guards, snapshots, auto-push, rich commits** `risk:medium` `depends:[S02]` - > After this: Pre-merge verification auto-detects test runners and blocks broken merges. Snapshot refs created before merges (visible via `git for-each-ref refs/gsd/snapshots/`). auto_push preference pushes main after merge. Squash commits include task lists. Remote fetch before branching when remote exists. All verified by unit tests. - -- [x] **S06: Cleanup and archive** `risk:low` `depends:[S05]` - > After this: CODEX-GIT-SYNTHESIS.md, CLAUDE-GIT-SYNTHESIS.md, GEMINI-GIT-SYNTHESIS.md, and ONBOARDING-PLAN.md are deleted. Final doc consistency check passes. - -## Boundary Map - -### S01 → S02 - -Produces: -- `git-service.ts` → `GitServiceImpl` class with constructor `(basePath: string, prefs: GitPreferences)` -- `git-service.ts` → `GitPreferences` interface (auto_push, push_branches, remote, snapshots, pre_merge_check, commit_type) -- `git-service.ts` → `commit(opts: CommitOptions)` — smart staging with exclusion filter, conventional commit message -- `git-service.ts` → `autoCommit(unitType: string, unitId: string)` — safety-net commit after LLM session -- `git-service.ts` → `ensureSliceBranch(milestoneId: string, sliceId: string)` — create/checkout slice branch -- `git-service.ts` → `switchToMain()` — switch to main, auto-commit dirty state first -- `git-service.ts` → `mergeSliceToMain(milestoneId: string, sliceId: string, sliceTitle: string)` — squash merge with inferred commit type -- `git-service.ts` → `inferCommitType(sliceTitle: string)` — keyword-based type inference -- `git-service.ts` → `getMainBranch()`, `getCurrentBranch()`, `isOnSliceBranch()`, `getActiveSliceBranch()` -- `git-service.ts` → Shared exclusion patterns (aligned with gitignore.ts BASELINE_PATTERNS) - -Consumes: -- nothing (first slice) - -### S02 → S03 - -Produces: -- `worktree.ts` — thin facade: all existing exports preserved, internals delegate to `GitServiceImpl` -- `auto.ts` — all git callsites route through GitService -- `preferences.ts` — `git?: GitPreferences` field with validation and merge logic -- `templates/preferences.md` — `git:` section in template -- `docs/preferences-reference.md` — git preferences documented - -Consumes from S01: -- `git-service.ts` → `GitServiceImpl`, `GitPreferences`, all public methods - -### S02 → S04 - -Produces: -- Same as S02 → S03 (prompts depend on the system committing automatically, which S02 enables) - -Consumes from S01: -- Same as S02 → S03 - -### S02 → S05 - -Produces: -- Same as S02 → S03 (enhanced features build on the GitService and preferences schema) - -Consumes from S01: -- Same as S02 → S03 - -### S03 → S06 - -Produces: -- Fixed `worktree-command.ts` — create ordering, merge dispatch -- Fixed `README.md` — branch lifecycle claims -- Fixed `GSD-WORKFLOW.md` — checkpoint/branch docs - -Consumes from S02: -- `worktree.ts` facade (for autoCommitCurrentBranch used in create ordering fix) -- `git-service.ts` (for mergeWorktreeToMain delegation) - -### S05 → S06 - -Produces: -- `git-service.ts` → `createSnapshot(label: string)` — hidden snapshot refs -- `git-service.ts` → `runPreMergeCheck()` — auto-detect and execute verification -- `git-service.ts` → auto-push logic in mergeSliceToMain -- `git-service.ts` → rich squash commit message builder -- `git-service.ts` → remote fetch before branching - -Consumes from S02: -- `git-service.ts` core methods -- `preferences.ts` git preferences (pre_merge_check, auto_push, remote) diff --git a/.gsd/milestones/M001/slices/S01/S01-PLAN.md b/.gsd/milestones/M001/slices/S01/S01-PLAN.md deleted file mode 100644 index b77c6f75d..000000000 --- a/.gsd/milestones/M001/slices/S01/S01-PLAN.md +++ /dev/null @@ -1,78 +0,0 @@ -# S01: GitService Core Implementation - -**Goal:** A standalone `GitServiceImpl` class in `git-service.ts` that encapsulates all git mechanics — commit, autoCommit, ensureSliceBranch, switchToMain, mergeSliceToMain, smart staging, commit type inference — with comprehensive unit tests passing in temp git repos. -**Demo:** `node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/git-service.test.ts` passes all assertions. - -## Must-Haves - -- `GitServiceImpl` class with constructor `(basePath: string, prefs?: GitPreferences)` -- `GitPreferences` interface exported (auto_push, push_branches, remote, snapshots, pre_merge_check, commit_type) -- `commit(opts: CommitOptions)` with smart staging exclusion filter + fallback to `git add -A` -- `autoCommit(unitType: string, unitId: string)` using smart staging -- `ensureSliceBranch(milestoneId, sliceId)` with worktree-aware naming, branch-from-current logic, pre-checkout auto-commit using smart staging -- `switchToMain()` with pre-checkout auto-commit using smart staging -- `mergeSliceToMain(milestoneId, sliceId, sliceTitle)` with `inferCommitType()` instead of hardcoded `feat` -- `inferCommitType(sliceTitle: string)` exported as pure function -- `getMainBranch()`, `getCurrentBranch()`, `isOnSliceBranch()`, `getActiveSliceBranch()` -- `RUNTIME_EXCLUSION_PATHS` exported constant (the 6 GSD runtime paths) -- Unit tests covering: smart staging exclusion, smart staging fallback, commit type inference for all types, branch lifecycle, merge with correct commit type, empty-commit-after-staging guard - -## Proof Level - -- This slice proves: contract -- Real runtime required: no (temp git repos in tests) -- Human/UAT required: no - -## Verification - -- `node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/git-service.test.ts` — all tests pass -- `npm run build` — TypeScript compilation still passes (git-service.ts is in extensions, excluded from tsc, but verify no import breakage) -- `npm run test` — all existing tests still pass (no regressions) - -## Observability / Diagnostics - -- Runtime signals: None — this is a library module, not a runtime service. Errors surface as thrown `Error` instances with descriptive messages including the failed git command and basePath. -- Inspection surfaces: Test output shows pass/fail counts per test group. `git log` in temp repos verifies commit messages and types. -- Failure visibility: All `runGit()` failures include the full git command and working directory in the error message. Smart staging fallback logs a warning to stderr when exclusion pathspecs fail. -- Redaction constraints: None — no secrets handled. - -## Integration Closure - -- Upstream surfaces consumed: None (first slice) -- New wiring introduced in this slice: `git-service.ts` module with `GitServiceImpl` class and exports — standalone, not yet consumed by any caller -- What remains before the milestone is truly usable end-to-end: S02 (wire into auto.ts/worktree.ts), S03 (bug fixes), S04 (remove git from prompts), S05 (enhanced features), S06 (cleanup) - -## Tasks - -- [x] **T01: Create git-service.ts with GitPreferences, RUNTIME_EXCLUSION_PATHS, runGit, and inferCommitType** `est:30m` - - Why: Foundation types, constants, and pure functions that everything else depends on. Separating these first means T02/T03 can build on stable exports. - - Files: `src/resources/extensions/gsd/git-service.ts`, `src/resources/extensions/gsd/tests/git-service.test.ts` - - Do: Define `GitPreferences` interface with all fields (defaulting to safe values). Export `RUNTIME_EXCLUSION_PATHS` array matching the 6 GSD runtime paths from BASELINE_PATTERNS/SKIP_PATHS. Implement local `runGit()` (same pattern as worktree.ts). Implement `inferCommitType(sliceTitle)` as exported pure function with keyword matching for fix/refactor/docs/test/chore, defaulting to feat. Create test file with test scaffolding (assert/assertEq helpers, temp repo setup) and tests for `inferCommitType` covering all types + default. Tests for `RUNTIME_EXCLUSION_PATHS` matching the known 6 paths. - - Verify: `node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/git-service.test.ts` passes - - Done when: `inferCommitType` returns correct types for all keyword variants, `RUNTIME_EXCLUSION_PATHS` has exactly the 6 expected paths, tests pass - -- [x] **T02: Implement GitServiceImpl — smart staging, commit, and autoCommit** `est:45m` - - Why: The core value of GitService is smart staging (R002) and centralized commit (R001). This task builds the `GitServiceImpl` class with the staging/commit methods that all other operations depend on. - - Files: `src/resources/extensions/gsd/git-service.ts`, `src/resources/extensions/gsd/tests/git-service.test.ts` - - Do: Implement `GitServiceImpl` class with `(basePath, prefs)` constructor. Implement private `smartStage()` using `git add -A -- . ':(exclude)path'` for each RUNTIME_EXCLUSION_PATHS entry, with fallback to `git add -A` + stderr warning on failure. Implement `commit(opts: CommitOptions)` that calls smartStage, checks `git diff --cached --stat` for empty, builds conventional commit message. Implement `autoCommit(unitType, unitId)`. Add tests: smart staging excludes runtime files, smart staging fallback works, commit with message, autoCommit on clean repo returns null, autoCommit on dirty repo commits and returns message, empty-after-staging guard (only runtime files dirty → no commit). - - Verify: All new tests pass alongside T01 tests - - Done when: Smart staging provably excludes `.gsd/activity/`, `.gsd/runtime/`, `.gsd/STATE.md`, `.gsd/auto.lock`, `.gsd/metrics.json`, `.gsd/worktrees/` while staging other files. Fallback to `git add -A` works when pathspec fails. - -- [x] **T03: Implement branch lifecycle — ensureSliceBranch, switchToMain, branch queries** `est:40m` - - Why: Covers R001 branch operations. These methods replicate the logic from worktree.ts but route staging through smart staging instead of `git add -A`. - - Files: `src/resources/extensions/gsd/git-service.ts`, `src/resources/extensions/gsd/tests/git-service.test.ts` - - Do: Implement `getMainBranch()`, `getCurrentBranch()`, `isOnSliceBranch()`, `getActiveSliceBranch()` — same logic as worktree.ts. Implement `ensureSliceBranch(milestoneId, sliceId)` with worktree detection, branch-from-current-not-main logic, pre-checkout smart staging auto-commit. Implement `switchToMain()` with pre-checkout smart staging auto-commit. Add tests: branch creation, idempotent ensure, branch-from-non-main-working-branch, branch-from-slice-falls-back-to-main, switchToMain auto-commits dirty files using smart staging (verify runtime files excluded), query methods return correct values on main vs slice branch. - - Verify: All tests pass including branch lifecycle tests - - Done when: `ensureSliceBranch` and `switchToMain` use smart staging for pre-checkout commits, branch creation logic matches worktree.ts behavior, all query methods work correctly - -- [x] **T04: Implement mergeSliceToMain with inferCommitType and full integration tests** `est:40m` - - Why: Closes R001 (merge), R003 (commit type inference in merge), R009 (fixes hardcoded feat). This is the capstone method that proves the full GitService lifecycle works end-to-end. - - Files: `src/resources/extensions/gsd/git-service.ts`, `src/resources/extensions/gsd/tests/git-service.test.ts` - - Do: Implement `mergeSliceToMain(milestoneId, sliceId, sliceTitle)` — switchToMain, verify on main, check branch exists, check commits ahead, squash merge, use `inferCommitType(sliceTitle)` for commit message (not hardcoded feat), delete branch. Add integration tests: full lifecycle (create branch → commit on branch → merge → verify commit message type), merge with fix title → `fix(...)` commit, merge with docs title → `docs(...)` commit, merge with feature title → `feat(...)` commit, error cases (not on main, branch doesn't exist, no commits ahead). Run `npm run build` and `npm run test` to verify no regressions. - - Verify: `node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/git-service.test.ts` — all tests pass. `npm run build` passes. `npm run test` passes. - - Done when: Full GitService lifecycle works in tests, merge commits use inferred type from slice title, all existing tests still pass, build is green - -## Files Likely Touched - -- `src/resources/extensions/gsd/git-service.ts` (new) -- `src/resources/extensions/gsd/tests/git-service.test.ts` (new) diff --git a/.gsd/milestones/M001/slices/S01/tasks/T01-PLAN.md b/.gsd/milestones/M001/slices/S01/tasks/T01-PLAN.md deleted file mode 100644 index effd4ab8d..000000000 --- a/.gsd/milestones/M001/slices/S01/tasks/T01-PLAN.md +++ /dev/null @@ -1,59 +0,0 @@ ---- -estimated_steps: 5 -estimated_files: 2 ---- - -# T01: Create git-service.ts with GitPreferences, RUNTIME_EXCLUSION_PATHS, runGit, and inferCommitType - -**Slice:** S01 — GitService Core Implementation -**Milestone:** M001 - -## Description - -Create the `git-service.ts` module with the foundational types, constants, and pure functions. This establishes the `GitPreferences` interface that the entire milestone depends on, the `RUNTIME_EXCLUSION_PATHS` constant that smart staging uses, and `inferCommitType()` which fixes the hardcoded `feat` bug (R009). Also sets up the test file with the project's established test pattern (manual assert/assertEq, temp git repos, main() async wrapper). - -## Steps - -1. Create `src/resources/extensions/gsd/git-service.ts` with imports (`node:fs`, `node:child_process`, `node:path`, `node:os`). -2. Define and export `GitPreferences` interface: `auto_push?: boolean`, `push_branches?: boolean`, `remote?: string`, `snapshots?: boolean`, `pre_merge_check?: boolean | string`, `commit_type?: string`. -3. Define and export `CommitOptions` interface: `message: string`, `allowEmpty?: boolean`. -4. Define and export `MergeSliceResult` interface (same shape as worktree.ts): `branch: string`, `mergedCommitMessage: string`, `deletedBranch: boolean`. -5. Export `RUNTIME_EXCLUSION_PATHS` constant: the 6 GSD runtime paths (`[".gsd/activity/", ".gsd/runtime/", ".gsd/worktrees/", ".gsd/auto.lock", ".gsd/metrics.json", ".gsd/STATE.md"]`). -6. Implement local `runGit(basePath, args, options?)` function — same pattern as worktree.ts (execSync, trim, allowFailure flag, descriptive error message). -7. Implement and export `inferCommitType(sliceTitle: string): string` — keyword matching: `fix`/`bug`/`patch`/`hotfix` → `fix`, `refactor`/`restructure`/`reorganize` → `refactor`, `doc`/`documentation` → `docs`, `test`/`testing` → `test`, `chore`/`cleanup`/`clean up`/`archive`/`remove`/`delete` → `chore`. Case-insensitive word boundary matching. Default: `feat`. -8. Create `src/resources/extensions/gsd/tests/git-service.test.ts` following worktree.test.ts pattern: imports, assert/assertEq helpers, `run()` helper, temp repo setup, async `main()`. -9. Add tests for `inferCommitType`: feature title → `feat`, fix title → `fix`, refactor title → `refactor`, docs title → `docs`, test title → `test`, chore title → `chore`, mixed keywords → first match wins, unknown → `feat`. -10. Add test verifying `RUNTIME_EXCLUSION_PATHS` contains exactly the 6 expected paths. - -## Must-Haves - -- [ ] `GitPreferences` interface exported with all 6 fields -- [ ] `CommitOptions` interface exported -- [ ] `MergeSliceResult` interface exported -- [ ] `RUNTIME_EXCLUSION_PATHS` exported with exactly 6 paths matching SKIP_PATHS + SKIP_EXACT -- [ ] `inferCommitType()` exported, returns correct type for all keyword categories -- [ ] `inferCommitType()` defaults to `feat` for unrecognized titles -- [ ] Test file follows project test pattern (assert/assertEq, async main, process.exit on failure) -- [ ] All tests pass - -## Verification - -- `node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/git-service.test.ts` — all tests pass with 0 failures - -## Observability Impact - -- Signals added/changed: None — pure types, constants, and functions -- How a future agent inspects this: Read exports from `git-service.ts`, run the test file -- Failure state exposed: `inferCommitType` is pure — bad output is immediately visible in test assertions - -## Inputs - -- `src/resources/extensions/gsd/worktree.ts` — `MergeSliceResult` interface shape, `runGit()` pattern -- `src/resources/extensions/gsd/gitignore.ts` — `BASELINE_PATTERNS` (first 6 entries = GSD runtime paths) -- `src/resources/extensions/gsd/worktree-manager.ts` — `SKIP_PATHS` + `SKIP_EXACT` (same 6 paths) -- `src/resources/extensions/gsd/tests/worktree.test.ts` — test infrastructure pattern - -## Expected Output - -- `src/resources/extensions/gsd/git-service.ts` — module with `GitPreferences`, `CommitOptions`, `MergeSliceResult`, `RUNTIME_EXCLUSION_PATHS`, `runGit()`, `inferCommitType()` -- `src/resources/extensions/gsd/tests/git-service.test.ts` — test file with passing tests for inferCommitType and RUNTIME_EXCLUSION_PATHS diff --git a/.gsd/milestones/M001/slices/S01/tasks/T02-PLAN.md b/.gsd/milestones/M001/slices/S01/tasks/T02-PLAN.md deleted file mode 100644 index 8a1886a35..000000000 --- a/.gsd/milestones/M001/slices/S01/tasks/T02-PLAN.md +++ /dev/null @@ -1,59 +0,0 @@ ---- -estimated_steps: 5 -estimated_files: 2 ---- - -# T02: Implement GitServiceImpl — smart staging, commit, and autoCommit - -**Slice:** S01 — GitService Core Implementation -**Milestone:** M001 - -## Description - -Build the `GitServiceImpl` class with the core value proposition: smart staging (R002) that excludes GSD runtime paths, and centralized commit/autoCommit methods (R001). The smart staging uses git's `:(exclude)` pathspec syntax to filter runtime paths from `git add`, with a fallback to `git add -A` if the pathspec fails. This is the foundational class that T03 and T04 build upon. - -## Steps - -1. Add `GitServiceImpl` class to `git-service.ts` with constructor `(basePath: string, prefs: GitPreferences = {})`. Store basePath and prefs as readonly properties. -2. Implement private `git(args, options?)` instance method that calls the module-level `runGit(this.basePath, args, options)`. -3. Implement private `smartStage()` method: build pathspec string `git add -A -- . ':(exclude).gsd/activity/' ':(exclude).gsd/runtime/' ...` for all RUNTIME_EXCLUSION_PATHS entries. Execute via `runGit`. On failure (catch), log warning to stderr (`console.error("GitService: smart staging failed, falling back to git add -A")`), then execute `git add -A` as fallback. -4. Implement `commit(opts: CommitOptions)` method: call `smartStage()`, check `git diff --cached --stat` — if empty and not `allowEmpty`, return null. Build commit message, execute `git commit -m ${JSON.stringify(opts.message)}`. Return the commit message string. -5. Implement `autoCommit(unitType: string, unitId: string)` method: check `git status --short` — if clean, return null. Call `smartStage()`, check `git diff --cached --stat` — if empty return null (all changes were runtime files). Build message `chore(${unitId}): auto-commit after ${unitType}`, commit, return message. -6. Add tests to `git-service.test.ts`: create temp repo, create GitServiceImpl instance. - - Test smart staging excludes runtime files: create `.gsd/activity/log.jsonl`, `.gsd/runtime/state.json`, `.gsd/STATE.md`, `.gsd/auto.lock`, `.gsd/metrics.json`, `.gsd/worktrees/wt/file.txt` plus a real file `src/code.ts`. Call `commit()`. Verify only `src/code.ts` is in the commit (check `git show --stat HEAD`). Verify runtime files are still untracked/unstaged. - - Test smart staging fallback: mock a scenario where exclusion fails (e.g., use a bad pathspec) and verify fallback to `git add -A` stages everything. - - Test autoCommit on clean repo returns null. - - Test autoCommit on dirty repo: create a file, call autoCommit, verify commit exists with correct message format. - - Test empty-after-staging guard: create only runtime files (`.gsd/activity/x.jsonl`), call autoCommit, verify returns null and no commit is created. - -## Must-Haves - -- [ ] `GitServiceImpl` class with constructor `(basePath, prefs?)` -- [ ] Smart staging uses `:(exclude)` pathspecs for all 6 RUNTIME_EXCLUSION_PATHS -- [ ] Smart staging falls back to `git add -A` with stderr warning on pathspec failure -- [ ] `commit()` returns null when nothing staged after smart staging -- [ ] `commit()` uses `JSON.stringify` for shell-escaping commit messages -- [ ] `autoCommit()` returns null on clean repo -- [ ] `autoCommit()` returns null when only runtime files are dirty (empty-after-staging) -- [ ] `autoCommit()` returns commit message string on success -- [ ] All tests pass - -## Verification - -- `node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/git-service.test.ts` — all tests pass including new staging/commit tests - -## Observability Impact - -- Signals added/changed: stderr warning when smart staging fallback activates — this is the primary diagnostic signal for staging issues -- How a future agent inspects this: Check stderr output during commits for "smart staging failed" messages. Check `git show --stat HEAD` after commits to verify which files were included. -- Failure state exposed: Fallback warning on stderr. Null return from commit/autoCommit when no files to stage. - -## Inputs - -- `src/resources/extensions/gsd/git-service.ts` — T01 output: types, constants, runGit, inferCommitType -- `src/resources/extensions/gsd/tests/git-service.test.ts` — T01 output: test scaffolding with passing inferCommitType tests - -## Expected Output - -- `src/resources/extensions/gsd/git-service.ts` — updated with `GitServiceImpl` class, `smartStage()`, `commit()`, `autoCommit()` -- `src/resources/extensions/gsd/tests/git-service.test.ts` — updated with smart staging and commit tests passing diff --git a/.gsd/milestones/M001/slices/S01/tasks/T03-PLAN.md b/.gsd/milestones/M001/slices/S01/tasks/T03-PLAN.md deleted file mode 100644 index c93850b18..000000000 --- a/.gsd/milestones/M001/slices/S01/tasks/T03-PLAN.md +++ /dev/null @@ -1,62 +0,0 @@ ---- -estimated_steps: 5 -estimated_files: 2 ---- - -# T03: Implement branch lifecycle — ensureSliceBranch, switchToMain, branch queries - -**Slice:** S01 — GitService Core Implementation -**Milestone:** M001 - -## Description - -Add branch management methods to `GitServiceImpl` that replicate the logic from `worktree.ts` but route all staging through smart staging. This covers `ensureSliceBranch`, `switchToMain`, and the branch query methods (`getMainBranch`, `getCurrentBranch`, `isOnSliceBranch`, `getActiveSliceBranch`). The key difference from worktree.ts: pre-checkout auto-commits use `smartStage()` instead of `git add -A`, so runtime files are never accidentally committed during branch switches. - -## Steps - -1. Add `getMainBranch()` method to `GitServiceImpl` — reuse exact logic from `worktree.ts` (`detectWorktreeName`, worktree branch check, `symbolic-ref`, main/master fallback, current branch fallback). Import `detectWorktreeName`, `getSliceBranchName`, `SLICE_BRANCH_RE` from worktree.ts (these are pure utility functions that don't change in S02). -2. Add `getCurrentBranch()`, `isOnSliceBranch()`, `getActiveSliceBranch()` methods — same logic as worktree.ts standalone functions, using `this.git()`. -3. Implement `ensureSliceBranch(milestoneId, sliceId)` method: detect worktree name, compute branch name, check if already on branch (return false), create branch if needed (branch-from-current-not-main logic, slice-to-slice falls back to main), check worktree conflict, pre-checkout auto-commit using `autoCommit("pre-switch", currentBranch)`, checkout, return created boolean. -4. Implement `switchToMain()` method: get main branch, check if already on main (return early), auto-commit dirty state via `autoCommit("pre-switch", currentBranch)`, checkout main. -5. Add tests: - - `ensureSliceBranch` creates branch and checks it out - - `ensureSliceBranch` is idempotent (second call returns false) - - `ensureSliceBranch` from non-main working branch inherits artifacts - - `ensureSliceBranch` from another slice branch falls back to main - - `ensureSliceBranch` auto-commits dirty files before checkout using smart staging (verify runtime files NOT in the auto-commit) - - `switchToMain` auto-commits dirty files using smart staging - - `switchToMain` is idempotent when already on main - - `getCurrentBranch`, `isOnSliceBranch`, `getActiveSliceBranch` return correct values on main vs slice branch - -## Must-Haves - -- [ ] `getMainBranch()` handles worktree, origin/HEAD, main/master fallback -- [ ] `getCurrentBranch()` returns current branch name -- [ ] `isOnSliceBranch()` returns true on slice branch, false on main -- [ ] `getActiveSliceBranch()` returns branch name or null -- [ ] `ensureSliceBranch()` creates branch from current working branch (not main) when current is not a slice branch -- [ ] `ensureSliceBranch()` creates branch from main when current branch IS a slice branch -- [ ] `ensureSliceBranch()` auto-commits dirty state via smart staging before checkout -- [ ] `switchToMain()` auto-commits dirty state via smart staging before checkout -- [ ] All tests pass - -## Verification - -- `node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/git-service.test.ts` — all tests pass including branch lifecycle tests - -## Observability Impact - -- Signals added/changed: None beyond what T02 established (smart staging fallback warning). Pre-checkout auto-commits are visible in `git log`. -- How a future agent inspects this: `git log --oneline` shows auto-commit messages before branch switches. `git branch -a` shows created slice branches. -- Failure state exposed: Throws descriptive Error if branch is checked out in another worktree. Throws on checkout failure with git command and basePath in message. - -## Inputs - -- `src/resources/extensions/gsd/git-service.ts` — T02 output: `GitServiceImpl` with smartStage, commit, autoCommit -- `src/resources/extensions/gsd/worktree.ts` — `detectWorktreeName`, `getSliceBranchName`, `SLICE_BRANCH_RE` imports (pure utilities) -- `src/resources/extensions/gsd/tests/git-service.test.ts` — T02 output: existing passing tests - -## Expected Output - -- `src/resources/extensions/gsd/git-service.ts` — updated with `getMainBranch()`, `getCurrentBranch()`, `isOnSliceBranch()`, `getActiveSliceBranch()`, `ensureSliceBranch()`, `switchToMain()` -- `src/resources/extensions/gsd/tests/git-service.test.ts` — updated with branch lifecycle tests passing diff --git a/.gsd/milestones/M001/slices/S01/tasks/T04-PLAN.md b/.gsd/milestones/M001/slices/S01/tasks/T04-PLAN.md deleted file mode 100644 index b7d29c71a..000000000 --- a/.gsd/milestones/M001/slices/S01/tasks/T04-PLAN.md +++ /dev/null @@ -1,63 +0,0 @@ ---- -estimated_steps: 4 -estimated_files: 2 ---- - -# T04: Implement mergeSliceToMain with inferCommitType and full integration tests - -**Slice:** S01 — GitService Core Implementation -**Milestone:** M001 - -## Description - -The capstone task: implement `mergeSliceToMain()` which uses `inferCommitType()` to produce correct conventional commit types instead of hardcoding `feat` (fixing R009). Add full lifecycle integration tests that exercise create branch → work on branch → merge → verify commit type. Then run `npm run build` and `npm run test` to verify no regressions across the entire codebase. - -## Steps - -1. Implement `mergeSliceToMain(milestoneId, sliceId, sliceTitle)` method on `GitServiceImpl`: call `switchToMain()`, verify on main branch, verify slice branch exists, check commits ahead (`git rev-list --count`), `git merge --squash`, build commit message using `inferCommitType(sliceTitle)` → `${type}(${milestoneId}/${sliceId}): ${sliceTitle}`, commit with `JSON.stringify(message)`, delete branch with `git branch -D`. Return `MergeSliceResult`. -2. Add integration tests for full lifecycle: - - Create branch → make changes → commit → switchToMain → mergeSliceToMain with feature title → verify commit message starts with `feat(` - - Same lifecycle with "Fix broken config" title → verify commit message starts with `fix(` - - Same lifecycle with "Docs update" title → verify commit message starts with `docs(` - - Same lifecycle with "Refactor state management" title → verify commit message starts with `refactor(` -3. Add error case tests: - - `mergeSliceToMain` when not on main → throws - - `mergeSliceToMain` when branch doesn't exist → throws - - `mergeSliceToMain` when branch has no commits ahead → throws -4. Run `npm run build` and `npm run test` to verify no regressions. Fix any issues. - -## Must-Haves - -- [ ] `mergeSliceToMain()` uses `inferCommitType(sliceTitle)` for commit message type -- [ ] `mergeSliceToMain()` squash merges and deletes the slice branch -- [ ] `mergeSliceToMain()` returns correct `MergeSliceResult` -- [ ] Merge commits have correct conventional type based on slice title keywords -- [ ] Error thrown when not on main branch -- [ ] Error thrown when slice branch doesn't exist -- [ ] Error thrown when no commits ahead -- [ ] `npm run build` passes -- [ ] `npm run test` passes (all existing + new tests) - -## Verification - -- `node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/git-service.test.ts` — all tests pass -- `npm run build` — passes -- `npm run test` — passes (no regressions) - -## Observability Impact - -- Signals added/changed: None beyond existing. Merge commit messages are the primary observable output — they now carry inferred types. -- How a future agent inspects this: `git log --oneline` after merge shows the conventional commit type. Test output verifies all type inference paths. -- Failure state exposed: Descriptive errors for each failure mode (not on main, branch missing, no commits ahead) include branch names and current state. - -## Inputs - -- `src/resources/extensions/gsd/git-service.ts` — T03 output: full `GitServiceImpl` with branch lifecycle methods -- `src/resources/extensions/gsd/tests/git-service.test.ts` — T03 output: existing passing tests for staging, commit, branch lifecycle - -## Expected Output - -- `src/resources/extensions/gsd/git-service.ts` — complete with `mergeSliceToMain()`, all public methods implemented -- `src/resources/extensions/gsd/tests/git-service.test.ts` — complete test suite covering all methods, all passing -- `npm run build` — green -- `npm run test` — green (all existing + new tests) diff --git a/.gsd/milestones/M001/slices/S01/tasks/T04-SUMMARY.md b/.gsd/milestones/M001/slices/S01/tasks/T04-SUMMARY.md deleted file mode 100644 index 8c16e9189..000000000 --- a/.gsd/milestones/M001/slices/S01/tasks/T04-SUMMARY.md +++ /dev/null @@ -1,59 +0,0 @@ ---- -id: T04 -parent: S01 -milestone: M001 -provides: - - GitServiceImpl.mergeSliceToMain() method with inferCommitType integration -key_files: - - src/resources/extensions/gsd/git-service.ts - - src/resources/extensions/gsd/tests/git-service.test.ts -key_decisions: - - Added "docs" (plural) to COMMIT_TYPE_RULES keyword list — word-boundary regex prevented "Docs update" from matching "doc", consistent with T01 decision that added "tests" plural -patterns_established: - - mergeSliceToMain delegates to inferCommitType for commit type instead of hardcoding — conventional commit type is always data-driven from slice title keywords - - Squash merge workflow: verify on main → verify branch exists → verify commits ahead → git merge --squash → commit with inferred type → git branch -D -observability_surfaces: - - Merge commit messages carry inferred conventional types — inspect via `git log --oneline` after merge - - Descriptive errors for each failure mode include branch names and current state -duration: 8min -verification_result: passed -completed_at: 2026-03-12 -blocker_discovered: false ---- - -# T04: Implement mergeSliceToMain with inferCommitType and full integration tests - -**Added `mergeSliceToMain()` to GitServiceImpl with `inferCommitType` integration and full lifecycle tests — 113 tests passing, build green.** - -## What Happened - -Implemented `mergeSliceToMain(milestoneId, sliceId, sliceTitle)` on `GitServiceImpl` that squash-merges a slice branch into main using `inferCommitType(sliceTitle)` for the conventional commit type. The method validates three preconditions (on main, branch exists, commits ahead) before performing the merge, commit, and branch deletion. - -During testing, discovered that the slice title "Docs update" failed to match the `doc` keyword due to word-boundary regex (`\bdoc\b` doesn't match "docs"). Added "docs" as a plural keyword to `COMMIT_TYPE_RULES`, consistent with the T01 precedent of adding "tests" for the same reason. - -Added 7 new test groups: 4 full lifecycle integration tests (feat, fix, docs, refactor) each exercising create branch → commit work → switch to main → merge → verify commit type, plus 3 error case tests (not on main, branch missing, no commits ahead). - -## Verification - -- `node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/git-service.test.ts` — 113 passed, 0 failed ✓ -- `npm run build` — passes ✓ -- `npm run test` — 116 passed, 2 failed (pre-existing AGENTS.md sync failures in app-smoke.test.ts, unrelated to git-service) ✓ - -## Diagnostics - -- `git log --oneline` after merge shows conventional commit type in the squash-merge message -- Error messages from `mergeSliceToMain` include: current branch name, expected main branch, missing branch name, and commits-ahead count context -- Test file can be re-run at any time: `node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/git-service.test.ts` - -## Deviations - -- Added "docs" (plural) to `COMMIT_TYPE_RULES` keyword list — not in original plan but required for correct type inference on titles like "Docs update". Same pattern as T01's "tests" addition. - -## Known Issues - -- 2 pre-existing test failures in `src/tests/app-smoke.test.ts` (tests 49 and 52) related to AGENTS.md syncing — completely unrelated to git-service. - -## Files Created/Modified - -- `src/resources/extensions/gsd/git-service.ts` — Added `mergeSliceToMain()` method and "docs" keyword to COMMIT_TYPE_RULES -- `src/resources/extensions/gsd/tests/git-service.test.ts` — Added 22 new assertions across 7 test groups for merge lifecycle and error cases diff --git a/.gsd/milestones/M001/slices/S02/S02-PLAN.md b/.gsd/milestones/M001/slices/S02/S02-PLAN.md deleted file mode 100644 index 0812be9eb..000000000 --- a/.gsd/milestones/M001/slices/S02/S02-PLAN.md +++ /dev/null @@ -1,82 +0,0 @@ -# S02: Wire GitService into codebase - -**Goal:** All git-mutation functions in `worktree.ts` delegate to `GitServiceImpl`. `auto.ts` creates a `GitServiceImpl` instance and routes its git calls through it. `preferences.ts` exposes `git?: GitPreferences` with validation, merge, and documentation. - -**Demo:** `npm run build` passes. All three test suites pass: `worktree.test.ts`, `worktree-integration.test.ts`, `git-service.test.ts`. All 6+ consumers of `worktree.ts` continue to import and call functions without changes. - -## Must-Haves - -- All 10 `worktree.ts` exports preserved with identical signatures -- `worktree.ts` git-mutation functions (`getMainBranch`, `getCurrentBranch`, `ensureSliceBranch`, `autoCommitCurrentBranch`, `switchToMain`, `mergeSliceToMain`) delegate to `GitServiceImpl` internally -- `MergeSliceResult` re-exported via `export type` from `git-service.ts` (eliminate type duplication per D014) -- No circular dependency crash at module-evaluation time between `worktree.ts` and `git-service.ts` -- `auto.ts` creates `GitServiceImpl` instance with `basePath` and git preferences after `basePath` is set -- `auto.ts` callsites for `autoCommitCurrentBranch`, `ensureSliceBranch`, `switchToMain`, `mergeSliceToMain` route through GitService (via worktree.ts facade) -- `GSDPreferences` interface includes `git?: GitPreferences` field -- `validatePreferences()` validates git sub-fields -- `mergePreferences()` merges git preferences with override semantics -- `templates/preferences.md` documents git section -- `docs/preferences-reference.md` documents git preferences -- Existing tests pass without regressions - -## Proof Level - -- This slice proves: integration -- Real runtime required: no (existing test suites with temp git repos exercise the full contract) -- Human/UAT required: no - -## Verification - -- `node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/worktree.test.ts` — all pass -- `node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/worktree-integration.test.ts` — all pass -- `node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/git-service.test.ts` — all pass -- `npx tsc --noEmit` — clean (no errors) -- `npm run test` — same pass/fail as baseline (116 pass, 2 pre-existing failures) -- `grep -n 'import.*from.*worktree' src/resources/extensions/gsd/state.ts src/resources/extensions/gsd/workspace-index.ts src/resources/extensions/gsd/worktree-command.ts` — unchanged, still importing from worktree.ts - -## Observability / Diagnostics - -- Runtime signals: `mergeSliceToMain` now returns commit messages with inferred conventional types (via `inferCommitType`) instead of hardcoded `feat`. `console.error` warning from `smartStage()` fallback signals exclusion failure. -- Inspection surfaces: Re-run any of the three test suites to verify delegation is working. `git log --oneline` after merge shows inferred commit types. -- Failure visibility: `runGit` errors include full command, basePath, and stderr. Lazy `GitServiceImpl` construction errors surface at first call, not module load. -- Redaction constraints: none (no secrets involved) - -## Integration Closure - -- Upstream surfaces consumed: `git-service.ts` → `GitServiceImpl`, `GitPreferences`, `MergeSliceResult`, all public methods (from S01) -- New wiring introduced in this slice: `worktree.ts` facade delegates to `GitServiceImpl`; `auto.ts` creates `GitServiceImpl` instance from `basePath` + preferences; `preferences.ts` exposes `git` field in `GSDPreferences` -- What remains before the milestone is truly usable end-to-end: S03 (bug fixes), S04 (remove git from prompts), S05 (enhanced features), S06 (cleanup/archive) - -## Tasks - -- [x] **T01: Convert worktree.ts to thin facade delegating to GitServiceImpl** `est:45m` - - Why: Core integration task — all 6+ consumers depend on worktree.ts exports being stable while internals switch to GitServiceImpl. Satisfies R005 (facade delegation) and R009 (inferCommitType replaces hardcoded feat). - - Files: `src/resources/extensions/gsd/worktree.ts`, `src/resources/extensions/gsd/tests/worktree.test.ts`, `src/resources/extensions/gsd/tests/worktree-integration.test.ts` - - Do: Import `GitServiceImpl`, `GitPreferences`, and re-export `MergeSliceResult` via `export type` (per D014) from `git-service.ts`. Add lazy `GitServiceImpl` cache with basePath-change guard. Convert 6 git-mutation functions to delegate. Remove unused private `branchExists` and `runGit`. Keep 4 pure functions and query functions unchanged. Run tests and fix any assertion mismatches. - - Verify: All three test suites pass. `npx tsc --noEmit` clean. No consumer import changes needed. - - Done when: `worktree.ts` delegates to `GitServiceImpl` for all git-mutation functions, all tests green, build clean. - -- [x] **T02: Wire auto.ts to use GitServiceImpl via worktree.ts facade** `est:30m` - - Why: auto.ts is the primary orchestrator — it must have a `GitServiceImpl` instance for future direct usage and verify all callsites work through the T01 facade. Satisfies R006. - - Files: `src/resources/extensions/gsd/auto.ts` - - Do: Import `GitServiceImpl` and `GitPreferences` from `git-service.ts`. Add module-level `gitService` variable. Initialize after `basePath` is set in `startAutoMode()` using git preferences from `loadEffectiveGSDPreferences()`. Keep bootstrap git calls and idle detection inline per spec. Verify build and tests. - - Verify: `npx tsc --noEmit` clean. `npm run test` same baseline. `grep -c 'new GitServiceImpl' src/resources/extensions/gsd/auto.ts` shows 1. - - Done when: auto.ts has a `GitServiceImpl` instance created from preferences, build clean, tests pass. - -- [x] **T03: Add git preferences to preferences.ts, template, and docs** `est:30m` - - Why: Preferences schema is needed for S05 features (auto_push, merge guards, snapshots) and must exist before those slices. Satisfies R004. - - Files: `src/resources/extensions/gsd/preferences.ts`, `src/resources/extensions/gsd/templates/preferences.md`, `src/resources/extensions/gsd/docs/preferences-reference.md` - - Do: Add `git?: GitPreferences` to `GSDPreferences` interface (import from `git-service.ts`). Add git validation in `validatePreferences()` for all 6 sub-fields. Add git merge in `mergePreferences()` with override-wins semantics. Add `git:` section to preferences template. Document git preferences in reference doc. - - Verify: `npx tsc --noEmit` clean. `npm run test` same baseline. `grep 'git.*GitPreferences' src/resources/extensions/gsd/preferences.ts` confirms field. - - Done when: `GSDPreferences.git` field exists with full validation, merge, template, and reference doc. - -## Files Likely Touched - -- `src/resources/extensions/gsd/worktree.ts` -- `src/resources/extensions/gsd/auto.ts` -- `src/resources/extensions/gsd/preferences.ts` -- `src/resources/extensions/gsd/git-service.ts` (minor — only if re-export adjustments needed) -- `src/resources/extensions/gsd/templates/preferences.md` -- `src/resources/extensions/gsd/docs/preferences-reference.md` -- `src/resources/extensions/gsd/tests/worktree.test.ts` (assertion updates if needed) -- `src/resources/extensions/gsd/tests/worktree-integration.test.ts` (assertion updates if needed) diff --git a/.gsd/milestones/M001/slices/S02/tasks/T01-PLAN.md b/.gsd/milestones/M001/slices/S02/tasks/T01-PLAN.md deleted file mode 100644 index cf8fd35aa..000000000 --- a/.gsd/milestones/M001/slices/S02/tasks/T01-PLAN.md +++ /dev/null @@ -1,66 +0,0 @@ ---- -estimated_steps: 5 -estimated_files: 3 ---- - -# T01: Convert worktree.ts to thin facade delegating to GitServiceImpl - -**Slice:** S02 — Wire GitService into codebase -**Milestone:** M001 - -## Description - -Convert `worktree.ts` from a standalone git-operations module into a thin facade that preserves all 10 exports but delegates git-mutation functions to `GitServiceImpl` from `git-service.ts`. Pure utility functions stay as-is. The `MergeSliceResult` type duplication is eliminated by re-exporting from `git-service.ts` using `export type` per D014. - -The circular dependency between `git-service.ts` (imports pure functions from `worktree.ts`) and `worktree.ts` (imports `GitServiceImpl` from `git-service.ts`) is handled by lazy construction: `GitServiceImpl` is only instantiated inside function bodies at call-time, never at module-evaluation time. The pure functions consumed by `git-service.ts` are available immediately at module evaluation. - -## Steps - -1. **Replace `MergeSliceResult` with type re-export:** Remove the local `MergeSliceResult` interface definition in `worktree.ts` and replace with `export type { MergeSliceResult } from "./git-service.ts"` (per D014 — type-only re-export avoids ESM cycle issues). Verify this doesn't break any consumer. - -2. **Add lazy GitServiceImpl cache:** Import `GitServiceImpl` from `git-service.ts`. Add a `let cachedService: GitServiceImpl | null = null` and a `function getService(basePath: string): GitServiceImpl` that creates or returns the cached instance with `{}` default prefs. Include a basePath-change guard that resets the cache if basePath changes between calls. - -3. **Convert 6 git-mutation functions to delegate:** Replace the bodies of `getMainBranch`, `getCurrentBranch`, `ensureSliceBranch`, `autoCommitCurrentBranch`, `switchToMain`, `mergeSliceToMain` with calls to the corresponding `GitServiceImpl` methods via `getService(basePath)`. Keep all function signatures identical. For `autoCommitCurrentBranch(basePath, unitType, unitId)`, map to `svc.autoCommit(unitType, unitId)`. For `mergeSliceToMain`, the GitServiceImpl version uses `inferCommitType` instead of hardcoded `feat` — this is the intended R009 fix. - -4. **Remove now-unused private code:** Delete the private `branchExists()` function and private `runGit()` function from `worktree.ts` — these are now handled by `GitServiceImpl` and `git-service.ts` respectively. Keep `isOnSliceBranch()` and `getActiveSliceBranch()` as-is (they use `getCurrentBranch` which now delegates). Keep all pure utility functions unchanged: `detectWorktreeName`, `getSliceBranchName`, `SLICE_BRANCH_RE`, `parseSliceBranch`. - -5. **Run all test suites and fix any assertion mismatches:** Run `worktree.test.ts`, `worktree-integration.test.ts`, and `git-service.test.ts`. The worktree tests don't assert on `mergedCommitMessage` format, so the switch from hardcoded `feat(` to `inferCommitType` should be transparent. Verify `npm run build` passes. - -## Must-Haves - -- [ ] All 10 `worktree.ts` exports preserved with identical type signatures -- [ ] `MergeSliceResult` re-exported via `export type` from `git-service.ts` (per D014, no local duplicate) -- [ ] Lazy `GitServiceImpl` construction (call-time, not module-evaluation) -- [ ] BasePath-change guard on cached service -- [ ] No circular dependency crash at import time -- [ ] `worktree.test.ts` passes — all assertions -- [ ] `worktree-integration.test.ts` passes — all assertions -- [ ] `git-service.test.ts` passes — all assertions -- [ ] `npx tsc --noEmit` clean - -## Verification - -- `node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/worktree.test.ts` — all pass -- `node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/worktree-integration.test.ts` — all pass -- `node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/git-service.test.ts` — all pass -- `npx tsc --noEmit` — no errors -- `grep -c 'GitServiceImpl' src/resources/extensions/gsd/worktree.ts` — at least 1 (confirms delegation wiring) -- `grep 'export type.*MergeSliceResult' src/resources/extensions/gsd/worktree.ts` — exactly 1 (type re-export per D014) - -## Observability Impact - -- Signals added/changed: `mergeSliceToMain` now returns commits with inferred conventional types (via `inferCommitType`) instead of hardcoded `feat`. This is an intentional R009 fix, not a regression. -- How a future agent inspects this: `git log --oneline` after merge shows the inferred commit type. Run worktree test suites to verify delegation. -- Failure state exposed: `runGit` errors from `git-service.ts` include command, basePath, and stderr. Lazy init errors surface at first function call, not import time. - -## Inputs - -- `src/resources/extensions/gsd/git-service.ts` — `GitServiceImpl` class, `GitPreferences` interface, `MergeSliceResult` interface (from S01) -- `src/resources/extensions/gsd/worktree.ts` — 10 exports, private `branchExists`, private `runGit`, `MergeSliceResult` duplicate -- D014 — `export type { MergeSliceResult }` decision - -## Expected Output - -- `src/resources/extensions/gsd/worktree.ts` — thin facade: imports `GitServiceImpl`, lazy cache, 6 functions delegate, 4 pure functions unchanged, `MergeSliceResult` type re-exported -- `src/resources/extensions/gsd/tests/worktree.test.ts` — unchanged (no assertion format changes needed) -- `src/resources/extensions/gsd/tests/worktree-integration.test.ts` — unchanged (no assertion format changes needed) diff --git a/.gsd/milestones/M001/slices/S02/tasks/T01-SUMMARY.md b/.gsd/milestones/M001/slices/S02/tasks/T01-SUMMARY.md deleted file mode 100644 index 50c85eaa9..000000000 --- a/.gsd/milestones/M001/slices/S02/tasks/T01-SUMMARY.md +++ /dev/null @@ -1,75 +0,0 @@ ---- -id: T01 -parent: S02 -milestone: M001 -provides: - - worktree.ts thin facade delegating git-mutation functions to GitServiceImpl - - MergeSliceResult type re-export from git-service.ts (D014) - - Lazy GitServiceImpl cache with basePath-change guard -key_files: - - src/resources/extensions/gsd/worktree.ts -key_decisions: - - Lazy construction via getService() avoids circular dependency crash at module-evaluation time - - isOnSliceBranch and getActiveSliceBranch kept as local functions using getCurrentBranch (which delegates) — no need to route through GitServiceImpl since they're pure regex checks on the branch name -patterns_established: - - Lazy singleton GitServiceImpl cache with basePath-change guard for facade modules -observability_surfaces: - - mergeSliceToMain now returns commits with inferred conventional types via inferCommitType (R009 fix) - - smartStage() console.error fallback warning surfaces exclusion failures - - runGit errors include command, basePath, and stderr -duration: 10m -verification_result: passed -completed_at: 2026-03-12 -blocker_discovered: false ---- - -# T01: Convert worktree.ts to thin facade delegating to GitServiceImpl - -**Converted worktree.ts from standalone git module to thin facade — all 13 exports preserved, 6 git-mutation functions delegate to GitServiceImpl via lazy cache, MergeSliceResult re-exported per D014.** - -## What Happened - -1. Removed local `MergeSliceResult` interface, replaced with `export type { MergeSliceResult } from "./git-service.ts"` (D014 type-only re-export). -2. Added lazy `GitServiceImpl` cache: `cachedService`/`cachedBasePath` module-level variables with `getService(basePath)` factory that resets on basePath change. Construction happens at call-time only, never at module evaluation — avoids circular dependency crash. -3. Converted 6 git-mutation functions to delegate: `getMainBranch`, `getCurrentBranch`, `ensureSliceBranch`, `autoCommitCurrentBranch` (maps to `svc.autoCommit`), `switchToMain`, `mergeSliceToMain`. All function signatures identical. -4. Removed private `runGit()` and `branchExists()` — now handled by `GitServiceImpl` internals. -5. Kept pure utility functions unchanged: `detectWorktreeName`, `getSliceBranchName`, `SLICE_BRANCH_RE`, `parseSliceBranch`. -6. Kept `isOnSliceBranch` and `getActiveSliceBranch` as local functions that use `getCurrentBranch` (which delegates). - -The circular dependency (git-service.ts imports pure functions from worktree.ts, worktree.ts imports GitServiceImpl from git-service.ts) works because GitServiceImpl is only instantiated inside function bodies at call-time, and the pure functions consumed by git-service.ts are available immediately at module evaluation. - -## Verification - -- `worktree.test.ts`: 56 passed, 0 failed ✓ -- `worktree-integration.test.ts`: 40 passed, 0 failed ✓ -- `git-service.test.ts`: 113 passed, 0 failed ✓ -- `npx tsc --noEmit`: clean, no errors ✓ -- `grep -c 'GitServiceImpl' worktree.ts` → 9 (confirms delegation wiring) ✓ -- `grep 'export type.*MergeSliceResult' worktree.ts` → exactly 1 match ✓ -- Consumer imports in state.ts, workspace-index.ts, worktree-command.ts unchanged ✓ - -### Slice-level verification (partial — T01 of 3): -- ✅ worktree.test.ts passes -- ✅ worktree-integration.test.ts passes -- ✅ git-service.test.ts passes -- ✅ npx tsc --noEmit clean -- ⏳ npm run test (full suite) — deferred to final task -- ✅ Consumer imports unchanged - -## Diagnostics - -- Run any of the three test suites to verify delegation is working -- `git log --oneline` after a merge shows inferred commit types (feat/fix/refactor/etc. instead of always feat) -- Lazy init errors surface at first function call, not import time — look for "git ... failed in ..." error messages - -## Deviations - -None. Plan executed as written. - -## Known Issues - -None. - -## Files Created/Modified - -- `src/resources/extensions/gsd/worktree.ts` — converted to thin facade: imports GitServiceImpl, lazy cache, 6 functions delegate, 4 pure functions unchanged, MergeSliceResult type re-exported diff --git a/.gsd/milestones/M001/slices/S02/tasks/T02-PLAN.md b/.gsd/milestones/M001/slices/S02/tasks/T02-PLAN.md deleted file mode 100644 index d9f54af58..000000000 --- a/.gsd/milestones/M001/slices/S02/tasks/T02-PLAN.md +++ /dev/null @@ -1,59 +0,0 @@ ---- -estimated_steps: 4 -estimated_files: 1 ---- - -# T02: Wire auto.ts to use GitServiceImpl via worktree.ts facade - -**Slice:** S02 — Wire GitService into codebase -**Milestone:** M001 - -## Description - -After T01 converts `worktree.ts` to a facade, all auto.ts calls already route through `GitServiceImpl` transparently. This task makes that explicit by creating a `GitServiceImpl` instance in auto.ts (for future direct usage by S05) and verifying all callsites work correctly through the facade. The instance is initialized after `basePath` is set, using git preferences from the preferences system. - -Bootstrap git calls (`git rev-parse --git-dir`, `git init`, `git add -A .gsd .gitignore && git commit`) and idle detection (`git status --porcelain`) remain inline per milestone success criteria. - -## Steps - -1. **Add GitServiceImpl import and module-level variable:** Import `GitServiceImpl` and `GitPreferences` from `./git-service.ts`. Add `let gitService: GitServiceImpl | null = null;` at module level near the existing `let basePath = ""` declaration. - -2. **Initialize GitServiceImpl after basePath is set:** In `startAutoMode()`, after `basePath = base` is set and after the git init/bootstrap block (line ~375), create the instance: `gitService = new GitServiceImpl(basePath, loadEffectiveGSDPreferences()?.preferences?.git ?? {})`. This must happen after the git repo is confirmed to exist. Note: `loadEffectiveGSDPreferences` is already imported in auto.ts. - -3. **Verify all callsites compile and route correctly:** The 8 imports from `worktree.ts` remain unchanged — `autoCommitCurrentBranch`, `ensureSliceBranch`, `getCurrentBranch`, `getMainBranch`, `getSliceBranchName`, `parseSliceBranch`, `switchToMain`, `mergeSliceToMain`. These now delegate through the T01 facade. No call signature changes needed. Remove `getSliceBranchName` from imports if unused (line 65 — imported but not called in auto.ts). - -4. **Verify build and tests pass:** Run `npx tsc --noEmit` and `npm run test` to confirm no regressions. The auto.ts changes are additive — existing behavior is preserved. - -## Must-Haves - -- [ ] `GitServiceImpl` imported from `git-service.ts` -- [ ] Module-level `gitService` variable initialized after `basePath` is set -- [ ] Instance created with git preferences from `loadEffectiveGSDPreferences()` -- [ ] Bootstrap git calls remain inline (lines 360-375) -- [ ] Idle detection `git status --porcelain` remains inline (line 2545) -- [ ] `npx tsc --noEmit` clean -- [ ] `npm run test` same baseline (116 pass, 2 pre-existing failures) - -## Verification - -- `npx tsc --noEmit` — no errors -- `npm run test` — same pass/fail as baseline -- `grep -c 'GitServiceImpl' src/resources/extensions/gsd/auto.ts` — at least 1 -- `grep -c 'new GitServiceImpl' src/resources/extensions/gsd/auto.ts` — exactly 1 - -## Observability Impact - -- Signals added/changed: None — this task adds the instance but doesn't change runtime behavior (facade handles delegation) -- How a future agent inspects this: `grep GitServiceImpl src/resources/extensions/gsd/auto.ts` to confirm the instance exists -- Failure state exposed: If preferences loading fails, `?? {}` ensures default empty prefs — no crash - -## Inputs - -- `src/resources/extensions/gsd/auto.ts` — orchestrator with 8 worktree.ts imports and git callsites -- `src/resources/extensions/gsd/worktree.ts` — T01 facade (all function calls now route to GitServiceImpl) -- `src/resources/extensions/gsd/git-service.ts` — `GitServiceImpl` constructor takes `(basePath, prefs?)` -- T01 completion — facade must be in place before this task verifies routing - -## Expected Output - -- `src/resources/extensions/gsd/auto.ts` — added `GitServiceImpl` import, module-level `gitService` variable, initialization in `startAutoMode()` after basePath is set diff --git a/.gsd/milestones/M001/slices/S02/tasks/T02-SUMMARY.md b/.gsd/milestones/M001/slices/S02/tasks/T02-SUMMARY.md deleted file mode 100644 index 88bde79a5..000000000 --- a/.gsd/milestones/M001/slices/S02/tasks/T02-SUMMARY.md +++ /dev/null @@ -1,62 +0,0 @@ ---- -id: T02 -parent: S02 -milestone: M001 -provides: - - GitServiceImpl instance in auto.ts initialized from basePath + git preferences - - Removed unused getSliceBranchName import from auto.ts -key_files: - - src/resources/extensions/gsd/auto.ts -key_decisions: - - Initialize gitService after bootstrap block (git init + .gsd mkdir) but before crash-lock check — ensures git repo exists - - Use `loadEffectiveGSDPreferences()?.preferences?.git ?? {}` for safe fallback to empty prefs -patterns_established: - - Module-level `gitService` variable with post-init construction in startAutoMode() -observability_surfaces: - - If preferences loading fails, `?? {}` ensures default empty prefs — no crash. gitService null before startAutoMode() runs. -duration: 8m -verification_result: passed -completed_at: 2026-03-12 -blocker_discovered: false ---- - -# T02: Wire auto.ts to use GitServiceImpl via worktree.ts facade - -**Added GitServiceImpl instance in auto.ts, initialized after basePath is set with git preferences from the preferences system. Removed unused `getSliceBranchName` import.** - -## What Happened - -Three changes to `auto.ts`: -1. Added imports for `GitServiceImpl` and `GitPreferences` from `git-service.ts` -2. Added module-level `let gitService: GitServiceImpl | null = null` next to the existing `basePath` declaration -3. Added initialization line after the bootstrap block in `startAutoMode()`: `gitService = new GitServiceImpl(basePath, loadEffectiveGSDPreferences()?.preferences?.git ?? {})` -4. Removed `getSliceBranchName` from the worktree.ts import list — it was imported but never used in auto.ts - -All 8 remaining worktree.ts imports continue to work through the T01 facade unchanged. Bootstrap git calls and idle detection remain inline per spec. - -## Verification - -- `npx tsc --noEmit` — clean, no errors -- `npm run test` — 116 pass, 2 pre-existing failures (matches baseline) -- `grep -c 'GitServiceImpl' auto.ts` → 4 (import, type import, variable declaration, instantiation) -- `grep -c 'new GitServiceImpl' auto.ts` → 1 (exactly one instantiation) -- All three test suites pass: worktree.test.ts, worktree-integration.test.ts, git-service.test.ts -- Consumer imports unchanged: state.ts, workspace-index.ts, worktree-command.ts still import from worktree.ts - -## Diagnostics - -- `grep GitServiceImpl src/resources/extensions/gsd/auto.ts` confirms instance exists -- `gitService` is null before `startAutoMode()` runs — any premature access will surface as TypeError -- Preferences fallback `?? {}` means no crash even if preferences file is missing or malformed - -## Deviations - -Removed unused `getSliceBranchName` import as noted in the plan (step 3). This is a cleanup, not a behavioral change. - -## Known Issues - -None. - -## Files Created/Modified - -- `src/resources/extensions/gsd/auto.ts` — Added GitServiceImpl import, module-level variable, initialization in startAutoMode(), removed unused getSliceBranchName import diff --git a/.gsd/milestones/M001/slices/S02/tasks/T03-PLAN.md b/.gsd/milestones/M001/slices/S02/tasks/T03-PLAN.md deleted file mode 100644 index 31c6eb280..000000000 --- a/.gsd/milestones/M001/slices/S02/tasks/T03-PLAN.md +++ /dev/null @@ -1,74 +0,0 @@ ---- -estimated_steps: 5 -estimated_files: 3 ---- - -# T03: Add git preferences to preferences.ts, template, and docs - -**Slice:** S02 — Wire GitService into codebase -**Milestone:** M001 - -## Description - -Add `git?: GitPreferences` to the `GSDPreferences` interface with full validation, merge semantics, documentation in the preferences template, and a reference doc entry. This enables all preference-gated git features in S05 (auto_push, merge guards, snapshots) via the existing preferences system. - -The `GitPreferences` type already exists in `git-service.ts` — this task imports it and wires it into the preferences infrastructure. - -## Steps - -1. **Add `git` field to `GSDPreferences` interface:** Import `GitPreferences` from `./git-service.ts`. Add `git?: GitPreferences` to the `GSDPreferences` interface alongside the existing fields. - -2. **Add git validation to `validatePreferences()`:** After the existing validation blocks, add a `git` section that validates each sub-field: - - `auto_push`: must be boolean if present - - `push_branches`: must be boolean if present - - `remote`: must be non-empty string if present - - `snapshots`: must be boolean if present - - `pre_merge_check`: must be boolean or the string `"auto"` if present - - `commit_type`: must be one of `feat`, `fix`, `refactor`, `docs`, `test`, `chore`, `perf`, `ci`, `build`, `style` if present - Collect errors for invalid values. Copy valid values to `validated.git`. - -3. **Add git merge to `mergePreferences()`:** Add `git: { ...(base.git ?? {}), ...(override.git ?? {}) }` to the merge return object. Override-wins for each field, same as `models` and `auto_supervisor`. - -4. **Update preferences template:** Add a `git:` section to `src/resources/extensions/gsd/templates/preferences.md` showing all available fields with sensible defaults (empty/unset). Place it after the existing sections in the frontmatter block. - -5. **Update preferences reference doc:** Add a "Git Preferences" section to `src/resources/extensions/gsd/docs/preferences-reference.md` documenting each field, its type, default value, and behavior. Include a YAML example. - -## Must-Haves - -- [ ] `GSDPreferences` interface includes `git?: GitPreferences` -- [ ] `GitPreferences` imported from `git-service.ts` -- [ ] `validatePreferences()` validates all 6 git sub-fields with type checking -- [ ] Invalid git values produce error messages (not silent drops) -- [ ] `mergePreferences()` merges git with override-wins semantics -- [ ] `templates/preferences.md` has `git:` section with all fields -- [ ] `docs/preferences-reference.md` documents git preferences -- [ ] `npx tsc --noEmit` clean -- [ ] `npm run test` same baseline - -## Verification - -- `npx tsc --noEmit` — no errors -- `npm run test` — same pass/fail as baseline -- `grep 'git.*GitPreferences' src/resources/extensions/gsd/preferences.ts` — confirms field exists -- `grep -c 'auto_push\|push_branches\|pre_merge_check\|snapshots\|commit_type' src/resources/extensions/gsd/preferences.ts` — at least 5 (validation of each field) -- `grep 'git:' src/resources/extensions/gsd/templates/preferences.md` — confirms template section -- `grep -i 'git preferences\|git:' src/resources/extensions/gsd/docs/preferences-reference.md` — confirms docs section - -## Observability Impact - -- Signals added/changed: None — this adds schema infrastructure only. Preferences are parsed at load time; invalid values produce error strings in the `validatePreferences` return. -- How a future agent inspects this: Call `loadEffectiveGSDPreferences()` and check `.preferences.git` for parsed values. Validation errors are in the return tuple. -- Failure state exposed: Invalid git preference values are reported as strings in the `errors` array from `validatePreferences()` — callers already log these. - -## Inputs - -- `src/resources/extensions/gsd/preferences.ts` — `GSDPreferences` interface, `validatePreferences()`, `mergePreferences()` -- `src/resources/extensions/gsd/git-service.ts` — `GitPreferences` interface -- `src/resources/extensions/gsd/templates/preferences.md` — existing template -- `src/resources/extensions/gsd/docs/preferences-reference.md` — existing reference doc - -## Expected Output - -- `src/resources/extensions/gsd/preferences.ts` — `git?: GitPreferences` in interface, validation logic, merge logic -- `src/resources/extensions/gsd/templates/preferences.md` — `git:` section added to frontmatter -- `src/resources/extensions/gsd/docs/preferences-reference.md` — git preferences documented with example diff --git a/.gsd/milestones/M001/slices/S03/S03-PLAN.md b/.gsd/milestones/M001/slices/S03/S03-PLAN.md deleted file mode 100644 index 1bf38b83d..000000000 --- a/.gsd/milestones/M001/slices/S03/S03-PLAN.md +++ /dev/null @@ -1,64 +0,0 @@ -# S03: Bug fixes and doc corrections - -**Goal:** Worktree create commits before fork, worktree merge uses deterministic helper by default (LLM fallback on conflict only), and README/GSD-WORKFLOW docs match actual branch deletion and commit behavior. -**Demo:** `npm run build` passes. `handleCreate()` calls `autoCommitCurrentBranch` before `createWorktree`. `handleMerge()` attempts `mergeWorktreeToMain()` first and only dispatches to LLM on conflict. README and GSD-WORKFLOW no longer claim branches are preserved or that checkpoint commits exist. - -## Must-Haves - -- `autoCommitCurrentBranch()` executes before `createWorktree()` in handleCreate (R007) -- `handleMerge()` attempts deterministic `mergeWorktreeToMain()` first; falls back to LLM dispatch only on merge conflict (R008) -- Deterministic merge path builds a conventional commit message using `inferCommitType()` (R008) -- On non-conflict errors in deterministic path, surface error to user rather than silently falling back to LLM (R008) -- README.md: branch example shows `(deleted after merge)` not `(preserved)`, removes "Per-task history preserved on branches" claim (R010) -- GSD-WORKFLOW.md: "Branch kept" → "Branch deleted after merge", checkpoint commit examples replaced with actual `chore(...)` auto-commit pattern, checkpoint row removed from commit conventions table, rollback table updated to remove checkpoint reference (R010) - -## Proof Level - -- This slice proves: integration -- Real runtime required: no (build + grep verification sufficient) -- Human/UAT required: no - -## Verification - -- `npm run build` — must pass (code changes compile) -- `npm run test` — existing tests still pass (4 pre-existing failures unrelated to this slice are acceptable) -- `grep -n 'autoCommitCurrentBranch' src/resources/extensions/gsd/worktree-command.ts` — autoCommit call appears before createWorktree call (lower line number) -- `grep -n 'mergeWorktreeToMain' src/resources/extensions/gsd/worktree-command.ts` — deterministic merge function is called in handleMerge -- `grep -c 'preserved' README.md` — returns 0 (no "preserved" claims about branches) -- `grep -c 'checkpoint' src/resources/GSD-WORKFLOW.md` — returns 0 (no checkpoint references) -- `grep -c 'Branch kept' src/resources/GSD-WORKFLOW.md` — returns 0 - -## Observability / Diagnostics - -- Runtime signals: None — these are bug fixes to CLI command handlers and doc corrections. No new runtime signals needed. -- Inspection surfaces: `git log --oneline` on main after a merge will show correct commit types (not always `feat`). The deterministic merge path produces a notification via `ctx.ui.notify`. -- Failure visibility: Deterministic merge failure surfaces error message to user via `ctx.ui.notify`. Conflict detection triggers LLM fallback with a notification explaining why. -- Redaction constraints: None - -## Integration Closure - -- Upstream surfaces consumed: `worktree-manager.ts` → `mergeWorktreeToMain()`, `worktree.ts` → `autoCommitCurrentBranch()`, `git-service.ts` → `inferCommitType()` -- New wiring introduced in this slice: `handleMerge()` now calls `mergeWorktreeToMain()` directly (deterministic path) before LLM fallback; `handleCreate()` ordering corrected -- What remains before the milestone is truly usable end-to-end: S04 (remove git commands from prompts), S05 (enhanced features — merge guards, snapshots, auto-push, rich commits), S06 (cleanup and archive) - -## Tasks - -- [x] **T01: Fix worktree create ordering and add deterministic merge dispatch** `est:25m` - - Why: R007 — new worktrees fork from uncommitted state (create before commit). R008 — merges always go through LLM even when deterministic helper exists and would succeed. - - Files: `src/resources/extensions/gsd/worktree-command.ts` - - Do: (1) In `handleCreate()`, move `autoCommitCurrentBranch()` call before `createWorktree()` call. (2) In `handleMerge()`, after confirmation and CWD switch to basePath, attempt `mergeWorktreeToMain(basePath, name, commitMessage)` first. Build commit message using `inferCommitType(name)` and worktree name. On success, notify user and return. On merge conflict (catch error, check for conflict indicators), fall back to existing LLM dispatch. On other errors, surface to user. (3) Import `mergeWorktreeToMain` from worktree-manager.ts and `inferCommitType` from git-service.ts. - - Verify: `npm run build` passes. `grep -n` confirms ordering. `grep` confirms `mergeWorktreeToMain` called in handleMerge. - - Done when: Build passes, autoCommit precedes createWorktree, deterministic merge attempted before LLM dispatch. - -- [x] **T02: Fix README and GSD-WORKFLOW doc claims** `est:15m` - - Why: R010 — docs claim branches are "preserved" and checkpoint commits exist, but actual code deletes branches after merge and produces `chore(...)` auto-commits instead of checkpoints. - - Files: `README.md`, `src/resources/GSD-WORKFLOW.md` - - Do: (1) README.md: change `gsd/M001/S01 (preserved)` to `gsd/M001/S01 (deleted after merge)`, remove "Per-task history preserved on branches" claim, update the main branch example to show inferred commit types not always `feat`. (2) GSD-WORKFLOW.md: change "Branch kept" to "Branch deleted after merge — squash commit is the permanent record", replace checkpoint commit examples with actual `chore(unitId): auto-commit after unitType` pattern, remove checkpoint row from commit conventions table, update rollback table to remove checkpoint reference, update squash merge commit example to show inferred types. - - Verify: `grep -c 'preserved' README.md` returns 0. `grep -c 'checkpoint' src/resources/GSD-WORKFLOW.md` returns 0. `grep -c 'Branch kept' src/resources/GSD-WORKFLOW.md` returns 0. - - Done when: All doc claims match actual code behavior. No "preserved", "checkpoint", or "Branch kept" in the corrected files. - -## Files Likely Touched - -- `src/resources/extensions/gsd/worktree-command.ts` -- `README.md` -- `src/resources/GSD-WORKFLOW.md` diff --git a/.gsd/milestones/M001/slices/S03/tasks/T01-PLAN.md b/.gsd/milestones/M001/slices/S03/tasks/T01-PLAN.md deleted file mode 100644 index d63805583..000000000 --- a/.gsd/milestones/M001/slices/S03/tasks/T01-PLAN.md +++ /dev/null @@ -1,54 +0,0 @@ ---- -estimated_steps: 5 -estimated_files: 1 ---- - -# T01: Fix worktree create ordering and add deterministic merge dispatch - -**Slice:** S03 — Bug fixes and doc corrections -**Milestone:** M001 - -## Description - -Fix two bugs in `worktree-command.ts`: (1) `handleCreate()` calls `createWorktree()` before `autoCommitCurrentBranch()`, meaning new worktrees fork from uncommitted HEAD — swap these so dirty state is committed first. (2) `handleMerge()` always dispatches to the LLM for merge even though `mergeWorktreeToMain()` exists as a deterministic helper — make the deterministic path the default, falling back to LLM only when a merge conflict occurs. - -## Steps - -1. **Add imports**: Import `mergeWorktreeToMain` from `./worktree-manager.js` and `inferCommitType` from `./git-service.js` at the top of `worktree-command.ts`. -2. **Fix handleCreate ordering (R007)**: Move the `autoCommitCurrentBranch(basePath, "worktree-switch", name)` call to occur BEFORE `createWorktree(mainBase, name)`. The `autoCommitCurrentBranch` uses `basePath` (current workspace), while `createWorktree` uses `mainBase` — no dependency conflict. -3. **Add deterministic merge path in handleMerge (R008)**: After the confirmation prompt and CWD switch (where `process.chdir(basePath)` already happens), insert a try/catch block that: (a) builds a conventional commit message using `inferCommitType(name)` and the worktree name as scope/description, (b) calls `mergeWorktreeToMain(basePath, name, commitMessage)`, (c) on success, notifies the user and returns early (skipping LLM dispatch). -4. **Add conflict fallback**: In the catch block for the deterministic merge, check if the error message indicates a merge conflict (contains "conflict" or "CONFLICT"). If so, run `git merge --abort` to clean up, then fall through to the existing LLM dispatch path with a notification that deterministic merge failed due to conflicts. If the error is NOT a conflict, surface it to the user and return (don't fall back to LLM for non-conflict errors). -5. **Verify**: Run `npm run build` to confirm compilation. Run `grep -n` to confirm ordering fix and presence of deterministic merge call. - -## Must-Haves - -- [ ] `autoCommitCurrentBranch()` call precedes `createWorktree()` call in `handleCreate()` -- [ ] `mergeWorktreeToMain()` attempted as first merge strategy in `handleMerge()` -- [ ] Commit message for deterministic merge uses `inferCommitType(name)` for the type -- [ ] Merge conflicts detected and handled: `git merge --abort` + LLM fallback -- [ ] Non-conflict errors surfaced to user, not silently swallowed -- [ ] `npm run build` passes - -## Verification - -- `npm run build` completes without errors -- `grep -n 'autoCommitCurrentBranch\|createWorktree' src/resources/extensions/gsd/worktree-command.ts` — autoCommit line number < createWorktree line number in handleCreate -- `grep -n 'mergeWorktreeToMain' src/resources/extensions/gsd/worktree-command.ts` — appears in handleMerge function -- `npm run test` — existing tests still pass (4 pre-existing failures acceptable) - -## Observability Impact - -- Signals added/changed: `ctx.ui.notify` messages for deterministic merge success, conflict fallback, and non-conflict errors -- How a future agent inspects this: Read the notification messages in the TUI after a merge operation -- Failure state exposed: Conflict detection triggers a visible notification before LLM fallback; non-conflict errors show the error message directly - -## Inputs - -- `src/resources/extensions/gsd/worktree-command.ts` — current handleCreate (lines 348-390) and handleMerge (lines 572-710) implementations -- `src/resources/extensions/gsd/worktree-manager.ts` — `mergeWorktreeToMain(basePath, name, commitMessage)` at line 379 -- `src/resources/extensions/gsd/git-service.ts` — `inferCommitType(sliceTitle)` at line 354 -- S03-RESEARCH.md — confirmed bug locations and existing function signatures - -## Expected Output - -- `src/resources/extensions/gsd/worktree-command.ts` — handleCreate has autoCommit before createWorktree; handleMerge attempts deterministic `mergeWorktreeToMain` before LLM dispatch with proper conflict handling diff --git a/.gsd/milestones/M001/slices/S03/tasks/T01-SUMMARY.md b/.gsd/milestones/M001/slices/S03/tasks/T01-SUMMARY.md deleted file mode 100644 index fe37db965..000000000 --- a/.gsd/milestones/M001/slices/S03/tasks/T01-SUMMARY.md +++ /dev/null @@ -1,70 +0,0 @@ ---- -id: T01 -parent: S03 -milestone: M001 -provides: - - handleCreate commits dirty state before forking worktree - - handleMerge uses deterministic squash-merge before LLM fallback -key_files: - - src/resources/extensions/gsd/worktree-command.ts -key_decisions: - - Deterministic merge builds commit message as `{inferCommitType(name)}({name}): merge worktree {name}` — uses worktree name both as scope and as input to type inference - - Non-conflict merge errors surface directly to user and do not fall back to LLM (only conflicts trigger fallback) -patterns_established: - - Deterministic-first with LLM fallback: try the fast/predictable path, catch specific failure class (conflicts), fall back to LLM only for that class -observability_surfaces: - - ctx.ui.notify messages distinguish deterministic merge success, conflict-triggered LLM fallback, and non-conflict errors -duration: 12m -verification_result: passed -completed_at: 2026-03-12 -blocker_discovered: false ---- - -# T01: Fix worktree create ordering and add deterministic merge dispatch - -**Fixed handleCreate to commit before forking and handleMerge to use deterministic squash-merge with conflict-aware LLM fallback.** - -## What Happened - -1. Added imports: `mergeWorktreeToMain` from worktree-manager.js, `inferCommitType` from git-service.js, `execSync` from node:child_process. -2. In `handleCreate()`, moved `autoCommitCurrentBranch()` call (now line 357) before `createWorktree()` call (now line 361). This ensures dirty working state is committed before the new worktree forks from HEAD. -3. In `handleMerge()`, after the confirmation prompt and CWD switch to basePath, inserted a deterministic merge attempt using `mergeWorktreeToMain(basePath, name, commitMessage)`. The commit message is built as `{inferCommitType(name)}({name}): merge worktree {name}`. -4. On success, the user is notified with file/line stats and the merge returns early (skipping LLM dispatch entirely). -5. On conflict (error message matches `/conflict/i`), `git merge --abort` cleans up the failed merge, a warning notification explains the fallback, and execution continues to the existing LLM dispatch path. -6. On non-conflict errors, the error is surfaced directly to the user and the function returns without LLM fallback. - -## Verification - -- `npm run build` — passes clean -- `npm run test` — 114 pass, 4 fail (pre-existing, unrelated) -- `grep -n` confirms `autoCommitCurrentBranch` at line 357 precedes `createWorktree` at line 361 in handleCreate -- `grep -n` confirms `mergeWorktreeToMain` called at line 676 inside handleMerge -- All 6 must-haves from the task plan verified - -### Slice-level checks (T01 scope): -- ✅ `npm run build` passes -- ✅ `npm run test` — 114/118 pass (4 pre-existing failures) -- ✅ autoCommitCurrentBranch line < createWorktree line in handleCreate -- ✅ mergeWorktreeToMain appears in handleMerge -- ⏳ `grep -c 'preserved' README.md` — not yet addressed (T02 scope) -- ⏳ `grep -c 'checkpoint' src/resources/GSD-WORKFLOW.md` — not yet addressed (T02 scope) -- ⏳ `grep -c 'Branch kept' src/resources/GSD-WORKFLOW.md` — not yet addressed (T02 scope) - -## Diagnostics - -After a `/worktree merge` operation, inspect the TUI notification messages: -- **Deterministic success**: shows "✓ Merged {name} → {mainBranch} (deterministic squash)" with commit message -- **Conflict fallback**: shows "Deterministic merge hit conflicts — falling back to LLM-guided merge." -- **Non-conflict error**: shows "Failed to merge: {error message}" - -## Deviations - -None. - -## Known Issues - -None. - -## Files Created/Modified - -- `src/resources/extensions/gsd/worktree-command.ts` — Reordered handleCreate (autoCommit before createWorktree), added deterministic merge path in handleMerge with conflict-aware LLM fallback, added imports for mergeWorktreeToMain, inferCommitType, and execSync diff --git a/.gsd/milestones/M001/slices/S03/tasks/T02-PLAN.md b/.gsd/milestones/M001/slices/S03/tasks/T02-PLAN.md deleted file mode 100644 index d001947b9..000000000 --- a/.gsd/milestones/M001/slices/S03/tasks/T02-PLAN.md +++ /dev/null @@ -1,56 +0,0 @@ ---- -estimated_steps: 4 -estimated_files: 2 ---- - -# T02: Fix README and GSD-WORKFLOW doc claims - -**Slice:** S03 — Bug fixes and doc corrections -**Milestone:** M001 - -## Description - -README.md and GSD-WORKFLOW.md contain incorrect claims about git branch lifecycle and commit patterns. README says branches are "preserved" — they're deleted after squash merge. GSD-WORKFLOW says "Branch kept", shows `checkpoint(...)` commit examples, and references checkpoint-based rollback — none of these exist in the actual code. Fix all doc claims to match actual behavior: branches deleted, auto-commits use `chore(...)` format, commit types are inferred (not always `feat`). - -## Steps - -1. **Fix README.md git strategy section**: (a) Change `gsd/M001/S01 (preserved)` to `gsd/M001/S01 (deleted after merge)`. (b) Replace "Per-task history preserved on branches" with accurate text about squash commits being the permanent record. (c) Update the main branch commit example to show varied commit types (not all `feat`) — e.g., `fix(M001/S03)`, `docs(M001/S04)` to demonstrate inference. -2. **Fix GSD-WORKFLOW.md branch lifecycle**: (a) Change step 4 "Branch kept — not deleted, available for per-task history" to "Branch deleted — squash commit on main is the permanent record". (b) Update the branch commit example to remove `checkpoint(...)` entries and replace with `chore(...)` auto-commit entries matching actual `autoCommit()` output. -3. **Fix GSD-WORKFLOW.md commit conventions table**: (a) Remove the `checkpoint(S01/T02): pre-task` row. (b) Add a row for auto-commits: `chore(S01/T02): auto-commit after task`. (c) Change the squash merge row from hardcoded `feat` to show that type is inferred: `type(M001/S01): ` with a note that type is inferred from title. -4. **Fix GSD-WORKFLOW.md rollback table**: Replace "Bad task → `git reset --hard` to checkpoint on the branch" with accurate rollback guidance that doesn't reference checkpoints — e.g., "Bad task → `git reset --hard HEAD~1` to previous commit on the branch". - -## Must-Haves - -- [ ] README.md: no occurrences of "preserved" in the git strategy section -- [ ] README.md: main branch example shows varied inferred commit types -- [ ] GSD-WORKFLOW.md: "Branch deleted" replaces "Branch kept" -- [ ] GSD-WORKFLOW.md: zero occurrences of "checkpoint" in any context -- [ ] GSD-WORKFLOW.md: commit conventions table uses `chore(...)` for auto-commits, inferred type for squash merge -- [ ] GSD-WORKFLOW.md: rollback table has no checkpoint reference - -## Verification - -- `grep -c 'preserved' README.md` returns 0 (in git strategy context — verify no false positives from other sections) -- `grep -c 'checkpoint' src/resources/GSD-WORKFLOW.md` returns 0 -- `grep -c 'Branch kept' src/resources/GSD-WORKFLOW.md` returns 0 -- `grep 'Branch deleted' src/resources/GSD-WORKFLOW.md` returns a match -- `grep 'chore(' src/resources/GSD-WORKFLOW.md` returns at least one match -- `npm run build` still passes (docs are bundled resources) - -## Observability Impact - -- Signals added/changed: None — pure documentation changes -- How a future agent inspects this: Read the doc files; grep for removed terms -- Failure state exposed: None - -## Inputs - -- `README.md` — current git strategy section at lines 253-270 -- `src/resources/GSD-WORKFLOW.md` — current git strategy section at lines 548-610 -- `git-service.ts` — actual behavior: `mergeSliceToMain` deletes branch, `autoCommit` produces `chore(...)` messages, `inferCommitType` determines squash merge type -- S03-RESEARCH.md — confirmed wrong claims and their line numbers - -## Expected Output - -- `README.md` — git strategy section reflects actual behavior (branches deleted, types inferred) -- `src/resources/GSD-WORKFLOW.md` — branch lifecycle, commit conventions, and rollback sections all match actual code behavior with zero checkpoint references diff --git a/.gsd/milestones/M001/slices/S03/tasks/T02-SUMMARY.md b/.gsd/milestones/M001/slices/S03/tasks/T02-SUMMARY.md deleted file mode 100644 index 98f79e3d1..000000000 --- a/.gsd/milestones/M001/slices/S03/tasks/T02-SUMMARY.md +++ /dev/null @@ -1,73 +0,0 @@ ---- -id: T02 -parent: S03 -milestone: M001 -provides: - - README.md git strategy section reflects actual behavior (branches deleted, commit types inferred) - - GSD-WORKFLOW.md branch lifecycle, commit conventions, and rollback sections match actual code -key_files: - - README.md - - src/resources/GSD-WORKFLOW.md -key_decisions: - - README "preserved" on line 125 refers to conversation state, not git branches — left untouched (not a false positive) -patterns_established: [] -observability_surfaces: - - none -duration: 5m -verification_result: passed -completed_at: 2026-03-12 -blocker_discovered: false ---- - -# T02: Fix README and GSD-WORKFLOW doc claims - -**Corrected all incorrect git strategy claims in README.md and GSD-WORKFLOW.md to match actual code behavior: branches deleted after merge, auto-commits use `chore(...)` format, commit types are inferred, no checkpoint commits exist.** - -## What Happened - -Four targeted doc corrections across two files: - -1. **README.md git strategy section**: Changed branch example from `(preserved)` to `(deleted after merge)`. Replaced "Per-task history preserved on branches" with accurate squash-commit-as-permanent-record language. Updated main branch example to show varied inferred commit types (`fix`, `docs`) instead of all `feat`. - -2. **GSD-WORKFLOW.md branch lifecycle**: Changed step 4 from "Branch kept" to "Branch deleted". Replaced `checkpoint(...)` commit examples with `chore(...)` auto-commit entries matching actual `autoCommit()` output. - -3. **GSD-WORKFLOW.md commit conventions table**: Removed `checkpoint(S01/T02): pre-task` row. Added `chore(S01/T02): auto-commit after task` row. Changed squash merge type from hardcoded `feat` to `type(M001/S01)` with note that type is inferred from title. - -4. **GSD-WORKFLOW.md rollback table**: Replaced checkpoint-based `git reset --hard` guidance with `git reset --hard HEAD~1` to previous commit. - -## Verification - -All must-haves confirmed: - -- `grep -n 'preserved' README.md` — only hit is line 125 (conversation context, not git strategy) ✅ -- README main branch example shows `fix(M001/S03)`, `docs(M001/S04)` — varied inferred types ✅ -- `grep -c 'checkpoint' src/resources/GSD-WORKFLOW.md` — returns 0 ✅ -- `grep -c 'Branch kept' src/resources/GSD-WORKFLOW.md` — returns 0 ✅ -- `grep 'Branch deleted' src/resources/GSD-WORKFLOW.md` — match found ✅ -- `grep 'chore(' src/resources/GSD-WORKFLOW.md` — 4 matches (3 branch examples + 1 conventions table) ✅ -- `npm run build` — passes ✅ - -Slice-level verification (final task): -- `npm run build` — passes ✅ -- autoCommit (line 357) before createWorktree (line 361) ✅ -- `mergeWorktreeToMain` called in handleMerge ✅ -- No "preserved" in git strategy context ✅ -- Zero "checkpoint" in GSD-WORKFLOW.md ✅ -- Zero "Branch kept" in GSD-WORKFLOW.md ✅ - -## Diagnostics - -None — pure documentation changes. Verify by reading the doc files or grepping for removed terms. - -## Deviations - -None. - -## Known Issues - -- Slice plan's `grep -c 'preserved' README.md` returns 1 not 0 because the word appears in an unrelated context (line 125: "conversation is preserved"). The task plan explicitly notes this as acceptable (not a false positive). The git strategy section itself has zero occurrences. - -## Files Created/Modified - -- `README.md` — Fixed git strategy section: branches deleted after merge, varied commit types -- `src/resources/GSD-WORKFLOW.md` — Fixed branch lifecycle, commit conventions, and rollback sections diff --git a/.gsd/milestones/M001/slices/S04/S04-PLAN.md b/.gsd/milestones/M001/slices/S04/S04-PLAN.md deleted file mode 100644 index 718c405c8..000000000 --- a/.gsd/milestones/M001/slices/S04/S04-PLAN.md +++ /dev/null @@ -1,59 +0,0 @@ -# S04: Remove git commands from prompts - -**Goal:** No raw git commands in LLM-facing prompts (except worktree-merge.md for conflict resolution). -**Demo:** `grep -rn 'git add\|git commit\|git update-index\|git hash-object' src/resources/extensions/gsd/prompts/ --include="*.md" | grep -v worktree-merge.md` returns zero results. - -## Must-Haves - -- execute-task.md step 16 replaced — no `git add`, `git commit`, `git update-index`, or `git hash-object` -- complete-slice.md step 10 replaced — no `git add` or `git commit`; preserves "do not squash-merge manually" context -- replan-slice.md step 6 replaced — no `git add` or `git commit` -- complete-milestone.md step 9 replaced — no `git add` or `git commit` -- worktree-merge.md untouched -- Step numbering remains sequential in all modified files -- `npm run build` passes -- `npm run test` passes - -## Proof Level - -- This slice proves: contract -- Real runtime required: no -- Human/UAT required: no - -## Verification - -- `grep -rn 'git add\|git commit\|git update-index\|git hash-object' src/resources/extensions/gsd/prompts/ --include="*.md" | grep -v worktree-merge.md` returns zero lines -- `npm run build` passes -- `npm run test` passes -- worktree-merge.md unchanged (diff shows no modifications) - -## Observability / Diagnostics - -Not applicable — this slice modifies static prompt templates with no runtime behavior. - -- Runtime signals: none -- Inspection surfaces: grep across prompt files -- Failure visibility: none -- Redaction constraints: none - -## Integration Closure - -- Upstream surfaces consumed: GitService auto-commit mechanism wired in S02 (auto.ts lines 498–504) — makes manual commit instructions in prompts redundant -- New wiring introduced in this slice: none -- What remains before the milestone is truly usable end-to-end: S05 (merge guards, snapshots, auto-push, rich commits), S06 (cleanup and archive) - -## Tasks - -- [x] **T01: Replace raw git commands in all four prompt files** `est:15m` - - Why: R011 — LLMs should not run git commands; the GitService auto-commit (wired in S02) makes these instructions redundant and harmful - - Files: `src/resources/extensions/gsd/prompts/execute-task.md`, `src/resources/extensions/gsd/prompts/complete-slice.md`, `src/resources/extensions/gsd/prompts/replan-slice.md`, `src/resources/extensions/gsd/prompts/complete-milestone.md` - - Do: Replace the git command text in each step with a declarative "system auto-commits" message. Keep step numbers intact. Preserve the "do not squash-merge manually" context in complete-slice.md. Do NOT touch worktree-merge.md. - - Verify: grep returns zero hits; build passes; test passes; worktree-merge.md has no diff - - Done when: all four verification commands pass - -## Files Likely Touched - -- `src/resources/extensions/gsd/prompts/execute-task.md` -- `src/resources/extensions/gsd/prompts/complete-slice.md` -- `src/resources/extensions/gsd/prompts/replan-slice.md` -- `src/resources/extensions/gsd/prompts/complete-milestone.md` diff --git a/.gsd/milestones/M001/slices/S04/tasks/T01-SUMMARY.md b/.gsd/milestones/M001/slices/S04/tasks/T01-SUMMARY.md deleted file mode 100644 index 206440166..000000000 --- a/.gsd/milestones/M001/slices/S04/tasks/T01-SUMMARY.md +++ /dev/null @@ -1,60 +0,0 @@ ---- -id: T01 -parent: S04 -milestone: M001 -provides: - - Raw git commands removed from all four LLM-facing prompt files -key_files: - - src/resources/extensions/gsd/prompts/execute-task.md - - src/resources/extensions/gsd/prompts/complete-slice.md - - src/resources/extensions/gsd/prompts/replan-slice.md - - src/resources/extensions/gsd/prompts/complete-milestone.md - - src/resources/extensions/gsd/tests/replan-slice.test.ts -key_decisions: - - Removed unused {{blockerTaskId}} template variable from replan-slice.md (was only used in the git commit message); kept the variable in auto.ts since it's still used in inlined context headings -patterns_established: - - Prompt steps that previously contained git commands now use declarative "system auto-commits" messages -observability_surfaces: - - none -duration: 8 minutes -verification_result: passed -completed_at: 2026-03-12 -blocker_discovered: false ---- - -# T01: Replace raw git commands in all four prompt files - -**Replaced git add/commit/update-index/hash-object instructions in execute-task.md, complete-slice.md, replan-slice.md, and complete-milestone.md with declarative auto-commit messages.** - -## What Happened - -Replaced the raw git command text in step 16 (execute-task.md), step 10 (complete-slice.md), step 6 (replan-slice.md), and step 9 (complete-milestone.md) with short declarative messages telling the LLM not to commit manually. The execute-task.md replacement also removed the `git update-index`/`git hash-object` workaround text. The complete-slice.md replacement preserves the squash-merge context. - -Discovered that the replan-slice test asserted `{{blockerTaskId}}` rendered in the prompt — that variable was only present in the removed git commit message line. Removed the stale `blockerTaskId` assertion and the corresponding template var from that test case. - -## Verification - -- `grep -rn 'git add\|git commit\|git update-index\|git hash-object' src/resources/extensions/gsd/prompts/ --include="*.md" | grep -v worktree-merge.md` → zero results ✓ -- `git diff src/resources/extensions/gsd/prompts/worktree-merge.md` → no changes ✓ -- `npm run build` → passes ✓ -- `npm run test` → 114 pass / 4 fail (same 4 pre-existing failures as before changes; replan-slice test now passes) ✓ - -## Diagnostics - -None — this task modifies static prompt templates with no runtime behavior. - -## Deviations - -Updated `src/resources/extensions/gsd/tests/replan-slice.test.ts` to remove the `blockerTaskId` assertion and template var from the prompt-variable-substitution test. This was not in the original plan but was necessary because removing `{{blockerTaskId}}` from the template broke the test. - -## Known Issues - -None. - -## Files Created/Modified - -- `src/resources/extensions/gsd/prompts/execute-task.md` — Step 16 replaced with auto-commit message -- `src/resources/extensions/gsd/prompts/complete-slice.md` — Step 10 replaced with auto-commit + merge message -- `src/resources/extensions/gsd/prompts/replan-slice.md` — Step 6 replaced with auto-commit message -- `src/resources/extensions/gsd/prompts/complete-milestone.md` — Step 9 replaced with auto-commit message -- `src/resources/extensions/gsd/tests/replan-slice.test.ts` — Removed stale blockerTaskId assertion diff --git a/.gsd/milestones/M001/slices/S05/S05-PLAN.md b/.gsd/milestones/M001/slices/S05/S05-PLAN.md deleted file mode 100644 index d2e4ece27..000000000 --- a/.gsd/milestones/M001/slices/S05/S05-PLAN.md +++ /dev/null @@ -1,79 +0,0 @@ -# S05: Enhanced features — merge guards, snapshots, auto-push, rich commits - -**Goal:** GitServiceImpl gains five enhanced features: pre-merge verification, snapshot refs, auto-push, rich squash commit messages, and remote fetch before branching. All preference-gated features work end-to-end through the worktree.ts facade. - -**Demo:** Unit tests pass proving: (1) `git for-each-ref refs/gsd/snapshots/` shows snapshot ref created before merge, (2) pre-merge check aborts merge on test failure, (3) `git log --oneline -1` on main after merge shows task list in commit body, (4) `git push` called when auto_push enabled, (5) `git fetch` called before new branch creation when remote exists. `npm run build` and `npm run test` pass. - -## Must-Haves - -- `createSnapshot(label)` creates `refs/gsd/snapshots/