From 6fdbe442881c8d0b09be692f233ee4b03d0d6c84 Mon Sep 17 00:00:00 2001 From: Vitor Pamplona Date: Wed, 30 Sep 2026 10:11:15 -0400 Subject: [PATCH] perf(concord): stop rebuilding Notifications on every fold while an invite is pending The pending Direct Invites fold in every session revision, and `visible()` mints new views each time. The views are plain classes, so the StateFlow never saw an equal value and re-emitted on every fold. Each emission clears and rebuilds all three Notifications feeds and Messages' New Requests. So an unanswered invite forced a full notification rescan on every Control Plane fold, back to back during boot. Emit only when what a row shows or ranks by changed: wrap id, catch-up, expired, followed sender, new channels. Co-Authored-By: Claude Opus 5.5 --- .../amethyst/commons/model/AccountConcordActions.kt | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/AccountConcordActions.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/AccountConcordActions.kt index e43fe44782..94bcd16f53 100644 --- a/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/AccountConcordActions.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/AccountConcordActions.kt @@ -126,6 +126,7 @@ import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asSharedFlow import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.combine +import kotlinx.coroutines.flow.distinctUntilChangedBy import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.stateIn @@ -949,8 +950,20 @@ class AccountConcordActions( visibleConcordDirectInvites(), acceptingConcordDirectInvites, ) { visible, accepting -> if (accepting.isEmpty()) visible else visible.filterNot { it.wrapId in accepting } } + // `visible()` re-runs on every session revision and mints new (identity-equal only) views, + // and each emission clears and rebuilds every Notifications feed. Emit only when something + // a row shows or ranks by actually moved. + .distinctUntilChangedBy { list -> list.map { InviteRowKey(it.wrapId, it.catchUp, it.expired, it.followedSender, it.newChannelIds) } } .stateIn(account.scope, SharingStarted.Eagerly, emptyList()) + private data class InviteRowKey( + val wrapId: HexKey, + val catchUp: Boolean, + val expired: Boolean, + val followedSender: Boolean, + val newChannelIds: List, + ) + private fun visibleConcordDirectInvites() = combine( directInviteInbox.pending,