mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-08 12:32:43 +00:00
The v1.4.26 scope-skip short-circuit in `sync-activity.ts` and `sync-sleep.ts` called `recordSyncFailure` for a deliberate no-op, which incremented `IntegrationStatus.consecutiveFailures` and tripped the 3-strike admin Telegram alert for every legacy connection. Webhook deliveries (appli=16 / appli=44) could run the counter from 0 to 3 in seconds on a freshly-deployed v1.4.26 install, and pre-existing counters that survived the deploy (e.g. an 87-strike row from the pre-fix transient burst) paged immediately on the first scope-skip after the 24h re-alert window closed. Extract a new `parkIntegrationAtReauth` helper next to `recordSyncFailure` that sets the row to `error_reauth` without incrementing the counter, without writing an `integrations.sync.failed` audit row, and without entering the threshold ladder. A standalone `integrations.reauth_required` audit row is written on the first park so the operations trail still shows the event; re-parking the same scope-skip is idempotent (no extra audit write). Swap the two deliberate scope-skip call-sites in `withings/sync-activity.ts` and `withings/sync-sleep.ts` to the new helper. The defence-in-depth 403 catch-block in each sync routine stays on `recordSyncFailure` — a 403 reaching the catch IS genuinely unexpected once the scope-skip lands above, so the alert ladder should still fire on that asymmetric pair. BL-P3-2 parity verified between activity and sleep. Tests extended: - `integrations/__tests__/admin-alert.test.ts` adds a `parkIntegrationAtReauth` block asserting state=error_reauth without counter increment, no `dispatchNotification`, and audit-log idempotency on a second call. - `withings/__tests__/sync-activity.test.ts` + `withings/__tests__/sync-sleep.test.ts` swap their scope-skip assertions to `parkIntegrationAtReauth` and keep the 403 catch-block on `recordSyncFailure` to prove the defence-in-depth alert path survives.