chore(claude-do): feat(worktrees): warn about git worktrees ClaudeDo doesn't k
From `docs/open.md` (re-verified against the code 2026-09-02, still open): nothing reconciles `git worktree list` against the `worktrees` table. `ExternalMcpService.ListWorktrees` and the Worktrees overview read DB rows only; `WorktreeManager` calls git solely inside its self-heal path (`ListWorktreePathsForBranchAsync`). Observed once: 22 git-registered worktrees + 26 `claudedo/*` branches in `C: ClaudeDo-Task: 765fed13-db66-44e4-9285-c4b2d415b443
This commit is contained in:
@@ -0,0 +1,73 @@
|
||||
using ClaudeDo.Worker.Hub;
|
||||
using ClaudeDo.Worker.Lifecycle;
|
||||
using ClaudeDo.Worker.Tests.Infrastructure;
|
||||
using Microsoft.Extensions.Logging.Abstractions;
|
||||
|
||||
namespace ClaudeDo.Worker.Tests.Lifecycle;
|
||||
|
||||
public sealed class UntrackedWorktreeRecoveryTests : IDisposable
|
||||
{
|
||||
private readonly DbFixture _db = new();
|
||||
|
||||
public void Dispose() => _db.Dispose();
|
||||
|
||||
[Fact]
|
||||
public void FindUntrackedPaths_PathNotInDb_IsReturned()
|
||||
{
|
||||
var registered = new[] { @"C:\repo\.worktrees\abc123" };
|
||||
var db = new[] { @"C:\repo\.worktrees\def456" };
|
||||
|
||||
var untracked = UntrackedWorktreeRecovery.FindUntrackedPaths(registered, db);
|
||||
|
||||
Assert.Equal(registered, untracked);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void FindUntrackedPaths_PathInDb_IsExcluded()
|
||||
{
|
||||
var registered = new[] { @"C:\repo\.worktrees\abc123" };
|
||||
var db = new[] { @"C:\repo\.worktrees\abc123" };
|
||||
|
||||
var untracked = UntrackedWorktreeRecovery.FindUntrackedPaths(registered, db);
|
||||
|
||||
Assert.Empty(untracked);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void FindUntrackedPaths_DifferentCasingAndSeparators_StillMatches()
|
||||
{
|
||||
var registered = new[] { @"C:\repo\.worktrees\abc123\" };
|
||||
var db = new[] { "c:/repo/.worktrees/ABC123" };
|
||||
|
||||
var untracked = UntrackedWorktreeRecovery.FindUntrackedPaths(registered, db);
|
||||
|
||||
Assert.Empty(untracked);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void FindUntrackedPaths_EmptyDb_ReturnsAllRegistered()
|
||||
{
|
||||
var registered = new[] { @"C:\repo\.worktrees\abc123", @"C:\repo\.worktrees\def456" };
|
||||
|
||||
var untracked = UntrackedWorktreeRecovery.FindUntrackedPaths(registered, Array.Empty<string>());
|
||||
|
||||
Assert.Equal(registered, untracked);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task StartAsync_NoLists_DoesNotThrow()
|
||||
{
|
||||
var hubContext = new CapturingHubContext();
|
||||
var sut = new UntrackedWorktreeRecovery(
|
||||
_db.CreateFactory(),
|
||||
new ClaudeDo.Data.Git.GitService(),
|
||||
new HubBroadcaster(hubContext),
|
||||
NullLogger<UntrackedWorktreeRecovery>.Instance);
|
||||
|
||||
await sut.StartAsync(CancellationToken.None);
|
||||
await sut.StopAsync(CancellationToken.None);
|
||||
|
||||
Assert.Contains(hubContext.Proxy.Calls, c =>
|
||||
c.Method == "OperationProgress" && (string)c.Args[0]! == "startup-recovery");
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user