Conflict Resolution | Cine Power Planner

Conflict Resolution

Resolve cloud sync conflicts with a guided merge wizard

Overview

The Conflict Resolution wizard activates when two versions of the same data arrive from different sources during cloud sync — typically when the same project is edited on multiple devices or by multiple collaborators while offline. The wizard presents both versions side-by-side and lets you choose how to merge them.

Requirements

Functional Requirements

IDRequirementAcceptance CriteriaPrioritySource
REQ-CFR-001The system shall detect field-level conflicts when syncing data from multiple sourcesSync detects a conflict → the wizard opens by itself, wherever you are; field-level diff displayedMustuseConflictResolverState
REQ-CFR-002The system shall present conflicting fields side-by-side (local vs. remote) with visual diff highlightingOpen conflict → two columns shown; changed fields highlighted in yellow/red; identical fields dimmedMustuseConflictResolverState
REQ-CFR-003The system shall support resolution strategies: Keep Local, Keep Remote, Merge (field-by-field), Auto-mergeClick Keep Local → local version saved; Keep Remote → remote saved; Merge → field-level picker; Auto → non-overlapping resolvedMustuseConflictResolverState
REQ-CFR-004The system shall queue unresolved conflicts and surface them via a notification badge — not shipped as stated; see the 2026-09-10 noteA skipped conflict does stay queued in the engine and the wizard reopens next sync — but there is no badge count and no list screenMustnotification badge (never built)
REQ-CFR-005The system shall support batch resolution: apply the same strategy to all conflicts at once — not shipped as stated; see the 2026-09-10 noteNo "Resolve All" and no cross-conflict strategy picker existShouldbatch resolution (never built)
REQ-CFR-006The system shall log all conflict resolutions for audit trail purposes — not shipped as stated; see the 2026-09-10 noteNo resolution log is written and no viewer exists; the backup_conflict_… safety backup is the recoverable recordShouldresolution log (never built)
REQ-CFR-007The system shall prevent data loss by always preserving both versions until the user explicitly resolvesConflict pending → both local and remote versions saved; no auto-overwrite; cancel resolution → both preservedMustuseConflictResolverState
REQ-CFR-008The system shall support exporting conflict resolution history as a JSON/CSV report for audit purposes — removed 2026-05-30 (dead code; never wired into the live wizard)Click export → file downloads; contains timestamps, entity IDs, resolution choices, user infoShoulduseConflictExport (removed)
REQ-CFR-009The system shall support keyboard shortcuts for conflict resolution (Accept Local, Accept Remote, Skip) — removed 2026-05-30 (dead code; never wired into the live wizard)Press L → accept local; press R → accept remote; press S → skip; shortcuts shown in toolbarShoulduseConflictKeyboardShortcuts (removed)
REQ-CFR-010The system shall support searching and filtering conflicts by entity type, date, or field name — removed 2026-05-30 (dead code; never wired into the live wizard)Type search term → conflicts filtered; clear → all shown; filter by entity type → matching conflicts onlyShoulduseConflictSearch (removed)

Note (2026-05-30): REQ-CFR-008 (export), REQ-CFR-009 (keyboard shortcuts), and REQ-CFR-010 (search/filter) describe surfaces that shipped as code but were never connected to the live conflict wizard. The unused code was removed; these requirements are retained as planned/future scope.

Note (2026-09-10): REQ-CFR-004, REQ-CFR-005 and REQ-CFR-006 are not shipped as stated, and are retained as planned scope on the same basis. All three describe a queue of conflicts; the engine surfaces one conflict at a time.

  • REQ-CFR-004 (queue + notification badge). sync.conflict is a single object, not a list — ConflictResolverModalContainer renders whichever one conflict is currently raised. There is no badge count to increment and no conflict-list screen to open: SyncStatusBadge has four states (Synced / Syncing… / Offline / Sync Error), carries role="status", and has no click handler. What is true is that nothing is lost — a skipped conflict stays queued inside the engine and the wizard reappears on the next sync pass.
  • REQ-CFR-005 (batch resolution). There is no "Resolve All" and no strategy picker across conflicts. useConflictResolverState takes one conflict and one onResolve.
  • REQ-CFR-006 (audit log). No resolution log is written and there is no viewer for one. The recoverable record of a resolution is the backup_conflict_… safety backup described under Resolution Strategies, which is a data backup rather than a chronological log of who chose what.

Non-Functional Requirements

IDRequirementMetricPriority
NFR-CFR-001Conflict diff view shall render within 1 second for projects with ≤500 itemsDiff renderShould
NFR-CFR-002Batch resolution shall process ≤50 conflicts within 2 seconds — planned scope; batch resolution is not built (REQ-CFR-005)Batch perfShould

Data Requirements

  • Conflict record: { entityType, entityId, localVersion, remoteVersion, conflictingFields[], timestamp }
  • Resolution log: planned scope, not written — see REQ-CFR-006 above
  • Persistence: what is written on resolution is a pair of backup_conflict_<type>_… safety backups, one per side, cleaned up later by conflictBackupCleanup. There is no conflict-queue store and no resolution log; an unresolved conflict lives in the sync engine and is re-raised on the next sync pass

Constraints & Limits

  • Only appears when cloud sync is enabled and conflicts are detected
  • Auto-merge resolves non-overlapping changes automatically (only true conflicts need manual resolution)
  • The sidebar sync indicator shows status only — Synced / Syncing… / Offline / Sync Error. It carries no conflict count and is not clickable; the wizard is what surfaces a conflict

Offline Behavior

  • Conflicts are not generated offline (sync is paused)
  • Conflict resolution UI works offline once conflicts are loaded
  • Resolved conflicts sync to cloud when connectivity is restored

Dependencies

  • Requires: Collaboration (REQ-COL-006) — conflicts arise from collaboration sync

When Conflicts Occur

Conflicts arise in these scenarios:

  1. Multi-device editing: Same item edited on two devices before sync completes
  2. Collaborative offline: Two collaborators edit the same project while both offline
  3. Concurrent category moves: Item moved to different categories by different users
  4. Edit-delete conflicts: Item deleted by one user while being edited by another

Internal sync bookkeeping is not a conflict. The engine's own lineage counter (syncRev) advances on every upload, so two devices that have synced a different number of times always hold different values. That difference alone carries no user content and is excluded from conflict detection and from the diff — see INTERNAL_FIELDS in app/src/data/collab/collabUtils.js.

Resolving Conflicts

Opening the Wizard

The wizard opens by itself the moment the sync engine detects a conflict — you do not navigate to it. ConflictResolverModalContainer is mounted app-wide and renders as soon as a conflict is raised, whichever screen you are on.

You cannot open it on demand, and there is no conflict queue screen. This guide told you to click a "sync conflict badge" in the top bar, or to navigate to "Settings → Cloud Sync → Conflicts", until 2026-09-08. Neither exists: the sidebar's sync badge shows status only (Synced / Syncing… / Offline / Sync Error) and is not clickable, and there is no Cloud Sync tab in Settings. If you dismiss a conflict with Skip This Conflict it stays queued and the wizard reappears on the next sync pass.

Resolution Strategies

StrategyDescriptionReversible?
MergeChoose field-by-field which version to keep — keeps both sidesYes — nothing is discarded
Auto-mergeSystem resolves non-overlapping changes automaticallyYes — nothing is discarded
Keep LocalDiscard remote changes; your version winsNo — replaces the whole record
Keep RemoteDiscard local changes; other device/user's version winsNo — replaces the whole record

Keep Local / Keep Remote are document-scoped and irreversible. Accepting one side drops the queued upload for that record and overwrites the other side wholesale, so everything the losing side changed since the last successful sync goes with it — not just the field on screen. Simple view therefore states the count up front ("… discards N cloud change(s)" / "… discards N change(s) made on this device since your last sync") and makes Review Field by Field the primary button. Safety backups of both variants are still written first (backup_conflict_…), so a wrong pick is recoverable, but recovery is manual.

When the Whole Record Is the Conflict

A few conflicts arrive as two complete versions of a record rather than as a list of differing fields. Two engine branches produce that shape: a stale local lineage (this device's copy is older than the last state synced to the cloud) and the record types that are never merged automatically (dataProjects, shootingDays, transferSessions, folderTemplates, offloads).

The wizard now splits those two versions into individual fields itself, so Review Field by Field works on them like any other conflict and both sides can be kept. The engine's own reason for refusing the automatic merge is shown at the top of the dialog — a stale local copy is a caveat to read each field against, not a reason to abandon the dialog.

Where field-by-field is genuinely absent, it is no longer offered. If the two versions differ only in internal sync bookkeeping there is nothing to choose per field. The wizard then says the conflict cannot be split, drops the Field-by-Field tab and the "Review field by field" button, and leaves only the two whole-record choices. Until 2026-09-09 it advertised the tab anyway and led to a single "Entire record" row carrying the same irreversible choice the Simple view already offered.

Step-by-Step Merge

  1. Review the conflict summary showing affected fields
  2. For each field, view local and remote values side-by-side
  3. Click Use Local or Use Remote per field
  4. Click Apply Resolution to finalize
  5. Repeat for remaining conflicts

Tips

  1. Prefer Review Field by Field: it is the only resolution that keeps both sides — and it is offered whenever the conflict can actually be split (see above)
  2. Resolve quickly: Unresolved conflicts can block future syncs
  3. Communicate with team: When conflicts arise in shared projects, coordinate before resolving
  4. Use auto-merge first: Let the system handle non-overlapping changes automatically
  5. Read the discard counts: they tell you how much each whole-record choice throws away

Last Updated: 2026-09-10 Version: 0.790.2