2d8c44ac87
get_hermes_dir(new_subpath, old_name) returned the legacy <old_name>/ location as soon as it existed on disk — even when empty. When an empty legacy stub is created on a profile that already has populated data at the new consolidated <new_subpath>/ (install scaffolds, profile init, a stray mkdir, or ensure_hermes_home() recreating legacy dirs), the resolver silently flipped to the empty legacy dir and the real data became invisible. No log, no error — the feature behaved as if state was wiped. Reproduced as a Discord pairing store losing every approved user when an empty pairing/ shadowed the populated platforms/pairing/. Resolve the legacy path only when it has content: a populated directory (any entry) or a non-directory file counts; an empty directory falls through to the new layout. Inspection failures (PermissionError on lstat/iterdir, or any OSError short of FileNotFoundError) are treated as "occupied" so a transient error never orphans legacy data — only a genuine FileNotFoundError counts as absent. The lstat()-based gate also fixes the prior exists()/is_dir() path swallowing PermissionError and mis-reading an unreadable legacy dir as absent. This hardens all 11+ call sites that share the resolver (pairing, image/audio/video/document caches, matrix/whatsapp session stores, vision/credential/tts/browser dirs). Adds TestGetHermesDir regression coverage (empty/populated/subdir/file/ unreadable/unstatable cases) and updates test_credential_files to populate its legacy dirs so they still count as content. Closes #27602 Closes #27715