* fix(scanner): reconcile deleted files promptly and honor file_removal_grace
Upgraded/replaced media files left dead playable versions until the next
full library scan: autoscan file-scope changes for deleted paths failed
resolution (ClassifyPath stats the path) and were silently dropped, and
scanner.file_removal_grace was dead config — empty_trash_after_scan
purged missing-marked rows folder-wide immediately.
- Add scantrigger.Resolver.ResolveVanishedPath: maps a vanished video
file to a subtree scan of its parent dir, a vanished dir to itself,
and an entry directly under a library root to a guarded library scan.
Rejects still-existing paths and requires the matched library root to
exist on disk so an unmounted share never triggers reconciliation.
- Autoscan falls back to it for file-scope and legacy parent-dir changes
that fail with a RequestError, closing the dead-version window from
~24h (daily full scan) to roughly one poll interval.
- DeleteMissingByFolder now takes the removal grace and only deletes
rows missing longer than it (default 24h, restart-required setting);
missing rows are already hidden from every client surface, so the
grace only preserves per-file state (probe/match/markers) in case the
file returns. Remove the uncalled DeleteMissing sweeper.
Part of #311
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* fix(scanner): only treat ENOENT as a vanished path in ResolveVanishedPath
Permission or other stat failures must not reconcile still-existing
files as missing; reject them with a RequestError instead.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* refactor(scanner): address PR 312 review nitpicks
- Extract shared matchEnabledFolder/normalizeTrigger helpers so
ResolveMissingSubtree and ResolveVanishedPath cannot drift.
- Warn when a negative scanner.file_removal_grace is clamped to 0.
- Add disabled-library test for ResolveVanishedPath.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>