From a2ff7aba90641a254fcead65eb1454e0290c5a3e Mon Sep 17 00:00:00 2001 From: Vitor Pamplona Date: Wed, 30 Sep 2026 08:26:01 -0400 Subject: [PATCH] fix(amy): list a readmission invite for a community you were banned from `concord invites` passed no held state to the inbox, so a re-invite at a newer epoch after an unban was filtered out as a catch-up for a community already held. Fold the held communities that have a pending newer-epoch invite and pass them, with our key, to `visible()`. Co-Authored-By: Claude Opus 5.5 --- .../amethyst/cli/commands/ConcordCommands.kt | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/cli/src/main/kotlin/com/vitorpamplona/amethyst/cli/commands/ConcordCommands.kt b/cli/src/main/kotlin/com/vitorpamplona/amethyst/cli/commands/ConcordCommands.kt index ce2ae3954b..9984aa6f1d 100644 --- a/cli/src/main/kotlin/com/vitorpamplona/amethyst/cli/commands/ConcordCommands.kt +++ b/cli/src/main/kotlin/com/vitorpamplona/amethyst/cli/commands/ConcordCommands.kt @@ -703,8 +703,17 @@ object ConcordCommands { Context.open(dataDir).use { ctx -> ctx.prepare() val inbox = sweepDirectInvites(ctx, dataDir) - val joined = ConcordStore(dataDir.concordFile).load().map { entryFor(it) } - val views = ConcordDirectInviteInbox.visible(inbox.pending.value.values, joined) + val stored = ConcordStore(dataDir.concordFile).load() + val joined = stored.map { entryFor(it) } + val pending = inbox.pending.value.values + // Fold only a held community some invite would move to a newer epoch: that is the one + // case (a readmission after a ban) whose visibility depends on the held roster. + val newerEpochIds = + pending + .filter { p -> stored.any { it.communityId.equals(p.invite.communityId, ignoreCase = true) && p.invite.rootEpoch > it.rootEpoch } } + .mapTo(HashSet()) { it.invite.communityId.lowercase() } + val folded = stored.filter { it.communityId.lowercase() in newerEpochIds }.associate { it.communityId.lowercase() to ConcordChannelCommands.foldState(ctx, it) } + val views = ConcordDirectInviteInbox.visible(pending, joined, heldStateOf = { folded[it.lowercase()] }, me = ctx.signer.pubKey) Output.emit(mapOf("invites" to views.map { directInviteJson(it) })) { if (views.isEmpty()) { "no pending direct invites"