Let two devices name the same photograph's version the same way
A version's uuid is the identity a cross-device merge keys on, and it was minted at random, per catalog, per image. Two devices indexing one Nextcloud library therefore held two different uuids for the same photograph — so the sidecar they shared collected a `default = 1` block each, `Version::merge` was never handed a matching pair to reconcile, and an afternoon's culling on the tablet did not exist as far as the laptop was concerned. `crate::merge` has said so in a comment since it was written: version uuids do not reconcile across devices, a uuid-keyed join unions nothing, so keywords are landed on the local default version instead. It named the problem and worked around it. `rating`'s own comment asserted the opposite — that generating the uuid here was what made it a cross-device identity — and `library::amend` repeated the claim. Uniqueness was never the difficulty; agreement was. `derived_version_uuid` computes it from `oc:fileid` instead. The server assigns that integer, every client pointed at the library sees the same one, and it survives a server-side rename and move — the three properties that already made `ASSIGN_BY_FILE_ID` prefer it to a content hash. The layout is a UUIDv8 (RFC 9562, an application-defined form) carrying all sixty-four bits verbatim across the variable fields with a fixed tag in the node field, so the mapping is injective by construction rather than by a hash's good behaviour, and a uuid in a sidecar can be read back to the file it belongs to by eye. A library with no server behind it has no shared identity to derive and keeps a generated one. The split is still reachable there if the folder is synced by something else; `Sidecar::fuse_default_versions` repairs that case rather than preventing it. Deriving it for new rows alone would have fixed nothing — every image in an existing library already has a version, so every one of them would have carried on writing to its own rival identity. `align_default_version_uuids` moves them, and runs from `schema::backfill` on every catalog open. It selects on the tag in SQL, so a catalog already realigned matches no rows and writes nothing, and it declines rather than fails where a virtual copy already holds the target. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
+18
-18
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user