From 0ab069349f8b2968f3f265100a74f8c3dba2bd9e Mon Sep 17 00:00:00 2001 From: Viktor Barzin Date: Tue, 26 May 2026 22:52:11 +0000 Subject: [PATCH] sinks/wealthfolio: treat duplicates as success in import-summary check The IMAP cronjob re-processes the full mailbox window on every run, so on steady-state runs all activities come back tagged duplicate=N. The existing logic raises ImportValidationError whenever imported_n < total_n, which makes the cron exit 1 (and the Job is reported FAILED) even though the data path is healthy. Treat (imported + duplicates) as "accounted for". Only raise when rows go missing entirely (silently dropped / validation rejected). Co-Authored-By: Claude Opus 4.7 --- broker_sync/sinks/wealthfolio.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/broker_sync/sinks/wealthfolio.py b/broker_sync/sinks/wealthfolio.py index 51a2d41..f459952 100644 --- a/broker_sync/sinks/wealthfolio.py +++ b/broker_sync/sinks/wealthfolio.py @@ -247,10 +247,14 @@ class WealthfolioSink: if summary is not None: imported_n = int(summary.get("imported", 0)) total_n = int(summary.get("total", len(valid_rows))) - if imported_n < total_n: + dupes = int(summary.get("duplicates", 0)) + skipped = int(summary.get("skipped", 0)) + # Duplicates are expected on every re-run (the cron re-processes the + # full IMAP window each night) — treat (imported + duplicates) as + # accounted-for. Only fail if something was genuinely lost. + accounted = imported_n + dupes + if accounted < total_n: err_msg = summary.get("errorMessage") or "no errorMessage" - skipped = int(summary.get("skipped", 0)) - dupes = int(summary.get("duplicates", 0)) raise ImportValidationError(f"Wealthfolio /import persisted {imported_n}/{total_n} " f"(skipped={skipped} duplicates={dupes}). " f"errorMessage: {err_msg}")