Skip to content

fix(server): rewind on chats imported from the Claude desktop app - #5

Merged
ziyadakl merged 2 commits into
custom-v2from
fix/imported-rewind
Oct 8, 2026
Merged

ziyadakl merged 2 commits into
custom-v2from
fix/imported-rewind

Conversation

@ziyadakl

@ziyadakl ziyadakl commented Oct 7, 2026

Copy link
Copy Markdown
Owner

Summary

Chats imported from the Claude desktop app had no rewind button, because the import heal recorded no rewind points for them. Two causes, both fixed:

 AgentSessionScanner.readThread
   for each transcript record
+    if its uuid was already seen: skip   # desktop app re-writes blocks of history
     keep record

 placedTurns(placed, transcript)
-  if first stored message != transcript's first prompt: return []   # long chats cut to their last 200
+  turns start at the first stored prompt; earlier stored replies get none
+  first turn remembers nativeResumeAt = transcript turn just before its prompt

A rewind to that first turn must not throw away the hidden earlier history:

 CheckpointRollbackService -> target thread_start
+  nativeResumeAt = threadStartResumeAt(providerTurns)
 ClaudeAdapterV2 rollback(thread_start)
-  start a fresh, empty Claude session
+  if nativeResumeAt: resume the same session at it
+  else: start a fresh session (unchanged for real first prompts)

nativeResumeAt is an optional field on the stored provider turn (JSON payload, no migration). Other providers ignore it; only Claude chats are imported.

Chats already imported heal on their own: ImportedRewindHeal runs every minute and skips only chats that already have rewind points.

Evidence

  • Before: on a copy of the owner's real data (Mac, build b1ba5788), 275 of 884 imported prompts had no rewind point. Examples: 60491f83 0/85, d733ff9e 2/75, e43fd16c 1/67. The server log repeated "matches 2–3 transcript lines" / first-prompt skips every minute.
    After: same copy, preview build 81ed912b, one heal pass: 60491f83 85/85, d733ff9e 75/75, e43fd16c 67/67, 7cdea96a 37/37. 14 prompts left across 2 chats, being looked at separately.
  • New tests, each red first, then green:
    • scanner keeps the first copy of a repeated uuid
    • heal of a transcript the desktop app wrote parts of twice
    • heal of a chat whose first stored message is a reply
    • Claude adapter resolves where a thread-start rewind resumes
    • replay: rewinding the first prompt of a mid-transcript import resumes at the prior reply
  • Targeted run on the VPS: Test Files 6 passed (6) · Tests 269 passed (269). apps/server typecheck: exit 0.

Merge Danger

Door: two-way

Reverting the code is enough. Rewind points the heal already recorded stay in the database; they are ordinary imported runs and older builds read them fine.

Blast Radius: imported-chats

Only chats imported from Claude desktop or Claude CLI, and only their rewind. Native T3 chats and Codex/OpenCode/Pi never set the new field.

⚠️ The last commit, temp: build Mac preview…, only exists to build a Mac test archive for this branch. Drop it before merging.

🤖 Generated with Claude Code

@github-actions github-actions Bot added vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. size:M labels Oct 7, 2026
@ziyadakl

ziyadakl commented Oct 7, 2026

Copy link
Copy Markdown
Owner Author

Full apps/server suite, run on the VPS because this fork's CI waits forever for Blacksmith runners it can't use:

Test Files  1 failed | 494 passed | 7 skipped (502)
     Tests  6836 passed | 41 skipped (6877)

The one failure is src/preview/ServerBrowserPage.test.ts: browserType.launch: Executable doesn't exist at ~/.cache/ms-playwright/chromium_headless_shell-1223/…. The VPS lacks that Playwright browser download. This PR doesn't touch apps/server/src/preview.

claude added 2 commits October 8, 2026 04:05
…ewind points

The desktop app writes blocks of a chat's history into its transcript again,
so a uuid could appear two or three times and the heal placed nothing. The
scanner now keeps the first record per uuid.

A chat imported from the middle of its transcript (its first message a
reply) got no turns. Turns now start at the first placed prompt, and that
turn records where the transcript before it ends (nativePriorMessageId), so
a rewind to the thread start resumes there instead of starting the session
over.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
@ziyadakl
ziyadakl force-pushed the fix/imported-rewind branch from b64744b to 7662a1e Compare October 8, 2026 02:05
@ziyadakl
ziyadakl merged commit 7464a1d into custom-v2 Oct 8, 2026
21 of 23 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:M vouch:trusted PR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants