Three changes that together eliminate the "Checking…" stall and excessive NAS
rescanning without requiring a database migration:
NASManifestCache: extend stale threshold from 5 min to 30 min. directoryCount
is now updated incrementally after every upload, and PHPhotoLibraryChangeObserver
keeps LocalPhotoIndex current — a full NAS roundtrip every 5 min was redundant
and forced the expensive reconcile path far more often than necessary.
BackupStatusService: add withTimeout(_:work:) using a racing ThrowingTaskGroup
so NAS operations (SMB connect, manifest download, directory listing) fail fast
instead of hanging indefinitely when the NAS is slow or unreachable. Timeouts:
15s for connect, 12s for manifest download, 12s for directory listings. On
timeout, BackupError.timeout is caught separately to preserve cached counts
instead of marking connectionState = .offline.
BackupStatusService: call LocalPhotoIndex.shared.loadOrBuild() at the start of
performRefresh before checking localIndexCount. Without this, AppDelegate's
concurrent loadOrBuild() task races with the first onActive() trigger; if it
loses, localIndexCount == 0 and the fast path is bypassed, forcing a full NAS
roundtrip on every cold launch.
Co-Authored-By: Kutesir <kutesir@provoc.ug>
Co-Authored-By: Sentry <sentry@provoc.ug>