From db2b9551f9d75a286adbadcd5cfaed5ec0efd1fa Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 27 May 2026 01:20:37 +0000 Subject: [PATCH] fix(user-metadata): fall back to indexer relays when outbox is exhausted If a user's NIP-65 outbox advertises only relays that don't hold their kind 0, profile fetching used to give up after EOSE on those relays. filterUserMetadataForKey now widens to the account's indexer relays once every outbox relay has either EOSE'd or is in cannotConnectRelays and metadata is still missing. UserWatcherSubAssembler invalidates filters on EOSE so the fallback re-evaluates without waiting for an unrelated trigger. --- .../user/watchers/FilterUserMetadataForKey.kt | 15 +++++++++++++-- .../user/watchers/UserWatcherSubAssembler.kt | 3 +++ 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/user/watchers/FilterUserMetadataForKey.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/user/watchers/FilterUserMetadataForKey.kt index e2d58bcb58..efbca44733 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/user/watchers/FilterUserMetadataForKey.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/user/watchers/FilterUserMetadataForKey.kt @@ -56,9 +56,20 @@ fun filterUserMetadataForKey( val perRelayUsers = mapOfSet { authors.forEach { key -> + val outbox = key.outboxRelays() val relays = - key.outboxRelays() - ?: (key.allUsedRelays() + LocalCache.relayHints.hintsForKey(key.pubkeyHex) + indexRelays) + when { + outbox == null -> + key.allUsedRelays() + LocalCache.relayHints.hintsForKey(key.pubkeyHex) + indexRelays + // Outbox is published but exhausted (every relay either EOSE'd + // or is known-unreachable) and metadata is still missing — + // widen to indexers so a misconfigured outbox doesn't strand + // the user's profile. + key.metadataOrNull()?.flow?.value == null && + outbox.all { it in cannotConnectRelays || since.since(key)?.get(it) != null } -> + outbox + indexRelays + else -> outbox + } (relays - cannotConnectRelays).forEach { add(it, key) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/user/watchers/UserWatcherSubAssembler.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/user/watchers/UserWatcherSubAssembler.kt index 3210d70cf4..6d8f7efb23 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/user/watchers/UserWatcherSubAssembler.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/relayClient/reqCommand/user/watchers/UserWatcherSubAssembler.kt @@ -59,6 +59,9 @@ class UserWatcherSubAssembler( } } } + // Re-evaluate filters: filterUserMetadataForKey may widen to indexer + // relays once a user's outbox is exhausted without yielding metadata. + invalidateFilters() } val sub =