The reconcile heals rows whose file is still in the library; it deliberately
leaves ORPHANS — history rows whose file is gone (deleted / replaced /
re-downloaded elsewhere). Those can never be healed (no file left to confirm)
and linger in the Unverified list forever. This adds an explicit, user-initiated
cleanup for them.
- core/downloads/orphan_history.py: pure, tested rule. A row is an orphan when
its file resolves nowhere; flags `suspicious` when EVERY reviewed file is
unreachable (the mount-down signature) so the caller refuses rather than
mass-delete a healthy log during an outage.
- POST /api/verification/clean-orphans (admin-only): runs it against
_resolve_history_audio_path (raw path -> prefix-swap resolver -> tracks-table
title fallback), refuses on the suspicious signature, and deletes only history
ROWS — never a file (the files are already gone).
- UI: "🧹 Clean orphaned" button in the Unverified bulk-actions row, with a
confirm dialog spelling out that it removes log rows only and refuses if the
library looks offline.
NEVER automatic / never at boot — a filesystem check during a mount outage would
otherwise wipe good history. 5 pure-rule tests + safety-gate coverage.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LWJk7EuM7YktQeNyqQwTZY