From 0a25a0ef664ef71be58065ab487862144d792bc9 Mon Sep 17 00:00:00 2001 From: Muhsin Keloth Date: Thu, 16 Jul 2026 13:35:20 +0400 Subject: [PATCH] fix(whatsapp): log manual transfer only for embedded signup migrations (#15032) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The `[WHATSAPP_MANUAL_TRANSFER] success` log introduced in #14975 to track embedded signup → manual migrations was firing on any WhatsApp credential change — including routine `api_key` rotations on inboxes that were already manually configured — inflating the migration count. The log now fires only for the actual migration, and uses a new tag so log searches don't match the older over-counted entries. ## How to reproduce 1. On a manually configured WhatsApp Cloud inbox, update the API key from inbox settings → Configuration. 2. Before this change, the app log records a `[WHATSAPP_MANUAL_TRANSFER] success` line even though no migration happened; after this change it stays silent. 3. Switching an embedded signup inbox to manual setup still logs the migration (now as `[WHATSAPP_EMBEDDED_TO_MANUAL] success`). ## What changed - `Channel::Whatsapp#log_credentials_transfer` now keys off the migration's unique signal — `provider_config['source']` changing from `embedded_signup` to absent — instead of diffing credential keys. - Renamed the log tag from `WHATSAPP_MANUAL_TRANSFER` to `WHATSAPP_EMBEDDED_TO_MANUAL` (success and failure lines) so the corrected entries are searchable without matching pre-fix false positives. 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Muhsin <12408980+muhsin-k@users.noreply.github.com> --- app/models/channel/whatsapp.rb | 16 ++++++++++++---- .../whatsapp/providers/whatsapp_cloud_service.rb | 6 +++--- 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/app/models/channel/whatsapp.rb b/app/models/channel/whatsapp.rb index 7a109c455..87ff199d5 100644 --- a/app/models/channel/whatsapp.rb +++ b/app/models/channel/whatsapp.rb @@ -101,6 +101,13 @@ class Channel::Whatsapp < ApplicationRecord end end + # Whether the pending (unsaved) provider_config change drops the embedded_signup + # source marker, i.e. this save is an embedded signup → manual setup transfer. + def embedded_to_manual_transfer_pending? + before, after = provider_config_change + before&.dig('source') == 'embedded_signup' && after['source'] != 'embedded_signup' + end + def mark_message_templates_updated # rubocop:disable Rails/SkipsModelValidations update_column(:message_templates_last_updated, Time.zone.now) @@ -130,13 +137,14 @@ class Channel::Whatsapp < ApplicationRecord errors.add(:provider_config, 'Invalid Credentials') unless provider_service.validate_provider_config? end - # Logs only credential changes, so config-only saves (e.g. calling toggles) stay silent. + # Logs only the embedded signup → manual migration (the save drops the + # embedded_signup source marker), so credential rotations on inboxes that are + # already manual stay silent. def log_credentials_transfer before, after = saved_change_to_provider_config - keys = %w[api_key phone_number_id business_account_id] - return if before.nil? || before.values_at(*keys) == after.values_at(*keys) + return unless before&.dig('source') == 'embedded_signup' && after['source'] != 'embedded_signup' - Rails.logger.info("[WHATSAPP_MANUAL_TRANSFER] success account_id=#{account_id} channel_id=#{id}") + Rails.logger.info("[WHATSAPP_EMBEDDED_TO_MANUAL] success account_id=#{account_id} channel_id=#{id}") end def perform_webhook_setup diff --git a/app/services/whatsapp/providers/whatsapp_cloud_service.rb b/app/services/whatsapp/providers/whatsapp_cloud_service.rb index 373e47b3c..d65c6cc62 100644 --- a/app/services/whatsapp/providers/whatsapp_cloud_service.rb +++ b/app/services/whatsapp/providers/whatsapp_cloud_service.rb @@ -94,12 +94,12 @@ class Whatsapp::Providers::WhatsappCloudService < Whatsapp::Providers::BaseServi private - # Only credential updates on existing channels are transfer attempts; creation failures are regular setup errors. Returns false. + # Only saves dropping the embedded_signup source marker are transfer attempts; creation/rotation failures are setup errors. Returns false. def log_transfer_failure(check, response) - return false unless whatsapp_channel.persisted? && whatsapp_channel.provider_config_changed? + return false unless whatsapp_channel.embedded_to_manual_transfer_pending? error_message = response.parsed_response.is_a?(Hash) ? response.parsed_response.dig('error', 'message') : nil - Rails.logger.warn("[WHATSAPP_MANUAL_TRANSFER] failure account_id=#{whatsapp_channel.account_id} channel_id=#{whatsapp_channel.id} " \ + Rails.logger.warn("[WHATSAPP_EMBEDDED_TO_MANUAL] failure account_id=#{whatsapp_channel.account_id} channel_id=#{whatsapp_channel.id} " \ "check=#{check} http_status=#{response.code} meta_error=#{error_message}") false end