fix: break sync feedback loop, respect timestamps, surface errors
- Add migration v2: source column on change_log to distinguish local vs sync-originated entries, preventing the echo loop where synced tasks get re-pushed as local changes - PushChanges handler now skips save when server version is newer - Client PushChanges/pushQueuedChanges collect and report marshal errors instead of silently dropping them - De-duplicate getLocalChanges/getLastSyncTime into exported sync package functions - Fix logConflict winner detection via pointer identity instead of fragile UUID+timestamp comparison - Fix sync down to actually parse, save, and tag-sync pulled changes Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -104,6 +104,8 @@ func PushChanges(w http.ResponseWriter, r *http.Request) {
|
||||
if err := task.Save(); err != nil {
|
||||
continue
|
||||
}
|
||||
// Mark as sync-originated to prevent feedback loop
|
||||
_ = engine.MarkChangeLogAsSync(task.UUID.String())
|
||||
// Add tags
|
||||
for _, tag := range task.Tags {
|
||||
_ = task.AddTag(tag)
|
||||
@@ -114,15 +116,18 @@ func PushChanges(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
// Task exists - check timestamps for conflicts
|
||||
if existing.Modified.Unix() > task.Modified.Unix() {
|
||||
// Server version is newer - conflict (but we'll apply last-write-wins)
|
||||
// Server version is newer - skip this push
|
||||
conflicts++
|
||||
continue
|
||||
}
|
||||
|
||||
// Apply changes (last-write-wins)
|
||||
// Apply changes (client is newer or equal)
|
||||
task.ID = existing.ID // Preserve database ID
|
||||
if err := task.Save(); err != nil {
|
||||
continue
|
||||
}
|
||||
// Mark as sync-originated to prevent feedback loop
|
||||
_ = engine.MarkChangeLogAsSync(task.UUID.String())
|
||||
|
||||
// Sync tags
|
||||
existingTags := make(map[string]bool)
|
||||
|
||||
Reference in New Issue
Block a user