Skip to content

Wheeler cloud sync: union-merge instead of pull-replace - #140

Merged
heyitsStylez merged 1 commit into
mainfrom
fix/wheeler-sync-union-merge
Aug 22, 2026
Merged

Wheeler cloud sync: union-merge instead of pull-replace#140
heyitsStylez merged 1 commit into
mainfrom
fix/wheeler-sync-union-merge

Conversation

@heyitsStylez

Copy link
Copy Markdown
Owner

Problem

A Wheeler trade entered on one device could silently vanish. authInit
replaced the entire local trade array with the cloud copy whenever the remote
savedAt was newer. Entering a trade doesn't bump wheeler_cloud_ts, so a
device holding an unpushed local trade looks "stale" and a later boot pull
clobbers it. This is how a manually-entered IBIT CSP went missing (present in
neither local nor cloud after the fact).

Fix

Reconcile local and remote by union-merging by trade id (mergeTradesById)
instead of wholesale replacement:

  • a trade present on only one side is always kept (no silent loss),
  • the newer side wins shared-id conflicts (preserves edit last-write-wins),
  • whichever store is behind is converged (push local-only trades up / pull
    remote-only trades down),
  • fingerprint guard avoids needless writes and cross-device push loops.

Applied to the incident: signing in on the device that still holds the IBIT
CSP now merges it up to the cloud instead of pulling PURR-only down over it.

Known limitation (deliberate)

Deletions do not propagate — a deleted trade can reappear from another
device's copy. Mild, visible annoyance vs. silent data loss; syncing deletes
needs tombstones (out of scope). Noted in code + ADR 0007 context.

Tests

test/unit/wheeler-merge.test.js (6 cases) incl. the local-only-survives-pull
regression. All 190 tests pass; both builds clean.

🤖 Generated with Claude Code

authInit previously replaced the entire local trade array with the cloud
copy whenever the remote savedAt was newer. A trade entered locally while
signed out (or before its push landed) never bumps wheeler_cloud_ts, so a
later boot pull would silently clobber it — how an IBIT CSP went missing.

Reconcile by union-merging local + remote by trade id (mergeTradesById):
a trade on only one side is always kept; the newer side wins shared-id
conflicts. Converge whichever store is behind. Deletions still don't
propagate (accepted tradeoff vs. silent loss).

Adds test/unit/wheeler-merge.test.js incl. the local-only-survives-pull
regression. All 190 tests pass; both builds clean.
@vercel

vercel Bot commented Aug 22, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
gowheeler Ready Ready Preview Aug 22, 2026 12:26am
hyperwheel Ready Ready Preview Aug 22, 2026 12:26am

@heyitsStylez
heyitsStylez merged commit 545e638 into main Aug 22, 2026
5 checks passed
@heyitsStylez
heyitsStylez deleted the fix/wheeler-sync-union-merge branch August 22, 2026 00:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant