Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> (cherry picked from commit 5f4b7a9e26af0635cfaecfbc55bfe928dd3466d2)
59 lines
2.8 KiB
Markdown
59 lines
2.8 KiB
Markdown
# Empty-repo hardening — implementation plan
|
|
|
|
Spec: `docs/superpowers/specs/2026-07-30-empty-repo-hardening-design.md`
|
|
|
|
## Task 1 — GitService: HasHeadCommitAsync + EnsureHeadCommitAsync + friendly unborn error
|
|
|
|
**Files:** `src/ClaudeDo.Data/Git/GitService.cs`,
|
|
`tests/ClaudeDo.Worker.Tests/Runner/GitServiceBootstrapTests.cs` (new)
|
|
|
|
1. Tests first (skip when git unavailable, mirroring `WorktreeManagerTests`):
|
|
- fresh `git init` repo (no commit): `HasHeadCommitAsync` false; after a commit true.
|
|
- `EnsureHeadCommitAsync` on empty repo → true; `RevParseHeadAsync` then succeeds;
|
|
`git ls-tree HEAD` empty; second call → false.
|
|
- staged file in empty repo survives bootstrap: still staged, not in the commit.
|
|
- corrupt HEAD (write a garbage SHA into `.git/HEAD` as a detached head):
|
|
`EnsureHeadCommitAsync` throws `InvalidOperationException` mentioning the dir.
|
|
- `RevParseHeadAsync` on empty repo: message says "has no commits yet" (no raw
|
|
"ambiguous argument").
|
|
2. Implement: `HasHeadCommitAsync` (`rev-parse --verify --quiet HEAD`),
|
|
`EnsureHeadCommitAsync` (symbolic-ref guard → hash-object/commit-tree/update-ref
|
|
plumbing behind a static `SemaphoreSlim` with post-acquire re-check), unborn-HEAD
|
|
message in `RevParseHeadAsync`.
|
|
3. Build Data + run new tests. Commit `fix(git): bootstrap empty repos with an initial commit`.
|
|
|
|
## Task 2 — CommitAsync identity fallback
|
|
|
|
**Files:** same two files.
|
|
|
|
1. Test: repo with local `user.name`/`user.email` set to empty strings → `CommitAsync`
|
|
succeeds (retry path), commit exists.
|
|
2. Implement: on identity-signature failure, retry once with
|
|
`-c user.name=ClaudeDo -c user.email=claudedo@local`.
|
|
3. Commit `fix(git): fall back to a ClaudeDo identity when git has none`.
|
|
|
|
## Task 3 — call sites
|
|
|
|
**Files:** `src/ClaudeDo.Worker/Runner/WorktreeManager.cs`,
|
|
`src/ClaudeDo.Worker/Planning/PlanningSessionManager.cs`,
|
|
`tests/ClaudeDo.Worker.Tests/Runner/WorktreeManagerTests.cs`
|
|
|
|
1. Test: `CreateAsync` on a commit-less repo succeeds; worktree on disk; DB row Active.
|
|
2. Wire `EnsureHeadCommitAsync` into `WorktreeManager.CreateAsync` (log info on
|
|
bootstrap) and `PlanningSessionManager.StartAsync`.
|
|
3. Full Worker.Tests run. Commit `fix(worktree): auto-bootstrap commit-less repos before creating worktrees`.
|
|
|
|
## Task 4 — docs
|
|
|
|
- `src/ClaudeDo.Data/CLAUDE.md`: GitService bullet gains bootstrap/identity-fallback.
|
|
- `docs/open.md`: verification item — open a ConPTY session on a fresh `git init` repo
|
|
on a second PC.
|
|
- Commit `docs: empty-repo hardening notes`.
|
|
|
|
## Verification
|
|
|
|
- `dotnet test tests/ClaudeDo.Worker.Tests -c Release` green.
|
|
- Manual: task 61609f79… in "Test List" (`C:\Dev\TestRepo`, currently commit-less) —
|
|
opening the ConPTY session must now succeed and leave `C:\Dev\TestRepo` with exactly
|
|
one empty commit by ClaudeDo.
|