# 10-Phase Rebuild — 2026-05-28

## Metrics (post-rebuild)
- 281 Kotlin source files (282 → 281 after 18 dead files removed)
- 6 domain use cases (was 1)
- 131 tests (all green)
- 35 MB debug APK
- 0 force-unwraps, 0 hardcoded secrets
- 8 BuildConfig keys

## Domain Use Cases Created
All in `domain/usecase/`, `@Singleton` + `@Inject constructor`, `suspend operator fun invoke()`:
1. `ResolvePlaybackSourceUseCase` — streams → rank → debrid resolve → best URL
2. `ManageAddonUseCase` — install/enable/disable/remove addons
3. `ToggleWatchlistUseCase` — add/remove watchlist via TraktService
4. `GetContinueWatchingUseCase` — in-progress items with metadata enrichment
5. `AuthenticateDebridUseCase` — OAuth device-code (RD/AD) + API key (PM/TB)
6. `EnsureActiveProfileUseCase` — pre-existing, validates active profile

## Critical Bug Fixes (Phase 3)
1. **Onboarding debrid auth**: `debridStates[provider]` map updated but UI read global fields — never populated. Fixed: sync both.
2. **Onboarding step mapping**: sidebar labels mismatched content panels. Fixed: renamed labels.
3. **Addon update button**: `onUpdate = { }` empty. Fixed: wired to `viewModel.installAddon()`.
4. **Stream validation bypass**: Debrid CDN URLs skipped `StreamValidator`. Fixed: validate after resolve.
5. **Resume playback**: `WatchProgress` saved but never restored. Fixed: load in `initialize()`, pass `seekToMs`.

## Playback + Source Fixes (Phase 4)
- `FallbackEngine`: codec/DRM failures skip all 4 tiers; `totalAttempted` consistency
- `SourceRanker`: UNKNOWN codec no longer penalized; safe fallback for deprecated enum
- `DebridResolveCache`: 100-entry eviction cap; `resolveAll` truly parallel via `coroutineScope { async }`
- `StreamValidator`: added `.webm/.mov/.ts/.m2ts/.m4v` progressive detection
- `SourcePreferences.kt`: extracted from `SourceRanker.kt`

## Security Fixes (Phase 7)
- ProGuard: fixed literal `\n` escapes — `DebridSettings` protected in release
- `DebridService`: redacted stream URL from logs
- Release signing: conditional via `RELEASE_STORE_FILE` Gradle property

## Performance + UI (Phases 5-6)
- Home screen: shimmer skeleton replaces spinner; `LaunchedEffect` key narrowed
- Room: `@Index` on `BridgeEntry.imdbId`; v5→v6 migration
- Color consistency: 6 raw `Color.White/Black` → `NexColors`
- Focus-aware color pulse on "See All" button

## Dead Code Removed (Phase 8)
18 files: `ColorBlindPalette` (duplicate), `SourceModule` (stub), `NexTypography` (unused), `NuvioScrollDefaults` (unused), 3× Debrid V2 APIs, `NuvioColors` compat object, 1 launcher icon, 1 XML colors file, 8 player SVGs.

## MockK Test Fix Pattern
When adding a new method call to a class tested with MockK strict mocks, all existing tests break. Fix: update shared mock helper (e.g., `mockDeps()`) to stub the new call. Use `answers { firstArg<String>() }` when the mock needs to echo input parameters.

## Remaining Risks
1. CoilModule API mismatch (pre-existing) — `bitmapPool()` API for Coil 3
2. Dual color system: 5 files still use `NexColors` directly vs `NuvioTheme.colors`
3. Branding: `app_name` = "Nuvio" in strings.xml
4. 16 medium-severity bugs from Phase 3 audit not yet fixed
