You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
paint a valid REST transcript as soon as it arrives instead of holding it behind a pending session.resume RPC
treat omitted messages as unavailable rather than authoritative empty history, recover by the resume-bound stored identity, and arm existing retry UI from authoritative message_count metadata
preserve optimistic, streaming, live-projection, and journal rows while enforcing the existing large-session paint budget and foreground array reuse
Testing
npx vitest run src/app/session/hooks/use-session-actions.test.tsx (51 tests)
npm run typecheck
npm run lint -- --quiet
npm run build
npx playwright test e2e/large-session-resume.spec.ts --grep "cold resume" (2 tests)
mutation check: an unconditional settle-time $messages clone fails the new reference-identity regression assertion
AI code review — automated review for reference, author can ignore or act on any point.
fix(desktop): recover stored session transcripts during resume
Exact paint-count assertion is timing-sensitive — apps/desktop/e2e/large-session-resume.spec.ts (assertUnchangedResume(..., { bursts: 1, kind: 'exact' }) → expect(paints.bursts).toBe(1)): the paint observer uses a 30ms flush debounce and the test waits a fixed waitForTimeout(1_000). On a slow CI runner the timer can coalesce or split bursts, making an exact equality flaky. The maximum budget path (toBeGreaterThanOrEqual(1) + toBeLessThanOrEqual) is far more forgiving; consider asserting a >= 1 lower bound alongside the exact upper bound, or polling the burst count with waitFor instead of a fixed sleep.
Fallback REST call passes an unverified profile argument — apps/desktop/src/app/session/hooks/use-session-actions/index.ts (getLatestSessionMessages(resumedStoredSessionId || storedSessionId, sessionProfile)): the new hook tests assert the fallback is invoked as ('stored-1', undefined), meaning sessionProfile is undefined in the harness. Confirm the production path passes the same profile to both the initial prefetch and the fallback; if they can differ, a profile-scoped gateway could hydrate the retry path from the wrong store.
Latch interplay with ancestor-prefix transcripts is untested — use-session-actions/index.ts (responseClaimsHistory = !createdThisRun.has(storedSessionId) && (resumed.message_count ?? 0) > 0): the design doc explicitly notes some gateway branches can have zero raw rows while the visible transcript comes from an ancestor prefix, and that case leans on the sidebar row as the other side of the OR. There is no test for "sidebar row absent + message_count > 0 + transcript legitimately from an ancestor prefix" — that combination would arm the failure latch and blank a valid session. An explicit test for the latch NOT arming there would pin the documented behavior.
JSON.stringify-based assertions are brittle — apps/desktop/src/app/session/hooks/use-session-actions.test.tsx (expect(JSON.stringify($messages.get())).toContain('persisted question')): string-containment on serialized message arrays is sensitive to key order/whitespace and only proves a substring exists. The file already uses this pattern elsewhere, but for the new tests a small helper that locates a message by content would make failures far easier to diagnose.
Thanks @friendfish. Closing as superseded: main now paints the prefetched REST transcript before resume settles and latches the stale-list-row case (ad800ea, f454288), which covers what this PR set out to do. #83729 is closed as fixed.
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
comp/desktopElectron desktop app (apps/desktop/*)P2Medium — degraded but workaround existssweeper:risk-session-stateSweeper risk: may lose/corrupt/mis-associate session or context statetype/bugSomething isn't working
4 participants
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
session.resumeRPCmessage_countmetadataTesting
npx vitest run src/app/session/hooks/use-session-actions.test.tsx(51 tests)npm run typechecknpm run lint -- --quietnpm run buildnpx playwright test e2e/large-session-resume.spec.ts --grep "cold resume"(2 tests)$messagesclone fails the new reference-identity regression assertionFixes #83729