# Full App Audit — Current Code First

Use this reference when resuming or auditing a mature Android streaming app from handoff docs.

## Principle

Treat handoff/audit docs as leads, not truth. Verify current repo state before coding because prior session-end docs can become stale after commits.

## Read-only audit sequence

1. Check current git state and recent commits:
   ```bash
   git status --short
   git log --oneline --decorate -20
   ```
2. Read existing audit/handoff docs, but mark claims as unverified until cross-checked.
3. Map current repo shape:
   - Android app modules (`app/src/main/java`, tests, Gradle tasks)
   - Backend/service modules actually present in the repo (e.g. Cloudflare Worker under `services/`, not a separately-mentioned FastAPI app unless it exists)
   - Playback/source ranking/settings/onboarding/network layers
4. Run safe baseline verification before edits:
   ```bash
   ./gradlew :app:compileDebugKotlin :app:testDebugUnitTest --console=plain
   ./gradlew :app:lintDebug --console=plain   # report baseline failures, do not block audit
   npm --prefix services/catalog-worker run typecheck
   npm --prefix services/catalog-worker run test:smoke
   ```
5. Write/update audit docs and prioritized fix plan before code changes if the user asked for read-only audit first.
6. Apply only low-risk/high-value fixes first, one area per commit, with compile/tests after each patch.

## Useful static scans

```bash
# Large/risky Kotlin files
python3 - <<'PY'
import os
files=[]
for dp, dns, fns in os.walk('app/src/main/java'):
    for f in fns:
        if f.endswith('.kt'):
            p=os.path.join(dp, f)
            files.append((sum(1 for _ in open(p, errors='ignore')), p))
for n,p in sorted(files, reverse=True)[:25]:
    print(n, p)
PY

# Compose lifecycle collection debt
grep -R "collectAsState(" app/src/main/java --include='*.kt'

# TV no-op click traps
grep -R "onClick *= *{ *}" app/src/main/java --include='*.kt'

# Broad catches / coroutine risks
grep -R "catch *(.*Exception\|GlobalScope\|Thread.sleep" app/src/main/java --include='*.kt'
```

## Findings that commonly warrant low-risk fixes

- Source picker displays a raw stream list while switching indexes into ranked streams.
- Screen-level ViewModel state uses `collectAsState()` instead of `collectAsStateWithLifecycle()`.
- Lint baseline exists but compile/tests are clean; split lint fixes by issue family.
- Worker/backend docs refer to a service not present in current repo; update architecture map instead of preserving stale claims.
- Media3 playback exceptions are logged but not connected to ViewModel fallback; wire playback-state errors into fallback and test retry behavior.
- Fallback compares only one URL field; streaming sources often have `resolvedUrl`, `debridUrl`, and original `url` variants that must be treated as one identity set.
- Debrid priority is implemented as loose sorting only; enforce cached/debrid filtering within resolution phases before free/non-cached candidates.
- Catalog Worker cache keys include unknown query params or public errors echo upstream exception text; whitelist effective params and redact public error messages.

For detailed remediation patterns for the last four findings, see `android-streaming-hardening-audit.md`.

## Commit pattern

- Commit docs/audit refresh separately from code fixes.
- Commit each safe fix separately.
- After code commits, update the fix plan with applied status and verification command/result.
