Fix Already Safe = 0: hybrid ManifestIndex preserves localIdentifiers + NAS filenames
The root cause: buildManifestIndex was discarding manifest localIdentifiers and switching to pure filename-only matching whenever dirCount > manifest.totalCount (which is always true when the NAS has files from other tools). If filenames didn't match exactly, Already Safe dropped to 0 on every stale-cache reconcile. Fix: introduce ManifestIndex(manifest:nasFilenames:totalCount:) — a hybrid that keeps Kisani's localIdentifiers as primary keys AND adds all NAS directory filenames for filename-fallback. Used in: - buildManifestIndex (full reconcile) - fast path (when dirCount > cached.entries.count, previously gated at <= 1) - BackupEngine step 3b (so "Back up again" only uploads genuinely missing files) Also simplify countSafe / pendingIDs / step-4 filter to always try filename fallback (removes the isFilenameOnly gate that blocked matches when the index had IDs). Co-Authored-By: Kutesir <kutesir@provoc.ug> Co-Authored-By: Sentry <sentry@provoc.ug>
This commit is contained in:
@@ -85,6 +85,29 @@ struct ManifestIndex: Sendable {
|
||||
self.totalCount = names.count
|
||||
}
|
||||
|
||||
// Hybrid: manifest localIdentifiers (Kisani primary key) + all NAS filenames
|
||||
// for filename-fallback matching when the NAS directory has more files than the
|
||||
// manifest tracks (uploaded by other tools). totalCount = actual NAS file count.
|
||||
init(manifest: BackupManifest, nasFilenames: [String], totalCount: Int) {
|
||||
var ids = Set<String>(minimumCapacity: manifest.entries.count)
|
||||
var names = Set<String>(minimumCapacity: manifest.entries.count + nasFilenames.count)
|
||||
var unclaimed = Set<String>()
|
||||
for entry in manifest.entries {
|
||||
let lower = entry.filename.lowercased()
|
||||
names.insert(lower)
|
||||
if !entry.localIdentifier.isEmpty {
|
||||
ids.insert(entry.localIdentifier)
|
||||
} else {
|
||||
unclaimed.insert(lower)
|
||||
}
|
||||
}
|
||||
for name in nasFilenames { names.insert(name.lowercased()) }
|
||||
self.localIdentifiers = ids
|
||||
self.lowercasedFilenames = names
|
||||
self.unclaimedFilenames = unclaimed
|
||||
self.totalCount = totalCount
|
||||
}
|
||||
|
||||
// Build from NAS directory listing (bootstrap — no localIdentifiers known)
|
||||
init(nasListing items: [NASItem]) {
|
||||
var names = Set<String>()
|
||||
|
||||
Reference in New Issue
Block a user