Spun off from #312 (trace findings in docs/brainstorm/2026-05-02-pr-312-dm-decrypt-surface-review-brainstorm.md).
Problem
#312 surfaced the bunker-decrypt-failure signal at MessagesPage only. Two other DM entry points still fail-silent:
src/pages/ConversationPage.tsx:189 reads useDmConversation but never useDmInboxStatus. Deeplink to /messages/<id> while bunker is broken renders an empty conversation.
src/components/AppHeader.tsx:35 and src/components/AppSidebar.tsx:69 read useUnreadDmCount, which silently returns 0 when the bunker is broken.
Acceptance criteria
ConversationPage consumes useDmInboxStatus() and renders an inline banner (same copy as <InboxUnavailableState /> in MessagesPage.tsx:71-91) when status is 'unavailable'.
useUnreadDmCount exposes { data, isUnavailable } so consumers distinguish zero-unread from unreadable inbox.
AppHeader and AppSidebar Messages nav item shows an alert dot (vs. unread-count badge) when isUnavailable.
- Tests cover the unavailable state at all three surfaces.
Out of scope
Spun off from #312 (trace findings in
docs/brainstorm/2026-05-02-pr-312-dm-decrypt-surface-review-brainstorm.md).Problem
#312 surfaced the bunker-decrypt-failure signal at
MessagesPageonly. Two other DM entry points still fail-silent:src/pages/ConversationPage.tsx:189readsuseDmConversationbut neveruseDmInboxStatus. Deeplink to/messages/<id>while bunker is broken renders an empty conversation.src/components/AppHeader.tsx:35andsrc/components/AppSidebar.tsx:69readuseUnreadDmCount, which silently returns 0 when the bunker is broken.Acceptance criteria
ConversationPageconsumesuseDmInboxStatus()and renders an inline banner (same copy as<InboxUnavailableState />inMessagesPage.tsx:71-91) when status is'unavailable'.useUnreadDmCountexposes{ data, isUnavailable }so consumers distinguish zero-unread from unreadable inbox.AppHeaderandAppSidebarMessages nav item shows an alert dot (vs. unread-count badge) whenisUnavailable.Out of scope