feat(engine): Phase M — sync transparency + local data backup
Test / fmt (pull_request) Successful in 5s
Test / test (pull_request) Successful in 4m22s

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>
This commit is contained in:
funman300
2026-07-16 18:06:01 -07:00
parent b4845564af
commit 2f373784bf
11 changed files with 617 additions and 7 deletions
+6
View File
@@ -133,6 +133,12 @@ pub use challenge::{CHALLENGE_SEEDS, challenge_count, challenge_seed_for};
pub mod difficulty_seeds;
pub use difficulty_seeds::{DifficultySeeds, seeds_for};
pub mod transfer;
pub use transfer::{
BundleError, DATA_BUNDLE_SCHEMA_VERSION, DataBundle, data_bundle_path, load_bundle_from,
save_bundle_to,
};
pub mod settings;
pub use settings::{
AnimSpeed, REPLAY_MOVE_INTERVAL_STEP_SECS, SOLVER_DEAL_RETRY_CAP, Settings, SyncBackend,