Skip to content

fix: self-heal blank screen after tab switch / iCloud sync#89

Closed
devin-ai-integration[bot] wants to merge 1 commit into
developfrom
devin/1781200840-fix-tab-switch-sync-bug
Closed

fix: self-heal blank screen after tab switch / iCloud sync#89
devin-ai-integration[bot] wants to merge 1 commit into
developfrom
devin/1781200840-fix-tab-switch-sync-bug

Conversation

@devin-ai-integration

Copy link
Copy Markdown
Contributor

Summary

Implements the fixes from the investigation in #88 to cure the blank-screen / stale-orb bug after tab-switch + iCloud sync.

Root cause recap: MessagingVC never observed .conversationStoreDidChange, so when pass-2 hydration (or iCloud surgicalRefresh) delivered messages after the UI had already loaded an empty stub, the screen stayed blank. Separately, the loadLastConversation → loadMessagesFromConversation path bypassed MainVC.loadConversation, so refreshAvatarVisibility() never ran — hero orb stayed visible even with messages present.

Changes

Fix A — MessagingVC self-heals on store changes:

// viewDidLoad observer registration:
NotificationCenter.default.addObserver(self,
    selector: #selector(handleConversationStoreDidChange),
    name: .conversationStoreDidChange, ...)

@objc func handleConversationStoreDidChange() {
    guard let current = currentConversationEntity else { return }
    if ai_state != .None || !streamingPartial.isEmpty { return } // don't clobber in-flight turn
    let fresh = conversationManager.getMessages(for: current)
    guard fresh.count > messages.count - 1 else { return }       // only reload if store has more
    loadMessagesFromConversation(...)
}

Fix D — messagesDidReload() hook:

// MessagingVC (base): called at end of loadMessagesFromConversation
func messagesDidReload() {}

// MainVC (override):
override func messagesDidReload() { refreshAvatarVisibility() }

Quick wins in ConversationFileStore:

  • prioritizeHydration(id:) — moves the active conversation to the front of the pass-2 hydration queue. Called from loadLastConversation.
  • isHydrated(id:) / requestHydrationIfNeeded(id:) — public queries used by the defensive guard in loadMessagesFromConversation: if the store returns 0 messages for a not-yet-hydrated conversation, defer render instead of clearing the screen.
  • Eviction tolerance in surgicalRefresh: a pendingEvictions: Set<String> stages missing IDs on the first pass; actual eviction only happens if the file is still missing on the next refresh — prevents transient iCloud download/rename from evicting the active conversation."

Link to Devin session: https://app.devin.ai/sessions/764ee807e9284b4998911008069229b9

Fix A: MessagingVC subscribes to .conversationStoreDidChange so it re-reads
the current conversation when pass-2 hydration or iCloud sync delivers new
messages. Guarded against clobbering in-flight agent turns (ai_state, streaming
partial).

Fix D: Add messagesDidReload() hook called at the end of every
loadMessagesFromConversation path. MainVC overrides it to call
refreshAvatarVisibility(), ensuring the hero orb collapses on every message-
load path — not just loadConversation and newMessageSent.

Quick wins:
- Prioritize the active conversation in pass-2 hydration queue so the user
  doesn't stare at a blank screen while other conversations hydrate first.
- Defensive empty-state guard: if the store returns 0 messages for a not-yet-
  hydrated conversation, defer render and request async hydration instead of
  clearing the screen.
- Eviction tolerance in surgicalRefresh: use a mark-for-eviction set so
  cache entries aren't evicted on the first miss (protects against transient
  iCloud file rename/download operations).

Co-Authored-By: bot_apk <apk@cognition.ai>
@devin-ai-integration

Copy link
Copy Markdown
Contributor Author
Original prompt from API User

Investigate a state/render bug in Loop (repo: theashbhat/LoopHarness).

Symptoms reported by Ash:

  • While in a conversation, switching to another tab and then returning seems to trigger an iCloud sync on re-entry.
  • After returning, the chat sometimes renders as a blank screen — as if it's a new chat — even though the user is (likely) still on the same conversation underneath.
  • Sometimes the agent orb is shown even though the conversation already has messages.
  • Feels like a state/render desync between the conversation store and the view after sync.

Goal of this session: investigate, do not ship a fix yet.

Please:

  1. Locate the code paths involved in:
    • Tab switching / tab focus regain
    • iCloud sync trigger + completion (CloudKit / NSUbiquitous… / whatever Loop uses)
    • Conversation message list rendering
    • Orb visibility logic (when the agent orb appears vs the populated chat view)
  2. Identify whether tab re-entry clears or replaces the in-memory messages before re-hydrating from iCloud (a likely race).
  3. Identify what signal drives orb-vs-messages visibility, and whether it can be wrongly true post-sync (e.g. keyed off "no messages currently loaded" rather than "conversation truly empty").
  4. Write up findings as a markdown report in the repo under docs/investigations/tab-switch-icloud-sync-bug.md including:
    • Suspected root cause(s)
    • Specific files / functions / state flows involved
    • Proposed fix direction(s) (don't implement yet)
    • Any quick wins or guardrails worth adding
  5. Open a PR with that report. Add ashbhat as a reviewer.

Keep the PR investigation-only — no behavior changes in this PR. A follow-up PR can implement the fix once Ash reviews the findings.

@devin-ai-integration

Copy link
Copy Markdown
Contributor Author

🤖 Devin AI Engineer

I'll be helping with this pull request! Here's what you should know:

✅ I will automatically:

  • Address comments on this PR. Add '(aside)' to your comment to have me ignore it.
  • Look at CI failures and help fix them

Note: I can only respond to comments from users who have write access to this repository.

⚙️ Control Options:

  • Disable automatic comment, CI, and merge conflict monitoring

@vercel

vercel Bot commented Jun 11, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
loop-harness Ready Ready Preview, Comment Jun 11, 2026 6:01pm

@theashbhat theashbhat closed this Jun 20, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant