Addresses the review of PR #46 (#12/#13):
- Age-retention backfill/prune loop: mark a folder complete at the
retention floor and resume from the persisted nextBeforeUid low-water
mark; loosening resumes via AccountRepository.resetBackfillProgress.
- Guard the windowed reconcile bound to the lowest positive UID so a
getUID==-1 message can't collapse it and wipe backfilled history.
- Order count-based retention by uid DESC to match the fetch window,
ending the re-fetch/re-prune churn for high-UID/old-Date messages.
- BackfillWorker chains slices while work remains.
- Extract shared effectiveRetention / isActiveNetworkUnmetered /
attachmentCacheDir helpers; remove dead deleteSyncedNotIn/getForAccount;
refresh only pre-existing rows in persistBatch; add composite index
(accountId, folder, uid) with migration + regenerated 13.json.
Adds an age-floor prune regression test. Fast gate + androidTest compile
green on JDK 21.
Follow-ups filed for below-the-cut findings: #93, #94, #95, #96.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>