Skip to content

fix(web): stop showing old messages during thread switches - #17142

Closed
artile wants to merge 1 commit into
pingdotgg:mainfrom
tao-io:fix/thread-switch-repaint
Closed

artile wants to merge 1 commit into
pingdotgg:mainfrom
tao-io:fix/thread-switch-repaint

Conversation

@artile

@artile artile commented Oct 8, 2026 •

Copy link
Copy Markdown

Switching to a thread whose history is still loading paints the last-viewed transcript under the new title and pane widths. That old text reflows before the selected transcript replaces it, causing the jump shown in #17115.

Reuse cached history only for the selected thread. Keep the bounded cache and existing loading surface, and remove the context and callback guards used to paint another thread’s history. This changes the shared web/desktop ChatView; mobile navigation, providers, and wire contracts do not change.

Closes #17115.

Validation:

  • Four regression cases fail with the old fallback and pass with the fix: cold destinations, remounts, cache eviction, and returning to a cached thread.
  • vp test run apps/web/src/components/ChatView.logic.test.ts apps/web/src/components/chat/MessagesTimeline.logic.test.ts: 285 passed.
  • vp run --filter @t3tools/web typecheck: passed.
  • Targeted lint: no errors; existing warnings remain.
  • Integrated Browser panel pass against isolated data with neutral fixtures. Hold the destination’s bounded-history HTTP request, then switch from A. Before: the new B title appears above A’s messages. After: the new C title appears with the loading surface and no A messages; releasing the request shows C’s messages. C is a fresh destination so the before pass cannot warm its cache.
  • Switch between cached A and C. Per-frame checks find no foreign transcript under either title.

Before, while destination history is pending:

Before: title B with thread A messages

After, while destination history is pending:

After: title C with its loading surface

After the request completes:

After: title C with thread C messages

Videos: before, after: cold loading, after: cached switches. The long idle wait is cut from the before video; the switch and final response remain. Evidence is hosted as assets in the fork’s PR evidence entry; no evidence files are committed.

Model: gpt-6.1-sol. Harness: Codex in T3 Code.

@github-actions github-actions Bot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:L 100-499 changed lines (additions + deletions). labels Oct 8, 2026
@artile
artile marked this pull request as ready for review October 8, 2026 09:54
@coderabbitai

coderabbitai Bot commented Oct 8, 2026 •

Copy link
Copy Markdown
Contributor

Review in Change Stack →

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration
  • Configuration used: Path: .coderabbit.config.ts
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 2b3fabfe-39f2-4bb0-a971-e50281e0af38
📥 Commits

Reviewing files that changed from the base of the PR and between 2ea7684 and 292479e.

📒 Files selected for processing (3)
  • apps/web/src/components/ChatView.logic.test.ts
  • apps/web/src/components/ChatView.logic.ts
  • apps/web/src/components/ChatView.tsx

Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 8 remain after this review.

📝 Walkthrough

Thread switches now resolve the destination thread’s timeline without borrowing another thread’s entries. ChatView passes active-thread state and actions to MessagesTimeline and removes the paint-only timeline path.

Changes: Thread timeline switching

Layer / File(s) Summary
Destination timeline cache and resolution
apps/web/src/components/ChatView.logic.ts, apps/web/src/components/ChatView.logic.test.ts
The bounded cache stores per-thread entries. Loading switches use destination entries instead of entries from another thread. Tests cover empty, cached, evicted, and remounted destinations.
Active-thread timeline rendering
apps/web/src/components/ChatView.tsx
ChatView removes the paint-only timeline path. MessagesTimeline receives active-thread state and actions, including runs, diffs, provider status, workspace paths, and live-follow state.

Priority: ➖ Normal

Estimated code review effort: 2 (Simple) | ~12 minutes

Change: Bug fix · Severity of issue fixed: Low

Suggested reviewers: juliusmarminge

Merge Risk: ⚪ Minimal · up to 29247

Switching threads should no longer briefly show the previous thread's transcript. No concrete merge-blocking risk was found in the supplied changes.

Security architecture risk: ⚪ Minimal · up to 29247

The change keeps displayed history and available actions aligned with the selected thread. It removes the previous-thread display fallback without adding command privileges or changing service contracts. No introduced or materially worsened security issue was found in the reviewed change.

Retained concerns
No architecture-level concerns identified.

Security review details

Security Blast Radius

  • inferred — The changed exposure is client-side transcript selection and action presentation for the selected environment/thread. The comparison does not add service endpoints, credentials, IAM authority, or deployment configuration.

Trust Boundaries and Controls

  • observed — Live actions retain their existing owners and controls. Checkpoint rollback targets the active thread and environment, checks busy/unavailable states, and requires confirmation. App messages target the active started thread in queue mode. Forking explicitly uses source lineage while creating its target in the active environment.

Resilience and Maintainability Implications

  • observed — The unchanged history producer partitions live and resume state by environment/thread. HTTP completion updates projection and history under a lock; definitive missing history clears that thread, transient failure falls back to its socket path, and scoped finalization persists committed state with ownership checks. These controls support destination isolation during interruption and recovery.
Pre-merge checks: Passed 4
Check name Status Explanation
Linked Issues check Passed Issue #17115 requires the selected thread to avoid flashing the previous transcript during restoration. resolveThreadSwitchTimeline now returns destination entries or a cached entry keyed to `active…
Out of Scope Changes check Passed The reported changes are limited to shared ChatView timeline logic, its rendering path, and regression tests. The changes remove paint-only context and callback guards that could render another thre…
Title check Passed The title clearly summarizes the main change: preventing old messages from appearing during web thread switches.
Description check Passed The description clearly explains the problem, the fix, scope, linked issue, and verification results. It includes screenshots, videos, test commands, observed outcomes, and agent details. It does not …
Full details: Linked Issues check

Explanation

Issue #17115 requires the selected thread to avoid flashing the previous transcript during restoration. resolveThreadSwitchTimeline now returns destination entries or a cached entry keyed to activeThreadKey; it no longer uses a last-ready or other-thread fallback. ChatView uses active-thread state and retains the existing loading surface. The updated logic tests cover cold destinations, remounts, cache eviction, cached destinations, and environment isolation. These changes address the reported desktop and shared web chat behavior.

Full details: Out of Scope Changes check

Explanation

The reported changes are limited to shared ChatView timeline logic, its rendering path, and regression tests. The changes remove paint-only context and callback guards that could render another thread's history. The summary identifies no changes to mobile navigation, providers, wire contracts, or unrelated product behavior.

Full details: Description check

Explanation

The description clearly explains the problem, the fix, scope, linked issue, and verification results. It includes screenshots, videos, test commands, observed outcomes, and agent details. It does not use the exact “## Change,” “## Scope and approval,” and “## Verification” headings, and it does not explicitly document maintainer approval or an exemption rationale, but the required information is otherwise substantially complete.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create a new PR
  • Autopilot · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Comment @coderabbitai help to get the list of available commands.

@juliusmarminge juliusmarminge self-assigned this Oct 19, 2026
@juliusmarminge

Copy link
Copy Markdown
Member

Taking over this one as maintainer for composer-chat-14. I will keep the selected-thread transcript fix focused while preserving newer find, handoff, and paint guards from main. Thanks @artile and @tao-io for the original fix and interaction evidence.

@juliusmarminge

Copy link
Copy Markdown
Member

Thanks @artile and @tao-io for identifying the wrong-thread transcript fallback and demonstrating the selected-thread cache approach. Rebuilt this as the one-layer replacement #21560, which is verified and unmerged.

GitHub advertised maintainer edits for this fork, but rejected the push with HTTP 403. The replacement keeps the fix focused on current main: it removes the foreign transcript fallback while retaining the existing selected-thread cache and newer find, handoff, and paint-only guards.

I compared the complete original diff with the replacement. Selected-thread caching and cold-switch behavior are covered there; the original removal of context/callback guards is intentionally omitted to preserve current safety paths. Overlapping tests were consolidated into the cold-switch regression. Both independent reviewers found no blockers in two rounds; 311 focused tests pass, current-head CI passes, and the replacement body includes matching Linux web screenshots and recordings. Two browser fixtures also now await their lazy resources without changing assertions or timeouts.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:L 100-499 changed lines (additions + deletions). vouch:unvouched PR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Desktop thread switches flash the previous transcript and make the chat layout jump

2 participants