feat(M001/S06): Cleanup and archive

This commit is contained in:
Lex Christopherson 2026-03-12 12:56:17 -06:00
parent d43322c45d
commit cd01a47461
10 changed files with 191 additions and 1223 deletions

Binary file not shown.

View file

@ -12,17 +12,17 @@ Deterministic, reliable git operations that keep main clean and working while ag
## Current State
GSD is a working, shipped product (v2.3.11). Branch-per-slice workflow works. Squash merge to trunk works. Worktree support works. The git strategy is architecturally sound but has a 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.
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: `worktree.ts` (slice branches), `worktree-manager.ts` (git worktrees), `worktree-command.ts` (CLI commands)
- Prompts: `prompts/*.md` — Handlebars-templated instructions for LLM units
- Preferences: `preferences.ts` — YAML frontmatter in markdown files
- Patterns: `execSync` for git, `runGit()` helper, `SKIP_PATHS` for diff filtering
- 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
@ -30,4 +30,4 @@ See `.gsd/REQUIREMENTS.md` for the explicit capability contract, requirement sta
## Milestone Sequence
- [ ] M001: Deterministic GitService — Centralize all git mechanics into a single service, fix bugs, remove git from prompts, add merge guards and recovery
- [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.

View file

@ -4,203 +4,207 @@ 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: active
- 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: unmapped
- Notes: Must reuse existing `runGit()` pattern from worktree.ts
- 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: active
- 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: unmapped
- 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: active
- 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: unmapped
- Notes: Default to `feat` when no keywords match
- 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: active
- 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: unmapped
- 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: active
- 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: unmapped
- 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: active
- Description: Replace inline git calls in auto.ts (git init, git add -A, autoCommitCurrentBranch, ensureSliceBranch, switchToMain, mergeSliceToMain) with GitService methods
- 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: unmapped
- Notes: git status --porcelain for idle detection and git rev-parse --git-dir for init check may remain inline
- 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: active
- Status: validated
- Description: Move autoCommitCurrentBranch() BEFORE createWorktree() in worktree-command.ts so new worktrees fork from committed state
- Why it matters: Currently new worktrees fork from pre-commit HEAD, missing the user's latest saved 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: unmapped
- Notes: worktree-command.ts ~line 352-357
- 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: active
- 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 isn't used as the default — merge currently goes through LLM unnecessarily
- 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: unmapped
- Notes: worktree-command.ts ~line 672-696, worktree-manager.ts lines 375-391
- 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: active
- Status: validated
- Description: Replace hardcoded `feat(...)` in mergeSliceToMain with inferCommitType() from GitService
- Why it matters: Bugfix slices, docs slices, refactor slices are all mislabeled as `feat`
- 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: unmapped
- Notes: worktree.ts line 258-260
- 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: active
- 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 currently claim behaviors the code doesn't implement — erodes trust
- 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: unmapped
- Notes: README.md lines 258-264, GSD-WORKFLOW.md lines 548-585
- 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: active
- 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: unmapped
- Notes: Keep worktree-merge.md as-is (conflict resolution needs LLM judgment)
- 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: active
- 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: unmapped
- 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: active
- Status: validated
- Description: Create refs/gsd/snapshots/<branch>/<timestamp> 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: unmapped
- 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: active
- 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: unmapped
- 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: active
- 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: unmapped
- 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: active
- 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: unmapped
- 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: active
- 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: unmapped
- 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: active
- 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: unmapped
- Notes: Delete rather than archive — git history preserves them
- Validation: All 4 files confirmed deleted. Git history preserves them.
- Notes: Deleted in S06
## Deferred
@ -309,24 +313,24 @@ This file is the explicit capability and coverage contract for the project.
| ID | Class | Status | Primary owner | Supporting | Proof |
|---|---|---|---|---|---|
| R001 | core-capability | active | M001/S01 | M001/S02 | unmapped |
| R002 | core-capability | active | M001/S01 | none | unmapped |
| R003 | quality-attribute | active | M001/S01 | none | unmapped |
| R004 | core-capability | active | M001/S02 | M001/S05 | unmapped |
| R005 | core-capability | active | M001/S02 | none | unmapped |
| R006 | core-capability | active | M001/S02 | none | unmapped |
| R007 | quality-attribute | active | M001/S03 | none | unmapped |
| R008 | quality-attribute | active | M001/S03 | none | unmapped |
| R009 | quality-attribute | active | M001/S01 | M001/S02 | unmapped |
| R010 | quality-attribute | active | M001/S03 | none | unmapped |
| R011 | core-capability | active | M001/S04 | none | unmapped |
| R012 | core-capability | active | M001/S05 | none | unmapped |
| R013 | core-capability | active | M001/S05 | none | unmapped |
| R014 | core-capability | active | M001/S05 | none | unmapped |
| R015 | quality-attribute | active | M001/S05 | none | unmapped |
| R016 | quality-attribute | active | M001/S05 | none | unmapped |
| R017 | quality-attribute | active | M001/S01 | M001/S05 | unmapped |
| R018 | quality-attribute | active | M001/S06 | none | unmapped |
| 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 |
@ -339,7 +343,9 @@ This file is the explicit capability and coverage contract for the project.
## Coverage Summary
- Active requirements: 18
- Active requirements: 0
- Validated requirements: 18
- Mapped to slices: 18
- Validated: 0
- Deferred: 3
- Out of scope: 6
- Unmapped active requirements: 0

View file

@ -67,7 +67,7 @@ This milestone is complete only when all are true:
- [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.
- [ ] **S06: Cleanup and archive** `risk:low` `depends:[S05]`
- [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

View file

@ -0,0 +1,55 @@
# S06: Cleanup and archive
**Goal:** Delete remaining design input files and verify doc consistency across the milestone.
**Demo:** `ONBOARDING-PLAN.md` no longer exists, no references to any of the 4 design input files remain in the codebase, docs match code behavior, prompts contain no raw git commands, and `npm run build` passes.
## Must-Haves
- `ONBOARDING-PLAN.md` deleted
- Zero references to `CODEX-GIT-SYNTHESIS.md`, `CLAUDE-GIT-SYNTHESIS.md`, `GEMINI-GIT-SYNTHESIS.md`, or `ONBOARDING-PLAN.md` in the codebase
- README.md branch lifecycle claims match code (deleted after merge, not preserved)
- GSD-WORKFLOW.md checkpoint/branch docs match code
- No raw git commands in execute-task.md, complete-slice.md, replan-slice.md, complete-milestone.md
- `npm run build` exits 0
## Proof Level
- This slice proves: final-assembly (milestone cleanup — all design inputs archived, all docs consistent)
- Real runtime required: no
- Human/UAT required: no
## Verification
- `test ! -f ONBOARDING-PLAN.md` — file deleted
- `test ! -f CODEX-GIT-SYNTHESIS.md && test ! -f CLAUDE-GIT-SYNTHESIS.md && test ! -f GEMINI-GIT-SYNTHESIS.md` — synthesis files stay deleted
- `rg -l 'CODEX-GIT-SYNTHESIS|CLAUDE-GIT-SYNTHESIS|GEMINI-GIT-SYNTHESIS|ONBOARDING-PLAN' --type md --glob '!.gsd/**' | wc -l` returns 0
- `rg 'git add|git commit|git checkout|git merge|git branch' 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 | wc -l` returns 0
- `npm run build` exits 0
## Observability / Diagnostics
Not applicable — this is a delete-only cleanup slice with no runtime surface, no new code, and no state changes.
- Runtime signals: none
- Inspection surfaces: none
- Failure visibility: none
- Redaction constraints: none
## Integration Closure
- Upstream surfaces consumed: S03 doc fixes (README, GSD-WORKFLOW), S04 prompt cleanup, S05 preference wiring
- New wiring introduced in this slice: none
- What remains before the milestone is truly usable end-to-end: nothing — this is the final slice
## Tasks
- [x] **T01: Delete ONBOARDING-PLAN.md and verify milestone doc consistency** `est:10m`
- Why: Only remaining design input file. Doc consistency check closes R018 and validates all prior slice doc work holds.
- Files: `ONBOARDING-PLAN.md`
- Do: Delete `ONBOARDING-PLAN.md`. Verify the 3 synthesis files remain deleted. Grep for references to all 4 files. Grep prompts for raw git commands. Verify README branch lifecycle claims. Verify GSD-WORKFLOW checkpoint docs. Run `npm run build`.
- Verify: All verification commands in the Verification section above pass.
- Done when: File deleted, zero references found, zero raw git commands in prompts, build passes.
## Files Likely Touched
- `ONBOARDING-PLAN.md` (deleted)

View file

@ -0,0 +1,53 @@
---
estimated_steps: 5
estimated_files: 1
---
# T01: Delete ONBOARDING-PLAN.md and verify milestone doc consistency
**Slice:** S06 — Cleanup and archive
**Milestone:** M001
## Description
Delete the last remaining design input file (`ONBOARDING-PLAN.md`) and run a comprehensive consistency check across all milestone documentation. This single task covers R018 (archive design input files) and validates that all prior slice work (S03 doc fixes, S04 prompt cleanup) remains intact.
## Steps
1. Delete `ONBOARDING-PLAN.md` from the repo root.
2. Verify all 4 design input files are gone: `CODEX-GIT-SYNTHESIS.md`, `CLAUDE-GIT-SYNTHESIS.md`, `GEMINI-GIT-SYNTHESIS.md`, `ONBOARDING-PLAN.md`.
3. Grep the codebase (excluding `.gsd/`) for any references to the 4 deleted files. Expect zero hits.
4. Grep prompts (`execute-task.md`, `complete-slice.md`, `replan-slice.md`, `complete-milestone.md`) for raw git commands (`git add`, `git commit`, `git checkout`, `git merge`, `git branch`). Expect zero hits.
5. Run `npm run build` and confirm exit 0.
## Must-Haves
- [ ] `ONBOARDING-PLAN.md` deleted
- [ ] Zero references to any of the 4 design input files in non-.gsd markdown
- [ ] Zero raw git commands in the 4 prompt files
- [ ] `npm run build` passes
## Verification
- `test ! -f ONBOARDING-PLAN.md && echo PASS || echo FAIL`
- `test ! -f CODEX-GIT-SYNTHESIS.md && test ! -f CLAUDE-GIT-SYNTHESIS.md && test ! -f GEMINI-GIT-SYNTHESIS.md && echo PASS || echo FAIL`
- `rg -l 'CODEX-GIT-SYNTHESIS|CLAUDE-GIT-SYNTHESIS|GEMINI-GIT-SYNTHESIS|ONBOARDING-PLAN' --type md --glob '!.gsd/**' | wc -l` returns 0
- `rg 'git add|git commit|git checkout|git merge|git branch' 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 | wc -l` returns 0
- `npm run build` exits 0
## Observability Impact
- Signals added/changed: None
- How a future agent inspects this: None — cleanup task with no runtime surface
- Failure state exposed: None
## Inputs
- `ONBOARDING-PLAN.md` — the file to delete
- S03 summary — confirmed README and GSD-WORKFLOW doc fixes landed
- S04 summary — confirmed prompt cleanup landed
## Expected Output
- `ONBOARDING-PLAN.md` — deleted
- All verification checks pass, confirming R018 is satisfied and milestone docs are consistent

View file

@ -1,693 +0,0 @@
# GSD2 Git Strategy: Cross-Model Synthesis
> Three AI models (Claude, Codex, Gemini) independently audited GSD2's git workflow and proposed improvements. This document synthesizes their findings into a single authoritative analysis: what GSD2 does, what's broken, what the best teams do, and exactly what to build.
---
## Source Audit Quality Assessment
| Model | Approach | Verdict |
|-------|----------|---------|
| **Codex** | Read every relevant source file. Cited specific line numbers. Found real bugs. Strongest architectural insight. | **Best audit. Primary source for architecture decisions.** |
| **Claude** | Thorough analysis with copy-paste-ready implementation code. Best structured for execution. | **Best audit for implementation specs. Secondary source.** |
| **Gemini** | No evidence of reading source code. No file paths or line numbers. Marketing language. | **Weakest audit. Two usable ideas extracted; rest discarded.** |
---
## Part 1: What GSD2 Does Today
All three audits agree on the current architecture. The ground truth:
### Core Git Files
| File | Role |
|------|------|
| `src/resources/extensions/gsd/worktree.ts` | Slice branch lifecycle: create, checkout, merge, delete |
| `src/resources/extensions/gsd/worktree-manager.ts` | Git worktree lifecycle: create, list, diff, merge, remove |
| `src/resources/extensions/gsd/auto.ts` | Orchestrator: ensures branches at dispatch, merges after slice completion |
| `src/resources/extensions/gsd/session-forensics.ts` | Crash recovery: captures git state for session restoration |
### Branch Naming
| Context | Pattern | Example |
|---------|---------|---------|
| Slice branch (main tree) | `gsd/<milestoneId>/<sliceId>` | `gsd/M001/S01` |
| Slice branch (worktree) | `gsd/<worktreeName>/<milestoneId>/<sliceId>` | `gsd/alpha/M001/S01` |
| Worktree base branch | `worktree/<name>` | `worktree/alpha` |
### What Works
All three audits confirm GSD2 is **already in the top tier** of agentic git implementations:
- **Branch-per-slice isolation** — each slice gets its own branch, main stays clean
- **Squash merge to trunk** — one commit per slice on main, individually revertable
- **Worktree support with namespace isolation** — parallel agents can't collide
- **Auto-commit safety nets** — dirty state never blocks branch operations
- **Merge guard in auto mode** — completed slices auto-merge before next dispatch
### What Does Not Exist
| Capability | Status |
|-----------|--------|
| `git push` | Zero remote operations anywhere in codebase |
| Pre-merge build/test verification | None — merge is blind |
| Git preferences/config surface | None — zero user-configurable git behavior |
| PR creation | None — local-only workflow |
| Commit type inference | None — everything is `feat(...)` |
| Git tags/releases | None |
| Commit signing | None |
| Stash operations | None — auto-commit philosophy instead |
---
## Part 2: Confirmed Bugs and Mismatches
These are real defects found across audits, verified against actual source code.
### Bug 1: Docs Say Branches Preserved; Code Deletes Them
**Found by**: Codex (with line numbers), Claude (without)
- README says `gsd/M001/S01 (preserved)``README.md` lines 258-264
- Workflow doc says "Branch kept" — `src/resources/GSD-WORKFLOW.md` lines 548-551
- Implementation calls `git branch -D` after squash merge — `worktree.ts` line 261
**Resolution**: Update docs to match behavior. Branches are deleted after merge. This is correct behavior (see Design Decision 2 below).
### Bug 2: Checkpoint Commits Are Documented but Not Enforced
**Found by**: Codex
- Workflow doc describes explicit checkpoint commits before each task — `GSD-WORKFLOW.md` lines 565-580
- No enforcement exists in auto mode or prompts
- System relies on the LLM remembering to commit and on broad fallback auto-commits
**Resolution**: Replace documented checkpoint model with hidden snapshot refs (see Priority 3 below).
### Bug 3: `git add -A` Stages Everything Indiscriminately
**Found by**: Codex
- `worktree.ts` lines 187-190 and 208-214 use `git add -A` as fallback
- Can accidentally commit unrelated user edits, generated files, partial experiments, dirt from failed attempts
**Resolution**: Implement scoped file ownership (see Priority 2 below).
### Bug 4: Squash Commit Type Is Always `feat`
**Found by**: Codex
- `worktree.ts` lines 258-260 hardcodes `feat(M###/S##): <slice title>`
- Bugfix slices, docs slices, refactor slices all mislabeled as `feat`
**Resolution**: Infer commit type from slice metadata (see Priority 5 below).
### Bug 5: Worktree Create Commits After Fork, Not Before
**Found by**: Codex
- `worktree-command.ts` lines 352-357: creates worktree first, then auto-commits dirty state
- New worktree forks from pre-commit HEAD rather than the user's saved state
**Resolution**: Swap ordering — commit dirty state before creating the worktree.
### Bug 6: Worktree Merge Uses LLM Instead of Existing Deterministic Helper
**Found by**: Codex
- Deterministic typed helper exists: `worktree-manager.ts` lines 375-391
- `/worktree merge` dispatches an LLM-driven flow instead: `worktree-command.ts` lines 672-696
**Resolution**: Use the deterministic helper as the default path. Fall back to LLM-mediated merge only for complex planning artifact reconciliation.
### Bug 7: Slice Branches Can Fork From Stale/Non-Trunk Base
**Found by**: Codex
- `worktree.ts` lines 161-170: may branch from current non-slice branch instead of repo default
- Added pragmatically (preserving planning artifacts on working branch) but violates trunk-first discipline
**Resolution**: When remote exists, fetch before branching. Always prefer true trunk HEAD as base.
---
## Part 3: What The Best Teams Do (2026 Consensus)
All three audits converge on the same industry picture. Disagreements are noted.
### Universal Agreement
| Practice | Status | GSD2 |
|----------|--------|------|
| Trunk-based development | Industry standard | **Already doing this** |
| Short-lived feature branches | Consensus winner | **Already doing this** (slice branches) |
| Squash merge to main | Standard for feature branches | **Already doing this** |
| GitFlow | Dead | **Already avoiding** |
| Permanent `develop` branch | Anti-pattern | **Already avoiding** |
| Pre-merge verification | Table stakes | **Not doing this** |
| Remote backup | Expected by professionals | **Not doing this** |
| Clean, parseable commit history | Universal expectation | **Partially — type is always `feat`** |
### Where Audits Disagree
| Topic | Codex | Claude | Gemini | Synthesis Verdict |
|-------|-------|--------|--------|-------------------|
| **Preserve merged branches** | Delete (correct) | Preserve (wrong) | Delete | **Delete.** The squash commit IS the record. Branches are work-in-progress scaffolding. Preserving them creates sprawl with near-zero debugging value — `git bisect` on main at feature granularity covers 99% of cases. |
| **Hidden snapshot refs** | Yes — `refs/gsd/snapshots/...` | Not proposed | Not proposed | **Yes.** Recovery points should be invisible infrastructure, not noisy checkpoint commits. |
| **Git operations in prompts vs code** | Move to deterministic code (critical) | Not identified as issue | Not identified | **Move to code.** This is the single most important architectural change. Git is deterministic; LLMs are probabilistic. Wrong trust boundary. |
| **Scoped file ownership** | Yes — track owned files per unit | Not proposed | Not proposed | **Yes.** `git add -A` in an agentic system is a liability. Commit only files the unit touched. |
| **Git Notes for metadata** | Not proposed | Not proposed | Yes — store task plans, verification in notes | **No.** Git Notes are fragile, poorly supported by most tools, don't survive typical push/pull workflows. Use commit trailers and GSD artifacts instead. |
| **Shadow worktrees as default** | Worktrees as automatic infrastructure | Not proposed | Yes — agent always works in shadow worktree | **Not as default.** Adds complexity for the common single-agent case. Auto-create worktrees when parallelism is detected, not by default. |
| **Stacked branches/PRs** | Advanced mode, opt-in | Not proposed | Proposed as core model | **Opt-in only.** Stacked changes are powerful for multi-agent and large refactors. They are over-engineering for a solo vibe coder doing one slice at a time. |
| **PR / merge queue awareness** | Yes — detect and participate in host policy | PR on milestone completion only | PR on "ship" command | **Codex has the right model.** Per-slice PRs when remote has protected trunk. Per-milestone PRs are too coarse. |
| **Feature flags** | Recommended for large features | Not proposed | Not proposed | **Out of scope for GSD's git layer.** Good practice, but GSD manages work orchestration, not application architecture. |
---
## Part 4: The GSD2 Git Philosophy
One sentence: **GSD2 is trunk-based by default, branch-per-slice always, verification-gated before merge, deterministic for every mechanical git operation, and policy-aware when a remote exists.**
### Five Design Rules
**Rule 1: Trunk is the source of truth.**
The repo's default branch is the integration branch. No `develop`. No shadow trunks. Every slice branches from it and merges back to it.
**Rule 2: Slice branches are the unit of work.**
The `gsd/M001/S01` pattern is the right abstraction. Branches are short-lived, isolated, and disposable after merge. The squash commit on main is the permanent record.
**Rule 3: Git mechanics are deterministic code, not LLM prose.**
The LLM decides what changed, why, and whether work is complete. The program decides what gets staged, committed, branched, merged, pushed, and cleaned up. This is the most important trust boundary in GSD2's architecture.
**Rule 4: Recovery is invisible infrastructure.**
Hidden snapshot refs (`refs/gsd/snapshots/...`) before risky operations. Auto-rollback on failure. No visible checkpoint commits cluttering branch history. Senior-grade recovery without novice-facing noise.
**Rule 5: Remote workflow is policy-aware.**
No remote? Local squash-to-main works perfectly. Remote with protected trunk? Detect it, push the branch, open the PR, participate in merge queue. The user's hosting setup determines the workflow, not manual configuration.
### Design Decisions (Resolved Disagreements)
**Decision 1: Delete merged slice branches.**
Codex is correct. The squash commit on main is the permanent record. Branch history is work-in-progress detail that rarely justifies the sprawl of keeping branches. Users who want preservation can opt in via preferences.
**Decision 2: No Git Notes.**
Gemini's proposal is rejected. Git Notes are fragile, poorly rendered by most tools, and have unreliable push/pull semantics. Commit message bodies (with task lists and branch references) plus GSD's own artifact files are more durable and more accessible.
**Decision 3: Worktrees are automatic infrastructure, not the default execution model.**
When GSD detects parallel agents, CI-wait scenarios, or risky spikes, it creates worktrees automatically. Single-agent execution in the main tree is fine for the common case. `/worktree` remains as an advanced manual escape hatch.
**Decision 4: Stacked branches are opt-in advanced mode.**
Auto-triggered when GSD detects benefit (many tasks, multiple independent sub-problems, high review surface). Not the default model for solo/vibe coder workflows.
---
## Part 5: Prioritized Implementation Plan
### P0: Fix The Trust Boundary (Ship-Blocking)
#### 1. Move Git Mechanics Out of Prompts Into Code
**Source**: Codex (primary architectural insight)
Create a deterministic Git service layer. The LLM never runs raw `git add`, `git commit`, `git checkout`, `git merge`, or `git push`. Instead:
```typescript
// New: src/resources/extensions/gsd/git-service.ts
interface GitService {
/** Cut a slice branch from fresh trunk HEAD */
beginSliceBranch(basePath: string, milestoneId: string, sliceId: string): SliceBranchResult;
/** Create hidden snapshot ref before risky operation */
createSnapshot(basePath: string, branch: string, unit: string): SnapshotRef;
/** Stage and commit only files owned by the current unit */
commitOwnedChanges(basePath: string, files: string[], message: string): CommitResult;
/** Park unrelated dirty files safely (stash or WIP branch) */
parkForeignDirtyState(basePath: string, ownedFiles: string[]): ParkResult;
/** Run merge guard, squash merge, optionally push and PR */
completeSliceMerge(basePath: string, options: MergeOptions): MergeResult;
/** Rollback to snapshot ref */
rollbackToSnapshot(basePath: string, ref: SnapshotRef): void;
}
```
**Files to modify**:
- `src/resources/extensions/gsd/worktree.ts` — extract git operations into service
- `src/resources/extensions/gsd/auto.ts` — call service instead of inline git
- `src/resources/extensions/gsd/prompts/execute-task.md` — remove `git add -A && git commit` instructions
- `src/resources/extensions/gsd/prompts/complete-slice.md` — remove raw git instructions
- `src/resources/extensions/gsd/prompts/replan-slice.md` — remove raw git instructions
**What the LLM provides to the service**: a commit message string and a "work complete" boolean. The service handles everything else.
#### 2. Replace `git add -A` With Scoped File Ownership
**Source**: Codex
Track which files a unit has created or modified. Commit only those files. If unrelated dirty files exist, park them.
```typescript
interface UnitFileOwnership {
/** Files the agent created or modified during this unit */
owned: string[];
/** GSD bookkeeping files (always allowed) */
bookkeeping: string[];
}
function commitOwnedChanges(basePath: string, ownership: UnitFileOwnership, message: string): void {
const allOwned = [...ownership.owned, ...ownership.bookkeeping];
// Check for foreign dirty files
const allDirty = getDirtyFiles(basePath);
const foreign = allDirty.filter(f => !allOwned.includes(f));
if (foreign.length > 0) {
parkForeignDirtyState(basePath, foreign);
}
// Stage only owned files
for (const file of allOwned) {
runGit(basePath, ["add", file]);
}
runGit(basePath, ["commit", "-m", message]);
}
```
**Fallback**: If ownership tracking fails or the unit didn't report files, fall back to `git add -A` with a warning logged. Pragmatism over purity — the system should never block on a tracking failure.
#### 3. Replace Checkpoint Commits With Hidden Snapshot Refs
**Source**: Codex
```typescript
function createSnapshot(basePath: string, branch: string, unit: string): string {
const timestamp = Date.now();
const refName = `refs/gsd/snapshots/${branch}/${unit}/${timestamp}`;
const head = runGit(basePath, ["rev-parse", "HEAD"]).trim();
runGit(basePath, ["update-ref", refName, head]);
return refName;
}
function rollbackToSnapshot(basePath: string, ref: string): void {
const target = runGit(basePath, ["rev-parse", ref]).trim();
runGit(basePath, ["reset", "--hard", target]);
}
function pruneOldSnapshots(basePath: string, maxAge: number = 7 * 24 * 60 * 60 * 1000): void {
// Delete snapshot refs older than maxAge
// Implementation: list refs/gsd/snapshots/**, parse timestamps, delete old ones
}
```
**When to snapshot**: before each task execution, before merge, before any destructive operation.
**When to prune**: on `gsd:cleanup`, on milestone completion, or after 7 days.
### P0.5: Fix Confirmed Bugs
#### 4. Fix Worktree Create Ordering
**Source**: Codex (`worktree-command.ts` lines 352-357)
Swap the order: auto-commit dirty state **before** creating the worktree, so the new worktree forks from the committed state.
#### 5. Use Deterministic Worktree Merge Helper
**Source**: Codex (`worktree-manager.ts` lines 375-391 vs `worktree-command.ts` lines 672-696)
Wire `/worktree merge` to use the existing typed helper as the default path. Keep the LLM-mediated path as a fallback for cases with complex planning artifact reconciliation.
#### 6. Align Docs With Behavior
**Source**: Codex
Fix mismatches in README.md and GSD-WORKFLOW.md:
- Branch preservation: docs say preserved, code deletes → update docs to say deleted
- Checkpoint commits: docs promise them, code doesn't enforce → update docs to describe snapshot refs
- Merge behavior: document exact squash merge semantics
### P1: Merge Guards and Commit Quality
#### 7. Pre-Merge Verification (Merge Guards)
**Source**: Claude (implementation), Codex (framing)
Before committing a squash merge to main, run a verification command. If it fails, abort the merge and return to the slice branch.
```typescript
function detectMergeGuardCommand(basePath: string): string | null {
// package.json: prefer typecheck + test, fall back to test, fall back to build
const pkgPath = join(basePath, "package.json");
if (existsSync(pkgPath)) {
const pkg = JSON.parse(readFileSync(pkgPath, "utf-8"));
const scripts = pkg.scripts ?? {};
if (scripts.typecheck && scripts.test) return "npm run typecheck && npm run test";
if (scripts.test) return "npm run test";
if (scripts.build) return "npm run build";
}
// Cargo.toml → cargo test
if (existsSync(join(basePath, "Cargo.toml"))) return "cargo test";
// Makefile → make test
if (existsSync(join(basePath, "Makefile"))) return "make test";
// pyproject.toml → pytest
if (existsSync(join(basePath, "pyproject.toml"))) return "python -m pytest";
return null; // No tests detected — skip (zero friction for vibe coders)
}
```
**Merge flow with guard**:
1. `git merge --squash <branch>` (stages changes, does not commit)
2. Run merge guard command
3. On success: `git commit`
4. On failure: `git reset --hard HEAD`, throw error, agent fixes on slice branch
**Preference**: `git.merge_guard: "auto" | "never" | "<custom command>"`
**Default**: `"auto"` (detect from project, skip if nothing found)
#### 8. Infer Commit Type From Slice Metadata
**Source**: Codex
Replace hardcoded `feat(M###/S##)` with type inference:
```typescript
function inferCommitType(sliceTitle: string, sliceMetadata?: SliceMetadata): string {
// Check explicit metadata first
if (sliceMetadata?.type) return sliceMetadata.type;
// Infer from title keywords
const title = sliceTitle.toLowerCase();
if (title.match(/\bfix(es|ed|ing)?\b|\bbug\b|\bpatch\b/)) return "fix";
if (title.match(/\brefactor\b|\bcleanup\b|\brestructure\b/)) return "refactor";
if (title.match(/\bdoc(s|umentation)?\b|\breadme\b/)) return "docs";
if (title.match(/\btest(s|ing)?\b|\bspec\b/)) return "test";
if (title.match(/\bchore\b|\bdep(s|endencies)?\b|\bbump\b|\bci\b/)) return "chore";
return "feat"; // Default
}
```
#### 9. Richer Squash Commit Messages
**Source**: Claude (implementation)
```
fix(M001/S03): resolve race condition in websocket handler
Tasks:
- T01: identify root cause in connection pool
- T02: implement mutex guard on shared state
- T03: add regression test for concurrent connections
Branch: gsd/M001/S03
```
The commit body includes:
- Task list extracted from branch commit history
- Branch reference (even though branch is deleted, the ref is useful for forensics)
- Commit type inferred from slice metadata
### P2: Remote Workflow and Preferences
#### 10. Git Preferences Schema
**Source**: Claude (schema), Codex (policy-awareness framing)
```typescript
interface GSDGitPreferences {
/** Pre-merge verification. Default: "auto" (detect from project). */
merge_guard?: "auto" | "never" | string;
/** Push main to remote after slice merge. Default: false. */
auto_push?: boolean;
/** Push slice branches during work (backup). Default: false. */
push_branches?: boolean;
/** Remote name. Default: "origin". */
remote?: string;
/** Create git tag on milestone completion. Default: true. */
tag_milestones?: boolean;
/** Create PR per slice when remote has protected trunk. Default: false. */
create_pr?: boolean;
}
```
#### 11. Optional Remote Push
**Source**: Claude (implementation), Codex (framing)
```typescript
// After successful slice merge to main:
if (gitPrefs.auto_push) {
const remote = gitPrefs.remote ?? "origin";
runGit(basePath, ["push", remote, mainBranch], { allowFailure: true });
}
// During slice execution (backup):
if (gitPrefs.push_branches) {
const remote = gitPrefs.remote ?? "origin";
runGit(basePath, ["push", "-u", remote, sliceBranch], { allowFailure: true });
}
```
**Default**: `false` for both. Vibe coders never see remote operations. Senior engineers opt in with one line in preferences.
#### 12. Remote-Aware Branch Freshness
**Source**: Codex
When a remote exists and `auto_push` is enabled:
- `git fetch --prune` before cutting a new slice branch
- Base from true latest default branch HEAD
- Eliminates "branched from stale main" class of problems
#### 13. Policy-Aware PR Workflow
**Source**: Codex (architecture), Claude (PR creation)
When `create_pr` is enabled:
1. Push slice branch
2. Create PR via `gh pr create` (graceful fallback if `gh` not installed)
3. If merge queue available, enable auto-merge
4. Mark slice complete only after merge to trunk succeeds
For solo developers: skip PR, squash merge locally (default behavior).
#### 14. Milestone Tags
**Source**: Claude
```typescript
function tagMilestone(basePath: string, milestoneId: string, title: string): void {
runGit(basePath, ["tag", "-a", milestoneId, "-m", `Milestone ${milestoneId}: ${title}`]);
if (gitPrefs.auto_push) {
runGit(basePath, ["push", gitPrefs.remote ?? "origin", milestoneId], { allowFailure: true });
}
}
```
Enables `git describe`, changelog generation, and clear release markers.
---
## Part 6: User Experience By Persona
### Vibe Coder (Zero Config)
What they experience:
- Say what to build → GSD isolates work on a branch automatically
- Main stays clean with readable one-line-per-feature history
- If tests exist, they run before merge (auto-detected)
- If something breaks, GSD rolls back invisibly using snapshot refs
- No git knowledge required. No configuration. No ceremony.
What they never see:
- Branch creation/deletion
- Checkout operations
- Merge mechanics
- Stash juggling
- Remote operations
### Senior Engineer (Opt-In)
Adds to `.gsd/preferences.yaml`:
```yaml
git:
auto_push: true
tag_milestones: true
```
What they experience on top of the vibe coder defaults:
- Work pushed to remote after each slice merge (backup + visibility)
- Milestone tags for release marking
- Typed commit messages (`fix`, `refactor`, `docs` — not always `feat`)
- Rich commit bodies with task lists
- Snapshot refs available for manual forensics if needed
- Deterministic git mechanics they can inspect and trust
### Team Lead (Full Config)
```yaml
git:
auto_push: true
push_branches: true
tag_milestones: true
create_pr: true
merge_guard: "npm run typecheck && npm run test && npm run lint"
```
What they experience on top of senior engineer:
- Slice branches pushed to remote during work (team visibility)
- PRs created per slice (review gate)
- Custom merge guard command matching CI requirements
- Merge queue participation when available
### Progressive Disclosure
1. **Install GSD2** → git workflow works automatically, zero config
2. **Curious**`git log` shows clean, typed, task-annotated history
3. **Serious** → enable `auto_push` for remote backup
4. **Team** → enable `create_pr` for review gates
---
## Part 7: Explicitly Rejected Approaches
| Approach | Why Rejected | Source of Rejection |
|----------|-------------|-------------------|
| GitFlow / permanent `develop` | Dead pattern. Enterprise ceremony with no value for trunk-based agentic workflows. | All three audits |
| Rebase workflows | Squash merge is cleaner, simpler, industry standard for feature branches. Interactive rebase requires human intervention. | Claude, Codex |
| GPG commit signing | Adds friction, zero value when the agent is the committer. Opt-in only. | Claude |
| Commit hooks (husky/lint-staged) | The agent runs verification explicitly via merge guards. Hooks add complexity without value in agentic context. | Claude |
| Preserving merged slice branches by default | Squash commit is the permanent record. Branch sprawl from preserved branches provides near-zero debugging value. Opt-in only. | Codex (Claude disagrees) |
| Git Notes for metadata | Fragile, poorly supported by most tools, unreliable push/pull semantics. Use commit trailers and GSD artifacts. | Rejected from Gemini's proposal |
| Shadow worktrees as default execution | Over-engineering for common single-agent case. Auto-create when parallelism detected. | Modified from Gemini's proposal |
| Cross-slice AI-driven rebase | Science fiction. Merge conflicts require deterministic resolution or human intervention, not LLM improvisation. | Rejected from Gemini's proposal |
| "Agentic Version Control" as a concept | Marketing term, not engineering. GSD2 uses standard git with smart automation. | Rejected from Gemini's framing |
| CI/CD integration | Deployment is the user's concern. Merge guards handle "is it broken?" GSD manages work, not infrastructure. | Claude |
| Monorepo tooling | Out of scope. GSD manages work orchestration, not build systems. | Claude |
| Feature flags as GSD feature | Good practice for application architecture, but out of scope for GSD's git layer. | Modified from Codex's proposal |
---
## Part 8: The Slice Lifecycle (Target State)
### Standard Flow (Local)
```
1. Fetch remote state (if configured)
2. Cut gsd/M001/S03 from fresh trunk HEAD
3. Create hidden snapshot ref
4. Execute task work
5. Commit only owned files with typed commit message
6. Repeat steps 3-5 for each task
7. Run slice verification (merge guard)
8. Squash merge to trunk
9. Delete slice branch
10. Push main (if configured)
11. Tag milestone (if completing milestone)
```
### Standard Flow (With Protected Remote)
```
1. Fetch and prune remote state
2. Cut gsd/M001/S03 from fresh trunk HEAD
3. Create hidden snapshot ref
4. Execute task work
5. Commit only owned files with typed commit message
6. Push slice branch (if configured)
7. Repeat steps 3-6 for each task
8. Run local verification
9. Push branch, create/update PR
10. Enable auto-merge or join merge queue
11. Wait for merge to succeed
12. Mark slice complete
13. Delete local and remote slice branch
```
### Failure Recovery
```
1. Detect failure (build error, test failure, merge conflict)
2. Rollback to most recent snapshot ref
3. Preserve failure context in GSD artifacts
4. Return to slice branch for agent to fix
5. If repeated failure: stop, surface exact issue, wait for human input
```
### Parallel Execution
```
1. Detect independent parallel work opportunity
2. Auto-create worktree for parallel stream
3. Execute parallel stream in worktree
4. Merge back deterministically (squash to trunk)
5. Remove worktree
```
---
## Part 9: What Main History Looks Like (Target State)
```
* a1b2c3d (tag: M001) chore(M001/S05): final cleanup and docs
|
| Tasks:
| - T01: update API documentation
| - T02: remove deprecated endpoints
| Branch: gsd/M001/S05
|
* d4e5f6a fix(M001/S04): resolve race condition in websocket handler
|
| Tasks:
| - T01: identify root cause in connection pool
| - T02: implement mutex guard on shared state
| - T03: add regression test
| Branch: gsd/M001/S04
|
* 7g8h9i0 feat(M001/S03): real-time notification system
|
| Tasks:
| - T01: websocket server setup
| - T02: client subscription manager
| - T03: push notification integration
| Branch: gsd/M001/S03
|
* j1k2l3m feat(M001/S02): user authentication flow
* n4o5p6q feat(M001/S01): project scaffold and database schema
```
Readable. Typed. Filterable. Bisectable. Revertable. Self-documenting.
---
## Part 10: Implementation Sequence
| Priority | Change | Effort | Impact |
|----------|--------|--------|--------|
| **P0.1** | Git service layer (move mechanics out of prompts) | Medium | Foundational — enables everything else |
| **P0.2** | Scoped file ownership (replace `git add -A`) | Medium | Eliminates accidental commits |
| **P0.3** | Hidden snapshot refs (replace checkpoint commits) | Small | Clean branch history + reliable recovery |
| **P0.5a** | Fix worktree create ordering | Trivial | Bug fix |
| **P0.5b** | Use deterministic worktree merge helper | Small | Bug fix |
| **P0.5c** | Align docs with behavior | Small | Trust |
| **P1.1** | Merge guards with auto-detect | Small | Main never breaks silently |
| **P1.2** | Infer commit type from slice metadata | Small | Accurate history |
| **P1.3** | Richer squash commit messages | Small | Self-documenting history |
| **P2.1** | Git preferences schema | Small | Enables all opt-in features |
| **P2.2** | Optional remote push | Small | Backup + visibility |
| **P2.3** | Remote-aware branch freshness | Small | Eliminates stale-main branching |
| **P2.4** | Policy-aware PR workflow | Medium | Team workflows |
| **P2.5** | Milestone tags | Trivial | Release markers |

View file

@ -1,249 +0,0 @@
# GSD2 Git Synthesis
Date: 2026-03-12
Repo: `/Users/lexchristopherson/Developer/gsd-2`
Inputs reviewed:
- `CODEX-GIT-AUDIT.md`
- `CLAUDE-GIT-AUDIT.md`
- `GEMINI-GIT-AUDIT.md`
## Bottom Line
`CODEX-GIT-AUDIT.md` is the strongest of the three and should be the baseline for product direction.
`CLAUDE-GIT-AUDIT.md` is strong on current-state analysis, but it recommends a few defaults that cut against both modern hosted Git practice and GSD2's "no theater" constraint.
`GEMINI-GIT-AUDIT.md` has some useful product instincts, but it is too speculative and too detached from the current codebase to use as the primary design document.
The right synthesis for GSD2 is:
1. Keep **trunk-based development with short-lived slice branches** as the default model.
2. Keep **worktrees** as an internal mechanism or an advanced tool, not the default user mental model.
3. Move **mechanical Git actions out of prompts and into deterministic code**.
4. Add **programmatic pre-merge verification** before anything lands on trunk.
5. Delete merged slice branches by default.
6. If a repo has a hosted remote and the user/repo policy allows it, support **push -> PR -> auto-merge / merge queue**.
7. Do **not** make stacked branches, Git Notes, AI-driven rebases, or milestone-sized PRs the default path.
## Verified Current State
These points are confirmed in the implementation, not inferred from the audits:
- Slice branches are real and automatically created before slice-level work runs.
- `src/resources/extensions/gsd/auto.ts:2222-2224`
- `src/resources/extensions/gsd/worktree.ts:152-195`
- Slice merges are local squash merges to the current integration branch, followed by branch deletion.
- `src/resources/extensions/gsd/worktree.ts:237-267`
- Worktrees are implemented with `git worktree add`, and slices inside worktrees merge into `worktree/<name>`, not the repo default branch.
- `src/resources/extensions/gsd/worktree-manager.ts:94-136`
- `src/resources/extensions/gsd/worktree.ts:100-128`
- Dirty state is frequently swept up with `git add -A` plus auto-commit.
- `src/resources/extensions/gsd/worktree.ts:183-191`
- `src/resources/extensions/gsd/worktree.ts:202-215`
- `src/resources/extensions/gsd/worktree-command.ts:356-357`
- `src/resources/extensions/gsd/worktree-command.ts:431-432`
- `src/resources/extensions/gsd/worktree-command.ts:468-469`
- Prompts still instruct the model to run raw Git commands directly.
- `src/resources/extensions/gsd/prompts/execute-task.md:57`
- `src/resources/extensions/gsd/prompts/complete-slice.md:21`
- `src/resources/extensions/gsd/prompts/replan-slice.md:34`
- Remote push / PR / merge-queue orchestration does not currently exist.
- Docs currently over-promise branch preservation and checkpoint commits relative to implementation.
- `README.md:258-264`
- `src/resources/GSD-WORKFLOW.md:548-585`
- `src/resources/extensions/gsd/worktree.ts:261`
## Review Of The Three Audits
### 1. CODEX audit: best overall
Why it is the best:
- It is the most accurate about the current implementation.
- It identifies the real trust-boundary problem: Git mechanics are still prompt-driven in places, even though they should be deterministic code.
- It aligns well with your stated constraint: best practice without enterprise theater.
- It correctly treats worktrees as useful infrastructure, not as the center of the product.
- It gives the best "two personas" framing:
- vibe coders get safety without Git choreography
- senior engineers get trunk discipline, observability, and optional power tools
What to keep from it:
- Trunk-based default
- Branch-per-slice default
- Programmatic merge verification
- Deterministic Git service in code
- Host-aware PR / merge-queue support only when a remote and policy exist
- Stacks only as an advanced mode
What to adjust:
- Hidden snapshot refs are a good direction, but they should follow, not precede, the more important fix of moving staging/committing/merging out of prompt text.
- Host-aware automation must respect the current safety contract: no outward-facing GitHub actions without explicit user confirmation or stored repo policy.
### 2. CLAUDE audit: solid repo audit, weaker product judgment
What it gets right:
- The current-state description is largely accurate.
- The highest-value near-term recommendation is correct: add code-level pre-merge verification before landing a slice.
- It correctly calls out the lack of remote operations and the over-broad `git add -A` auto-commit behavior.
Where it misses:
- It recommends preserving slice branches by default.
- That conflicts with the repo's current implementation and with the usual short-lived-branch discipline of trunk-based development.
- It also conflicts with GitHub's built-in support for automatically deleting merged head branches.
- It explicitly downplays hosted branch protection and merge policy.
- That is the wrong default for shared repos. Protected branches, required checks, linear history, auto-merge, and merge queues are exactly how modern hosted repos encode Git discipline without human nagging.
- It suggests PR creation on **milestone completion** rather than on **slice completion**.
- That is the wrong unit of integration for GSD2's branch-per-slice model.
- It would create larger, slower, more review-hostile PRs than the rest of the audit advocates.
Net: use CLAUDE's current-state findings, but do not adopt its default policy decisions wholesale.
### 3. GEMINI audit: interesting vision, not a reliable design basis
What is useful:
- It correctly pushes toward "Git should feel invisible to the user."
- It is directionally right that GSD2 should protect the user's main workspace more aggressively.
Why it should not be the main design document:
- Its current-state audit is materially inaccurate in places.
- It treats manual checkpoint commits as an implemented strength, but those are documented, not enforced in code.
- It proposes major new abstractions that are not grounded in the current codebase:
- "Autonomous Shadow Stack"
- `gsd stack`
- `gsd undo`
- `gsd ship`
- `land-slice`
- `gsd-executor`
- It relies heavily on Git Notes.
- Git Notes are not a simple default metadata layer. They require display/rewrite configuration and are much less visible than ordinary commit history.
- It normalizes AI-driven rebases and conflict resolution.
- That is exactly the kind of hidden magic that makes senior engineers distrust an automation system.
Net: keep the product instinct of "invisible Git UX," but reject the proposed mechanism set as the default plan.
## Recommended GSD2 Git Strategy
### Default mode: local trunk
Use this when there is no configured remote workflow, or when the user wants zero ceremony.
Behavior:
1. Start each slice on a short-lived slice branch from the true integration branch.
2. Keep the user on the slice abstraction, not on raw branch management.
3. Run deterministic Git operations from extension code, not from prompts.
4. Verify before merge.
5. Squash-merge to trunk.
6. Delete the merged slice branch.
This matches trunk-based development better than preserving branches forever, and it keeps GSD2 simple.
### Hosted mode: policy-aware trunk
Use this only when:
- a remote exists
- the repo host is supported
- the user has explicitly opted in, or repo policy has already been stored
Behavior:
1. Create the same short-lived slice branch.
2. Run local verification.
3. Push branch.
4. Create or update PR.
5. If the repo uses required checks / auto-merge / merge queue, integrate with that policy instead of bypassing it locally.
6. Treat "merged to default branch" as the actual completion boundary.
This is the right bridge between solo-maker mode and serious shared-repo mode.
### Advanced mode: optional worktrees and optional stacks
Use only when there is a real payoff:
- parallel agents
- risky spikes
- long-running refactors
- waiting on CI while continuing other work
Worktrees belong here.
Stacked branches belong here.
Neither should be the default explanation of how GSD2 works.
## What GSD2 Should Not Do By Default
- Do not preserve every merged slice branch forever.
- Do not create milestone-sized PRs.
- Do not use Git Notes as the primary audit trail.
- Do not rely on the model to decide what gets staged or merged.
- Do not hide rebases, conflict resolution, or cross-slice history surgery behind "magic."
- Do not make worktree management the first thing a casual user has to understand.
## Concrete Implementation Priorities
### P0
1. Move staging, committing, branch creation, and merging out of prompt text and into code.
2. Add merge-time verification before slice squash commits land.
3. Replace blind `git add -A` auto-commit behavior with owned-file or scoped-file staging.
4. Fix doc/code mismatches around branch preservation and checkpoint commits.
### P1
1. Detect remote/default-branch freshness before branching.
2. Add opt-in hosted workflow support:
- push
- PR create/update
- auto-merge
- merge queue where available
3. Add Git observability in the UI:
- current branch
- current worktree
- dirty status
- ahead/behind
- verification state
### P2
1. Add hidden recovery snapshots if needed after P0 is complete.
2. Auto-create worktrees for parallel execution where the product can justify it.
3. Add stacked execution only as an explicitly advanced mode.
## Final Recommendation
If only one audit becomes the design seed, use `CODEX-GIT-AUDIT.md`.
If you want the actual synthesis:
- take CODEX's strategic direction
- take CLAUDE's strongest implementation findings
- discard GEMINI's speculative mechanism set
That yields the cleanest 2026 answer for GSD2:
**short-lived slice branches, deterministic Git in code, verified merges to trunk, optional hosted PR automation, and advanced worktree/stack behavior only when it genuinely helps.**
## External References
- GitHub: protected branches and required checks
- https://docs.github.com/en/repositories/configuring-branches-and-merges-in-your-repository/managing-protected-branches
- GitHub: merge queue
- https://docs.github.com/repositories/configuring-branches-and-merges-in-your-repository/configuring-pull-request-merges/using-a-merge-queue
- GitHub: auto-merge
- https://docs.github.com/pull-requests/collaborating-with-pull-requests/incorporating-changes-from-a-pull-request/automatically-merging-a-pull-request
- GitHub: automatic deletion of branches
- https://docs.github.com/en/repositories/configuring-branches-and-merges-in-your-repository/configuring-pull-request-merges/managing-the-automatic-deletion-of-branches
- Git: worktree
- https://git-scm.com/docs/git-worktree
- Git: notes
- https://git-scm.com/docs/git-notes
- Trunk-based development: short-lived feature branches
- https://trunkbaseddevelopment.com/short-lived-feature-branches/
- Trunk-based development: feature flags
- https://trunkbaseddevelopment.com/feature-flags/

View file

@ -1,56 +0,0 @@
# GEMINI-GIT-SYNTHESIS: The New GSD 2 Git Standard (2026)
This document synthesizes the 2026 Git audit findings and the subsequent implementation of elite Git best practices into the core of GSD 2.
## 1. The Challenge (Audit Findings)
GSD 2 was already doing "branch-per-slice" and "squash-merge" correctly, but it suffered from three primary architectural weaknesses identified during the audit:
- **LLM Improv:** Git commands were mostly driven by prompts. This led to non-deterministic staging (`git add -A`), repetitive commit messages, and a lack of programmatic safety.
- **Trunk Pollution:** A broken slice could be merged to `main` without verification, potentially breaking the starting point for all subsequent work.
- **Context Noise:** Frequent "auto-commits" for dirty state recovery cluttered the branch history with `chore: auto-commit` messages, making the development log harder to read for senior engineers.
## 2. The Solution: Deterministic Git Orchestration
We transitioned GSD 2 from an **agent-mediated** Git model to a **system-mediated** Git model. The system now acts as a high-fidelity ledger that manages the "how" of Git while the agent focuses on the "what" and "why."
### Key Architectural Pillars:
- **`GitService`:** A centralized, deterministic TypeScript service for all high-level Git operations.
- **Hidden Snapshot Refs:** We introduced `refs/gsd/snapshots/<branch>/<timestamp>` to provide atomic recovery points without polluting the human-visible commit log.
- **Programmatic Merge Guards:** GSD 2 now automatically detects and executes verification commands (e.g., `npm run test`, `cargo test`) before a squash-merge. A failure blocks the merge, keeping `main` pristine.
- **High-Fidelity Main History:** Squash commits on `main` are now enriched with the list of completed tasks and the GSD slice title, providing a perfect changelog out of the box.
## 3. The Implementation Details
### For the "Vibe Coder" (Zero Config)
- **Invisible Git:** All task commits are handled automatically by the system.
- **Automatic Cleanup:** Merged branches are deleted by default (configurable) to keep the repository clean.
- **Safe by Default:** Verification runs automatically if tests are detected.
### For the "Senior Engineer" (Opt-In Power)
- **`preserve_branches: true`:** Keeps slice branches for `git bisect` or detailed drill-downs.
- **`auto_push: true`:** Automatically pushes `main` (and optionally slice branches) to remotes for backup and team visibility.
- **Custom `merge_guard`:** Define exact CI-equivalent commands to run before landing work.
## 4. Final Lifecycle of a GSD Slice
1. **Start Slice:** System cuts a branch from a fresh trunk (namespaced if in a worktree).
2. **Execute Task:**
- Agent builds the feature and writes the task summary.
- System detects the task summary title and performs a `feat(sid/tid): <Title>` commit automatically.
- System takes a hidden snapshot for recovery.
3. **Complete Slice:**
- Agent writes the slice summary and UAT results.
- System performs the final branch commit.
4. **Land Work (Merge Guard):**
- System triggers the verification command.
- If passed, system squash-merges to `main` with a rich commit message.
- System pushes to remote (if enabled).
- System cleans up the branch.
## 5. Conclusion
By baking these practices into GSD 2, we have removed the "Git Tax" from the developer. Git is no longer a tool the agent *operates*; it is the **database of progress** that GSD 2 *manages* on behalf of the user.
**Trunk is always green. History is always clean. Recovery is always possible.**

View file

@ -1,148 +0,0 @@
# GSD Onboarding & Install Experience — Implementation Plan
## Problem
1. **Postinstall output is invisible** — npm ≥7 suppresses stdout from lifecycle scripts. The branded GSD banner during `npm install -g gsd-pi` is swallowed unless the user passes `--foreground-scripts`.
2. **The clack onboarding wizard is dead code**`src/onboarding.ts` was deleted from source, but its compiled `dist/onboarding.js` ships in the package. Nothing imports it. The actual first-launch flow (`wizard.ts`) is a plain-text readline prompt that only asks for tool API keys — no LLM provider selection, no OAuth, no branding.
3. **No `gsd config` command** — users who want to update keys later must manually edit `~/.gsd/agent/auth.json`.
## Desired End State
### 1. `npm install -g gsd-pi@latest`
- Shows the GSD ASCII banner, version, and setup progress (patches, playwright)
- All output goes to **stderr** so npm never suppresses it
- **No interactive prompts** — install is non-interactive
- Already works correctly except for the stderr routing (partially done, needs audit)
### 2. First `gsd` launch (no LLM provider configured)
- Full branded **clack-based** onboarding wizard:
1. GSD ASCII logo + "Welcome to GSD — let's get you set up"
2. **Choose LLM provider** — Anthropic OAuth (recommended), Anthropic API key, OpenAI, GitHub Copilot, Codex, Gemini CLI, Antigravity, Other, Skip
3. **Authenticate** — OAuth browser flow or masked API key input, with retry/skip on failure
4. **Optional tool API keys** — Brave Search, Brave Answers, Context7, Jina, Tavily, Slack Bot, Discord Bot (confirm gate: "Set up optional tool API keys?")
5. **Summary note** — what was configured, what was skipped
6. **Outro** — "Launching GSD..."
7. TUI launches regardless of what was skipped
- Gate: `shouldRunOnboarding()` — runs when no LLM provider has credentials AND stdin is TTY
- All steps skippable, all errors recoverable, never crashes boot
### 3. Returning user launches `gsd`
- **Straight to TUI** — no prompts, no wizard
- `loadStoredEnvKeys()` hydrates env vars from auth.json as before
- Never re-prompted for keys already stored (even if stored as empty/skipped)
### 4. `gsd config` command
- Replays the full onboarding wizard with current values shown
- Available anytime — re-run to change LLM provider or update tool keys
- Exits after wizard completes (does not launch TUI)
---
## Implementation Steps
### Step 1: Recreate `src/onboarding.ts`
Reverse-engineer from the compiled `dist/onboarding.js` (full source is intact). Create `src/onboarding.ts` with proper TypeScript types.
**Exports:**
- `shouldRunOnboarding(authStorage: AuthStorage): boolean`
- `runOnboarding(authStorage: AuthStorage): Promise<void>`
**Dependencies verified against AuthStorage API (from pi-coding-agent d.ts):**
- `authStorage.list(): string[]`
- `authStorage.has(provider): boolean`
- `authStorage.get(provider): AuthCredential | undefined`
- `authStorage.set(provider, credential): void`
- `authStorage.login(providerId, callbacks): Promise<void>`
- `authStorage.getOAuthProviders(): OAuthProviderInterface[]`
### Step 2: Create `src/logo.ts`
The logo module also doesn't exist in source. Recreate from `dist/logo.js`:
- `GSD_LOGO: string[]` — raw logo lines
- `renderLogo(color: (s: string) => string): string`
### Step 3: Update `src/wizard.ts`
- **Keep** `loadStoredEnvKeys()` — still needed on every launch
- **Remove** `runWizardIfNeeded()` — replaced by onboarding flow
- File becomes just the env hydration utility
### Step 4: Update `src/cli.ts`
Replace:
```ts
import { loadStoredEnvKeys, runWizardIfNeeded } from './wizard.js'
// ...
if (!isPrintMode) {
await runWizardIfNeeded(authStorage)
}
```
With:
```ts
import { loadStoredEnvKeys } from './wizard.js'
import { shouldRunOnboarding, runOnboarding } from './onboarding.js'
// ...
if (!isPrintMode && shouldRunOnboarding(authStorage)) {
await runOnboarding(authStorage)
}
```
### Step 5: Add `gsd config` subcommand
In `src/cli.ts`, detect `config` as the first positional argument before the main flow:
```ts
// After parseCliArgs, before isPrintMode check:
if (cliFlags.messages[0] === 'config') {
await runOnboarding(authStorage) // Full wizard replay
process.exit(0)
}
```
Also add to `--help` output.
### Step 6: Audit `scripts/postinstall.js` stderr routing
The postinstall already has `process.stdout.write = process.stderr.write.bind(process.stderr)` which redirects clack's stdout to stderr. Verify this works by:
1. Confirming the banner, spinner, and summary all route through this redirect
2. Testing `npm install -g` without `--foreground-scripts`
If npm still suppresses it, the fallback is to replace clack calls in postinstall with direct `process.stderr.write()` calls (the postinstall doesn't need interactivity — it's spinners and status only).
### Step 7: Update `src/loader.ts` first-launch banner
`loader.ts` currently prints its own ASCII banner on first launch (`!existsSync(appRoot)`). This will now conflict with the onboarding wizard's banner. Options:
- **Remove the loader banner** — let onboarding handle branding on first launch
- **Keep it** — onboarding will print its own intro, so skip the logo in onboarding if loader already printed it
Recommended: Remove the loader banner. The onboarding wizard is the proper branded first-launch experience. Returning users never see either banner (appRoot exists).
### Step 8: Build and verify
1. `npm run build` — confirm TypeScript compiles
2. Delete `~/.gsd/agent/auth.json` to simulate fresh install
3. Run `gsd` — verify full clack onboarding appears
4. Run `gsd` again — verify straight to TUI (no wizard)
5. Run `gsd config` — verify wizard replays
6. `npm install -g .` — verify postinstall banner shows without `--foreground-scripts`
---
## Files Changed
| File | Action | Description |
|------|--------|-------------|
| `src/logo.ts` | **Create** | Shared ASCII logo module |
| `src/onboarding.ts` | **Create** | Full clack-based onboarding wizard |
| `src/wizard.ts` | **Trim** | Remove `runWizardIfNeeded`, keep `loadStoredEnvKeys` |
| `src/cli.ts` | **Edit** | Wire onboarding + `gsd config` subcommand |
| `src/loader.ts` | **Edit** | Remove first-launch banner (onboarding handles it) |
| `scripts/postinstall.js` | **Audit** | Verify stderr routing works without `--foreground-scripts` |
## Risks
- **`@clack/prompts` availability** — It's a transitive dependency (not in gsd-pi's direct deps). The onboarding module already has a try/catch fallback for this. Should work, but if clack is tree-shaken or hoisted away, the fallback fires and the user just gets the TUI with no wizard. Non-fatal.
- **OAuth flow in onboarding** — Depends on pi's `authStorage.login()` + `getOAuthProviders()`. These are stable public API per the d.ts. If a provider's OAuth config changes upstream, the onboarding gracefully falls back to retry/skip.
- **stdin contention** — Clack's prompts take over stdin. Must ensure clack fully releases stdin before the TUI's InteractiveMode starts. The existing onboarding code's `p.outro()` should handle this.