"The string /Users/you/report.pdf is an address, not a person. Addresses get reassigned."
The Same Path, a Different File
Here is the bug that eats naive file managers. You show a row for a file. The user glances away. In that gap, some other process deletes that file and writes a brand-new, unrelated file to the exact same path — same name, same folder. The user clicks "Move to Trash" on your row. If your app resolved the action by path string, it just trashed a file the user never even saw. The path was identical; the file was not.
Identity Lives in Bookmarks and Resource IDs
macOS gives you better handles than a path. A bookmark is a durable, relocatable reference that can survive a rename or a move. A resource identifier (via URL resource values) ties to the actual file object, not its name. Waygate wraps both in a LocationReference and treats that as identity — a path string is kept only as a display hint and a last-resort fallback.
Revalidate Before You Act
Holding a good reference is only half the rule. The other half: before any mutation, Waygate revalidates — it resolves the reference against the live filesystem and confirms the volume identity, the resource identity, and the relevant preconditions still hold. Only then does the operation proceed. A path that no longer resolves to the same file doesn't get acted on; it gets flagged.
A path string never authorizes a mutation. Waygate keeps bookmarks and resource identifiers, treats those as identity, and revalidates the live URL, volume, and preconditions at apply time. The name on the row is a label for humans, not a handle for the engine.
The reused-path deletion. The nastiest data-loss bug in file tooling is acting on a path that now points at a different file than the one displayed. SMB and removable volumes make it worse — identities drift when a share reconnects. Any operation that skips revalidation is one unlucky race away from trashing the wrong thing.
Code
LocationReference: identity, not just a path·swift
struct LocationReference {
let bookmarkData: Data // survives rename / move where possible
let resourceID: String? // ties to the file object, not the name
let volumeID: String? // which volume this identity belongs to
let displayPath: String // for humans + last-resort fallback ONLY
}
// Before a mutation, resolve and confirm identity still holds:
func revalidate(_ ref: LocationReference) throws -> URL {
var stale = false
let url = try URL(resolvingBookmarkData: ref.bookmarkData,
options: [], relativeTo: nil,
bookmarkDataIsStale: &stale)
let values = try url.resourceValues(forKeys: [.fileResourceIdentifierKey,
.volumeIdentifierKey])
guard matches(values, ref) else { throw OpError.identityChanged }
return url // safe to act on THIS url, now
}
Why the path alone is dangerous·text
t0: row shows report.pdf (file A, the one the user sees)
t1: another process deletes A, writes B to the SAME path
t2: user clicks 'Move to Trash' on the row
PATH-BASED app: trashes whatever is at the path now -> trashes B (wrong!)
WAYGATE: revalidates identity, sees A is gone -> stops, flags it
Same string. Different file. Only identity tells them apart.
Write down the sequence of events for a 'reused path' data-loss bug in your own words: a file displayed, the same path repurposed, an action taken. Then describe the one check that stops it. Why can't that check be 'does a file exist at this path?' — what does it have to compare instead?
Hint
'Does a file exist here?' returns true for the wrong file — that's the whole trap. The check has to be 'is the file here still the SAME file I displayed?', which means comparing resource identity (bookmark / resource id), not mere existence at a path. Existence is presence; identity is sameness.
Progress
Progress is local-only — sign in to sync across devices.