From 9eb2b12fea03f5e1b71893845c189f956c39e404 Mon Sep 17 00:00:00 2001 From: AI Assistant Date: Sat, 28 Mar 2026 10:19:47 +0200 Subject: [PATCH] fix(parcel-sync): safety check prevents mass deletion on stale remote data If >80% of local features would be deleted (and >100 exist), skip deletion and log a warning. This protects against session expiry returning empty remote results, which previously caused the sync to mark ALL local features as "removed" and attempt to delete them. Co-Authored-By: Claude Opus 4.6 (1M context) --- src/modules/parcel-sync/services/sync-service.ts | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/modules/parcel-sync/services/sync-service.ts b/src/modules/parcel-sync/services/sync-service.ts index f627749..91068df 100644 --- a/src/modules/parcel-sync/services/sync-service.ts +++ b/src/modules/parcel-sync/services/sync-service.ts @@ -319,7 +319,15 @@ export async function syncLayer( } // Mark removed features (batch to avoid PostgreSQL 32767 bind variable limit) - if (removedObjIds.length > 0) { + // Safety: if remote returned very few features compared to local, the session + // likely expired mid-sync — skip deletion to avoid wiping valid data. + const removedRatio = localObjIds.size > 0 ? removedObjIds.length / localObjIds.size : 0; + if (removedObjIds.length > 0 && removedRatio > 0.8 && localObjIds.size > 100) { + console.warn( + `[sync] SKIP delete: ${removedObjIds.length}/${localObjIds.size} features (${Math.round(removedRatio * 100)}%) ` + + `would be removed for ${layerId}/${siruta} — likely stale remote data. Aborting deletion.`, + ); + } else if (removedObjIds.length > 0) { push({ phase: "Marcare șterse" }); const BATCH = 30_000; for (let i = 0; i < removedObjIds.length; i += BATCH) {