feat(session): non-destructive duplicate Claude session-ID resolution (prototype)#1338
feat(session): non-destructive duplicate Claude session-ID resolution (prototype)#1338alanvgreen wants to merge 1 commit into
Conversation
… (prototype) When two live Claude sessions in the same project dir end up sharing a ClaudeSessionID, UpdateClaudeSessionsWithDedup blanks the newer one's ID and zeroes ClaudeDetectedAt. CanFork() requires a non-empty, recently-detected ID, so the newer session becomes un-forkable — the TUI never renders `f` — and because its tmux env still asserts the shared ID it re-adopts it on the next poll and flip-flops forever. This is the "can't fork a same-cwd session" symptom. Add RepairDuplicateClaudeSessions, which resolves the collision non-destructively: the older session (by CreatedAt) keeps the ID; the newer collider is re-keyed to its OWN fresh session ID, forked from the shared conversation (claude --session-id <fresh> --resume <shared> --fork-session) via the existing fork machinery. It stays forkable, and once restarted the two sessions have genuinely distinct CLAUDE_SESSION_IDs so restart_sweep no longer cross-kills them (issue #1246 family). Falls back to the legacy blank when the owner cannot be forked. Prototype scope: adds the function plus unit + characterization tests; not yet wired into the dedup call sites (the caller must Restart() the returned instances for the fork to materialize). Opening as a draft for design review of that wiring (auto-restart vs. user-prompted "split this session?"). Refs #1147, #1246 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
Important Review skippedDraft detected. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Plus Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
|
@alanvgreen can you expland this to support the know f agents, which includes codex, pi and opencode? |
|
Checking in on this prototype — a lot has shipped since it was opened (v1.9.50→56, incl. the #1352 session-id collision guards and #1384 credential-chain fix, which overlap this PR's problem space). Is the non-destructive duplicate-session-ID resolution still something you want to pursue? If yes: a rebase onto current main + un-draft and it'll get a prompt review. If the recent fixes cover your original pain, no hard feelings closing it — just let us know either way so the board stays accurate. |
|
Rebase-or-close check — here's what's changed in this problem space, and where this PR still stands. Not superseded. The two big collision-family fixes that shipped since this draft opened address adjacent symptoms, not this PR's core mechanism:
Neither touches the destructive dedup this PR targets. Confirmed on current Caveat: the branch is ~91 commits behind Next step — your call: if you still want this, a rebase onto current |
|
This is a really nicely-scoped prototype. The characterization test that pins the current blank-and-zero behavior before introducing the non-destructive path is exactly the right instinct, and reusing A few things to consider on the way to completion:
A rebase onto current main would help too. The underlying bug is confirmed still present, so this is solving a real problem — nice work. Leaving as draft per its status; flagging the above for whenever you pick it back up. |
|
🤖 autopilot: No CI check runs found for this PR. Cannot merge without a passing CI run. This PR also appears to address session-ID deduplication that may be superseded by #1526 — please check for overlap before reviving. Please push a commit or re-run CI to trigger checks if still relevant. Generated by Claude Code |
|
🤖 autopilot 2026-06-29: DRAFT — PR is marked as draft and no CI checks have run. Additionally FLAGGED as data-sensitive (touches Generated by Claude Code |
Summary
Prototype fix for the "can't fork a session in a multi-session project dir" symptom: pressing
f(oragent-deck session fork) does nothing on the newer of two Claude sessions that share a working directory.Root cause
New sessions and forks already get distinct
--session-ids. But when two live Claude sessions in the same project dir end up sharing aClaudeSessionIDat runtime,UpdateClaudeSessionsWithDedup(internal/session/instance.go) resolves the collision destructively:CanFork()requires a non-empty, recently-detected ID, so the newer session becomes un-forkable — the TUI never renders thefkey. And because the session's tmux env still asserts the shared ID,UpdateClaudeSessionre-adopts it on the next poll, so it flip-flops forever.This change
Adds
RepairDuplicateClaudeSessions, which resolves the collision non-destructively:CreatedAt) keeps the ID;claude --session-id <fresh> --resume <shared> --fork-session) via the existing fork machinery;CLAUDE_SESSION_IDs, sorestart_sweepno longer cross-kills them (issue Default multi-instance mode (allow_multiple=true) lets concurrent instances tear down each other's live sessions #1246 family);The function + tests are here, but it is not yet wired into the dedup call sites (
internal/ui/home.go). Wiring requires the caller toRestart()the returned instances so the fork materializes. The open design question is how:Feedback on that wiring approach is what this draft is for.
Tests
TestLegacyDedup_ReproducesUnforkableSymptom— characterizes the current destructive behavior (blank + zero →CanFork()false).TestRepairDuplicateClaudeSessions_RekeysNewerCollider— newer collider gets a fresh, distinct ID, stays forkable, fork command set.TestRepairDuplicateClaudeSessions_FallsBackToBlankWhenOwnerNotForkable— degenerate case.All pass (
5/5in a cleanHOME);gofmt/go vetclean; fullinternal/sessionpackage shows zero new failures vs. baseline.Refs #1147, #1246
🤖 Generated with Claude Code