fix(server): skip imports of native agent sessions - #10950
Conversation
| return; | ||
| } | ||
| const thread = outcome.thread; | ||
| if (nativeSessions.has(`${thread.providerInstanceId}\0${thread.providerSessionId}`)) { |
There was a problem hiding this comment.
🟡 Medium project/AgentSessionImporter.ts:188
The importer creates an import: thread even when a native Claude/Codex session has been started or resumed for the same provider session after listBindings() runs, producing duplicate conversations with different threadId values. Because nativeSessions is only a one-time snapshot, and insert-ignore applies to the import threadId, this race is not prevented; perform the native-session check atomically with the import/reservation (or under the relevant binding lock).
🤖 Copy this AI Prompt to have your agent fix this:
In file @apps/server/src/project/AgentSessionImporter.ts around line 188:
The importer creates an `import:` thread even when a native Claude/Codex session has been started or resumed for the same provider session after `listBindings()` runs, producing duplicate conversations with different `threadId` values. Because `nativeSessions` is only a one-time snapshot, and insert-ignore applies to the import `threadId`, this race is not prevented; perform the native-session check atomically with the import/reservation (or under the relevant binding lock).
There was a problem hiding this comment.
Confirmed and fixed. Both Claude and Codex regression cases failed when a native binding was persisted immediately before the import reservation. The insert-ignore reservation now checks native ownership in the same SQLite INSERT ... SELECT WHERE NOT EXISTS statement; the importer skips publication when no binding was reserved. The batch snapshot remains a fast path. All 26 importer and directory tests pass, including provider-instance isolation; server typecheck and targeted lint pass.
There was a problem hiding this comment.
Sorry, I'm unable to act on this request because you do not have permissions within this repository.
ApprovabilityVerdict: Would Approve Macroscope's review found this PR approvable — This is a localized, well-tested bug fix that prevents native Claude/Codex sessions from being imported as duplicate conversations without changing schemas or product defaults. An unresolved Medium finding identifies a possible concurrent-import race, which should be addressed separately as a correctness concern. Not approved because:
Adjust the Minimum Blocking Severity for this repo — including turning it Off — in Settings. You can add or adjust custom eligibility rules. Learn more. |
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Advanced Run ID: 📒 Files selected for processing (4)
Included review availability: Your plan provides up to 10 included reviews per hour; 6 remain after this review. 📝 WalkthroughWalkthroughThe importer now checks native provider bindings before creating imported threads. It extracts Claude and Codex session identifiers, skips matching sessions, and protects the reservation against concurrent native bindings. ChangesNative session import deduplication
Priority: ➖ Normal Estimated code review effort: 3 (Moderate) | ~20 minutes Severity of issue fixed: Medium Merge Risk: ⚪ Minimal · up to Bulk imports now skip sessions already owned by matching native threads while preserving imports for other provider instances. The duplicate-prevention behavior and reservation race are covered, with no remaining concrete merge-blocking risk. Suggested reviewers: Sequence Diagram(s)sequenceDiagram
participant AgentSessionImporter
participant ProviderSessionDirectory
participant ProviderSessionRuntime
participant ThreadStore
AgentSessionImporter->>ProviderSessionDirectory: list native bindings
ProviderSessionDirectory-->>AgentSessionImporter: native session identifiers
AgentSessionImporter->>ThreadStore: inspect imported thread
AgentSessionImporter->>ProviderSessionDirectory: upsert with unlessNativeSessionId
ProviderSessionDirectory->>ProviderSessionRuntime: reserve imported session
ProviderSessionRuntime-->>ProviderSessionDirectory: create or skip reservation
ProviderSessionDirectory-->>AgentSessionImporter: binding state
AgentSessionImporter-->>ThreadStore: create imported thread only when reservation succeeds
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
|
Reviewed CodeRabbit's linked-issue warning. Keeping project discovery unchanged is intentional: Removing an entire project candidate because it contains native history would also hide unrelated importable sessions. This PR protects the shared bulk-import path, including an atomic native-ownership check when reserving a new import binding. Session-level discovery UX and cross-environment deduplication remain separate scope. |
Bulk import could create a second thread for a Claude or Codex session already owned by a native T3 thread. The importer only checked the generated
import:thread ID.Read runtime bindings once per import batch to skip known native sessions, scoped to the provider instance. Check native ownership again atomically in the SQLite insert that reserves each new import binding, covering bindings created during transcript scanning. Existing import retries keep their current behavior.
Fixes #10933's same-environment duplication. This does not remove existing duplicates or deduplicate across environments. Project discovery keeps its existing path-based meaning; related #10631 handles individual Claude attachment.
Validation: reproduced duplicate creation before the initial fix and reproduced the concurrent binding race before this follow-up, for both providers. All 26 importer and directory tests pass, including unchanged native threads, no duplicate bindings, and provider-instance isolation. Server typecheck and targeted lint pass. No UI changes.
Implemented with GPT-6 in Codex.
Summary by CodeRabbit