Customisation Sync compares 32-bit-truncated mtimes, so "Newer/Older" and "Select All Shiny" pick at random
Version: Self-hosted LiveSync 1.0.28, Obsidian 1.13.7, Windows + Android, Customisation Sync (per-file).
Problem
In the Customisation Sync dialog the freshness chip ("Newer"/"Older") is unreliable, and Select All Shiny can pick an older copy. Apply All Selected then downgrades plugins. In my case it selected Editing Toolbar 4.1.1 from another device over my local 4.1.4 — the version chip in the same row says "Higher (4.1.4 > 4.1.1)" (screenshot).
Root cause
PluginDataExDisplayV2.mtime (CmdConfigSync.ts#L370-L372):
return ~~this.files.reduce((a, b) => a + b.mtime, 0) / this.files.length;~~ binds before / and keeps only the low 32 bits of a sum of millisecond timestamps (~1.8e12 each). The result is used by the freshness chip (PluginCombo.svelte#L70) and by Select All Shiny (PluginCombo.svelte#L207). Identical copies still produce equal values and show "Same", which is why it looks intermittent.
Minimal check:
const avg = (ts) => ~~ts.reduce((a, b) => a + b, 0) / ts.length;
avg([Date.UTC(2026, 8, 15)]) - avg([Date.UTC(2026, 8, 2)]); // -3171767296: 15 Sep looks older than 2 SepWith the real mtimes from my database the dialog shows the remote as "Newer (3.61d)", "Newer (36.97d)", "Newer (7.04d)"; the correct averages give "Older (12.96d)", "Older (12.74d)", "Older (42.67d)".
Fix
return Math.floor(this.files.reduce((a, b) => a + b.mtime, 0) / this.files.length);~~(sum / length) would overflow as well: a millisecond timestamp alone exceeds 2^31.
Related
- #506 — Select All Shiny selects older version of plugin (same root cause)
- #821 — local file newer than remote but marked older; local changes overwritten (same root cause)
- #501 — may be partly the same: identical copies with different mtimes get selected
Source: vrtmrz/obsidian-livesync