measureRetention static method

List<RetentionBucket> measureRetention(
  1. List<ReviewLog> logs
)

Bucket review events by interval and compute retained/lapsed ratio.

A review is "retained" if quality ≥ 3 (Hard or better).

Implementation

static List<RetentionBucket> measureRetention(List<ReviewLog> logs) {
  // Assign each review to the nearest bucket.
  final bucketCounts = <int, int>{};
  final bucketRetained = <int, int>{};
  for (final b in retentionBuckets) {
    bucketCounts[b] = 0;
    bucketRetained[b] = 0;
  }

  for (final log in logs) {
    final bucket = _nearestBucket(log.elapsedDays);
    bucketCounts[bucket] = (bucketCounts[bucket] ?? 0) + 1;
    if (log.quality >= 3) {
      bucketRetained[bucket] = (bucketRetained[bucket] ?? 0) + 1;
    }
  }

  return retentionBuckets
      .map(
        (b) => RetentionBucket(
          intervalDays: b,
          totalReviews: bucketCounts[b]!,
          retainedCount: bucketRetained[b]!,
        ),
      )
      .where((b) => b.totalReviews > 0)
      .toList();
}