From ac0016331c14598e5102d2a405f6740f7fd57514 Mon Sep 17 00:00:00 2001
From: Matthias Urhahn <matthias.urhahn@sap.com>
Date: Fri, 9 Apr 2021 16:59:27 +0200
Subject: [PATCH] Adjust EW/PT riskresult combination (EXPOSUREAPP-6169)
 (#2788)

* Refactoring, move extensions closer to their use-case.

* Adjust riskState combination, if either calculation fails, the combined riskstate is also CALCULATION_FAILED and should show the white failure card on the home screen.

* Introduce ptRiskLevelResult.checkInOverlapCount as analog to ewRiskLevelResult.matchedKeyCount for the CombinedEwPtRiskLevelResult to allow the UI show information for "low risk with encounters" situations.

* LINTs

* Adjust unit tests to reflect the risk status combination priority (FAILED>HIGH>LOW).

* Home screen download/calculation progress should include PresenceTracingWarningTask

* LINTs

Co-authored-by: Lukas Lechner <lukas.lechner@sap.com>
Co-authored-by: harambasicluka <64483219+harambasicluka@users.noreply.github.com>
---
 .../coronawarnapp/ui/tracing/TracingData.kt   |  8 +-
 .../presencetracing/risk/PtRiskLevelResult.kt | 12 ++-
 .../risk/calculation/CheckInWarningMatcher.kt |  4 +
 .../calculation/PresenceTracingConversions.kt | 16 ----
 .../calculation/PresenceTracingRiskMapper.kt  |  1 +
 .../execution/PresenceTracingWarningTask.kt   | 16 ++--
 .../PresenceTracingWarningTaskProgress.kt     | 16 ++++
 .../storage/PresenceTracingRiskRepository.kt  | 32 +++++--
 .../coronawarnapp/risk/CombinedEwPtRisk.kt    | 13 ++-
 .../de/rki/coronawarnapp/risk/RiskState.kt    | 10 +++
 .../risk/storage/BaseRiskLevelStorage.kt      | 13 +--
 .../storage/TracingRepository.kt              | 44 ++++++++--
 .../coronawarnapp/tracing/TracingProgress.kt  | 12 ++-
 .../tracing/states/TracingState.kt            |  4 +-
 .../ui/details/TracingDetailsItemProvider.kt  |  4 +-
 .../items/riskdetails/DetailsLowRiskBox.kt    |  7 +-
 ...cing_details_item_riskdetails_low_view.xml |  1 +
 .../risk/storage/BaseRiskLevelStorageTest.kt  | 10 +--
 .../risk/storage/CombineRiskTest.kt           | 85 +++++++++++++------
 .../details/TracingDetailsItemProviderTest.kt |  2 +-
 20 files changed, 216 insertions(+), 94 deletions(-)
 delete mode 100644 Corona-Warn-App/src/main/java/de/rki/coronawarnapp/presencetracing/risk/calculation/PresenceTracingConversions.kt
 create mode 100644 Corona-Warn-App/src/main/java/de/rki/coronawarnapp/presencetracing/risk/execution/PresenceTracingWarningTaskProgress.kt

diff --git a/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/ui/tracing/TracingData.kt b/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/ui/tracing/TracingData.kt
index c1b30a16e..44c7ad447 100644
--- a/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/ui/tracing/TracingData.kt
+++ b/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/ui/tracing/TracingData.kt
@@ -48,7 +48,7 @@ object TracingData {
                 daysSinceInstallation = 4,
                 tracingStatus = GeneralTracingStatus.Status.TRACING_INACTIVE
             ),
-            DetailsLowRiskBox.Item(riskState = RiskState.LOW_RISK, matchedKeyCount = 0)
+            DetailsLowRiskBox.Item(riskState = RiskState.LOW_RISK, matchedRiskCount = 0)
         )
     )
 
@@ -79,7 +79,7 @@ object TracingData {
                 daysSinceInstallation = 4,
                 tracingStatus = GeneralTracingStatus.Status.TRACING_ACTIVE
             ),
-            DetailsLowRiskBox.Item(riskState = RiskState.LOW_RISK, matchedKeyCount = 0)
+            DetailsLowRiskBox.Item(riskState = RiskState.LOW_RISK, matchedRiskCount = 0)
         )
     )
 
@@ -110,7 +110,7 @@ object TracingData {
                 daysSinceInstallation = 4,
                 tracingStatus = GeneralTracingStatus.Status.TRACING_ACTIVE
             ),
-            DetailsLowRiskBox.Item(riskState = RiskState.LOW_RISK, matchedKeyCount = 0)
+            DetailsLowRiskBox.Item(riskState = RiskState.LOW_RISK, matchedRiskCount = 0)
         )
     )
 
@@ -141,7 +141,7 @@ object TracingData {
                 daysSinceInstallation = 4,
                 tracingStatus = GeneralTracingStatus.Status.TRACING_ACTIVE
             ),
-            DetailsLowRiskBox.Item(riskState = RiskState.LOW_RISK, matchedKeyCount = 0)
+            DetailsLowRiskBox.Item(riskState = RiskState.LOW_RISK, matchedRiskCount = 0)
         )
     )
 
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/presencetracing/risk/PtRiskLevelResult.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/presencetracing/risk/PtRiskLevelResult.kt
index 62b25b760..541496f3b 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/presencetracing/risk/PtRiskLevelResult.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/presencetracing/risk/PtRiskLevelResult.kt
@@ -1,15 +1,20 @@
 package de.rki.coronawarnapp.presencetracing.risk
 
+import de.rki.coronawarnapp.presencetracing.risk.calculation.CheckInWarningOverlap
 import de.rki.coronawarnapp.presencetracing.risk.calculation.PresenceTracingDayRisk
 import de.rki.coronawarnapp.risk.RiskState
 import org.joda.time.Instant
 import org.joda.time.LocalDate
 
+/**
+ * @param presenceTracingDayRisk Only available for the last calculation, if successful, otherwise null
+ * @param checkInWarningOverlaps Only available for the last calculation, if successful, otherwise null
+ */
 data class PtRiskLevelResult(
     val calculatedAt: Instant,
     val riskState: RiskState,
-    // only available for the last calculation if successful, otherwise null
-    val presenceTracingDayRisk: List<PresenceTracingDayRisk>? = null
+    val presenceTracingDayRisk: List<PresenceTracingDayRisk>? = null,
+    private val checkInWarningOverlaps: List<CheckInWarningOverlap>? = null,
 ) {
 
     val wasSuccessfullyCalculated: Boolean
@@ -39,4 +44,7 @@ data class PtRiskLevelResult(
             RiskState.LOW_RISK -> numberOfDaysWithLowRisk
             else -> 0
         }
+
+    val checkInOverlapCount: Int
+        get() = checkInWarningOverlaps?.size ?: 0
 }
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/presencetracing/risk/calculation/CheckInWarningMatcher.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/presencetracing/risk/calculation/CheckInWarningMatcher.kt
index 157a55a75..8dce26bef 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/presencetracing/risk/calculation/CheckInWarningMatcher.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/presencetracing/risk/calculation/CheckInWarningMatcher.kt
@@ -15,6 +15,7 @@ import kotlinx.coroutines.withContext
 import org.joda.time.Instant
 import timber.log.Timber
 import java.lang.reflect.Modifier.PRIVATE
+import java.util.concurrent.TimeUnit
 import javax.inject.Inject
 import kotlin.coroutines.CoroutineContext
 
@@ -143,4 +144,7 @@ internal fun CheckIn.calculateOverlap(
     )
 }
 
+// converts number of 10min intervals into milliseconds
+internal fun Int.tenMinIntervalToMillis() = this * TimeUnit.MINUTES.toMillis(10L)
+
 private const val TAG = "CheckInWarningMatcher"
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/presencetracing/risk/calculation/PresenceTracingConversions.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/presencetracing/risk/calculation/PresenceTracingConversions.kt
deleted file mode 100644
index 4e529779d..000000000
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/presencetracing/risk/calculation/PresenceTracingConversions.kt
+++ /dev/null
@@ -1,16 +0,0 @@
-package de.rki.coronawarnapp.presencetracing.risk.calculation
-
-import de.rki.coronawarnapp.risk.RiskState
-import de.rki.coronawarnapp.server.protocols.internal.v2.RiskCalculationParametersOuterClass.NormalizedTimeToRiskLevelMapping.RiskLevel
-import java.util.concurrent.TimeUnit
-
-// converts number of 10min intervals into milliseconds
-internal fun Int.tenMinIntervalToMillis() = this * TimeUnit.MINUTES.toMillis(10L)
-
-fun RiskLevel.mapToRiskState(): RiskState {
-    return when (this) {
-        RiskLevel.UNSPECIFIED, RiskLevel.UNRECOGNIZED -> RiskState.CALCULATION_FAILED
-        RiskLevel.LOW -> RiskState.LOW_RISK
-        RiskLevel.HIGH -> RiskState.INCREASED_RISK
-    }
-}
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/presencetracing/risk/calculation/PresenceTracingRiskMapper.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/presencetracing/risk/calculation/PresenceTracingRiskMapper.kt
index 1cebd0aec..06b72ed46 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/presencetracing/risk/calculation/PresenceTracingRiskMapper.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/presencetracing/risk/calculation/PresenceTracingRiskMapper.kt
@@ -4,6 +4,7 @@ import de.rki.coronawarnapp.appconfig.AppConfigProvider
 import de.rki.coronawarnapp.appconfig.PresenceTracingRiskCalculationParamContainer
 import de.rki.coronawarnapp.risk.DefaultRiskLevels.Companion.inRange
 import de.rki.coronawarnapp.risk.RiskState
+import de.rki.coronawarnapp.risk.mapToRiskState
 import kotlinx.coroutines.flow.first
 import timber.log.Timber
 import javax.inject.Inject
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/presencetracing/risk/execution/PresenceTracingWarningTask.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/presencetracing/risk/execution/PresenceTracingWarningTask.kt
index db128bc5d..8000745d6 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/presencetracing/risk/execution/PresenceTracingWarningTask.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/presencetracing/risk/execution/PresenceTracingWarningTask.kt
@@ -12,7 +12,6 @@ import de.rki.coronawarnapp.presencetracing.warning.storage.TraceWarningReposito
 import de.rki.coronawarnapp.task.Task
 import de.rki.coronawarnapp.task.TaskCancellationException
 import de.rki.coronawarnapp.task.TaskFactory
-import de.rki.coronawarnapp.task.common.DefaultProgress
 import de.rki.coronawarnapp.util.TimeStamper
 import kotlinx.coroutines.channels.ConflatedBroadcastChannel
 import kotlinx.coroutines.flow.Flow
@@ -31,10 +30,10 @@ class PresenceTracingWarningTask @Inject constructor(
     private val presenceTracingRiskRepository: PresenceTracingRiskRepository,
     private val traceWarningRepository: TraceWarningRepository,
     private val checkInsRepository: CheckInRepository,
-) : Task<DefaultProgress, PresenceTracingWarningTask.Result> {
+) : Task<PresenceTracingWarningTaskProgress, PresenceTracingWarningTask.Result> {
 
-    private val internalProgress = ConflatedBroadcastChannel<DefaultProgress>()
-    override val progress: Flow<DefaultProgress> = internalProgress.asFlow()
+    private val internalProgress = ConflatedBroadcastChannel<PresenceTracingWarningTaskProgress>()
+    override val progress: Flow<PresenceTracingWarningTaskProgress> = internalProgress.asFlow()
 
     private var isCanceled = false
 
@@ -61,6 +60,9 @@ class PresenceTracingWarningTask @Inject constructor(
         val nowUTC = timeStamper.nowUTC
         checkCancel()
 
+        Timber.tag(TAG).d("Syncing packages.")
+        internalProgress.send(PresenceTracingWarningTaskProgress.Downloading())
+
         val syncResult = syncTool.syncPackages()
 
         if (syncResult.successful) {
@@ -97,6 +99,8 @@ class PresenceTracingWarningTask @Inject constructor(
         }
 
         Timber.tag(TAG).d("Running check-in matcher.")
+        internalProgress.send(PresenceTracingWarningTaskProgress.Calculating())
+
         val matcherResult = checkInWarningMatcher.process(
             checkIns = checkIns,
             warningPackages = unprocessedPackages,
@@ -147,13 +151,13 @@ class PresenceTracingWarningTask @Inject constructor(
     class Factory @Inject constructor(
         private val taskByDagger: Provider<PresenceTracingWarningTask>,
         private val appConfigProvider: AppConfigProvider
-    ) : TaskFactory<DefaultProgress, Task.Result> {
+    ) : TaskFactory<PresenceTracingWarningTaskProgress, Task.Result> {
 
         override suspend fun createConfig(): TaskFactory.Config = Config(
             executionTimeout = appConfigProvider.getAppConfig().overallDownloadTimeout
         )
 
-        override val taskProvider: () -> Task<DefaultProgress, Task.Result> = {
+        override val taskProvider: () -> Task<PresenceTracingWarningTaskProgress, Task.Result> = {
             taskByDagger.get()
         }
     }
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/presencetracing/risk/execution/PresenceTracingWarningTaskProgress.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/presencetracing/risk/execution/PresenceTracingWarningTaskProgress.kt
new file mode 100644
index 000000000..a7c986995
--- /dev/null
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/presencetracing/risk/execution/PresenceTracingWarningTaskProgress.kt
@@ -0,0 +1,16 @@
+package de.rki.coronawarnapp.presencetracing.risk.execution
+
+import de.rki.coronawarnapp.task.Task
+import de.rki.coronawarnapp.util.ui.CachedString
+import de.rki.coronawarnapp.util.ui.LazyString
+
+sealed class PresenceTracingWarningTaskProgress : Task.Progress {
+
+    data class Downloading(
+        override val primaryMessage: LazyString = CachedString { "" }
+    ) : PresenceTracingWarningTaskProgress()
+
+    data class Calculating(
+        override val primaryMessage: LazyString = CachedString { "" }
+    ) : PresenceTracingWarningTaskProgress()
+}
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/presencetracing/risk/storage/PresenceTracingRiskRepository.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/presencetracing/risk/storage/PresenceTracingRiskRepository.kt
index daf5c60bc..9dbccbc3e 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/presencetracing/risk/storage/PresenceTracingRiskRepository.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/presencetracing/risk/storage/PresenceTracingRiskRepository.kt
@@ -128,9 +128,15 @@ class PresenceTracingRiskRepository @Inject constructor(
                 if (!lastSuccessfulFound && entity.riskState != RiskState.CALCULATION_FAILED) {
                     lastSuccessfulFound = true
                     // add risk per day to the last successful result
-                    entity.toCheckInWarningOverlap(presenceTracingDayRisk.first())
+                    entity.toRiskLevelResult(
+                        presenceTracingDayRisks = presenceTracingDayRisk.first(),
+                        checkInWarningOverlaps = checkInWarningOverlaps.first(),
+                    )
                 } else {
-                    entity.toCheckInWarningOverlap(null)
+                    entity.toRiskLevelResult(
+                        presenceTracingDayRisks = null,
+                        checkInWarningOverlaps = null,
+                    )
                 }
             }
     }
@@ -144,16 +150,22 @@ class PresenceTracingRiskRepository @Inject constructor(
                 if (!lastSuccessfulFound && entity.riskState != RiskState.CALCULATION_FAILED) {
                     lastSuccessfulFound = true
                     // add risk per day to the last successful result
-                    entity.toCheckInWarningOverlap(presenceTracingDayRisk.first())
+                    entity.toRiskLevelResult(
+                        presenceTracingDayRisks = presenceTracingDayRisk.first(),
+                        checkInWarningOverlaps = checkInWarningOverlaps.first(),
+                    )
                 } else {
-                    entity.toCheckInWarningOverlap(null)
+                    entity.toRiskLevelResult(
+                        presenceTracingDayRisks = null,
+                        checkInWarningOverlaps = null,
+                    )
                 }
             }
     }
 
     private fun addResult(result: PtRiskLevelResult) {
         Timber.i("Saving risk calculation from ${result.calculatedAt} with result ${result.riskState}.")
-        riskLevelResultDao.insert(result.toTraceTimeIntervalMatchEntity())
+        riskLevelResultDao.insert(result.toRiskLevelEntity())
     }
 
     suspend fun clearAllTables() {
@@ -242,15 +254,17 @@ data class PresenceTracingRiskLevelResultEntity(
     @ColumnInfo(name = "riskStateCode") val riskState: RiskState
 )
 
-private fun PresenceTracingRiskLevelResultEntity.toCheckInWarningOverlap(
-    presenceTracingDayRisk: List<PresenceTracingDayRisk>?
+private fun PresenceTracingRiskLevelResultEntity.toRiskLevelResult(
+    presenceTracingDayRisks: List<PresenceTracingDayRisk>?,
+    checkInWarningOverlaps: List<CheckInWarningOverlap>?
 ) = PtRiskLevelResult(
     calculatedAt = Instant.ofEpochMilli((calculatedAtMillis)),
     riskState = riskState,
-    presenceTracingDayRisk = presenceTracingDayRisk
+    presenceTracingDayRisk = presenceTracingDayRisks,
+    checkInWarningOverlaps = checkInWarningOverlaps,
 )
 
-private fun PtRiskLevelResult.toTraceTimeIntervalMatchEntity() = PresenceTracingRiskLevelResultEntity(
+private fun PtRiskLevelResult.toRiskLevelEntity() = PresenceTracingRiskLevelResultEntity(
     calculatedAtMillis = calculatedAt.millis,
     riskState = riskState
 )
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/risk/CombinedEwPtRisk.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/risk/CombinedEwPtRisk.kt
index b4e6305fb..1e2a96561 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/risk/CombinedEwPtRisk.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/risk/CombinedEwPtRisk.kt
@@ -13,8 +13,8 @@ data class CombinedEwPtDayRisk(
 )
 
 data class CombinedEwPtRiskLevelResult(
-    val ptRiskLevelResult: PtRiskLevelResult,
-    val ewRiskLevelResult: EwRiskLevelResult
+    private val ptRiskLevelResult: PtRiskLevelResult,
+    private val ewRiskLevelResult: EwRiskLevelResult
 ) {
 
     val riskState: RiskState by lazy {
@@ -56,6 +56,15 @@ data class CombinedEwPtRiskLevelResult(
             else -> null
         }
     }
+
+    /**
+     * The combination of matched exposure windows and overlaps.
+     * If we have matches > 0, but are still in a low risk state,
+     * the UI displays additional information in the risk details screen.
+     */
+    val matchedRiskCount: Int by lazy {
+        ewRiskLevelResult.matchedKeyCount + ptRiskLevelResult.checkInOverlapCount
+    }
 }
 
 data class LastCombinedRiskResults(
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/risk/RiskState.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/risk/RiskState.kt
index e71d6f7a4..facbcb948 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/risk/RiskState.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/risk/RiskState.kt
@@ -1,7 +1,17 @@
 package de.rki.coronawarnapp.risk
 
+import de.rki.coronawarnapp.server.protocols.internal.v2.RiskCalculationParametersOuterClass.NormalizedTimeToRiskLevelMapping.RiskLevel
+
 enum class RiskState {
     LOW_RISK,
     INCREASED_RISK,
     CALCULATION_FAILED
 }
+
+fun RiskLevel.mapToRiskState(): RiskState {
+    return when (this) {
+        RiskLevel.UNSPECIFIED, RiskLevel.UNRECOGNIZED -> RiskState.CALCULATION_FAILED
+        RiskLevel.LOW -> RiskState.LOW_RISK
+        RiskLevel.HIGH -> RiskState.INCREASED_RISK
+    }
+}
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/risk/storage/BaseRiskLevelStorage.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/risk/storage/BaseRiskLevelStorage.kt
index d5d0d71f0..af277a073 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/risk/storage/BaseRiskLevelStorage.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/risk/storage/BaseRiskLevelStorage.kt
@@ -5,7 +5,6 @@ import com.google.android.gms.nearby.exposurenotification.ExposureWindow
 import de.rki.coronawarnapp.presencetracing.risk.PtRiskLevelResult
 import de.rki.coronawarnapp.presencetracing.risk.TraceLocationCheckInRisk
 import de.rki.coronawarnapp.presencetracing.risk.calculation.PresenceTracingDayRisk
-import de.rki.coronawarnapp.presencetracing.risk.calculation.mapToRiskState
 import de.rki.coronawarnapp.presencetracing.risk.storage.PresenceTracingRiskRepository
 import de.rki.coronawarnapp.risk.CombinedEwPtDayRisk
 import de.rki.coronawarnapp.risk.CombinedEwPtRiskLevelResult
@@ -13,6 +12,7 @@ import de.rki.coronawarnapp.risk.EwRiskLevelResult
 import de.rki.coronawarnapp.risk.EwRiskLevelTaskResult
 import de.rki.coronawarnapp.risk.LastCombinedRiskResults
 import de.rki.coronawarnapp.risk.RiskState
+import de.rki.coronawarnapp.risk.mapToRiskState
 import de.rki.coronawarnapp.risk.result.EwAggregatedRiskResult
 import de.rki.coronawarnapp.risk.result.ExposureWindowDayRisk
 import de.rki.coronawarnapp.risk.storage.internal.RiskResultDatabase
@@ -256,10 +256,13 @@ internal fun combineRisk(
     }
 }
 
-internal fun combine(left: RiskState?, right: RiskState?): RiskState {
-    return if (left == RiskState.INCREASED_RISK || right == RiskState.INCREASED_RISK) RiskState.INCREASED_RISK
-    else if (left == RiskState.LOW_RISK || right == RiskState.LOW_RISK) RiskState.LOW_RISK
-    else RiskState.CALCULATION_FAILED
+internal fun combine(vararg states: RiskState?): RiskState {
+    if (states.any { it == RiskState.CALCULATION_FAILED }) return RiskState.CALCULATION_FAILED
+    if (states.any { it == RiskState.INCREASED_RISK }) return RiskState.INCREASED_RISK
+
+    require(states.filterNotNull().all { it == RiskState.LOW_RISK })
+
+    return RiskState.LOW_RISK
 }
 
 internal fun max(left: Instant, right: Instant): Instant {
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/storage/TracingRepository.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/storage/TracingRepository.kt
index 49488cc0e..6f9fdeed6 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/storage/TracingRepository.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/storage/TracingRepository.kt
@@ -1,11 +1,14 @@
 package de.rki.coronawarnapp.storage
 
+import android.annotation.SuppressLint
 import android.content.Context
 import de.rki.coronawarnapp.diagnosiskeys.download.DownloadDiagnosisKeysTask
 import de.rki.coronawarnapp.nearby.ENFClient
 import de.rki.coronawarnapp.nearby.InternalExposureNotificationClient
 import de.rki.coronawarnapp.nearby.modules.detectiontracker.ExposureDetectionTracker
 import de.rki.coronawarnapp.nearby.modules.detectiontracker.lastSubmission
+import de.rki.coronawarnapp.presencetracing.risk.execution.PresenceTracingWarningTask
+import de.rki.coronawarnapp.presencetracing.risk.execution.PresenceTracingWarningTaskProgress
 import de.rki.coronawarnapp.risk.RiskLevelTask
 import de.rki.coronawarnapp.task.TaskController
 import de.rki.coronawarnapp.task.TaskInfo
@@ -21,7 +24,7 @@ import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.flow.Flow
 import kotlinx.coroutines.flow.combine
 import kotlinx.coroutines.flow.first
-import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.firstOrNull
 import kotlinx.coroutines.launch
 import org.joda.time.Duration
 import timber.log.Timber
@@ -45,26 +48,49 @@ class TracingRepository @Inject constructor(
     private val backgroundModeStatus: BackgroundModeStatus
 ) {
 
+    @SuppressLint("BinaryOperationInTimber")
     val tracingProgress: Flow<TracingProgress> = combine(
-        taskController.tasks.map { it.isDownloadDiagnosisKeysTaskRunning() },
+        taskController.tasks,
         enfClient.isPerformingExposureDetection(),
-        taskController.tasks.map { it.isRiskLevelTaskRunning() }
-    ) { isDownloading, isExposureDetecting, isRiskLeveling ->
+    ) { taskInfos, isExposureDetecting ->
+
+        val isEWDownloading = taskInfos.isEWDownloadingPackages()
+        val isEWCalculatingRisk = taskInfos.isEWCalculatingRisk()
+
+        val isPTDownloading = taskInfos.isPTDownloadingPackages()
+        val isPTCalculatingRisk = taskInfos.isPTCalculatingRisk()
+
         when {
-            isDownloading -> TracingProgress.Downloading
-            isExposureDetecting || isRiskLeveling -> TracingProgress.ENFIsCalculating
+            isEWDownloading || isPTDownloading -> TracingProgress.Downloading
+            isExposureDetecting || isEWCalculatingRisk || isPTCalculatingRisk -> TracingProgress.IsCalculating
             else -> TracingProgress.Idle
+        }.also {
+            Timber.tag(TAG).v(
+                "TracingProgress: $it, isExposureDetecting=$isExposureDetecting, " +
+                    "isEWDownloading=$isEWDownloading, isEWCalculatingRisk=$isEWCalculatingRisk, " +
+                    "isPTDownloading=$isPTDownloading, isPTCalculatingRisk=$isPTCalculatingRisk"
+            )
         }
     }
 
-    private fun List<TaskInfo>.isRiskLevelTaskRunning() = any {
-        it.taskState.isActive && it.taskState.request.type == RiskLevelTask::class
+    private suspend fun List<TaskInfo>.isPTDownloadingPackages() = any {
+        it.taskState.isActive && it.taskState.request.type == PresenceTracingWarningTask::class &&
+            it.progress.firstOrNull() is PresenceTracingWarningTaskProgress.Downloading
     }
 
-    private fun List<TaskInfo>.isDownloadDiagnosisKeysTaskRunning() = any {
+    private suspend fun List<TaskInfo>.isPTCalculatingRisk() = any {
+        it.taskState.isActive && it.taskState.request.type == PresenceTracingWarningTask::class &&
+            it.progress.firstOrNull() is PresenceTracingWarningTaskProgress.Calculating
+    }
+
+    private fun List<TaskInfo>.isEWDownloadingPackages() = any {
         it.taskState.isActive && it.taskState.request.type == DownloadDiagnosisKeysTask::class
     }
 
+    private fun List<TaskInfo>.isEWCalculatingRisk() = any {
+        it.taskState.isActive && it.taskState.request.type == RiskLevelTask::class
+    }
+
     /**
      * Refresh the diagnosis keys. For that isRefreshing is set to true which is displayed in the ui.
      * Afterwards the RetrieveDiagnosisKeysTransaction and the RiskLevelTransaction are started.
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/tracing/TracingProgress.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/tracing/TracingProgress.kt
index aa4416de0..955d17a6a 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/tracing/TracingProgress.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/tracing/TracingProgress.kt
@@ -2,9 +2,15 @@ package de.rki.coronawarnapp.tracing
 
 sealed class TracingProgress {
 
-    object Idle : TracingProgress()
+    object Idle : TracingProgress() {
+        override fun toString(): String = "TracingProgress.Idle"
+    }
 
-    object Downloading : TracingProgress()
+    object Downloading : TracingProgress() {
+        override fun toString(): String = "TracingProgress.Downloading"
+    }
 
-    object ENFIsCalculating : TracingProgress()
+    object IsCalculating : TracingProgress() {
+        override fun toString(): String = "TracingProgress.IsCalculating"
+    }
 }
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/tracing/states/TracingState.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/tracing/states/TracingState.kt
index a12be64f0..58cf7f537 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/tracing/states/TracingState.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/tracing/states/TracingState.kt
@@ -226,13 +226,13 @@ data class TracingInProgress(
 
     fun getProgressCardHeadline(c: Context): String = when (tracingProgress) {
         TracingProgress.Downloading -> R.string.risk_card_progress_download_headline
-        TracingProgress.ENFIsCalculating -> R.string.risk_card_progress_calculation_headline
+        TracingProgress.IsCalculating -> R.string.risk_card_progress_calculation_headline
         TracingProgress.Idle -> null
     }?.let { c.getString(it) } ?: ""
 
     fun getProgressCardBody(c: Context): String = when (tracingProgress) {
         TracingProgress.Downloading -> R.string.risk_card_progress_download_body
-        TracingProgress.ENFIsCalculating -> R.string.risk_card_progress_calculation_body
+        TracingProgress.IsCalculating -> R.string.risk_card_progress_calculation_body
         TracingProgress.Idle -> null
     }?.let { c.getString(it) } ?: ""
 
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/tracing/ui/details/TracingDetailsItemProvider.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/tracing/ui/details/TracingDetailsItemProvider.kt
index f47238e68..7537905dc 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/tracing/ui/details/TracingDetailsItemProvider.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/tracing/ui/details/TracingDetailsItemProvider.kt
@@ -47,7 +47,7 @@ class TracingDetailsItemProvider @Inject constructor(
         mutableListOf<DetailsItem>().apply {
             if (status != Status.TRACING_INACTIVE &&
                 latestCalc.riskState == RiskState.LOW_RISK &&
-                latestCalc.ewRiskLevelResult.matchedKeyCount > 0
+                latestCalc.matchedRiskCount > 0
             ) {
                 add(AdditionalInfoLowRiskBox.Item)
             }
@@ -81,7 +81,7 @@ class TracingDetailsItemProvider @Inject constructor(
                 }
                 latestCalc.riskState == RiskState.LOW_RISK -> DetailsLowRiskBox.Item(
                     riskState = latestCalc.riskState,
-                    matchedKeyCount = latestCalc.ewRiskLevelResult.matchedKeyCount
+                    matchedRiskCount = latestCalc.matchedRiskCount
                 )
                 latestCalc.riskState == RiskState.INCREASED_RISK -> DetailsIncreasedRiskBox.Item(
                     riskState = latestCalc.riskState,
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/tracing/ui/details/items/riskdetails/DetailsLowRiskBox.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/tracing/ui/details/items/riskdetails/DetailsLowRiskBox.kt
index 574698d97..d3c84c6c0 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/tracing/ui/details/items/riskdetails/DetailsLowRiskBox.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/tracing/ui/details/items/riskdetails/DetailsLowRiskBox.kt
@@ -33,7 +33,8 @@ class DetailsLowRiskBox(
         payloads: List<Any>
     ) -> Unit = { item, _ ->
         info = item
-        if (item.matchedKeyCount > 0) {
+        // Low risk, but matched risk item? More info! Don't worry!
+        if (item.matchedRiskCount > 0) {
             riskDetailsInformationLowriskBodyUrl.visibility = View.VISIBLE
             riskDetailsInformationLowriskBodyUrl.convertToHyperlink(
                 context.getString(R.string.risk_details_explanation_faq_link)
@@ -46,13 +47,13 @@ class DetailsLowRiskBox(
 
     data class Item(
         val riskState: RiskState,
-        val matchedKeyCount: Int
+        val matchedRiskCount: Int
     ) : RiskDetailsStateItem {
 
         fun getRiskDetailsRiskLevelBody(c: Context): String {
             // TODO consider pt encounters?
             return c.getString(
-                if (matchedKeyCount > 0) R.string.risk_details_information_body_low_risk_with_encounter
+                if (matchedRiskCount > 0) R.string.risk_details_information_body_low_risk_with_encounter
                 else R.string.risk_details_information_body_low_risk
             )
         }
diff --git a/Corona-Warn-App/src/main/res/layout/tracing_details_item_riskdetails_low_view.xml b/Corona-Warn-App/src/main/res/layout/tracing_details_item_riskdetails_low_view.xml
index c18fabd78..47d969b24 100644
--- a/Corona-Warn-App/src/main/res/layout/tracing_details_item_riskdetails_low_view.xml
+++ b/Corona-Warn-App/src/main/res/layout/tracing_details_item_riskdetails_low_view.xml
@@ -60,6 +60,7 @@
             android:clickable="true"
             android:focusable="true"
             android:linksClickable="true"
+            tools:visibility="visible"
             android:visibility="gone"
             android:text="@string/risk_details_explanation_dialog_faq_body"
             app:layout_constraintEnd_toEndOf="parent"
diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/risk/storage/BaseRiskLevelStorageTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/risk/storage/BaseRiskLevelStorageTest.kt
index 03c675890..fdff4062d 100644
--- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/risk/storage/BaseRiskLevelStorageTest.kt
+++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/risk/storage/BaseRiskLevelStorageTest.kt
@@ -220,7 +220,7 @@ class BaseRiskLevelStorageTest : BaseTest() {
             riskLevelResults.size shouldBe 2
 
             riskLevelResults[0].calculatedAt shouldBe calculatedAt
-            riskLevelResults[0].riskState shouldBe RiskState.INCREASED_RISK
+            riskLevelResults[0].riskState shouldBe RiskState.CALCULATION_FAILED
             riskLevelResults[1].calculatedAt shouldBe ewCalculatedAt
             riskLevelResults[1].riskState shouldBe RiskState.INCREASED_RISK
 
@@ -241,7 +241,7 @@ class BaseRiskLevelStorageTest : BaseTest() {
                 PtRiskLevelResult(
                     calculatedAt = calculatedAt,
                     presenceTracingDayRisk = null,
-                    riskState = RiskState.CALCULATION_FAILED
+                    riskState = RiskState.LOW_RISK
                 )
             )
         )
@@ -303,12 +303,12 @@ class BaseRiskLevelStorageTest : BaseTest() {
                 PtRiskLevelResult(
                     calculatedAt = calculatedAt,
                     presenceTracingDayRisk = null,
-                    riskState = RiskState.CALCULATION_FAILED
+                    riskState = RiskState.INCREASED_RISK
                 ),
                 PtRiskLevelResult(
                     calculatedAt = calculatedAt.minus(400L),
                     presenceTracingDayRisk = null,
-                    riskState = RiskState.LOW_RISK
+                    riskState = RiskState.CALCULATION_FAILED
                 )
             )
         )
@@ -319,7 +319,7 @@ class BaseRiskLevelStorageTest : BaseTest() {
             riskLevelResults.size shouldBe 2
 
             riskLevelResults[0].calculatedAt shouldBe ewCalculatedAt
-            riskLevelResults[0].riskState shouldBe RiskState.LOW_RISK
+            riskLevelResults[0].riskState shouldBe RiskState.INCREASED_RISK
             riskLevelResults[1].calculatedAt shouldBe ewCalculatedAt.minus(200L)
             riskLevelResults[1].riskState shouldBe RiskState.INCREASED_RISK
 
diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/risk/storage/CombineRiskTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/risk/storage/CombineRiskTest.kt
index a1099568a..9e1122826 100644
--- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/risk/storage/CombineRiskTest.kt
+++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/risk/storage/CombineRiskTest.kt
@@ -17,7 +17,11 @@ class CombineRiskTest {
 
     @Test
     fun `combineRisk works`() {
-        val ptRisk = PresenceTracingDayRisk(
+        val ptRisk0 = PresenceTracingDayRisk(
+            localDateUtc = LocalDate(2021, 3, 19),
+            riskState = RiskState.LOW_RISK
+        )
+        val ptRisk1 = PresenceTracingDayRisk(
             localDateUtc = LocalDate(2021, 3, 20),
             riskState = RiskState.INCREASED_RISK
         )
@@ -29,50 +33,81 @@ class CombineRiskTest {
             localDateUtc = LocalDate(2021, 3, 22),
             riskState = RiskState.CALCULATION_FAILED
         )
-        val ewRisk = ExposureWindowDayRisk(
-            dateMillisSinceEpoch = Instant.parse("2021-03-22T14:00:00.000Z").millis,
+        val ptRisk4 = PresenceTracingDayRisk(
+            localDateUtc = LocalDate(2021, 3, 23),
+            riskState = RiskState.LOW_RISK
+        )
+        val ptRisk5 = PresenceTracingDayRisk(
+            localDateUtc = LocalDate(2021, 3, 24),
+            riskState = RiskState.INCREASED_RISK
+        )
+
+        val ewRisk0 = ExposureWindowDayRisk(
+            dateMillisSinceEpoch = Instant.parse("2021-03-24T14:00:00.000Z").millis,
+            riskLevel = RiskLevel.HIGH,
+            0,
+            0
+        )
+        val ewRisk1 = ExposureWindowDayRisk(
+            dateMillisSinceEpoch = Instant.parse("2021-03-23T14:00:00.000Z").millis,
             riskLevel = RiskLevel.HIGH,
             0,
             0
         )
         val ewRisk2 = ExposureWindowDayRisk(
+            dateMillisSinceEpoch = Instant.parse("2021-03-22T14:00:00.000Z").millis,
+            riskLevel = RiskLevel.HIGH,
+            0,
+            0
+        )
+        val ewRisk3 = ExposureWindowDayRisk(
             dateMillisSinceEpoch = Instant.parse("2021-03-19T14:00:00.000Z").millis,
             riskLevel = RiskLevel.LOW,
             0,
             0
         )
-        val ewRisk3 = ExposureWindowDayRisk(
+        val ewRisk4 = ExposureWindowDayRisk(
             dateMillisSinceEpoch = Instant.parse("2021-03-20T14:00:00.000Z").millis,
             riskLevel = RiskLevel.UNSPECIFIED,
             0,
             0
         )
-        val ewRisk4 = ExposureWindowDayRisk(
+        val ewRisk5 = ExposureWindowDayRisk(
             dateMillisSinceEpoch = Instant.parse("2021-03-15T14:00:00.000Z").millis,
             riskLevel = RiskLevel.UNSPECIFIED,
             0,
             0
         )
 
-        val ptDayRiskList: List<PresenceTracingDayRisk> = listOf(ptRisk, ptRisk2, ptRisk3)
-        val ewDayRiskList: List<ExposureWindowDayRisk> = listOf(ewRisk, ewRisk2, ewRisk3, ewRisk4)
+        val ptDayRiskList: List<PresenceTracingDayRisk> = listOf(ptRisk0, ptRisk1, ptRisk2, ptRisk3, ptRisk4, ptRisk5)
+        val ewDayRiskList: List<ExposureWindowDayRisk> = listOf(ewRisk0, ewRisk1, ewRisk2, ewRisk3, ewRisk4, ewRisk5)
         val result = combineRisk(ptDayRiskList, ewDayRiskList)
-        result.size shouldBe 5
-        result.find {
+        result.size shouldBe 7
+
+        result.single {
             it.localDate == LocalDate(2021, 3, 15)
-        }!!.riskState shouldBe RiskState.CALCULATION_FAILED
-        result.find {
+        }.riskState shouldBe RiskState.CALCULATION_FAILED
+        result.single {
             it.localDate == LocalDate(2021, 3, 19)
-        }!!.riskState shouldBe RiskState.LOW_RISK
-        result.find {
+        }.riskState shouldBe RiskState.LOW_RISK
+        result.single {
             it.localDate == LocalDate(2021, 3, 20)
-        }!!.riskState shouldBe RiskState.INCREASED_RISK
-        result.find {
+        }.riskState shouldBe RiskState.CALCULATION_FAILED
+        result.single {
             it.localDate == LocalDate(2021, 3, 21)
-        }!!.riskState shouldBe RiskState.LOW_RISK
-        result.find {
+        }.riskState shouldBe RiskState.LOW_RISK
+        result.single {
+            it.localDate == LocalDate(2021, 3, 22)
+        }.riskState shouldBe RiskState.CALCULATION_FAILED
+        result.single {
             it.localDate == LocalDate(2021, 3, 22)
-        }!!.riskState shouldBe RiskState.INCREASED_RISK
+        }.riskState shouldBe RiskState.CALCULATION_FAILED
+        result.single {
+            it.localDate == LocalDate(2021, 3, 23)
+        }.riskState shouldBe RiskState.INCREASED_RISK
+        result.single {
+            it.localDate == LocalDate(2021, 3, 24)
+        }.riskState shouldBe RiskState.INCREASED_RISK
     }
 
     @Test
@@ -85,7 +120,7 @@ class CombineRiskTest {
         )
         val ptResult2 = PtRiskLevelResult(
             calculatedAt = startInstant.plus(3000L),
-            riskState = RiskState.CALCULATION_FAILED
+            riskState = RiskState.LOW_RISK
         )
         val ptResult3 = PtRiskLevelResult(
             calculatedAt = startInstant.plus(6000L),
@@ -99,7 +134,7 @@ class CombineRiskTest {
         val ptResults = listOf(ptResult, ptResult2, ptResult4, ptResult3)
         val ewResult = createEwRiskLevelResult(
             calculatedAt = startInstant.plus(2000L),
-            riskState = RiskState.CALCULATION_FAILED
+            riskState = RiskState.LOW_RISK
         )
         val ewResult2 = createEwRiskLevelResult(
             calculatedAt = startInstant.plus(4000L),
@@ -126,11 +161,11 @@ class CombineRiskTest {
         result[3].calculatedAt shouldBe startInstant.plus(5000L)
         result[4].riskState shouldBe RiskState.INCREASED_RISK
         result[4].calculatedAt shouldBe startInstant.plus(4000L)
-        result[5].riskState shouldBe RiskState.CALCULATION_FAILED
+        result[5].riskState shouldBe RiskState.LOW_RISK
         result[5].calculatedAt shouldBe startInstant.plus(3000L)
         result[6].riskState shouldBe RiskState.LOW_RISK
         result[6].calculatedAt shouldBe startInstant.plus(2000L)
-        result[7].riskState shouldBe RiskState.LOW_RISK
+        result[7].riskState shouldBe RiskState.CALCULATION_FAILED
         result[7].calculatedAt shouldBe startInstant.plus(1000L)
     }
 
@@ -138,11 +173,11 @@ class CombineRiskTest {
     fun `max RiskState works`() {
         combine(RiskState.INCREASED_RISK, RiskState.INCREASED_RISK) shouldBe RiskState.INCREASED_RISK
         combine(RiskState.INCREASED_RISK, RiskState.LOW_RISK) shouldBe RiskState.INCREASED_RISK
-        combine(RiskState.INCREASED_RISK, RiskState.CALCULATION_FAILED) shouldBe RiskState.INCREASED_RISK
+        combine(RiskState.INCREASED_RISK, RiskState.CALCULATION_FAILED) shouldBe RiskState.CALCULATION_FAILED
         combine(RiskState.LOW_RISK, RiskState.INCREASED_RISK) shouldBe RiskState.INCREASED_RISK
-        combine(RiskState.CALCULATION_FAILED, RiskState.INCREASED_RISK) shouldBe RiskState.INCREASED_RISK
+        combine(RiskState.CALCULATION_FAILED, RiskState.INCREASED_RISK) shouldBe RiskState.CALCULATION_FAILED
         combine(RiskState.LOW_RISK, RiskState.LOW_RISK) shouldBe RiskState.LOW_RISK
-        combine(RiskState.CALCULATION_FAILED, RiskState.LOW_RISK) shouldBe RiskState.LOW_RISK
+        combine(RiskState.CALCULATION_FAILED, RiskState.LOW_RISK) shouldBe RiskState.CALCULATION_FAILED
         combine(RiskState.CALCULATION_FAILED, RiskState.CALCULATION_FAILED) shouldBe RiskState.CALCULATION_FAILED
     }
 }
diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/tracing/ui/details/TracingDetailsItemProviderTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/tracing/ui/details/TracingDetailsItemProviderTest.kt
index daf12a721..1be311fd3 100644
--- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/tracing/ui/details/TracingDetailsItemProviderTest.kt
+++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/tracing/ui/details/TracingDetailsItemProviderTest.kt
@@ -87,7 +87,7 @@ class TracingDetailsItemProviderTest : BaseTest() {
             exposureWindows = listOf(exposureWindow)
         )
 
-        every { combinedResult.ewRiskLevelResult } returns ewRiskLevelTaskResult
+        every { combinedResult.matchedRiskCount } returns matchedKeyCount
 
         val lastCombined = LastCombinedRiskResults(
             lastCalculated = combinedResult,
-- 
GitLab