Skip to content

fix(swift-ios): keep thread catch-up complete and visible - #9678

Merged
t3dotgg merged 6 commits into
t3code/rebuild-mobile-app-swiftfrom
t3code/swift-thread-load-clarity
Sep 4, 2026
Merged

fix(swift-ios): keep thread catch-up complete and visible#9678
t3dotgg merged 6 commits into
t3code/rebuild-mobile-app-swiftfrom
t3code/swift-thread-load-clarity

Conversation

@t3dotgg

@t3dotgg t3dotgg commented Sep 4, 2026

Copy link
Copy Markdown
Member

Messages could go missing when they arrived during a required thread snapshot read. The follow-up read was skipped because the WebSocket was still open, and the app could label incomplete cached content as current.

Track skipped event cursors and keep fetching until the replacement covers them. Required reads start without the fixed 250 ms delay and cancel older fallback reads. Cached messages stay visible with a catch-up or failure label. Confirmed live thread data takes precedence over stale environment status.

Image, PDF, and video URL requests no longer block text recovery. Late results from an old thread or connection cannot replace current content.

Verification:

  • 83 focused native tests passed, including held snapshot responses, missing cursors, disconnect/navigation cancellation, and delayed PDF/video URLs. A final combined pass passed 180 tests.
  • Simulator checked cached reopen, server loss, retry, and recovery against an isolated environment with 1,013 threads.
  • Independent review passed after fixing attachment and connection-state findings.

Simulator states, with the same cached content kept visible:

Current Catching up Could not update
Current thread Cached thread catching up Cached thread with Retry

Based on the main SwiftUI branch. No transcript layout or scrolling changes.

Created with GPT-6 Astra (preview) in Codex.


Note

Medium Risk
Touches real-time thread streaming, snapshot/HTTP race recovery, and sync state presentation—high user-visible impact but bounded to iOS native client with strong test coverage.

Overview
Fixes thread detail sync on iOS so messages are not dropped or shown as “live” while a mandatory snapshot is still in flight.

NativeFeatureClient now tracks when a replacement snapshot must include events that arrived without a usable cursor (detailSnapshotRequiredAfterEpoch / threadHistoryEpoch). Forced HTTP refreshes skip the 250 ms coalesce delay, cancel stale catch-up fallbacks, and surface .catchingUp; refresh failures can emit .failed without treating cancellation as an error. Socket snapshots from an older subscription are ignored until the required read completes; a fresher socket snapshot can supersede a held HTTP read. Trailing refreshes after coalesced work use force: true when there was no base thread to reduce. refreshThread rejects outdated snapshots (threadSnapshotOutdated) when history moved during the read, and attachment URL hydration is scheduled asynchronously for all attachments missing URLs so PDF/video/image lookups do not block text catch-up.

UI (ThreadDetailView, ThreadRefreshPresentation, FeatureRootModel): cached transcript stays visible during catch-up/retry; working timers and empty-state copy are suppressed while a refresh banner is shown; .live thread sync wins over stale environment disconnect/reconnect probes; duplicate .threadSync values no longer churn observation.

Adds extensive catch-up integration tests and brief user docs for thread connection status and Retry.

Reviewed by Cursor Bugbot for commit 02ba3e2. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Fix thread catch-up visibility and snapshot ordering in Swift iOS client

  • Thread detail sync now tracks a required snapshot epoch per stream subscription and rejects snapshots from older subscriptions, so stale reads can no longer satisfy a newer required replacement.
  • Required refreshes enter a catching-up state immediately, cancel stale fallback reads, force trailing reads to run without coalescing delay, and surface non-cancellation failures as failed thread-sync events instead of silently discarding them.
  • Invalid stream reductions now discard the cached raw thread and trigger a forced replacement read; valid snapshots reset refresh state, clear the required epoch, and can restore live synchronization.
  • Non-image attachment URL resolution (files, videos) now runs async and no longer blocks publication of current thread text; scheduleAttachmentHydration resolves every attachment without a URL.
  • UI in ThreadDetailView.swift now shows refresh status above cached working indicators, hides stale environment reachability warnings when a thread is synced, and suppresses the ready-for-task empty state during refresh.
  • Risk: refreshThread ignores in-flight reads that cross an epoch change and may surface NativeFeatureClientError.threadSnapshotOutdated to callers when no replacement is pending; verify callers handle this new retryable error case.

Macroscope summarized 02ba3e2.

@github-actions github-actions Bot added vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. size:XL 500-999 changed lines (additions + deletions). labels Sep 4, 2026
@github-actions

github-actions Bot commented Sep 4, 2026

Copy link
Copy Markdown
Contributor

Thread transfer impact

✅ Thread transfer remains within every enforced ceiling.

ℹ️ No successful main baseline artifact is available yet. This run establishes the initial measurement.

Provider Metric Main baseline This PR Impact PR ceiling
Codex Total thread wire 13.6 KiB 15.1 KiB
Codex Thread snapshot wire 7.0 KiB 7.3 KiB
Codex Live turn WebSocket wire 6.6 KiB 7.8 KiB
Codex Live turn WebSocket decoded 57.1 KiB 66.4 KiB
Codex Live turn messages 10 21
Claude Total thread wire 13.6 KiB 15.1 KiB
Claude Thread snapshot wire 7.0 KiB 7.3 KiB
Claude Live turn WebSocket wire 6.5 KiB 7.8 KiB
Claude Live turn WebSocket decoded 57.8 KiB 66.4 KiB
Claude Live turn messages 9 21

Baseline: unavailable · PR result: 02ba3e2 · Source CI: success

Scenario and decoded snapshot size

10 historical turns, 5 command tools per turn, 878.9 KiB retained MCP result per historical turn, and a 1.05 MiB retained result in the measured turn.

  • Codex decoded thread snapshot: 113.8 KiB
  • Claude decoded thread snapshot: 114.5 KiB

Updated in place by a trusted workflow. PR artifacts are strictly validated and never executed.

@cursor cursor Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit beb19de. Configure here.

Comment thread apps/swift-ios/App/NativeFeatureClient.swift
@macroscopeapp

macroscopeapp Bot commented Sep 4, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Not approved

Macroscope's review found this PR not approvable — This PR substantially changes existing iOS thread synchronization and presentation behavior, coordinating WebSocket and HTTP recovery while altering cached-content, retry, attachment, and status handling. The focused tests reduce risk, but the concurrent state-management scope and customer-visible runtime impact warrant human review.

You can add or adjust custom eligibility rules. Learn more.

Comment thread apps/swift-ios/App/NativeFeatureClient.swift
@t3dotgg
t3dotgg merged commit f9498b7 into t3code/rebuild-mobile-app-swift Sep 4, 2026
25 checks passed
@t3dotgg
t3dotgg deleted the t3code/swift-thread-load-clarity branch September 4, 2026 19:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XL 500-999 changed lines (additions + deletions). vouch:trusted PR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant