Make the pedigree id sticky across profile sync
The dog id in the synced profile shares one last-write-wins timestamp with name and birthday, and that timestamp comes from each device's own clock. A device whose profile was stamped later (clock skew, or a more recent name/birthday edit) would refuse to adopt a newer server profile that had just gained an id, or even push its empty id back over the stored one — so the pedigree id set on one device never reached the others. Make the id sticky on both sides of sync: an empty value never clears a set one, and a device/server adopts an id it is missing regardless of the blob timestamp. When both sides have an id, the newer profile still wins, so the dog can still be changed. Name and birthday keep plain last-write-wins.
This commit is contained in:
+28
-4
@@ -230,6 +230,28 @@
|
||||
localStorage.setItem(configKey(), JSON.stringify(cfg));
|
||||
}
|
||||
|
||||
// Reconcile a local and a server profile. Name/birthday/updatedAt are plain
|
||||
// last-write-wins by timestamp. The pedigree id is sticky: a non-empty value
|
||||
// never loses to an empty one — so it can't be dropped by a clock race between
|
||||
// devices — and when both are set the newer profile's id wins with the rest.
|
||||
// (The server merge mirrors this, so a set id is only changed, never cleared,
|
||||
// by sync.)
|
||||
function reconcileConfig(local, server) {
|
||||
const base = server.updatedAt >= local.updatedAt ? server : local;
|
||||
return {
|
||||
name: base.name,
|
||||
birthday: base.birthday,
|
||||
pedigreeId: (local.pedigreeId && server.pedigreeId)
|
||||
? base.pedigreeId
|
||||
: (local.pedigreeId || server.pedigreeId),
|
||||
updatedAt: base.updatedAt,
|
||||
};
|
||||
}
|
||||
function sameConfig(a, b) {
|
||||
return a.name === b.name && a.birthday === b.birthday
|
||||
&& a.pedigreeId === b.pedigreeId && a.updatedAt === b.updatedAt;
|
||||
}
|
||||
|
||||
// Age in whole days / weeks / calendar months from a "YYYY-MM-DD" birthday,
|
||||
// measured at `at` (defaults to now — pass a weigh-in's timestamp for its age
|
||||
// at that point). Returns null for a missing/invalid birthday or a date before it.
|
||||
@@ -2040,12 +2062,14 @@
|
||||
pedigreeId: body.pedigreeId || "",
|
||||
updatedAt: Number.isFinite(body.updatedAt) ? body.updatedAt : 0,
|
||||
};
|
||||
if (server.updatedAt > local.updatedAt) {
|
||||
saveConfig(server);
|
||||
const merged = reconcileConfig(local, server);
|
||||
if (!sameConfig(merged, local)) {
|
||||
saveConfig(merged);
|
||||
renderHeader();
|
||||
refreshPedigreeButton();
|
||||
} else if (local.updatedAt > server.updatedAt) {
|
||||
await pushConfig(local);
|
||||
}
|
||||
if (!sameConfig(merged, server)) {
|
||||
await pushConfig(merged);
|
||||
}
|
||||
} catch (err) {
|
||||
console.warn("config sync failed:", err);
|
||||
|
||||
Reference in New Issue
Block a user