# Cross-Row Catalog Deduplication Pattern

## The Problem

When a home screen has multiple catalog rows (Popular, Action, Sci-Fi, Netflix, etc.) all fetching from TMDB, the same movies appear across multiple rows. "Dune: Part Two" shows in Popular Movies, Best Action, AND Best Sci-Fi simultaneously.

Root causes:
1. **All rows sorted by `popularity.desc`** — genre rows show the same popular items
2. **No cross-row deduplication** — `CatalogDedup.kt` only dedups WITHIN a single row
3. **OTT provider rows overlap with Popular** — Netflix/Prime most-popular = TMDB most-popular

## Fix 1: Different Sort for Genre Rows

Change genre rows from `popularity.desc` to `vote_average.desc` so they show genuinely different content:

```kotlin
// BEFORE — sorts by popularity, overlaps with "Popular Movies" row (70-80% overlap)
TmdbCatalogDefinition("genre_action", "Action", "movie", "tmdb.top", RowType.GENRE,
    mapOf("genre" to "Action"))

// AFTER — sorts by rating, shows different movies ("The Dark Knight" vs latest blockbuster)
TmdbCatalogDefinition("genre_action", "Best Action", "movie", "tmdb.top", RowType.GENRE,
    mapOf("genre" to "Action", "sort_by" to "vote_average.desc"))
```

Update the discover endpoint to respect `sort_by`:
```kotlin
val sortBy = extra["sort_by"] ?: "popularity.desc"
// ... pass to TMDB discover endpoint
```

## Fix 2: Cross-Row Deduplication Pass

After all catalog rows load, run a single pass that removes duplicate items:

```kotlin
private fun deduplicateAcrossRows(rows: List<RowLoadResult>, priorityRows: List<HomeRow>): List<RowLoadResult> {
    val seenIds = mutableSetOf<String>()
    // Priority rows take precedence — mark their items as "seen" first
    priorityRows.forEach { row -> row.items.forEach { seenIds.add(it.id) } }
    
    return rows.map { rowResult ->
        if (rowResult.row.items.isEmpty()) return@map rowResult
        val unique = rowResult.row.items.filter { seenIds.add(it.id) }
        rowResult.copy(row = rowResult.row.copy(items = unique))
    }
}
```

This ensures each movie/series appears only in its FIRST (highest-priority) row.

## Overlap Severity Guide

| Row 1 | Row 2 | Overlap (popularity sort) | Overlap (rating sort + dedup) |
|-------|-------|---------------------------|------------------------------|
| Popular Movies | Genre (Action) | 70-80% | <10% |
| Popular Movies | OTT (Netflix) | 30-40% | <15% |
| Top Rated | Genre (Sci-Fi) | 20-30% | <10% |
