Reproduction:
- Open a conversation with many turns (e.g. a large OpenCode or codex thread).
- On iOS, the app can block the main thread until the watchdog kills it (0x8BADF00D), or render a blank conversation surface.
- Scrolling up to read older messages requires tapping "Load earlier messages" repeatedly, with small (5-turn) pages.
Root cause:
The client issues metadata-only thread/read requests (include_turns=false) in the shared multi-runtime resume/fallback path. Some bridges — including the opencode bridge — return the full turn archive even for metadata-only reads. The client merged all embedded turns unconditionally, so a 5-turn page could silently become hundreds of UI items rendered at once, exceeding SwiftUI's layout budget and blocking the main thread.
Additionally, iOS had no scroll integration for history loading: a manual button, page size 5, and a "Latest" jump that could be swallowed by a decelerating ScrollView.
Fix (two PRs):
- #PR1: honor include_turns=false so metadata reads stay bounded (shared Rust, all runtimes), plus pin the alleycat fork's pagination commits.
- #PR2: replace the manual button with scroll-triggered infinite scroll, larger pages, a working "Latest" jump, and auto-collapse for large conversations (iOS).
Reproduction:
Root cause:
The client issues metadata-only thread/read requests (include_turns=false) in the shared multi-runtime resume/fallback path. Some bridges — including the opencode bridge — return the full turn archive even for metadata-only reads. The client merged all embedded turns unconditionally, so a 5-turn page could silently become hundreds of UI items rendered at once, exceeding SwiftUI's layout budget and blocking the main thread.
Additionally, iOS had no scroll integration for history loading: a manual button, page size 5, and a "Latest" jump that could be swallowed by a decelerating ScrollView.
Fix (two PRs):