Skip to main content

Normalize CDP field name before CRM↔CDP field-property matching

Jira Story: TF-3515 · Task: TF-3486 (linked via "Work item split" — direction currently backwards, pending fix; see bucket README) · Epic: TF-3477

Overview

Crm::BackfillCdpFieldPropertiesService decides whether a CRM field already has a matching CDP field property by looking up the CRM-derived expected name (field.name, translated through CRM_TO_CDP_NAME_MAP where applicable) against CDP's raw name value. CRM's own name is always normalized via snake_case.chomp('_') before it is saved (additional_field.rb:101), but CDP's name may not be stored in that same normalized form (different casing, spaces, trailing underscores) — so an exact-string lookup can miss even when the two systems refer to the same field, causing the backfill service to create a duplicate CDP field property instead of linking to the existing one.

Fix: normalize CDP's name with the identical snake_case.chomp('_') transformation before comparing (backfill_cdp_field_properties_service.rb:85-94, fetch_cdp_fields), rather than introducing a new matching key or changing what CRM_TO_CDP_NAME_MAP is for. The CRM-side lookup key (field.name / CRM_TO_CDP_NAME_MAP) is untouched — those values are already normalized constants; only the CDP side needed fixing. Outbound payload construction (build_cdp_payload, build_update_payload_for_field) is unaffected.

Scope Changes

  • BackendCrm::BackfillCdpFieldPropertiesService field-name normalization on the CDP side of the match.

8. User Stories + Acceptance Criteria

User StoryImportanceMockup / Technical NotesAcceptance Criteria
[FIELDMATCH-S01] — CRM/CDP field matching survives name-formatting differences

As the platform, I want a CRM field to correctly match its existing CDP field property even when the two systems' stored name values differ only in casing/spacing/trailing characters, so that the backfill never creates a spurious duplicate field property.
Must Havefetch_cdp_fields indexes CDP fields by a normalized key (name.to_s.snake_case.chomp('_')), matching how CRM already normalizes its own name on save. A select guard on non-blank name avoids collapsing multiple blank-name CDP fields onto one key.— Happy Path —
• AC-1: Given a CRM field whose derived CDP name matches an existing CDP field property's name only after normalization (e.g. CDP stores "Notes"/"notes_" where CRM expects notes), when the backfill service runs, then it links to the existing field property rather than creating a duplicate.
• AC-2: Given a CRM field whose derived CDP name is already an exact match (no normalization needed), when the backfill service runs, then linking behavior is unchanged from before this fix.
— Guard-rail —
• NEG-1: Given a CDP field with a blank name, when fetch_cdp_fields builds its lookup index, then that field is not indexed/matched against any CRM field (guards against collapsing multiple blank-name fields onto the same key).

Verification

Shipped and code-corroborated: merged in qontak.com (PR #12102, 1d0e99e38d) per the 2026-07-14 code-evidence.mjs check.