Repository navigation
fix(rewind): skip turns Claude never answered when finding the turn before - #68
Merged
Merged
Conversation
… turn before previousConversationRun returned the nearest earlier run that was not rolled back, even a cancelled one with no provider turn. providerTurnForRun then returned undefined and thread.rewind refused with "the turn before it is not part of the current Claude session". It now skips runs with no provider turn, so the rewind resumes at the last answered run. A previous turn on a different provider thread still refuses. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…iderTurnForRun for skip and refusal The skip test now drains the effect worker and checks the provider rolled back to the answered run, lastRunOrdinal is that run's, and the cancelled runs and the rewound run end rolled_back. Red when the provider-turn skip is removed from ThreadRewindService. previousConversationRun and the rewind refusal now share one exported providerTurnForRun in ThreadRewindTargets, replacing runHasProviderTurn and the copy injected from Orchestrator, so they cannot drift. Orchestrator only stops passing the dependency. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Rewind refused a message when the turn just before it was a stopped turn Claude never answered: the messages typed mid-answer were folded into the earlier run, which left empty cancelled runs. The error blamed "the current Claude session" even though the chat had only one.
previousConversationRun(projection, run) earlier runs, in conversation order not rolled_back + and providerTurnForRun(run) exists # skip runs Claude never answered → last oneBoth users of it now agree: the refusal check (
ThreadRewindCommands.ts) and the rollback target (ThreadRewindService.ts). They share one exportedproviderTurnForRuninThreadRewindTargets.ts, so the skip and the refusal can't drift.Real case (affinity-vps, 2026-11-14): runs 29 completed → 30, 31 cancelled with no turn and 0 messages → 32 completed. Rewinding 32 was refused. It now rolls back to 29's turn.
Closes #67
Evidence
rewinds past cancelled turns Claude never answered, back to the last answered turnfails withCannot rewind to this message: the turn before it is not part of the current Claude session.(Tests 1 failed | 2 passed)After:
ThreadRewind,ThreadRewindService,AgentSessionImporter:Tests 23 passed (23). The test drains the effect worker and asserts oneprovider_turnrollback at the answered run, itslastRunOrdinal, and runs after itrolled_back. It goes red when the skip is removed fromThreadRewindService.vp run check:changed: format, lint, knip, typecheck and react compiler pass locally.Merge Danger
Door: two-way
Server-only logic change; revert the merge to undo. No data migration.
Blast Radius: rewind
Only rewinds that used to be refused behave differently. In those, unanswered runs between the target and the rewound message are now marked rolled back, which hides any message left on them. Claude never saw such a message.
🤖 Generated with Claude Code