Skip to content

fix: clone notes fetch and carryover snapshot for non-repo CWD#838

Merged
svarlamov merged 1 commit intomainfrom
fix/clone-notes-carryover-snapshot
Mar 28, 2026
Merged

fix: clone notes fetch and carryover snapshot for non-repo CWD#838
svarlamov merged 1 commit intomainfrom
fix/clone-notes-carryover-snapshot

Conversation

@svarlamov
Copy link
Copy Markdown
Member

@svarlamov svarlamov commented Mar 27, 2026

Summary

  • Skip carryover snapshot capture for clone/init commands — they create repos, so there is no pre-existing state to snapshot, and the worktree hint may point to a non-repo CWD causing a spurious error
  • Fall back to resolving CloneCompleted::target (from argv) when cmd.worktree doesn't contain a git repo, fixing clone notes fetch when def_repo hasn't updated the worktree hint
  • Add regression test: clone from inside an unrelated repo (exercises the fallback path)

Test plan

  • notes_sync_regression — 48/48 passed (all modes)
  • daemon_mode — 50/50 passed
  • integration (wrapped-daemon) — 3056/3056 passed
  • cargo clippy — no warnings
  • New test notes_sync_clone_from_inside_another_repo_fetches_authorship_notes passes in all 5 modes

🤖 Generated with Claude Code


Open with Devin

devin-ai-integration[bot]

This comment was marked as resolved.

Copy link
Copy Markdown
Contributor

@devin-ai-integration devin-ai-integration bot left a comment

Choose a reason for hiding this comment

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

Devin Review found 1 new potential issue.

View 3 additional findings in Devin Review.

Open in Devin Review

src/daemon.rs Outdated
Comment on lines +6383 to +6388
} else {
// No family resolved — this can happen for clone/init from a
// non-repo CWD when def_repo is not emitted or family
// resolution fails. Clone notes sync only needs the target
// path, not a family, so apply it directly.
self.maybe_apply_familyless_clone_side_effect(&applied);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 Missing exit_code guard in familyless clone side-effect path

The familied path guards against applying clone notes sync for failed commands via the if cmd.exit_code != 0 { ... return Ok(()); } early return at src/daemon.rs:6112. However, the new maybe_apply_familyless_clone_side_effect function has no such check, and neither does its call site at line 6388. This means when a git clone fails (exit_code != 0) from a non-repo CWD where family_key is None, the code will still attempt to resolve the clone target and call apply_clone_notes_sync_side_effect, potentially issuing unnecessary network requests (fetch_authorship_notes) against a partially-created or broken repository. Errors are caught and logged so there's no crash, but this is inconsistent with the familied path's behavior.

Suggested change
} else {
// No family resolved — this can happen for clone/init from a
// non-repo CWD when def_repo is not emitted or family
// resolution fails. Clone notes sync only needs the target
// path, not a family, so apply it directly.
self.maybe_apply_familyless_clone_side_effect(&applied);
} else {
// No family resolved — this can happen for clone/init from a
// non-repo CWD when def_repo is not emitted or family
// resolution fails. Clone notes sync only needs the target
// path, not a family, so apply it directly.
if applied.command.exit_code == 0 {
self.maybe_apply_familyless_clone_side_effect(&applied);
}
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Copy link
Copy Markdown
Contributor

@devin-ai-integration devin-ai-integration bot left a comment

Choose a reason for hiding this comment

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

Devin Review found 1 new potential issue.

View 6 additional findings in Devin Review.

Open in Devin Review

Comment on lines +931 to 937
if let Some(target) = target_from_def_repo.as_ref() {
candidates.push(target.clone());
}
if let Some(target) = target_from_def_repo.as_ref() {
if let Some(target) = target_from_argv.as_ref() {
let duplicate = candidates.iter().any(|existing| existing == target);
if !duplicate {
candidates.push(target.clone());
Copy link
Copy Markdown
Contributor

@devin-ai-integration devin-ai-integration bot Mar 27, 2026

Choose a reason for hiding this comment

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

🟡 Fallback worktree preference not updated to match swapped candidate ordering

The PR swaps the candidate ordering at lines 931–938 to prefer target_from_def_repo (always absolute) over target_from_argv (potentially relative), with an explicit comment (lines 924–930) explaining that def_repo should be preferred to avoid storing relative paths. However, the !resolved fallback at line 970 still uses target_from_argv.or(target_from_def_repo), which prefers the argv-derived target — directly contradicting the stated intent.

When both candidates fail common_dir_for_repo_path (e.g., the clone just finished but filesystem state is slightly delayed), the fallback stores the potentially-relative argv path into pending.worktree. Downstream, maybe_apply_familyless_clone_side_effect (src/daemon.rs:6403-6435) uses cmd.worktree to call apply_clone_notes_sync_side_effect, which runs git -C <path> — a relative path will fail to resolve from the daemon's unrelated CWD, causing clone notes sync to silently not happen.

Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

@svarlamov svarlamov force-pushed the fix/clone-notes-carryover-snapshot branch from 591dfad to ac00b76 Compare March 28, 2026 00:17
devin-ai-integration[bot]

This comment was marked as resolved.

Root cause: during `git clone`, child processes (remote-https, index-pack,
rev-list) emit trace2 def_repo events with the CWD as worktree — not the
clone destination. These arrive after the root process's correct def_repo
and overwrite pending.worktree, so the daemon tried to sync notes against
the parent directory (e.g. ~/projects) instead of the cloned repo.

Fix: for clone/init, once the first def_repo is captured (root process),
skip subsequent child def_repo events.

Supporting changes:
- Skip carryover snapshot for clone/init (target repo doesn't exist yet)
- Add familyless clone handler for when family resolution fails
- Prefer def_repo (absolute) over argv (may be relative/URL) in candidate
  and fallback ordering
- Add unit test for child def_repo overwrite scenario
- Add integration tests for absolute-target and implicit-target clone from
  non-repo CWD

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@svarlamov svarlamov force-pushed the fix/clone-notes-carryover-snapshot branch from ac00b76 to f441e36 Compare March 28, 2026 00:25
@svarlamov svarlamov merged commit 2c4a5cc into main Mar 28, 2026
18 of 21 checks passed
@svarlamov svarlamov deleted the fix/clone-notes-carryover-snapshot branch March 28, 2026 00:55
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.

1 participant