From bfb0eb53f071e9633f59b5d9770314102846da95 Mon Sep 17 00:00:00 2001 From: Vitor Pamplona Date: Mon, 28 Sep 2026 10:48:35 -0400 Subject: [PATCH] refactor(marmot): drop the retry arm that could never reopen anything The catch-up retry also queued "decrypts on no canonical epoch" failures. The inbound processor remembers that result's id, so a retry only ever came back as a duplicate, and the outer layer had already opened on an epoch we hold, so no later commit could help it. Only an undecryptable outer layer is retried now; the comment that said otherwise is fixed. Co-Authored-By: Claude Opus 5.5 --- .../amethyst/commons/marmot/MarmotSyncPolicy.kt | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/marmot/MarmotSyncPolicy.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/marmot/MarmotSyncPolicy.kt index 3fc71f2066..bf579e4ab7 100644 --- a/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/marmot/MarmotSyncPolicy.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/marmot/MarmotSyncPolicy.kt @@ -145,7 +145,7 @@ class MarmotSyncPolicy( // Relays answer newest-first and several relays interleave, but a kind:445 can only // be opened at the epoch its predecessors built: a message sent after a commit fails - // (UndecryptableOuter, "no canonical epoch") if it is tried before that commit. The + // (UndecryptableOuter) if it is tried before that commit. The // cursor then moves past it and it is never fetched again, which is how an offline // member came back missing a rename and every message after a membership change. // Welcomes first (they create the groups), then group events oldest first. @@ -254,7 +254,10 @@ class MarmotSyncPolicy( } } -/** Failed only because the epoch it was sent at isn't reached yet; a later commit may open it. */ -private fun MarmotIngestResult.couldOpenAfterACommit(): Boolean = - this is MarmotIngestResult.UndecryptableOuter || - (this is MarmotIngestResult.Failure && message.startsWith(MarmotManager.NO_CANONICAL_EPOCH_ERROR)) +/** + * Failed only because the epoch it was sent at isn't reached yet; a later commit may open it. + * Only an undecryptable outer layer qualifies. A "no canonical epoch" failure already opened + * its outer layer on an epoch we hold, so no commit can help it, and the inbound processor + * remembers its id: a retry would only come back as a duplicate. + */ +private fun MarmotIngestResult.couldOpenAfterACommit(): Boolean = this is MarmotIngestResult.UndecryptableOuter