Skip to content

feat(sync): Rebuild from iCloud — self-serve full resync (#300) - #303

Merged
yicheng47 merged 1 commit into
mainfrom
feature/300-rebuild-from-icloud
Aug 9, 2026
Merged

feat(sync): Rebuild from iCloud — self-serve full resync (#300)#303
yicheng47 merged 1 commit into
mainfrom
feature/300-rebuild-from-icloud

Conversation

@yicheng47

Copy link
Copy Markdown
Owner

Closes #300.

What

A Resync action in Library Sync settings that discards the local materialized view of synced data and reconstructs it from the peer snapshots and event logs in the shared folder. One-way pull — nothing in iCloud is deleted or rewritten beyond the device's own log/snapshot/manifest. Escape hatch for diverged/stuck sync (#298).

How

sync_rebuild runs, single-flight and serialized:

  1. Pre-wipe fold tick — drains the outbox and applies any own events not yet replayed locally, so tombstones for recent deletes exist before anything is snapshotted.
  2. Sealed bootstrap publish — under the outbox seal, re-applies the full own log (the self watermark can sit past a failed event, so it isn't trusted as proof of application), failing closed on any apply error, then publishes the bootstrap snapshot. Every local row that ever reached SQL is durable in iCloud before anything is deleted.
  3. Rebuild marker in the local-only settings table, then one wipe transaction clearing the eight synced tables and every _replay_state watermark, under the tick lock.
  4. Full replay via tick_with_progress (covers cover re-ingest and drives the existing sidebar progress chip), marker cleared only on a complete, un-cancelled pass.

Interrupted/cancelled rebuilds resume on next launch from both engine-boot sites; retries and sync_enable are marker-aware so a wiped/partial DB can never be published over the recovery snapshot. Cancellation uses a monotonic generation captured inside the serialized section, with gates before every destructive step.

Spec deviation: translations is preserved rather than wiped — no replay source exists (snapshots don't carry it; its events are no-ops since #263), and the table is already dropped on dev DBs stamped by a since-deleted migration 14. Spec should be updated nine → eight tables.

Testing

  • ~20 new backend unit tests covering: publish-before-wipe survival, local-table/tombstone preservation, watermark clearing, healthy-library convergence with cover re-ingest, interrupted-rebuild resume, retry/enable marker-awareness, unapplied-delete tombstone materialization, watermark-hole abort, fail-closed sealed publish, single-flight concurrency, and the full cancellation matrix.
  • Full suite: 282 passed / 0 failed; clippy clean; tsc + vite build clean.
  • Reviewed through five working-tree review rounds (crew reviewer); final verdict clean.
  • Smoke-tested on the dev install against the real iCloud library.

🤖 Generated with Claude Code

Adds a sync_rebuild command that discards the local materialized view
of synced data and reconstructs it from the peer snapshots and event
logs in the shared folder. One-way pull — nothing in iCloud is deleted
or rewritten beyond the device's own log/snapshot/manifest.

Sequence: pre-wipe fold tick (drains the outbox and materializes
tombstones for not-yet-applied own deletes) → sealed bootstrap publish
(re-applies the full own log under the outbox seal, failing closed on
apply errors, so no own event can be masked by the snapshot id) →
rebuild marker in the local-only settings table → one wipe tx clearing
the eight synced tables and every replay watermark under the tick
lock → full replay → marker cleared only on a complete un-cancelled
pass. The whole state machine is single-flight; an interrupted or
cancelled rebuild resumes on the next launch from either engine-boot
site. Cancellation uses a monotonic generation captured inside the
serialized section, with gates before every destructive step.

Deviation from the spec: translations is preserved, not wiped — it has
no replay source (snapshots don't carry it, its events are no-ops
since #263), and it's already dropped on dev DBs stamped by a deleted
migration 14.

UI: danger-styled Resync row + confirm dialog in Library Sync settings
(disabled with the paused tooltip in queue-only mode), two-phase
progress through the existing sidebar chip, en/zh strings.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@yicheng47
yicheng47 merged commit e7e2589 into main Aug 9, 2026
2 checks passed
@yicheng47
yicheng47 deleted the feature/300-rebuild-from-icloud branch August 9, 2026 02:24
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.

feat: rebuild library from iCloud (full resync)

1 participant