feat(engine): Phase M — sync transparency + local data backup #189
Reference in New Issue
Block a user
Delete Branch "feat/sync-transparency"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
The last remaining item of the 13-phase menu redesign.
1. Post-sync merge summary
The pull poller keeps the
ConflictReports fromsolitaire_sync::merge(previously discarded atsync_plugin.rs) in a newSyncConflictLogresource, and toastsSynced — N conflicts, kept newer valueswhen a merge wasn't clean. No §8 territory touched —SyncResponse.conflictsalready existed on the wire; no solitaire_sync type or merge-strategy changes.2. Account tab detail
Under the sync row: a clean-merge caption or a per-field conflict list (
win_streak_current — this device: 3 / server: 5), timestamped.SyncStatus::LastSyncedremains live-updated as before.3. Local data export/import
New
solitaire_data::transfer: one versioned JSON bundle (settings, stats, achievements, progress) written atomically (.tmp→ rename) next to the other saves. Loader is version-gated and error-surfacing (never default-restores). Account tab gains Export/Import pill buttons (hidden on wasm) with the backup path shown in a caption. Handler runs inLast— off the annotated Update spine, so the ambiguity gate is untouched.Tests
Gate:
cargo test --workspacegreen,clippy --all-targets -D warningsclean, rustfmt applied.🤖 Generated with Claude Code
Closes out the 13-phase menu redesign. Three parts: 1. Post-sync merge summary: the pull poller now keeps the `ConflictReport`s the merge produces (previously discarded) in a new `SyncConflictLog` resource and toasts "Synced — N conflicts, kept newer values" when a merge wasn't clean. No wire changes — the server-side `SyncResponse.conflicts` field already existed. 2. Account tab detail: a per-field conflict list under the sync row ("win_streak_current — this device: 3 / server: 5") plus a clean-merge caption, so the last merge is always inspectable. 3. Local data export/import: new `solitaire_data::transfer` module — one versioned JSON bundle (settings, stats, achievements, progress) written atomically next to the other saves, with a version-gated loader that surfaces every failure instead of defaulting. Account tab grows an Export/Import button pair (desktop+Android only); the handler runs in `Last`, off the annotated Update spine. Import rewrites the live resources, persists via the existing save fns, and fires SettingsChangedEvent so appliers react normally. Tests: bundle round-trip/version-gate/missing-file in solitaire_data; ECS-level export→import round trip and failed-import-warns in settings_plugin. Gate: workspace tests green, clippy -D warnings clean. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>