diff --git a/apps/desktop/src/app/session/hooks/use-route-resume.test.tsx b/apps/desktop/src/app/session/hooks/use-route-resume.test.tsx index ac6f24b016..47abc5c1fa 100644 --- a/apps/desktop/src/app/session/hooks/use-route-resume.test.tsx +++ b/apps/desktop/src/app/session/hooks/use-route-resume.test.tsx @@ -101,6 +101,60 @@ describe('useRouteResume', () => { expect(resumeSession).not.toHaveBeenCalled() }) + it('does not honor a leftover 4001 rebind during a /:sid -> /new delete transition', () => { + const resumeSession = vi.fn(async () => undefined) + const startFreshSessionDraft = vi.fn() + const activeSessionIdRef: MutableRefObject = { current: 'runtime-1' } + const creatingSessionRef = { current: false } + const runtimeIdByStoredSessionIdRef = { current: new Map([['session-1', 'runtime-1']]) } + const selectedStoredSessionIdRef: MutableRefObject = { current: 'session-1' } + + const { rerender } = render( + + ) + + expect(resumeSession).not.toHaveBeenCalled() + + // Idle reap queued requestSessionResume, then the user deleted the chat. + // Draft state lands before React Router flips /:sid -> /new. + activeSessionIdRef.current = null + selectedStoredSessionIdRef.current = null + rerender( + + ) + + expect(resumeSession).not.toHaveBeenCalled() + }) + it('self-heals a stranded routed session (null selected/active, same pathname, not a fresh draft)', () => { const resumeSession = vi.fn(async () => undefined) const startFreshSessionDraft = vi.fn() diff --git a/apps/desktop/src/app/session/hooks/use-session-actions.test.tsx b/apps/desktop/src/app/session/hooks/use-session-actions.test.tsx index d203de8e71..3027f7b1ef 100644 --- a/apps/desktop/src/app/session/hooks/use-session-actions.test.tsx +++ b/apps/desktop/src/app/session/hooks/use-session-actions.test.tsx @@ -1077,6 +1077,8 @@ describe('resumeSession failure recovery', () => { setResumeFailedSessionId(null) setMessages([]) setSessions([]) + $removedSessionIds.set(new Set()) + $sessionMutationsInFlight.set(new Set()) clearClarifyRequest() vi.restoreAllMocks() }) @@ -1094,6 +1096,20 @@ describe('resumeSession failure recovery', () => { await resume!('stored-1', true) } + it('does not resume a tombstoned session after delete', async () => { + $removedSessionIds.set(new Set(['stored-1'])) + + const requestGateway = vi.fn(async () => { + throw new Error('404: Session not found') + }) + + await runResume(requestGateway) + + expect(requestGateway).not.toHaveBeenCalled() + expect($resumeFailedSessionId.get()).toBeNull() + expect($selectedStoredSessionId.get()).toBeNull() + }) + it.each([ ['Codex tool-only', ''], ['DeepSeek text-plus-tool', 'I found two paths; choose one.']