feat(M001/S03): Bug fixes and doc corrections
This commit is contained in:
parent
dfe9527641
commit
b2e7dbdc25
9 changed files with 377 additions and 17 deletions
|
|
@ -58,7 +58,7 @@ This milestone is complete only when all are true:
|
|||
- [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.
|
||||
|
||||
- [ ] **S03: Bug fixes and doc corrections** `risk:medium` `depends:[S02]`
|
||||
- [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.
|
||||
|
||||
- [ ] **S04: Remove git commands from prompts** `risk:low` `depends:[S02]`
|
||||
|
|
|
|||
64
.gsd/milestones/M001/slices/S03/S03-PLAN.md
Normal file
64
.gsd/milestones/M001/slices/S03/S03-PLAN.md
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
# 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`
|
||||
54
.gsd/milestones/M001/slices/S03/tasks/T01-PLAN.md
Normal file
54
.gsd/milestones/M001/slices/S03/tasks/T01-PLAN.md
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
---
|
||||
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
|
||||
70
.gsd/milestones/M001/slices/S03/tasks/T01-SUMMARY.md
Normal file
70
.gsd/milestones/M001/slices/S03/tasks/T01-SUMMARY.md
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
---
|
||||
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
|
||||
56
.gsd/milestones/M001/slices/S03/tasks/T02-PLAN.md
Normal file
56
.gsd/milestones/M001/slices/S03/tasks/T02-PLAN.md
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
---
|
||||
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): <slice title>` 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
|
||||
73
.gsd/milestones/M001/slices/S03/tasks/T02-SUMMARY.md
Normal file
73
.gsd/milestones/M001/slices/S03/tasks/T02-SUMMARY.md
Normal file
|
|
@ -0,0 +1,73 @@
|
|||
---
|
||||
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
|
||||
|
|
@ -252,17 +252,18 @@ Branch-per-slice with squash merge. Fully automated.
|
|||
|
||||
```
|
||||
main:
|
||||
feat(M001/S03): auth and session management
|
||||
docs(M001/S04): workflow documentation and examples
|
||||
fix(M001/S03): bug fixes and doc corrections
|
||||
feat(M001/S02): API endpoints and middleware
|
||||
feat(M001/S01): data model and type system
|
||||
|
||||
gsd/M001/S01 (preserved):
|
||||
gsd/M001/S01 (deleted after merge):
|
||||
feat(S01/T03): file writer with round-trip fidelity
|
||||
feat(S01/T02): markdown parser for plan files
|
||||
feat(S01/T01): core types and interfaces
|
||||
```
|
||||
|
||||
One commit per slice on main. Per-task history preserved on branches. Git bisect works. Individual slices are revertable.
|
||||
One commit per slice on main. Squash commits are the permanent record — branches are deleted after merge. Git bisect works. Individual slices are revertable.
|
||||
|
||||
### Verification
|
||||
|
||||
|
|
|
|||
|
|
@ -548,7 +548,7 @@ If files disagree, **pause and surface to the user**:
|
|||
1. **Slice starts** → create branch `gsd/M001/S01` from main
|
||||
2. **Per-task commits** on the branch — atomic, descriptive, bisectable
|
||||
3. **Slice completes** → squash merge to main as one clean commit
|
||||
4. **Branch kept** — not deleted, available for per-task history
|
||||
4. **Branch deleted** — squash commit on main is the permanent record
|
||||
|
||||
### What Main Looks Like
|
||||
|
||||
|
|
@ -566,21 +566,21 @@ One commit per slice. Individually revertable. Reads like a changelog.
|
|||
gsd/M001/S01:
|
||||
test(S01): round-trip tests passing
|
||||
feat(S01/T03): file writer with round-trip fidelity
|
||||
checkpoint(S01/T03): pre-task
|
||||
chore(S01/T03): auto-commit after task
|
||||
feat(S01/T02): markdown parser for plan files
|
||||
checkpoint(S01/T02): pre-task
|
||||
chore(S01/T02): auto-commit after task
|
||||
feat(S01/T01): core types and interfaces
|
||||
checkpoint(S01/T01): pre-task
|
||||
chore(S01/T01): auto-commit after task
|
||||
```
|
||||
|
||||
### Commit Conventions
|
||||
|
||||
| When | Format | Example |
|
||||
|------|--------|---------|
|
||||
| Before each task | `checkpoint(S01/T02): pre-task` | Safety net for `git reset` |
|
||||
| Auto-commit (dirty state) | `chore(S01/T02): auto-commit after task` | Automatic save of work in progress |
|
||||
| After task verified | `feat(S01/T02): <what was built>` | The real work |
|
||||
| Plan/docs committed | `docs(S01): add slice plan` | Bundled with first task |
|
||||
| Slice squash to main | `feat(M001/S01): <slice title>` | Clean one-liner on main |
|
||||
| Slice squash to main | `type(M001/S01): <slice title>` | Type inferred from title (`feat`, `fix`, `docs`, etc.) |
|
||||
|
||||
Commit types: `feat`, `fix`, `test`, `refactor`, `docs`, `chore`
|
||||
|
||||
|
|
@ -601,7 +601,7 @@ Tasks completed:
|
|||
|
||||
| Problem | Fix |
|
||||
|---------|-----|
|
||||
| Bad task | `git reset --hard` to checkpoint on the branch |
|
||||
| Bad task | `git reset --hard HEAD~1` to previous commit on the branch |
|
||||
| Bad slice | `git revert <squash commit>` on main |
|
||||
| UAT failure after merge | Fix tasks on `gsd/M001/S01-fix` branch, squash as `fix(M001/S01): <fix>` |
|
||||
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ import {
|
|||
createWorktree,
|
||||
listWorktrees,
|
||||
removeWorktree,
|
||||
mergeWorktreeToMain,
|
||||
diffWorktreeAll,
|
||||
diffWorktreeNumstat,
|
||||
getMainBranch,
|
||||
|
|
@ -28,7 +29,9 @@ import {
|
|||
worktreeBranchName,
|
||||
worktreePath,
|
||||
} from "./worktree-manager.js";
|
||||
import { inferCommitType } from "./git-service.js";
|
||||
import type { FileLineStat } from "./worktree-manager.js";
|
||||
import { execSync } from "node:child_process";
|
||||
import { existsSync, realpathSync, readFileSync, readdirSync, rmSync, unlinkSync, utimesSync } from "node:fs";
|
||||
import { join, resolve, sep } from "node:path";
|
||||
|
||||
|
|
@ -349,13 +352,14 @@ async function handleCreate(
|
|||
ctx: ExtensionCommandContext,
|
||||
): Promise<void> {
|
||||
try {
|
||||
// Auto-commit dirty files before leaving current workspace (must happen
|
||||
// before createWorktree so the new worktree forks from committed HEAD)
|
||||
const commitMsg = autoCommitCurrentBranch(basePath, "worktree-switch", name);
|
||||
|
||||
// Create from the main tree, not from inside another worktree
|
||||
const mainBase = originalCwd ?? basePath;
|
||||
const info = createWorktree(mainBase, name);
|
||||
|
||||
// Auto-commit dirty files before leaving current workspace
|
||||
const commitMsg = autoCommitCurrentBranch(basePath, "worktree-switch", name);
|
||||
|
||||
// Track original cwd before switching
|
||||
if (!originalCwd) originalCwd = basePath;
|
||||
|
||||
|
|
@ -655,9 +659,8 @@ async function handleMerge(
|
|||
return;
|
||||
}
|
||||
|
||||
// Switch to the main tree before dispatching the merge.
|
||||
// The LLM needs to run git merge --squash from the main branch, and if
|
||||
// it later removes the worktree, the agent's CWD must not be inside it.
|
||||
// Switch to the main tree before merging.
|
||||
// Must be on the main branch to run git merge --squash.
|
||||
if (originalCwd) {
|
||||
const prevCwd = process.cwd();
|
||||
process.chdir(basePath);
|
||||
|
|
@ -665,6 +668,45 @@ async function handleMerge(
|
|||
originalCwd = null;
|
||||
}
|
||||
|
||||
// --- Deterministic merge path (preferred) ---
|
||||
// Try a direct squash-merge first. Only fall back to LLM on conflict.
|
||||
const commitType = inferCommitType(name);
|
||||
const commitMessage = `${commitType}(${name}): merge worktree ${name}`;
|
||||
try {
|
||||
mergeWorktreeToMain(basePath, name, commitMessage);
|
||||
ctx.ui.notify(
|
||||
[
|
||||
`${CLR.ok("✓")} Merged ${CLR.name(name)} → ${CLR.branch(mainBranch)} ${CLR.muted("(deterministic squash)")}`,
|
||||
"",
|
||||
` ${totalChanges} file${totalChanges === 1 ? "" : "s"} changed, ${CLR.ok(`+${totalAdded}`)} ${RED}-${totalRemoved}${RESET} lines`,
|
||||
` ${CLR.muted("commit:")} ${commitMessage}`,
|
||||
].join("\n"),
|
||||
"info",
|
||||
);
|
||||
return;
|
||||
} catch (mergeErr) {
|
||||
const mergeMsg = mergeErr instanceof Error ? mergeErr.message : String(mergeErr);
|
||||
const isConflict = /conflict/i.test(mergeMsg);
|
||||
|
||||
if (isConflict) {
|
||||
// Abort the failed merge so the working tree is clean for LLM retry
|
||||
try {
|
||||
execSync("git merge --abort", { cwd: basePath, stdio: "pipe" });
|
||||
} catch { /* already clean */ }
|
||||
|
||||
ctx.ui.notify(
|
||||
`${CLR.muted("Deterministic merge hit conflicts — falling back to LLM-guided merge.")}`,
|
||||
"warning",
|
||||
);
|
||||
// Fall through to LLM dispatch below
|
||||
} else {
|
||||
// Non-conflict error — surface it directly, don't fall back
|
||||
ctx.ui.notify(`Failed to merge: ${mergeMsg}`, "error");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// --- LLM fallback path (conflict resolution) ---
|
||||
// Format file lists for the prompt
|
||||
const formatFiles = (files: string[]) =>
|
||||
files.length > 0 ? files.map(f => `- \`${f}\``).join("\n") : "_(none)_";
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue