CPLAT-11789: fix ccx navigation freeze — preview reads block the UI loop - #161
Merged
Merged
Conversation
Moving the cursor in the session browser froze intermittently: most moves were fine, then one landed on a large session and the UI locked up. Three preview reads ran synchronously inside Update, so the event loop was blocked for the whole file read: updateSessionConvPreview -> LoadMessagesSummary 465ms (180 MB) updateSessionStatsPreview -> ScanSessionStats 790ms refreshSessionPreviewLive -> LoadMessagesSummary every tick Measured over 120 cursor moves on a real corpus with the conversation preview open: p50 9ms, p99 191ms, max 466ms, 6/120 moves over 100ms — which is exactly the "sometimes" in the report. The existing 30ms navigation debounce does not help. It delays the stall until the cursor stops rather than removing it. Dispatch all three as commands instead, following the refs/outputs pattern already in the file: show "(loading…)", read off the loop, and apply the result from a completion message. Each keeps a per-session in-flight latch so it cannot dispatch twice, and discards results whose session is no longer selected — the cursor moves on while a read is in flight, and a late result must not overwrite the pane the user is looking at now. previewDispatchesFromView is deliberately a separate predicate from previewDispatchesCmd rather than an extension of it. View() cannot dispatch a command, so it must not drive these modes; but project rows use previewDispatchesCmd to decide whether to fall through to the project summary, and adding conversation there would reroute them to a representative session instead. Callers that discarded the return value had to be updated or the load would silently never run: handleTick (live sessions), mouse scroll, and the resize path in View — the last re-renders existing entries rather than dispatching, since View cannot dispatch and the pane would stick on "(loading…)". UI-loop blocking on the real corpus is now 0ms for both conversation and stats, with the preview still rendering on 120/120 moves.
|
| CVE | Package | Version | Fix |
|---|---|---|---|
| CVE-2026-39824 | golang.org/x/sys |
v0.42.0 |
0.44.0 |
View full analysis in Upwind Console
Scan completed in 18s
Scan history (1 scan)
| Commit | Scanned at | New | Resolved | Net |
|---|---|---|---|---|
71db971 < |
2026-08-30 12:23 UTC | +1 | 0 | +1 |
Last scanned: 71db971 · 2026-08-30 12:23 UTC
|
| Commit | Scanned at | New | Resolved | Net |
|---|---|---|---|---|
71db971 |
2026-08-30 12:23 UTC | — | — | — |
71db971 < |
2026-08-30 12:23 UTC | 0 | 0 | 0 |
Last scanned: 71db971 · 2026-08-30 12:23 UTC
Kairo-Kim
approved these changes
Aug 30, 2026
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.
JIRA: https://sendbird.atlassian.net/browse/CPLAT-11789
Problem
Navigating the session browser freezes intermittently — most cursor moves are fine, then one lands on a large session and the UI locks up.
Three preview reads ran synchronously inside
Update, blocking the Bubble Tea event loop for the entire file read:updateSessionConvPreview→LoadMessagesSummaryupdateSessionStatsPreview→ScanSessionStatsrefreshSessionPreviewLiveconversation re-readMeasured over 120 cursor moves on my real corpus with the conversation preview open:
That distribution is the report — usually fine, occasionally a visible lock-up.
The existing 30ms navigation debounce does not help: it delays the stall until the cursor stops rather than removing it.
LoadMessagesSummaryis the worst offender per byte — it needs only the first 50 messages but keeps a ring buffer for the tail, so it scans to EOF regardless of size.Fix
Dispatch all three as
tea.Cmd, following the refs/outputs pattern already in the file: show(loading…), read off the loop, apply from a completion message.previewDispatchesFromViewis a deliberately separate predicate frompreviewDispatchesCmd.View()cannot dispatch, so it must not drive these modes — but project rows usepreviewDispatchesCmdto decide whether to fall through to the project summary, and adding conversation there would reroute them to a representative session. Merging the two would have been a silent regression.Callers that discarded the return value had to be updated or the load would never run:
handleTick(live sessions), mouse scroll, and the resize path inView— the last re-renders existing entries instead of dispatching, since View cannot dispatch and the pane would otherwise stick on(loading…).Result
UI-loop blocking on the real corpus: 465ms → 0ms (conversation and stats both), with the preview still rendering on 120/120 moves.
Testing
go test ./...),go vet ./...clean.Note
Verified by measurement, not by eye — I can't drive the TUI interactively. Worth a quick
make build && ./bin/ccxscroll through the session list to confirm it feels right, particularly that the brief(loading…)on large sessions is not distracting.