Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.getcode.utils

/**
* Interface for errors where notifiability depends on runtime state.
* [ErrorUtils] checks [isNotifiable] to decide whether to report to Bugsnag.
*/
interface ConditionallyNotifiable {
val isNotifiable: Boolean
}
8 changes: 5 additions & 3 deletions libs/logging/src/main/kotlin/com/getcode/utils/ErrorUtils.kt
Original file line number Diff line number Diff line change
Expand Up @@ -64,9 +64,11 @@ object ErrorUtils {
ignoredErrors.none { it.isInstance(throwable) } &&
ignoredErrors.none { it.isInstance(throwableCause) }
) {
val isNotifiable = throwable is NotifiableError
|| throwableCause is NotifiableError
|| throwableCause !is CodeServerError
val isNotifiable = when {
throwable is ConditionallyNotifiable -> throwable.isNotifiable
throwableCause is ConditionallyNotifiable -> throwableCause.isNotifiable
else -> throwableCause !is CodeServerError
}

reporters.forEach { it.report(throwable, throwableCause, isNotifiable) }
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,6 @@ package com.getcode.utils
* Marker interface for errors representing unexpected failures (not user-caused).
* Errors implementing this are tagged in Bugsnag with metadata that triggers Slack notifications.
*/
interface NotifiableError
interface NotifiableError : ConditionallyNotifiable {
override val isNotifiable: Boolean get() = true
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import com.getcode.opencode.model.core.errors.SubmitIntentError.Signature
import com.getcode.opencode.model.core.errors.SubmitIntentError.StaleState
import com.getcode.opencode.model.core.errors.SubmitIntentError.Unrecognized
import com.getcode.utils.CodeServerError
import com.getcode.utils.ConditionallyNotifiable
import com.getcode.utils.NotifiableError

sealed class CodeAccountCheckError(
Expand Down Expand Up @@ -122,11 +123,27 @@ sealed class SubmitIntentError(
if (details.isNotEmpty()) append(": ${details.joinToString()}")
}), NotifiableError
data class StaleState(private val reasons: List<String>) :
SubmitIntentError(message = reasons.joinToString()), NotifiableError {
SubmitIntentError(message = reasons.joinToString()), ConditionallyNotifiable {
val isRaceCondition: Boolean
get() = reasons.any { it.startsWith("race detected:") }
val isGiftCardAlreadyClaimed: Boolean
get() = reasons.any { it.contains("gift card balance has already been claimed") }
val isGiftCardExpired: Boolean
get() = reasons.any { it.contains("gift card is expired") }
val isPoolAlreadyDistributed: Boolean
get() = reasons.any { it.contains("pool balance has already been distributed") }
val isIntentAlreadyExists: Boolean
get() = reasons.any { it.contains("intent already exists") }

val isExpected: Boolean
get() = isRaceCondition
|| isGiftCardAlreadyClaimed
|| isGiftCardExpired
|| isPoolAlreadyDistributed
|| isIntentAlreadyExists

override val isNotifiable: Boolean
get() = !isExpected
}

data class Denied(private val reasons: List<String>) :
Expand Down
Loading