Fix main-thread freeze on large conversations#10
Merged
nickdirienzo merged 1 commit intomainfrom Apr 26, 2026
Merged
Conversation
5323408 to
8d35526
Compare
Three changes working together: 1. Paginate ChatMessageListView to max 150 visible sections — prevents the AttributeGraph from growing unbounded during long remote sessions and bounds the work done by scrollToBottom. 2. Replace ForEach(Array(sections.enumerated()), id: \.element.id) with ForEach(visibleSections) using native Identifiable — eliminates the per-layout-pass initializeWithCopy for ChatSection that was copying entire [AgentMessage] arrays to evaluate tuple key paths, visible in the cpu_resource.diag crash trace. 3. Throttle scrollToBottom with a scrollQueued flag — lastMessageLength fires per streaming token, previously queuing hundreds of proxy.scrollTo calls per second and keeping the main thread in a continuous layout loop. Adds FlightBench targets for visibleSections slice cost and section ID enumeration, and wires FlightBench into the PR workflow so regressions in these paths block CI. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
8d35526 to
69a5bf3
Compare
5 tasks
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
Replace
ForEach(Array(sections.enumerated()), id: \.element.id)withForEach(visibleSections)— the tuple key path\.element.idwas copying the entireChatSectionenum (including[AgentMessage]arrays) on every layout pass to evaluate identities. Visible in the cpu_resource.diag crash trace asForEach.IDGenerator.makeID→initializeWithCopy for ChatSection. Using nativeIdentifiableevaluates\.iddirectly — for tool/thinking/provision groups this reads the stored UUID without touching the message arrays at all.Throttle
scrollToBottomwith ascrollQueuedflag —lastMessageLengthfires per streaming token, previously queuing hundreds ofproxy.scrollTocalls per burst. Each call triggers a layout pass; the 89% CPU for 100s in the second crash report was this hot loop.Add FlightBench targets + wire bench into CI — two new targets guard against regressions in
visibleSectionsslice cost and section ID enumeration.swift run -c release FlightBenchnow runs on every PR and blocks on failure.Test plan
swift run -c release FlightBench— all 10 targets green🤖 Generated with Claude Code