diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/account/nip01Notifications/AccountNotificationsEoseFromInboxRelaysManager.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/account/nip01Notifications/AccountNotificationsEoseFromInboxRelaysManager.kt index c8f58630ce..0008693396 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/account/nip01Notifications/AccountNotificationsEoseFromInboxRelaysManager.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/account/nip01Notifications/AccountNotificationsEoseFromInboxRelaysManager.kt @@ -28,7 +28,6 @@ import com.vitorpamplona.quartz.nip01Core.relay.client.INostrClient import com.vitorpamplona.quartz.nip01Core.relay.client.pool.RelayBasedFilter import com.vitorpamplona.quartz.nip01Core.relay.client.subscriptions.Subscription import com.vitorpamplona.quartz.nip01Core.relay.normalizer.RelayUrlNormalizer -import com.vitorpamplona.quartz.utils.TimeUtils import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.FlowPreview import kotlinx.coroutines.Job @@ -51,17 +50,35 @@ class AccountNotificationsEoseFromInboxRelaysManager( key: AccountQueryState, since: SincePerRelayMap?, ): List { + // Backward-paging boundary: once the feed has filled a page, ask for everything older than + // its oldest card. It stays null until then — see the note on the missing week floor below, + // which is what let it stay null forever on a quiet inbox. + val pagingBoundary = key.feedContentStates.notifications.lastNoteCreatedAtIfFilled() + val inbox = key.account.notificationRelays.flow.value.flatMap { + // No `since` floor on the first fetch. These filters are scoped by `#p` to my own + // key and carry a relay-side `limit`, so an all-time query costs one index scan and + // returns at most `limit` events, newest first — exactly what Home does (it passes + // `since ?: boundary`, i.e. null on a cold start). + // + // This used to fall back to `oneWeekAgo()`, which silently emptied the tab for + // anyone whose last mention was older than a week: EOSE `since` is in-memory only, + // so EVERY cold start re-pinned the window to 7 days, and the paging boundary above + // could never rescue it — it only arms once the feed holds a full page, and the feed + // could not fill because the query only ever asked for a week. A fresh install of an + // established account hit the same deadlock. + val notificationSince = since?.get(it)?.time ?: pagingBoundary + filterSummaryNotificationsToPubkey( relay = it, pubkey = user(key).pubkeyHex, - since = since?.get(it)?.time ?: TimeUtils.oneWeekAgo(), + since = notificationSince, ) + filterNotificationsToPubkey( relay = it, pubkey = user(key).pubkeyHex, - since = since?.get(it)?.time ?: key.feedContentStates.notifications.lastNoteCreatedAtIfFilled() ?: TimeUtils.oneWeekAgo(), + since = notificationSince, ) } @@ -76,7 +93,9 @@ class AccountNotificationsEoseFromInboxRelaysManager( relay = relay, pubkey = user(key).pubkeyHex, groupIds = groupIds.distinct(), - since = since?.get(relay)?.time ?: TimeUtils.oneWeekAgo(), + // Same reasoning as the inbox filters above: `#p` + `#h` + `limit = 200` + // already bound this, so a week floor only hides older group activity. + since = since?.get(relay)?.time ?: pagingBoundary, ) } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/account/nip01Notifications/AccountNotificationsEoseFromRandomRelaysManager.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/account/nip01Notifications/AccountNotificationsEoseFromRandomRelaysManager.kt index 9aa0acc87d..7cfc8cd385 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/account/nip01Notifications/AccountNotificationsEoseFromRandomRelaysManager.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/account/nip01Notifications/AccountNotificationsEoseFromRandomRelaysManager.kt @@ -27,7 +27,6 @@ import com.vitorpamplona.amethyst.service.relays.SincePerRelayMap import com.vitorpamplona.quartz.nip01Core.relay.client.INostrClient import com.vitorpamplona.quartz.nip01Core.relay.client.pool.RelayBasedFilter import com.vitorpamplona.quartz.nip01Core.relay.client.subscriptions.Subscription -import com.vitorpamplona.quartz.utils.TimeUtils import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.FlowPreview import kotlinx.coroutines.Job @@ -51,8 +50,11 @@ class AccountNotificationsEoseFromRandomRelaysManager( key: AccountQueryState, since: SincePerRelayMap?, ): List { - // only loads this after the feed is built - val defaultSince = key.feedContentStates.notifications.lastNoteCreatedAtIfFilled() ?: TimeUtils.oneWeekAgo() + // only loads this after the feed is built, so it stays null on a quiet inbox. No week floor + // behind it: this probe is `#p`-scoped to me with `limit = 20`, so relays answer with the 20 + // newest either way — the floor only ever hid notifications older than a week, and since the + // boundary above needs a full page to arm, a quiet inbox could never page past it. + val defaultSince = key.feedContentStates.notifications.lastNoteCreatedAtIfFilled() return (key.account.followsPerRelay.value.keys - key.account.notificationRelays.flow.value).flatMap { val since = since?.get(it)?.time ?: defaultSince filterJustTheLatestNotificationsToPubkeyFromRandomRelays(it, user(key).pubkeyHex, since)