---
id: CAP-CRM-DQ-002
title: Explain the strength of a duplicate suggestion
feature: FEAT-CRM-DQ-01
product_area: crm
module: data-quality
revision: 1
status: draft
product_intent: confirmed
implementation_evidence: observed
supersedes:
  - CAP-CRM-MRG-003
source_sha:
  services-crm: a8d1364f1dd44b723bb5f9acba12f983e9ec8d69
  react-console: baf6dae382d6f41dce976c7f848667ccc37e076f
intent_sources:
  - 'services-crm:docs/merging/README.md#Status (architecture and plan approved by Andrew 2026-10-11)'
  - 'services-crm:docs/merging/decisions.md#D5 (decided 2026-10-13: option 3)'
  - >-
    services-crm:docs/merging/experience/functional-requirements.md#REV-1 to REV-3 (package approved by Andrew
    2026-10-13)
purpose: Reviewers can judge a suggestion using repeatable scores and readable explanations.
outcomes:
  - Confidence separates strong suggestions from weaker resemblance.
  - 'Contradictory household, spouse and hierarchy evidence limits false confidence.'
  - Reasons communicate evidence while masking full private matching values.
concepts:
  - CON-CRM-DQ-001
actors:
  - ACT-CRM-005
  - ACT-CRM-008
surfaces:
  - job
  - api
  - console
permissions:
  - key: crm.duplicates.read
    where_checked: api
    scope: tenant
rules:
  - id: BR-CAP-CRM-DQ-002-01
    proved_by: [ATS-CRM-DQ-002-01, ATS-CRM-DQ-002-08, ATS-CRM-DQ-002-11, TST-CRM-DQ-176]
    statement: >-
      Contact evidence contributes: shared origin 60; primary e-mail on both 40, another slot 30 or an address
      shared by at least three contacts 10; shared mobile 20; other phone 10 or zero with at least three
      holders; exact surname 15, phonetic surname 8, maiden-name match 5 or surname disagreement -20; exact
      first name 15, nickname 12, phonetic first name 8, initial 3 or disagreement -15; equal birth date 25 or
      conflict -40; conflicting middle initials -10; conflicting suffixes -30; equal street and postal code 15
      or postal code alone 8; equal employer 8; reciprocal spouse evidence -30.
    kind: calculation
    enforced_at:
      - service
    must_prove: true
    provenance: test
    source: >-
      services-crm:modules/duplicates/tests/unit/services/matching/bands.spec.js#declares the weight of every
      row of §5.1
    origin: 'services-crm:docs/merging/README.md#Status (architecture and plan approved by Andrew 2026-10-11)'
  - id: BR-CAP-CRM-DQ-002-02
    proved_by: [ATS-CRM-DQ-002-02, ATS-CRM-DQ-002-11]
    statement: >-
      Contact scores cannot exceed 49 for conflicting first and last names or birth dates, or 35 for
      conflicting suffixes; the lowest applicable ceiling wins.
    kind: calculation
    enforced_at:
      - service
    must_prove: true
    provenance: test
    source: >-
      services-crm:modules/duplicates/tests/unit/services/matching/contact-scoring.spec.js#holds a pair to the
      lowest cap when two of them fire
    origin: 'services-crm:docs/merging/README.md#Status (architecture and plan approved by Andrew 2026-10-11)'
    examples:
      positive: 'For example, two spouses sharing a household e-mail address score below the lowest band.'
      negative: 'By comparison, two records of one person with the same e-mail address and names score very high.'
  - id: BR-CAP-CRM-DQ-002-03
    proved_by: [ATS-CRM-DQ-002-03, ATS-CRM-DQ-002-11]
    statement: >-
      Organization evidence contributes: shared origin 60; exact normalized name 35, phonetic name 20, close
      name 15 or disagreement -20; shared non-free-mail domain 30; shared phone 15 or zero with at least three
      holders; equal street and postal code 20 or postal code alone 5; equal parent 5; ancestor relationship
      -40; different types -10; domain agreement without name agreement caps the score at 69 and ancestry caps
      it at 35.
    kind: calculation
    enforced_at:
      - service
    must_prove: true
    provenance: test
    source: >-
      services-crm:modules/duplicates/tests/unit/services/matching/organization-scoring.spec.js#holds a parent
      and its child to 35, however alike they read
    origin: 'services-crm:docs/merging/README.md#Status (architecture and plan approved by Andrew 2026-10-11)'
  - id: BR-CAP-CRM-DQ-002-04
    proved_by: [ATS-CRM-DQ-002-04, ATS-CRM-DQ-002-08, ATS-CRM-DQ-002-11, TST-CRM-DQ-176]
    statement: >-
      Confidence is very high at 90 or above, high at 70–89, medium at 50–69 and low at 35–49; scores below 35
      produce no stored candidate.
    kind: calculation
    enforced_at:
      - service
      - database
    must_prove: true
    provenance: test
    source: >-
      services-crm:modules/duplicates/tests/unit/services/matching/bands.spec.js#gives 34 no band at all, so
      the pair is not stored
    origin: 'services-crm:docs/merging/README.md#Status (architecture and plan approved by Andrew 2026-10-11)'
  - id: BR-CAP-CRM-DQ-002-05
    proved_by: [ATS-CRM-DQ-002-05, ATS-CRM-DQ-002-08, ATS-CRM-DQ-002-11, TST-CRM-DQ-176]
    statement: >-
      Explanations list a sentence and point contribution for each evidence item in scoring order, then
      describe every applied score ceiling.
    kind: policy
    enforced_at:
      - service
    must_prove: true
    provenance: test
    source: >-
      services-crm:modules/duplicates/tests/unit/services/matching/explanation.spec.js#renders the caps after
      the evidence
    origin: 'services-crm:docs/merging/experience/functional-requirements.md#REV-1'
  - id: BR-CAP-CRM-DQ-002-06
    proved_by: [ATS-CRM-DQ-002-06, ATS-CRM-DQ-002-11]
    statement: >-
      Explanations mask e-mail to its first character and domain and phone to its last four digits, omit full
      birth dates and retain public organization domains and matching names.
    kind: policy
    enforced_at:
      - service
    must_prove: true
    provenance: test
    source: >-
      services-crm:modules/duplicates/tests/unit/services/matching/explanation.spec.js#never carries a full
      e-mail address into a sentence
    origin: 'services-crm:docs/merging/experience/functional-requirements.md#REV-3'
  - id: BR-CAP-CRM-DQ-002-07
    proved_by: []
    statement: >-
      Reason text uses the records' accented and punctuated name spellings where available, falling back to
      stored evidence when neither record still supplies the name.
    kind: policy
    enforced_at:
      - service
    must_prove: false
    provenance: test
    source: >-
      services-crm:modules/duplicates/tests/integration/services/candidates/duplicate-candidate-view.integration.spec.js#names
      a last name that agrees as the records spell it, never in the lower-case form it is stored in
    origin: none
  - id: BR-CAP-CRM-DQ-002-08
    proved_by: [ATS-CRM-DQ-002-07, ATS-CRM-DQ-002-11]
    statement: 'Repeated scoring and reversed record order produce the same score, reasons and limits.'
    kind: invariant
    enforced_at:
      - service
    must_prove: true
    provenance: test
    source: >-
      services-crm:modules/duplicates/tests/unit/services/matching/contact-scoring.spec.js#answers the same
      reasons and caps whichever record is first
    origin: none
  - id: BR-CAP-CRM-DQ-002-09
    proved_by: []
    statement: >-
      A candidate stores the scoring version associated with its evidence, allowing results from different
      weight versions to be distinguished.
    kind: policy
    enforced_at:
      - service
      - database
    must_prove: false
    provenance: test
    source: >-
      services-crm:modules/duplicates/tests/unit/services/matching/organization-scoring.spec.js#stores the
      rule set version the weights belong to
    origin: none
  - id: BR-CAP-CRM-DQ-002-10
    proved_by: []
    statement: Detection uses deterministic matching without a language model or database fuzzy-matching extension.
    kind: policy
    enforced_at:
      - service
    must_prove: false
    provenance: documented
    source: >-
      services-crm:docs/merging/decisions.md#Settled by inspection or engineering practice (not up for
      decision)
    origin: >-
      services-crm:docs/merging/decisions.md#Settled by inspection or engineering practice (LLM in detection:
      none)
  - id: BR-CAP-CRM-DQ-002-11
    proved_by: []
    statement: >-
      The product should calibrate weights with synthetic examples and Rhythm 2.0 review decisions, excluding
      Rhythm 1.0 data.
    kind: policy
    enforced_at:
      - service
    must_prove: false
    provenance: unknown
    source: FND-CRM-DQ-020
    origin: 'services-crm:docs/merging/decisions.md#D5 (decided 2026-10-13: option 3)'
  - id: BR-CAP-CRM-DQ-002-12
    proved_by: [ATS-CRM-DQ-002-02, ATS-CRM-DQ-002-11]
    statement: >-
      The tested household sharing one e-mail address remains low-confidence, while the tested spouse pair
      falls below the candidate threshold.
    kind: calculation
    enforced_at:
      - service
    must_prove: true
    provenance: test
    source: >-
      services-crm:modules/duplicates/tests/unit/services/matching/contact-scoring.spec.js#scores a spouse
      pair below the band floor, which is what fixes 1.0’s “spouses score 94”
    origin: none
  - id: BR-CAP-CRM-DQ-002-13
    proved_by: [ATS-CRM-DQ-002-09, ATS-CRM-DQ-002-11]
    statement: >-
      The final score sums evidence, clamps the total between zero and 100 and applies the lowest triggered
      ceiling without permitting a negative result.
    kind: calculation
    enforced_at:
      - service
    must_prove: true
    provenance: observed
    source: 'services-crm:modules/duplicates/services/matching/scoring.ts:scoreOf'
    origin: none
scenarios:
  - id: SC-CAP-CRM-DQ-002-01
    given: 'Two member records share e-mail, names, mobile and birth date.'
    when: The scorer evaluates their pair.
    then: Very-high confidence includes an explanation for each evidence item with masked e-mail.
    provenance: test
    source: >-
      services-crm:modules/duplicates/tests/unit/services/matching/contact-scoring.spec.js#scores one person
      written twice very high
  - id: SC-CAP-CRM-DQ-002-02
    given: A parent organization and its chapter have nearly identical names.
    when: The scorer evaluates their resemblance.
    then: The ancestry limit holds the result to 35 and low confidence.
    provenance: test
    source: >-
      services-crm:modules/duplicates/tests/unit/services/matching/organization-scoring.spec.js#holds a parent
      and its child to 35, however alike they read
edge_cases: []
constraints: []
depends_on:
  - CAP-CRM-DQ-001
related:
  - CAP-CRM-DQ-003
  - CAP-CRM-DQ-007
journeys:
  - JNY-CRM-DQ-001
open_questions: []
evidence:
  - repository: services-crm
    source_sha: a8d1364f1dd44b723bb5f9acba12f983e9ec8d69
    paths:
      - docs/merging/README.md
      - docs/merging/decisions.md
      - docs/merging/experience/functional-requirements.md
      - modules/duplicates/db/duplicate-candidates.table.ts
      - modules/duplicates/services/matching/scoring.ts
      - modules/duplicates/tests/integration/services/candidates/duplicate-candidate-view.integration.spec.js
      - modules/duplicates/tests/unit/services/matching/bands.spec.js
      - modules/duplicates/tests/unit/services/matching/contact-scoring.spec.js
      - modules/duplicates/tests/unit/services/matching/explanation.spec.js
      - modules/duplicates/tests/unit/services/matching/organization-scoring.spec.js
    note: 'Static examination connects rule claims to implementation, declared checks and the cited tests.'
preconditions: []
postconditions: []
controls: [TC-AZ-001, TC-AZ-002, TC-AZ-003, TC-AZ-004, TC-AZ-006, TC-CRY-004, TC-DAT-001, TC-DAT-002, TC-DAT-003, TC-LOG-004, TC-LOG-005, TC-PI-001, TC-PRV-001, TC-PRV-002, TC-TEN-001, TC-TEN-002, TC-TEN-003]
exercised_by: [FAS-CRM-DQ-01-01, FAS-CRM-DQ-02-01]
suites: [TST-CRM-DQ-176]
---

# Explain the strength of a duplicate suggestion

## Purpose

Reviewers can judge a suggestion using repeatable scores and readable explanations.

## How It Works

Rhythm assigns fixed points to matching and conflicting information. Contacts and organizations have different evidence models. Strong contradictions also limit the final score, even when other details agree. The score places a stored pair in one of four confidence bands. Each reason identifies the evidence and its contribution; score limits appear after those reasons. E-mail and phone values are masked in explanations. Names retain the spelling staff recognize rather than the normalized form used for comparison. Swapping the order of the two records does not change the result. A scoring version makes later comparisons traceable. The product should demonstrate calibration with synthetic examples and current staff decisions before treating these initial weights as measured accuracy.

## Relationships

Detection and draft checks use this scoring model. Review queues present its explanations, while duplicate settings use confidence bands to choose an action.
