Skip to content

fix: prevent worktree reuse across different local clones#1186

Closed
halindrome wants to merge 5 commits intocoleam00:devfrom
halindrome:fix/worktree-reuse-cross-checkout
Closed

fix: prevent worktree reuse across different local clones#1186
halindrome wants to merge 5 commits intocoleam00:devfrom
halindrome:fix/worktree-reuse-cross-checkout

Conversation

@halindrome
Copy link
Copy Markdown
Contributor

@halindrome halindrome commented Apr 13, 2026

Summary

Fixes #1183

  • Store source_repo_root in isolation environment metadata when creating worktrees via the CLI
  • Before reusing an existing worktree (--branch flag), verify the stored repo root matches the current cwd's repo root
  • Skip reuse with a log warning when the roots differ (falls through to create a new worktree)
  • Backward-compatible: environments without source_repo_root (pre-existing) are reused as before

Root Cause

The remote_agent_codebases table derives codebase identity from the remote URL. Two local clones of the same remote (e.g., ~/project-a and ~/project-b) resolve to the same codebase_id. findActiveByWorkflow then returns isolation environments from the wrong local clone since it only filters on codebase_id + workflow_type + workflow_id.

Approach

Rather than changing the database schema or codebase identity model, this fix adds a guard at the reuse check site in workflow.ts. The current repo root is stored in the existing metadata JSONB column at creation time, and compared at reuse time. This is the minimal change with the smallest blast radius.

Known Limitations

  • Only guards the CLI workflow path (the reported bug). The IsolationResolver (Slack/Telegram/GitHub/Web) has the same theoretical gap but lower risk since server-side paths don't involve multiple local clones.
  • Does not guard git-level worktree adoption in WorktreeProvider.findExisting(), which checks filesystem paths that are shared across clones of the same remote.
  • Submodule initialization in worktrees is a separate gap (tracked separately).

Test plan

  • bun run type-check — all packages pass
  • bun run lint — zero warnings
  • bun run test — all tests pass
  • Manual verification: existing environments without source_repo_root metadata are still reused (backward compat)

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Bug Fixes

    • Prevents reusing an environment from a different local checkout by persisting detected repo-root in environment metadata; reuse is now conditional and the app emits warnings when reuse is undetectable or skipped due to a checkout mismatch.
  • Tests

    • Added tests validating reuse vs. recreation when repo-root metadata is present, missing, mismatched, or undetectable.

)

When two local clones of the same remote exist, they share a codebase_id
(derived from the remote URL). findActiveByWorkflow could return an
isolation environment created from a sibling checkout, causing the
workflow to operate in the wrong directory.

Store source_repo_root in the isolation environment metadata at creation
time, and verify it matches the current working directory's repo root
before reusing. Environments without source_repo_root (pre-existing)
are reused as before for backward compatibility.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 13, 2026

📝 Walkthrough

Walkthrough

Worktree reuse is now gated by comparing the current repository canonical root to existingEnv.metadata.source_repo_root; reuse occurs only when roots match (or roots are unavailable as allowed). Warnings emitted for undetectable current root and for root mismatches. New isolation records persist metadata.source_repo_root when available.

Changes

Cohort / File(s) Summary
Workflow command logic
packages/cli/src/commands/workflow.ts
Resolve currentRepoRoot via git, read existingEnv.metadata.source_repo_root, compute reuseSameCheckout only when canonical roots match; gate provider health-check/reuse on that check; emit worktree.reuse_root_undetectable and worktree.reuse_different_checkout warnings; persist metadata.source_repo_root on new isolation records when detected.
Tests for reuse behavior
packages/cli/src/commands/workflow.test.ts
Add mock getCanonicalRepoPath and tests covering: differing source_repo_root → skip reuse/create called; absent source_repo_root → allow reuse; matching roots → reuse (no create); canonical root undetectable while env has source_repo_root → reuse with warning.

Sequence Diagram(s)

sequenceDiagram
    participant CLI as CLI (workflow command)
    participant Git as git (findRepoRoot / getCanonicalRepoPath)
    participant Env as existingEnv (metadata)
    participant Provider as Isolation Provider
    participant Logger as Logger

    CLI->>Git: detect currentRepoRoot
    CLI->>Env: read metadata.source_repo_root
    alt currentRepoRoot undetectable
        CLI->>Logger: warn worktree.reuse_root_undetectable
        CLI->>Provider: create new environment (store source_repo_root if available)
    else both roots present and equal
        CLI->>Provider: health-check existingEnv
        Provider-->>CLI: healthy?
        alt healthy
            CLI->>Logger: reuse existingEnv
        else unhealthy
            CLI->>Provider: create new environment (store currentRepoRoot)
        end
    else roots present but different
        CLI->>Logger: warn worktree.reuse_different_checkout
        CLI->>Provider: create new environment (store currentRepoRoot)
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related issues

Poem

🐰 I sniff the roots where worktrees grew,
I hop where canonical paths are true,
I warn when roots are lost or stray,
I keep the source when found that way,
New nests form only when roots align.

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Description check ⚠️ Warning The description covers the problem, approach, and test plan, but is missing required sections from the template (UX Journey, Architecture Diagram, Label Snapshot, Change Metadata, Validation Evidence, Security Impact, Compatibility, Human Verification, Side Effects, and Rollback Plan). Complete the pull request description by adding the missing required template sections: UX Journey, Architecture Diagram, Label Snapshot, Change Metadata, Validation Evidence format, Security Impact details, Compatibility assessment, Human Verification checklist, Side Effects analysis, and Rollback Plan.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main change: preventing worktree reuse across different local clones by comparing repository roots.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/cli/src/commands/workflow.ts`:
- Around line 431-437: The reuse guard currently compares a worktree-local path
from git.findRepoRoot(cwd) against existingEnv.metadata.source_repo_root, which
can differ for linked worktrees; change the logic to compare clone-stable
canonical repo identifiers instead: call getCanonicalRepoPath(cwd) (or use git
rev-parse --git-common-dir via an existing helper) to normalize the current
working directory and, if present, normalize
existingEnv.metadata.source_repo_root before computing reuseSameCheckout; update
the reuseSameCheckout assignment to use these canonical paths (or the shared
.git path) so the comparison is stable across linked worktrees and matches the
value persisted later as metadata.source_repo_root.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: bea74955-cbf2-418d-ac15-8f8362eaf6b4

📥 Commits

Reviewing files that changed from the base of the PR and between bf20063 and f9d54ac.

📒 Files selected for processing (1)
  • packages/cli/src/commands/workflow.ts

Comment thread packages/cli/src/commands/workflow.ts Outdated
@halindrome halindrome marked this pull request as draft April 13, 2026 13:08
Add 3 tests for the cross-checkout guard: mismatch (skip reuse),
absent metadata (backward compat), and matching root (normal reuse).
Add warning log when currentRepoRoot is null but envSourceRoot exists.
Document the intentional fallback behavior with a comment.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@halindrome
Copy link
Copy Markdown
Contributor Author

QA Round 1 Report

Critical Issues

# Severity Confidence Finding Status
1 Critical 95 Guard is permanently bypassed in all existing tests — findRepoRoot mock returns null, making reuseSameCheckout always true. Zero test coverage for the three new code paths. Fixed in 9f38502 — added 3 tests

Added tests for:

  • Cross-checkout mismatch (different source_repo_root → reuse skipped, new worktree created)
  • Backward compatibility (no source_repo_root in metadata → reuse allowed)
  • Matching checkout (same source_repo_root → normal reuse)

Important Issues

# Severity Confidence Finding Status
2 Important 85 Null currentRepoRoot silently bypasses guard without any log Fixed in 9f38502 — added worktree.reuse_root_undetectable warning log
3 Important 80 findRepoRoot(cwd) called unconditionally even when no existing env Advisory — needed for metadata storage on new envs

Advisory Notes

# Note
A cwd vs codebase.default_cwd ambiguity — inherent in the approach, not introduced by this PR. Documented in the comment.
B metadata?.source_repo_root optional chaining is redundant (metadata is non-optional Record<string, unknown>). Cosmetic only.
C No backfill for existing environments — until an env is destroyed and recreated, old rows without source_repo_root use backward-compat path. Documented in PR description.

Verdict

Critical issue fixed (tests added). QA round 1 complete.

🤖 Generated with Claude Code

Add test for worktree.reuse_root_undetectable: when findRepoRoot
returns null but the existing env has a source_repo_root, reuse is
allowed (fallback) with a warning logged.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@halindrome
Copy link
Copy Markdown
Contributor Author

QA Round 2 Report

Findings

# Severity Confidence Finding Status
1 Important 85 worktree.reuse_root_undetectable warning path has no test coverage — the exact path Round 1 flagged as a silent bypass Fixed in e92ee2d — added 4th test

The four logical branches of the guard are now all tested:

  1. Cross-checkout mismatch → reuse skipped ✓
  2. Backward compat (no metadata) → reuse allowed ✓
  3. Same root → reuse allowed ✓
  4. Null root with known env source → reuse allowed with warning ✓ (new)

All other aspects verified clean:

  • Tests properly override findRepoRoot mock with mockResolvedValueOnce
  • Warning log follows {domain}.{action}_{state} convention
  • Change is focused (~40 lines production, ~150 lines tests)
  • No interface changes, backward compatible

Verdict

QA round 2: CLEAN — ready for review.

🤖 Generated with Claude Code

@halindrome halindrome marked this pull request as ready for review April 13, 2026 13:20
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/cli/src/commands/workflow.test.ts`:
- Around line 1118-1163: The test description says “with warning” but never
asserts a warning; update the test for the workflowRunCommand scenario (where
isolationDb.findActiveByWorkflow returns metadata.source_repo_root and
gitModule.findRepoRoot returns null) to assert the logger warning was emitted:
mock or grab the logger used by workflowRunCommand (e.g., processLogger or the
module logger), ensure its warn method is spied/mocked before calling
workflowRunCommand('/clone-a', 'assist', 'hello', { branchName: 'my-feature' }),
and add an expectation that logger.warn was called (or called with a message
containing identifiers like "repo root" or "source_repo_root") after execution
so the warning path is actually verified.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: cddfa05a-389d-4adb-9c87-fd5d17ae81f0

📥 Commits

Reviewing files that changed from the base of the PR and between f9d54ac and e92ee2d.

📒 Files selected for processing (2)
  • packages/cli/src/commands/workflow.test.ts
  • packages/cli/src/commands/workflow.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/cli/src/commands/workflow.ts

Comment thread packages/cli/src/commands/workflow.test.ts Outdated
Address CodeRabbit review: git rev-parse --show-toplevel returns
different paths inside linked worktrees. Use getCanonicalRepoPath
instead, which resolves any worktree path back to the main repo
via .git/worktrees/ gitdir linkage. This makes the source_repo_root
comparison stable whether the user runs from the main checkout or
from inside an Archon-managed worktree.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@halindrome
Copy link
Copy Markdown
Contributor Author

CodeRabbit Review — Addressed

CodeRabbit flagged that git rev-parse --show-toplevel (used by findRepoRoot) returns different paths inside linked worktrees, making the comparison unstable if a user runs from inside an Archon-managed worktree.

Fixed in e2af7a2: Replaced findRepoRoot(cwd) with getCanonicalRepoPath(cwd), which resolves any worktree path back to the main repo by reading the .git/worktrees/ gitdir linkage. The comparison is now stable whether the user runs from the main checkout or from inside a linked worktree.

The getCanonicalRepoPath call is wrapped in a try/catch since it throws (rather than returning null) when the path is not a git repo — the catch produces null, preserving the existing fallback behavior.

Tests updated to mock getCanonicalRepoPath instead of findRepoRoot.

🤖 Generated with Claude Code

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/cli/src/commands/workflow.ts`:
- Around line 432-448: The code should resolve the repo top-level before
canonicalizing and must not silently swallow real errors: call findRepoRoot(cwd)
first and if it returns a string pass that value into getCanonicalRepoPath(...)
to compute currentRepoRoot (treat null as “not a git repo” but do not ignore
thrown errors); replace the empty catch with logic that logs the caught error
via processLogger (or appropriate logger) and rethrows unexpected errors, while
only allowing a benign fallback when findRepoRoot returned null; ensure the
value persisted into existingEnv.metadata.source_repo_root and the
reuseSameCheckout comparison use this canonicalized root.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 5499dbc9-54b7-46a3-8292-be192d2350e0

📥 Commits

Reviewing files that changed from the base of the PR and between e92ee2d and e2af7a2.

📒 Files selected for processing (2)
  • packages/cli/src/commands/workflow.test.ts
  • packages/cli/src/commands/workflow.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/cli/src/commands/workflow.test.ts

Comment on lines +432 to +448
let currentRepoRoot: string | null = null;
try {
currentRepoRoot = await git.getCanonicalRepoPath(cwd);
} catch {
// Non-fatal: cwd may not be a git repo (handled later) or git unavailable
}
const envSourceRoot =
existingEnv && typeof existingEnv.metadata?.source_repo_root === 'string'
? existingEnv.metadata.source_repo_root
: undefined;

// Intentional: when currentRepoRoot or envSourceRoot is unavailable, fall back
// to allowing reuse. This preserves backward compat for pre-existing envs and
// avoids blocking workflows when git is temporarily unavailable. Risk: could
// allow cross-checkout reuse in edge cases — logged as a warning below.
const reuseSameCheckout =
!existingEnv || !envSourceRoot || !currentRepoRoot || envSourceRoot === currentRepoRoot;
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "workflow.ts changed block:"
sed -n '426,536p' packages/cli/src/commands/workflow.ts

echo
echo "findRepoRoot() implementation:"
sed -n '14,40p' packages/git/src/repo.ts

echo
echo "getCanonicalRepoPath() implementation:"
sed -n '232,257p' packages/git/src/worktree.ts

Repository: coleam00/Archon

Length of output: 6635


Resolve the repo root before canonicalizing it.

Line 434 calls getCanonicalRepoPath(cwd) directly, but that function returns non-worktree paths unchanged. If the command runs from a subdirectory like /repo/subdir, it returns /repo/subdir as-is, causing same-clone comparisons to fail across different directory invocations. This unstable value is then persisted into metadata.source_repo_root at line 535. Additionally, the empty catch block swallows all exceptions—including real worktree metadata failures—and silently falls back to reuse-allowed behavior.

Call findRepoRoot(cwd) first to resolve any subdirectory to the actual repo top-level (returning null only for non-repo cases), then canonicalize that root. Log and throw on real errors rather than silencing them.

🛠️ Proposed fix
    let currentRepoRoot: string | null = null;
    try {
-     currentRepoRoot = await git.getCanonicalRepoPath(cwd);
-   } catch {
-     // Non-fatal: cwd may not be a git repo (handled later) or git unavailable
+     const repoRoot = await git.findRepoRoot(cwd);
+     currentRepoRoot = repoRoot ? await git.getCanonicalRepoPath(repoRoot) : null;
+   } catch (error) {
+     const err = error as Error;
+     getLog().error({ err, cwd }, 'worktree.reuse_root_detection_failed');
+     throw new Error(`Failed to resolve repository root for ${cwd}: ${err.message}`);
    }

Violates: "Never silently swallow errors related to unsupported or unsafe states — throw early with clear error messages."

Also applies to: 535

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/cli/src/commands/workflow.ts` around lines 432 - 448, The code
should resolve the repo top-level before canonicalizing and must not silently
swallow real errors: call findRepoRoot(cwd) first and if it returns a string
pass that value into getCanonicalRepoPath(...) to compute currentRepoRoot (treat
null as “not a git repo” but do not ignore thrown errors); replace the empty
catch with logic that logs the caught error via processLogger (or appropriate
logger) and rethrows unexpected errors, while only allowing a benign fallback
when findRepoRoot returned null; ensure the value persisted into
existingEnv.metadata.source_repo_root and the reuseSameCheckout comparison use
this canonicalized root.

…g errors, assert warning

- Call findRepoRoot(cwd) first to resolve subdirectories to repo
  top-level, then getCanonicalRepoPath to normalize worktree paths.
- Replace empty catch with debug log for unexpected detection errors.
- Add logger assertion to the undetectable-root test per CodeRabbit.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@halindrome
Copy link
Copy Markdown
Contributor Author

CodeRabbit Comments 2 & 3 — Addressed

Comment 2 (Minor): Test says "with warning" but didn't assert the warning was logged.
Fixed in 14c57f1 — added expect(mockLogger.warn).toHaveBeenCalledWith(...) assertion for worktree.reuse_root_undetectable.

Comment 3 (Major): getCanonicalRepoPath(cwd) doesn't resolve subdirectories to repo root first, causing instability when invoked from a subdir.
Fixed in 14c57f1 — now calls findRepoRoot(cwd) first (resolves subdirs to repo top-level), then getCanonicalRepoPath(root) (normalizes linked worktrees). Empty catch replaced with debug level log. Error is not rethrown because this path is intentionally non-fatal (failing to detect the root falls back to allowing reuse with a warning).

All 4 guard tests updated to mock the findRepoRoot → getCanonicalRepoPath chain.

🤖 Generated with Claude Code

@halindrome
Copy link
Copy Markdown
Contributor Author

Related Issues

This PR is a targeted fix for the DB-level worktree reuse path. During investigation, we identified the broader issue family:

Issue Scope Status
#1183 Worktree reuse across clones (original report) Fixed by this PR
#1187 Submodule initialization in worktrees Fixed by #1189
#1188 Git-level worktree adoption bypass + parallel collision Open
#1189 PR: optional submodule init config Ready for review
#1192 Project registration can't distinguish multiple clones of the same remote Open — architectural root cause

This PR (#1186) mitigates the symptom at the isolation layer. #1192 describes the architectural root cause: registerRepoAtPath deduplicates by remote-derived name, so two local clones share one codebase_id. A fix to #1192 would also resolve #1188, since distinct codebase IDs would produce distinct worktree namespaces.

🤖 Generated with Claude Code

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
packages/cli/src/commands/workflow.test.ts (1)

980-1026: Assert the mismatch warning in the cross-checkout test.

This case validates recreate behavior, but it should also assert worktree.reuse_different_checkout so the warning branch is explicitly covered.

🧪 Suggested assertion
     expect(provider.create).toHaveBeenCalled();
+    expect(mockLogger.warn).toHaveBeenCalledWith(
+      expect.objectContaining({ envSourceRoot: '/clone-a', currentRepoRoot: '/clone-b' }),
+      'worktree.reuse_different_checkout'
+    );
   });
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/cli/src/commands/workflow.test.ts` around lines 980 - 1026, The test
"skips reuse when existing env has different source_repo_root (GH-1183)" is
missing an assertion that the reuse-different-checkout warning branch was taken;
after calling workflowRunCommand add an assertion that
conversationDb.updateConversation was invoked with
worktree.reuse_different_checkout set true (e.g.
expect(conversationDb.updateConversation).toHaveBeenCalledWith(expect.objectContaining({
worktree: { reuse_different_checkout: true } }))). This uses the existing mocked
symbols conversationDb.updateConversation, workflowRunCommand, and the scenario
set up via isolationDb.findActiveByWorkflow to ensure the warning branch is
explicitly covered.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@packages/cli/src/commands/workflow.test.ts`:
- Around line 980-1026: The test "skips reuse when existing env has different
source_repo_root (GH-1183)" is missing an assertion that the
reuse-different-checkout warning branch was taken; after calling
workflowRunCommand add an assertion that conversationDb.updateConversation was
invoked with worktree.reuse_different_checkout set true (e.g.
expect(conversationDb.updateConversation).toHaveBeenCalledWith(expect.objectContaining({
worktree: { reuse_different_checkout: true } }))). This uses the existing mocked
symbols conversationDb.updateConversation, workflowRunCommand, and the scenario
set up via isolationDb.findActiveByWorkflow to ensure the warning branch is
explicitly covered.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 4ac3ece2-c2d9-4bdc-85e2-9ce65ae92eed

📥 Commits

Reviewing files that changed from the base of the PR and between e2af7a2 and 14c57f1.

📒 Files selected for processing (2)
  • packages/cli/src/commands/workflow.test.ts
  • packages/cli/src/commands/workflow.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/cli/src/commands/workflow.ts

@Wirasm
Copy link
Copy Markdown
Collaborator

Wirasm commented Apr 14, 2026

Thanks for this contribution, @halindrome! 🙏

Closing as superseded by #1198, which landed a stronger fix for the same class of bug at the provider layer (WorktreeProvider.findExisting()) rather than the CLI workflow layer. Your PR correctly identified the root cause and even flagged the remaining gap in its own "Known Limitations" section ("Does not guard git-level worktree adoption in WorktreeProvider.findExisting()") — that's exactly what #1198 closed.

Key differences in coverage:

Concern This PR (#1186) #1198
Coverage CLI workflow path only All entry points (CLI, Slack, Telegram, GitHub, Web)
Enforcement layer Application pre-check Provider hard guard
Failure mode Silent skip → create new Explicit throw with classified user message
Source of truth Stored source_repo_root metadata Live .git file pointer

Your work shaped the fix — the problem framing, the repro approach, and the clear scoping of limitations all fed directly into the investigation for #1198. Credit noted in that PR as well.

Thanks again for digging into this!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Worktree reuse matches environments from different local clones of the same remote

3 participants