The first honest witness
Hedge is a daily calibration trivia game I build solo; the architecture lives in the case study. This closes the iCloud sync trilogy after the design entry and the trail guide: the bug that shipped with sync, and the device that exposed it.
Two days after iCloud sync shipped, I opened Hedge on my Mac for the first time and caught my own sync system lying to me. Not the Mac's copy. All the others.
It didn't look like a lie at first. It looked like the Mac was broken. Settings synced over fine, and the day's round even arrived half-played: I had answered two questions on my phone that afternoon, and the Mac picked up at question three like the feature demo it was designed to be. I finished the round there and watched it flow back to the phone and the iPad within seconds. Sync was visibly, demonstrably alive. And yet the Mac showed a 1-day streak against my phone's 21, the calibration page was locked behind its 40-answer gate like I was a brand-new player, and every Gut Check pack showed locked. My whole history just... wasn't there.
Two against one
Here's the trap I nearly fell into: my phone and iPad agreed with each other perfectly, so the obvious read was two healthy devices and one broken Mac. The actual situation was the reverse. The phone and iPad shared a past, and they shared the same wrong belief because of it. The Mac was the only device that had never been part of the development bring-up, which made it the only device with no stake in the story. The first honest witness to walk in, and its testimony was: the cloud is nearly empty.
The flight recorder
The nice thing about a Mac app is that its database is just a file on disk. I didn't have to guess; I opened the SQLite and read the timestamps like a flight recorder. Twelve answers total: seven from a TestFlight test night the previous week, five from today. And the tell was in the sync stamps. The Mac's first successful sync cycle ever had run that evening, a full-from-the-beginning pull of the production zone, and that pull had delivered exactly two answers. Two. My phone had 420. Sync wasn't broken. The cloud was never filled.
A claim about a place
The root cause is the kind that only bites the developer. Dev builds and store builds deliberately sync to different CloudKit zones, so test junk can never touch a tester's real data. That wall is load-bearing and it worked. But the local database survives swapping binaries, and during the real-device bring-up my phone had pushed its entire history into the dev zone and stamped every row "confirmed in cloud." When the App Store build took over, it believed the stamps. Nothing old ever got pushed to the production zone; only answers committed after the swap made the trip. The iPad had adopted that same history through that same dev-era sync, which is why the two of them agreed so convincingly. Agreement between devices that share a past proves nothing. The bookkeeping said "synced" but a synced flag is really a claim about a place, and mine didn't record which place.
The fix that ships itself
So that became the fix. The sync state now records which zone its bookkeeping was earned against, and any mismatch invalidates all of it: forget the change token, mark everything unsynced, push it all again. That sounds violent until you remember what the earlier entries in this log earned: saves are fail-if-exists and the merge is an idempotent set union, so the recovery for any confusion, no matter how deep, is just "sync harder." Replaying the whole world converges to the same answer. And because a device that predates the fix has no zone recorded at all, no zone reads as a mismatch, which means the repair ships itself. No support steps, no toggle ritual, no "have you tried reinstalling."
I merged the fix, opened my phone, and pointed a little watcher at the Mac's database file to see it happen. About five minutes after the merge, the file jumped from 12 answers to 420, the streak read 21 days, the calibration chart unlocked, and all five packs opened. The iPad converged the same way. Total user interaction required: zero, unless you count me staring at a terminal watching a number change.
The scar
One scar stayed, and I decided I like it. On the TestFlight test night I had played that day's round on the Mac as well as the phone, and when the Mac's copies finally reached the production zone first, first-to-server did exactly what it promises: the Mac's answers own that date now, and my phone's originals adopted them. Seven answers, replaced by other answers I also genuinely gave. The conflict rule didn't malfunction. It adjudicated a race I accidentally staged against myself, and every question in my history is still one I legitimately answered at some point.
The lesson
The bug reached exactly one person, because only one person's devices had a development past: mine. But the fix is permanent armor. Every future dev session on a real device now heals itself on the way back to the store build instead of quietly stranding history. And the lesson I'm keeping is about the witness, not the bug. Your test devices can agree with each other forever and prove nothing, because they were all in the room when the story was written. The audit you actually want is a machine with no past walking in cold and telling you what's really in the cloud. Mine happened to be a Mac, and it was the only one telling the truth.