fix(concord): store the kind-13302 list replaceably so the hub populates

The Concord hub was empty even after the 13302 arrived: ConcordCommunityListEvent
extended plain Event, so LocalCache filed it by id and the dispatch when() had no
branch for it — it fell through to consumeRegularEvent. But ConcordChannelListState
observes the addressable note at Address(13302, pubkey, ""), which never received
the event, so liveCommunities stayed empty.

Make ConcordCommunityListEvent a BaseReplaceableEvent (kind 13302 is a NIP-01
replaceable — fixed empty d-tag, address = (kind, pubkey, "")) and add the
consumeBaseReplaceable branch next to the kind-10009 list, so it lands in the
addressable cache exactly like its NIP-29 sibling. The plane-wrap path (1059 ->
concordSessions.ingest in DecryptAndIndexProcessor) was already correct.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CzJ2Cwo8tg4oZq43oRa3ig
This commit is contained in:
Claude
2026-07-11 03:53:17 +00:00
parent ec51d4020c
commit f18ba03a48
2 changed files with 11 additions and 2 deletions
@@ -49,6 +49,7 @@ import com.vitorpamplona.amethyst.model.nipBCOnchainZaps.OnchainZapResolver
import com.vitorpamplona.amethyst.service.BundledInsert
import com.vitorpamplona.amethyst.service.checkNotInMainThread
import com.vitorpamplona.amethyst.ui.note.dateFormatter
import com.vitorpamplona.quartz.concord.cord02Community.ConcordCommunityListEvent
import com.vitorpamplona.quartz.concord.cord03Channels.ConcordChannelId
import com.vitorpamplona.quartz.experimental.agora.FundraiserEvent
import com.vitorpamplona.quartz.experimental.attestations.attestation.AttestationEvent
@@ -3772,6 +3773,14 @@ object LocalCache : ILocalCache, ICacheProvider {
consumeBaseReplaceable(event, relay, wasVerified)
}
// Concord private joined-communities list (kind 13302). Replaceable, self-encrypted;
// ConcordChannelListState observes it via the addressable cache (Address(13302, me, "")),
// so — exactly like the 10009 list above — it must be stored replaceably or the Concord
// hub stays empty even after the event arrives.
is ConcordCommunityListEvent -> {
consumeBaseReplaceable(event, relay, wasVerified)
}
is GroupMetadataEvent -> {
consume(event, relay, wasVerified)
}
@@ -23,7 +23,7 @@ package com.vitorpamplona.quartz.concord.cord02Community
import androidx.compose.runtime.Immutable
import com.vitorpamplona.quartz.concord.events.ConcordKinds
import com.vitorpamplona.quartz.nip01Core.core.Address
import com.vitorpamplona.quartz.nip01Core.core.Event
import com.vitorpamplona.quartz.nip01Core.core.BaseReplaceableEvent
import com.vitorpamplona.quartz.nip01Core.core.HexKey
import com.vitorpamplona.quartz.nip01Core.signers.NostrSigner
import com.vitorpamplona.quartz.utils.TimeUtils
@@ -48,7 +48,7 @@ class ConcordCommunityListEvent(
tags: Array<Array<String>>,
content: String,
sig: HexKey,
) : Event(id, pubKey, createdAt, KIND, tags, content, sig) {
) : BaseReplaceableEvent(id, pubKey, createdAt, KIND, tags, content, sig) {
override fun isContentEncoded() = true
/** Decrypts this list's entries with [signer], or empty on failure / wrong key. */