Conflict Resolution
In offline-first apps, conflicts are inevitable: multiple devices editing the same data while disconnected. Locorda resolves these using state-based CRDTs (Conflict-free Replicated Data Types) and merge contracts.
Why Conflicts Happen
Section titled “Why Conflicts Happen”TODO: Document conflict scenarios with real examples from the implementation
Without automatic resolution, you’d need to:
- Show conflict UI to users (poor UX)
- Manually write merge logic (error-prone)
- Accept data loss (one edit discarded)
Locorda uses state-based CRDTs to provide deterministic, automatic, conflict-free merge.
CRDT Merge Strategies
Section titled “CRDT Merge Strategies”Locorda implements state-based CRDT algorithms for different property types:
@CrdtLwwRegister() - Last-Write-Wins Register
Section titled “@CrdtLwwRegister() - Last-Write-Wins Register”TODO: Document:
- Timestamp-based resolution
- Causality tracking mechanism (if implemented)
- Tie-breaking rules
- Real examples from codebase
@CrdtOrSet() - Observed-Remove Set
Section titled “@CrdtOrSet() - Observed-Remove Set”TODO: Document:
- How additions and removals merge
- Tombstone mechanism (if used)
- Re-addition behavior
- Real examples (e.g., tags on Note)
@CrdtImmutable() - Immutable Values
Section titled “@CrdtImmutable() - Immutable Values”Immutable properties never change once set:
- Creation timestamps
- Identifying properties
- Write-once data
TODO: Document behavior when conflicts occur on immutable fields
Property-Level Merge Resolution
Section titled “Property-Level Merge Resolution”TODO: Document how property-level merging actually works in the implementation:
Per-Field Resolution
Section titled “Per-Field Resolution”Each field is resolved independently using its CRDT strategy.
Real example from personal notes app:
@RootResource(appVocab, mergeContract: MergeContract())class Note { @RdfIriPart() final String id;
@RdfProperty(Schema.name) @CrdtLwwRegister() final String title; // Resolved using LWW
@RdfProperty(Schema.keywords) @CrdtOrSet() final Set<String> tags; // Resolved using OR-Set
@RdfProperty(Schema.dateCreated) @CrdtImmutable() final DateTime createdAt; // Immutable}TODO: Add concrete merge scenario examples showing:
- How timestamps work
- Field-level resolution
- Concurrent edits behavior
Concurrent Edits
Section titled “Concurrent Edits”TODO: Document how the implementation handles truly concurrent edits:
- Timestamp comparison mechanism
- Tie-breaking rules (if any)
- Node/device ID usage (if implemented)
- Real-world examples
Deletion Handling
Section titled “Deletion Handling”TODO: Document actual deletion behavior:
Deletion Strategy
Section titled “Deletion Strategy”TODO: Verify and document:
- Does Locorda use tombstones?
- Deletion-wins vs edit-wins semantics
- How deletion timestamps work
- Garbage collection mechanism (if any)
Resurrection
Section titled “Resurrection”TODO: Document if/how deleted resources can be recreated
Collection Handling
Section titled “Collection Handling”TODO: Document how collections are actually handled:
Sets with @CrdtOrSet()
Section titled “Sets with @CrdtOrSet()”Real example from personal notes app:
@RdfProperty(Schema.keywords)@CrdtOrSet()final Set<String> tags;TODO: Document:
- How OR-Set merge works
- Addition/removal semantics
- Re-addition behavior
TODO: Document list handling (if supported)
TODO: Document map handling (if supported)
Edge Cases
Section titled “Edge Cases”TODO: Document actual edge cases from implementation:
Clock Skew
Section titled “Clock Skew”TODO: How does the implementation handle clock skew?
- Is there clock synchronization?
- Mitigation strategies
- Best practices
Schema Evolution
Section titled “Schema Evolution”TODO: Document schema evolution support:
- Adding new properties
- Removing properties
- Changing property types
- Backward compatibility
RDF’s schema-flexible nature helps with evolution.
Unmapped Triples
Section titled “Unmapped Triples”Real example from personal notes app:
@RdfUnmappedTriples(globalUnmapped: true)final RdfGraph other;TODO: Document:
- How unmapped triples are preserved
- Merge behavior for unmapped data
- Round-tripping guarantees
CRDT Theory and Guarantees
Section titled “CRDT Theory and Guarantees”TODO: Document theoretical properties:
Convergence Guarantees
Section titled “Convergence Guarantees”TODO: Explain why Locorda’s CRDTs guarantee eventual consistency:
- Commutativity
- Associativity
- Idempotency
State-Based CRDTs
Section titled “State-Based CRDTs”TODO: Explain state-based vs operation-based CRDTs and why Locorda uses state-based
Testing and Debugging
Section titled “Testing and Debugging”TODO: Document:
Testing Conflict Scenarios
Section titled “Testing Conflict Scenarios”TODO: Provide real test examples from the codebase
Debugging Merge Behavior
Section titled “Debugging Merge Behavior”TODO: Document logging and debugging tools
Best Practices
Section titled “Best Practices”TODO: Document best practices based on real implementation experience:
- Choose appropriate CRDT strategies for each property
- Design for eventual consistency
- Test conflict scenarios
- TODO: Add more based on actual patterns
Summary
Section titled “Summary”TODO: Summarize actual conflict resolution behavior:
- State-based CRDTs provide automatic conflict resolution
- @CrdtLwwRegister() for single-value properties
- @CrdtOrSet() for multi-value properties (sets)
- @CrdtImmutable() for write-once properties
- Property-level merge using CRDT annotations
- Deterministic convergence - all devices eventually agree
Next Steps
Section titled “Next Steps”TODO: Add proper links once corresponding pages are created
- 📘 Merge Contracts - Understand RootResource, SubResource, LocalResource
- 📘 Architecture Overview - TODO
- 📘 Testing Guide - TODO