From ccd4677f5d7afe2c9dd02b9ab879e61049c82e13 Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 14 Jul 2026 22:45:25 +0000 Subject: [PATCH] fix: render p-tagged NIP-29 group replies on the Notifications tab MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A reply to my message inside a joined NIP-29 relay group is a kind-9 ChatEvent that p-tags me (see ChannelNewMessageViewModel). It is already fetched at startup by filterGroupNotificationsToPubkey (scoped `#p`=me + `#h`=my groups on the group's host relay), but NotificationFeedFilter's `acceptableEvent` checks `kind in NOTIFICATION_KINDS` before the p-tag gate, and kind 9 (ChatEvent) was missing from that set — so those replies were dropped before ever reaching the p-tag check and never surfaced. Add ChatEvent.KIND to NOTIFICATION_KINDS. The existing gates handle the rest: my own messages are excluded (author != me), the reply p-tags me (isTaggedUser), and its `q`-tag to my message makes it pass tagsAnEventByUser in Selected mode too. Pin the behaviour with a tripwire test in NotificationKindsContractTest. Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_01VxpT7J4xt37EF5yJDw1htK --- .../dal/NotificationFeedFilter.kt | 7 +++++++ .../dal/NotificationKindsContractTest.kt | 20 +++++++++++++++++++ 2 files changed, 27 insertions(+) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/notifications/dal/NotificationFeedFilter.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/notifications/dal/NotificationFeedFilter.kt index 124e578ad0..8f4cdc9eb2 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/notifications/dal/NotificationFeedFilter.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/notifications/dal/NotificationFeedFilter.kt @@ -81,6 +81,7 @@ import com.vitorpamplona.quartz.nipA0VoiceMessages.VoiceEvent import com.vitorpamplona.quartz.nipA0VoiceMessages.VoiceReplyEvent import com.vitorpamplona.quartz.nipA4PublicMessages.PublicMessageEvent import com.vitorpamplona.quartz.nipBCOnchainZaps.zap.OnchainZapEvent +import com.vitorpamplona.quartz.nipC7Chats.ChatEvent import com.vitorpamplona.quartz.nipF4Podcasts.episode.PodcastEpisodeEvent import com.vitorpamplona.quartz.nipF4Podcasts.metadata.PodcastMetadataEvent import kotlinx.coroutines.flow.MutableStateFlow @@ -136,6 +137,12 @@ class NotificationFeedFilter( setOf( BadgeAwardEvent.KIND, ChannelMessageEvent.KIND, + // NIP-29 group chat (kind 9). A reply to my group message is a + // kind-9 that p-tags me (see ChannelNewMessageViewModel), fetched + // at startup by filterGroupNotificationsToPubkey. Without kind 9 + // here the acceptableEvent kind gate drops it before the p-tag + // check, so those replies never render on the Notifications tab. + ChatEvent.KIND, ChatMessageEvent.KIND, ChatMessageEncryptedFileHeaderEvent.KIND, CommentEvent.KIND, diff --git a/amethyst/src/test/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/notifications/dal/NotificationKindsContractTest.kt b/amethyst/src/test/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/notifications/dal/NotificationKindsContractTest.kt index 0e49022cf9..886bf711b9 100644 --- a/amethyst/src/test/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/notifications/dal/NotificationKindsContractTest.kt +++ b/amethyst/src/test/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/notifications/dal/NotificationKindsContractTest.kt @@ -23,6 +23,7 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn.notifications.dal import com.vitorpamplona.amethyst.commons.moderation.notifications.NotificationKinds import com.vitorpamplona.quartz.nip59Giftwrap.wraps.EphemeralGiftWrapEvent import com.vitorpamplona.quartz.nip59Giftwrap.wraps.GiftWrapEvent +import com.vitorpamplona.quartz.nipC7Chats.ChatEvent import org.junit.Assert.assertTrue import org.junit.Test @@ -73,4 +74,23 @@ class NotificationKindsContractTest { unaccounted.isEmpty(), ) } + + /** + * A reply to my message inside a NIP-29 relay group is a kind-9 [ChatEvent] + * that p-tags me. It is fetched at startup by `filterGroupNotificationsToPubkey` + * (scoped `#p`=me + `#h`=my groups on the group's host relay), but the + * `acceptableEvent` gate first checks `kind in NOTIFICATION_KINDS`, so without + * kind 9 in the set the reply is dropped before the p-tag check and never + * surfaces on the Notifications tab. Pin its presence so it can't silently + * regress. + */ + @Test + fun `nip-29 group chat replies render on the Android notifications tab`() { + assertTrue( + "ChatEvent.KIND (9) is missing from NOTIFICATION_KINDS. NIP-29 group " + + "replies that p-tag the user would be dropped by the acceptableEvent " + + "kind gate before the p-tag check and never notify.", + ChatEvent.KIND in NotificationFeedFilter.NOTIFICATION_KINDS, + ) + } }