`_reconcile_cache()` replaced the recorded folder list only when *nothing* was left
unverified: one switched-off drive, one directory `os.walk` could not enter, or one
symlink whose target was gone, and the whole list fell back to a union with what
the walk found. A folder moved with a file manager therefore stayed in the sidebar
for good — the walk kept adding the new location while the old entry was never
dropped, a restart re-hydrated the union from SQLite, and the ghost could not be
deleted in the UI either because its directory was gone.
* `_UnreachablePaths.covers_folder()` answers "could this specific entry have been
read?" for a library-relative folder: it is kept only while a directory the walk
failed to enter (or an offline symlink) may still hold it. A root that is
unreadable *as a whole* deliberately does not count: library-relative names carry
no root, so a missing drive would trivially cover every entry and no ghost could
ever be cleared. Its folders still show while they hold cached models
(`get_all_folders()` unions the model-derived folders) and a genuinely empty one
comes back the next time that root is walked.
* The merge keeps today's union for a scoped scan, and for a root-scoped scan that
does not cover every root: those cannot speak for the roots they were not asked
about. Asking for every root is a full refresh and cleans again.
Verified: a folder moved externally is dropped while another root is offline, the
offline root keeps its own folders and cached models, and a scoped scan still never
drops a folder of a root it did not scan. The Windows-only half of this (a
backslash `os.sep` making the configured twin shadow the live root, so deleted
models were never pruned) is now reproduced in CI by patching `os.sep` instead of
needing a Windows runner.