Watch-state synchronization looks simple until the same episode has four provider identities, a rebuilt library, a delayed webhook, and a user who watched it twice.
A boolean watched flag is not enough to explain what happened. A useful sync system needs a canonical record, an event lifecycle, per-destination evidence, and a recovery path that a person can understand.
Why watched and unwatched are insufficient
A destination can be behind, unavailable, ambiguous, or based on a different item identity. Treating the latest provider response as absolute truth makes a sync layer overwrite information without showing why.
A better model keeps the canonical record separate from delivery state. The canonical record answers what the local system believes. Delivery records answer what each destination received, when it was attempted, and why a retry is or is not needed.
Canonical identity and event lifecycle
The first hard problem is identity. A movie or episode can be represented differently after a library rebuild or across Plex, Emby, Jellyfin, and Trakt. The sync layer needs a stable internal identity and an explicit review path when a match is uncertain.
The second hard problem is lifecycle. A play can be new, repeated, partially watched, completed, corrected, or superseded by a newer state. Each transition should be idempotent so retrying a delivery does not create a second play by accident.
Per-destination delivery results
A single sync status hides too much. For each destination, record the source event, destination, outcome, reason, attempt time, and retry context. This turns a vague failure into an actionable answer such as a missing match, a rate limit, a provider outage, or a deliberate manual review.
That record is the basis of Plembfin's Sync Activity view. It is designed as an operational ledger, not a green checkmark that asks the user to trust an invisible process.
Conflicts, rewatches, and rebuilt libraries
Conflict handling needs to be explicit. When two sources disagree, the system should preserve the evidence, identify the newer or stronger signal, and explain the choice. Rewatches need their own event semantics so a repeat play is not mistaken for a duplicate import.
A rebuilt library is a recovery case, not just another sync. Matching should be conservative, surface uncertainty, and let a person review before a large batch changes history.
Backup and recovery boundaries
Backups are part of the feature. A safe workflow starts with a backup and a small library, then expands after the Sync Activity results look correct. Recovery documentation should state what can be restored, what needs to be reconnected, and which provider actions are not reversible.
Testing provider integrations
Integration tests cover request and response handling, but browser flows matter too. A practical test pass checks onboarding, manual watch review, retries, backups, metadata, and the visible reason attached to each delivery outcome. The test data should include missing matches, provider failures, duplicate plays, partial progress, and a rebuilt library.
AI assistance and review
Plembfin was heavily AI-assisted under my direction. I reviewed the generated changes, tested the integrations and browser flows, and maintain the project. AI is not required at runtime. This article is written as a technical explanation of the design and its trade-offs, not as a claim that the difficult edge cases are solved.
If you want to inspect the implementation or test the workflow, start here: https://plembfin.com
The project is self-hosted and available under AGPL-3.0. Back up first and test with a small library.


Top comments (2)
The explainability angle is the part that usually gets skipped, and it's the part that actually saves you in prod. Watching the latest provider response as truth will silently overwrite state, and then nobody can say why the episode shows watched on one box but not the other. Keeping the canonical record separate from per-destination delivery state is the right split.
One thing I'd push on: idempotency across identity reconsolidation. When a library rebuild changes the item identity, the sync layer has to decide whether an old delivery record belongs to the new identity without counting a re-match as a brand-new play. Do you stamp delivery records with the canonical identity they were created under, or do you re-parent them on match? That decision is where "retry doesn't create a duplicate" tends to actually break.
Thanks, I agree that identity reconciliation is where the duplicate risk becomes real. In Plembfin, Fix Match updates the affected watch history rows in place, recomputes their media keys from the selected provider identity, and migrates the matching playstate rows. A provider ID change does not create a new play by itself.
Older audit and sync entries remain historical evidence of what was originally dispatched. A later retry resolves the current watch record using the rematched show identity and episode coordinates. Duplicate prevention also checks canonical state across provider IDs and episode coordinates, while outbound echo guards stop provider acknowledgements from becoming a second play.
Rematch and retry ordering is still an important edge case to test, especially when a library rebuild changes both the provider ID and the title.