The Sync Bug That Looked Fine
My health dashboard showed stale data for weeks. It looked fine — numbers were there, charts rendered. The bug was invisible because the data was real data. Just the wrong real data.
I have a health dashboard on my personal site that pulls data from my Oura ring and Strava. Sleep scores, heart rate variability, running stats. For weeks it worked perfectly — or so I thought. The numbers were there. The charts rendered. My sleep score said 82% and I thought "yeah, that sounds about right."
It wasn’t right. The actual score was 74%. The dashboard was showing data from three weeks ago.
The first bug was a path mismatch. A cron job synced Oura data and wrote to `data/oura.json`. The UI component read from `data/oura-sync.json`. Different files. Both existed. The cron kept the first one fresh while the UI kept reading the stale second one. This is the kind of bug that passes every code review because both paths look intentional — you’d assume the sync file is the processed version of the raw file.
The second bug was sort order. The cron wrote newest-first: today, yesterday, the day before. The display logic grabbed the last element in the array, assuming oldest-first. So `arr[arr.length - 1]` — which should have been "latest" — was actually the oldest entry. The sleep score I was seeing wasn’t just stale, it was the oldest score in the dataset.
The third bug was a static import. `import data from ’@/data/oura-sync.json’` is a build-time snapshot. After deploy, the cron updates the file on disk, but the page serves the build-time value forever. Even if I’d fixed the path and the sort order, the page would still show the value from the last deploy, not the current one.
All three bugs were invisible because sleep scores don’t change dramatically day to day. An 82% looks exactly as plausible as a 74%. There’s no type error, no runtime crash, no visual glitch. The data is real — it’s just from the wrong time. I only caught it because I happened to check the Oura app on the same day and noticed the numbers didn’t match.
The fix was three changes: unified to one file path, added explicit sort at the read boundary (`sortByDateAscending()` before any access), and replaced the static import with a runtime fetch using `cache: ’no-store’`. I wrote the whole thing up as a skill file — `failure-modes/split-sync-paths.md` — so every future data pipeline gets checked against the same three failure modes before it ships.
// The three bugs, in order of subtlety:
// 1. PATH MISMATCH
// Cron writes: data/oura.json
// UI reads: data/oura-sync.json ← stale copy
// 2. SORT ORDER ASSUMPTION
// Cron writes newest-first: [today, yesterday, ...]
// UI assumes oldest-first: arr[arr.length - 1] ← gets oldest
// 3. STATIC IMPORT = BUILD-TIME ONLY
import data from '@/data/oura-sync.json' // ← frozen at deploy
// vs
const res = await fetch('/api/oura', { cache: 'no-store' }) // ← live
// The fix: one path, explicit sort, runtime fetch