-
Notifications
You must be signed in to change notification settings - Fork 54
Description
Problem
Currently, when a client is significantly out of date (e.g., 10+ commits behind the remote), it pushes its local changes directly to the remote, forcing the remote and other clients to handle merge conflicts. This creates unnecessary merge complexity on the server side and can lead to performance issues in multi-client scenarios.
Proposed Solution
Implement a "merge-first" strategy where out-of-date clients:
- Detect when they are significantly behind (10+ commits)
- Pull the latest remote state locally
- Merge their local changes with the remote state client-side
- Push the already-merged result to remote
This reduces server-side merge complexity and improves sync performance for all clients.
Implementation Plan
Detection Logic
File: core/base/crdt-clock.ts
- Add method to compare local head with remote head length
- Determine "out of date" threshold (10+ head length difference)
Merge Strategy
File: core/base/crdt.ts
- Modify
applyMeta()to trigger local merge when out-of-date detected - Add pre-push merge logic in sync operations
Sync Coordination
File: core/base/crdt-clock.ts (in int_applyHead)
- Add logic to detect remote head advancement
- Trigger local merge before pushing local changes
Validation Strategy
Console.log Diagnostic Points
1. Out-of-Date Detection (core/base/crdt-clock.ts):
console.log('🔍 MERGE_STRATEGY: Checking if client is out of date', {
localHeadLength: this.head.length,
remoteHeadLength: remoteHead.length,
commitsBehind: remoteHead.length - this.head.length,
shouldMergeFirst: (remoteHead.length - this.head.length) >= 10,
dbName: this.opts.name,
timestamp: Date.now()
});2. Pre-Push Merge Decision (core/base/crdt.ts):
console.log('🔄 MERGE_STRATEGY: Executing local merge before push', {
strategy: 'merge-first',
localChanges: localHead.length,
remoteChanges: remoteHead.length,
mergeComplexity: 'low|medium|high',
dbName: this.opts.name,
timestamp: Date.now()
});3. Merge Completion (core/base/crdt-clock.ts):
console.log('✅ MERGE_STRATEGY: Local merge completed', {
originalHeadLength: originalHead.length,
mergedHeadLength: mergedHead.length,
conflictsResolved: conflictCount,
readyForPush: true,
dbName: this.opts.name,
timestamp: Date.now()
});Testing Strategy
Test File: core/tests/fireproof/merge-first-strategy.test.ts
Test Cases:
-
Client not out-of-date (< 10 commits behind)
- Should push directly without local merge
- Verify no merge-first console logs appear
-
Client significantly out-of-date (10+ commits behind)
- Should trigger local merge before push
- Verify merge-first console logs appear in correct sequence
- Verify final push contains merged result
-
Multi-client scenario
- Multiple clients with different lag levels
- Verify only out-of-date clients trigger merge-first
- Verify reduced merge conflicts on remote
Validation Commands:
# Test out-of-date detection
pnpm test core/tests/fireproof/merge-first-strategy.test.ts -t "should detect out-of-date client" --reporter=verbose
# Test merge-first execution
pnpm test core/tests/fireproof/merge-first-strategy.test.ts -t "should merge locally before push" --reporter=verbose
# Test multi-client coordination
pnpm test core/tests/fireproof/merge-first-strategy.test.ts -t "should coordinate merge-first across clients" --reporter=verboseExpected Benefits
- Reduced server-side merge complexity
- Better performance for clients that aren't out-of-date
- Fewer merge conflicts propagated to other clients
- More predictable sync behavior in multi-client scenarios
Success Criteria
- ✅ Out-of-date detection works reliably (console logs confirm)
- ✅ Local merge executes only when needed (10+ commits behind)
- ✅ Merged results push successfully without conflicts
- ✅ Non-out-of-date clients unaffected (no performance regression)
- ✅ Multi-client scenarios show reduced merge conflicts
This enhancement would make Fireproof's sync behavior more intelligent and reduce the burden on remotes and other clients when dealing with significantly out-of-date clients.