---
id: CAP-CRM-DQ-019
title: Inspect merge outcomes and attribution
feature: FEAT-CRM-DQ-05
product_area: crm
module: data-quality
revision: 1
status: draft
product_intent: confirmed
implementation_evidence: partially-observed
supersedes:
  - CAP-CRM-MRG-021
source_sha:
  services-crm: a8d1364f1dd44b723bb5f9acba12f983e9ec8d69
  react-console: baf6dae382d6f41dce976c7f848667ccc37e076f
intent_sources:
  - 'services-crm:docs/milestones/CRM-M4-duplicates-and-merge.md#D-30'
  - 'services-crm:docs/milestones/CRM-M6-access-and-audit.md#D-21'
  - 'services-crm:docs/merging/decisions.md#D4 (decided 2026-10-11: option 1)'
  - >-
    services-crm:docs/merging/experience/functional-requirements.md#AUD-1 to AUD-3, DQ-9 (package approved by
    Andrew 2026-10-13)
purpose: Staff can understand who requested a merge and what information and connections it changed.
outcomes:
  - Retained originals support explanation and recreation after an incorrect merge.
  - Record readers can inspect successful lineage and its originals.
  - Merge-management readers can investigate workspace-wide attempts and outcomes.
concepts:
  - CON-CRM-DQ-004
actors:
  - ACT-CRM-009
  - ACT-CRM-008
  - ACT-CRM-002
surfaces:
  - console
  - api
permissions:
  - key: crm.merges.read
    where_checked: api
    scope: tenant
  - key: crm.contacts.read
    where_checked: api
    scope: record
  - key: crm.organizations.read
    where_checked: api
    scope: record
rules:
  - id: BR-CAP-CRM-DQ-019-01
    proved_by: [ATS-CRM-DQ-019-01, ATS-CRM-DQ-019-10, TST-CRM-DQ-181, TST-CRM-DQ-183]
    statement: >-
      Workspace history requires merge-read authority, lists newest first with succeeded as the default
      status, supports status/type/requester/date filters and defaults to 25 entries with a maximum of 50.
    kind: policy
    enforced_at:
      - api
    must_prove: true
    provenance: test
    source: >-
      services-crm:modules/merges/tests/integration/services/merges/tenant-merge-history.integration.spec.js#answers
      the merges that succeeded, which is what a history screen asks for by default
    origin: 'services-crm:docs/merging/experience/functional-requirements.md#AUD-3'
  - id: BR-CAP-CRM-DQ-019-02
    proved_by: [ATS-CRM-DQ-019-02, ATS-CRM-DQ-019-10, TST-CRM-DQ-183]
    statement: >-
      Record history includes merges survived by the record and its absorbed identities, with equivalent
      results when requested through an alias.
    kind: policy
    enforced_at:
      - service
    must_prove: true
    provenance: test
    source: >-
      services-crm:modules/merges/tests/e2e/merges.e2e.spec.js#answers the same history when asked under an id
      the merge took away, under the survivor
    origin: 'services-crm:docs/merging/experience/functional-requirements.md#AUD-1'
  - id: BR-CAP-CRM-DQ-019-03
    proved_by: [ATS-CRM-DQ-019-03, ATS-CRM-DQ-019-10, TST-CRM-DQ-181, TST-CRM-DQ-183]
    statement: >-
      History uses participant names and numbers captured at merging and the requester's current name, leaving
      unavailable names blank rather than displaying internal identities.
    kind: policy
    enforced_at:
      - service
    must_prove: true
    provenance: test
    source: >-
      services-crm:modules/merges/tests/integration/services/merges/tenant-merge-history.integration.spec.js#is
      the name Platform knows the requester by now, never the id a screen cannot read
    origin: 'services-crm:docs/merging/experience/functional-requirements.md#DQ-9'
  - id: BR-CAP-CRM-DQ-019-04
    proved_by: [ATS-CRM-DQ-019-04, ATS-CRM-DQ-019-10, TST-CRM-DQ-181, TST-CRM-DQ-183]
    statement: >-
      Details retain originals, the written survivor and field outcomes with final, discarded and gap-filling
      values, sources, rules and attributed decisions, together with relationship, login and validation
      actions.
    kind: policy
    enforced_at:
      - service
    must_prove: true
    provenance: test
    source: >-
      services-crm:modules/merges/tests/integration/services/merges/merge-outcome.integration.spec.js#keeps
      the reviewer’s choice with what it was, who made it, and the record it was taken from
    origin: 'services-crm:docs/milestones/CRM-M4-duplicates-and-merge.md#D-30'
  - id: BR-CAP-CRM-DQ-019-05
    proved_by: [ATS-CRM-DQ-019-05, ATS-CRM-DQ-019-10, TST-CRM-DQ-181]
    statement: >-
      Merge records remain for the workspace lifetime as retained originals and ordinary application
      operations cannot erase or relocate them.
    kind: invariant
    enforced_at:
      - database
    must_prove: true
    provenance: test
    source: >-
      services-crm:modules/merges/tests/integration/db/record-merges.table.integration.spec.js#may not erase a
      merge, which holds the only copy left of the records it deleted
    origin: 'services-crm:docs/merging/decisions.md#D4 (decided 2026-10-11: option 1)'
  - id: BR-CAP-CRM-DQ-019-06
    proved_by: [ATS-CRM-DQ-019-09, ATS-CRM-DQ-019-10]
    statement: >-
      The product should allow removal of a person's original merge values in response to a privacy deletion
      request.
    kind: policy
    enforced_at:
      - service
    must_prove: true
    provenance: unknown
    source: FND-CRM-DQ-010
    origin: 'services-crm:docs/merging/decisions.md#D4 (decided 2026-10-11: option 1)'
  - id: BR-CAP-CRM-DQ-019-07
    proved_by: [ATS-CRM-DQ-019-06, ATS-CRM-DQ-019-10, TST-CRM-DQ-181, TST-CRM-DQ-183]
    statement: >-
      Record readers may inspect successful merged-from history, field outcomes and originals without merge
      authority; login actions, carried dismissals and checks require merge-read authority.
    kind: permission
    enforced_at:
      - api
    must_prove: true
    provenance: test
    source: >-
      services-crm:modules/merges/tests/integration/services/merges/merged-from-history.integration.spec.js#leaves
      what only merge management reads out of a reader’s details
    origin: 'services-crm:docs/milestones/CRM-M6-access-and-audit.md#D-21'
  - id: BR-CAP-CRM-DQ-019-08
    proved_by: [ATS-CRM-DQ-019-06, ATS-CRM-DQ-019-10, TST-CRM-DQ-181, TST-CRM-DQ-183]
    statement: >-
      Merged-from requests reject authority for only the other record type and return not found for an
      unreachable record or a merge outside its lineage.
    kind: permission
    enforced_at:
      - api
    must_prove: true
    provenance: test
    source: >-
      services-crm:modules/merges/tests/e2e/merged-from-history.e2e.spec.js#refuses a reader of organizations
      a contact’s merged-from history
    origin: >-
      D-45 (cited in services-crm:docs/merging/api.md#2. Authorization; no milestone record holds it,
      FND-CRM-DQ-018)
  - id: BR-CAP-CRM-DQ-019-09
    proved_by: [ATS-CRM-DQ-019-07, ATS-CRM-DQ-019-10, TST-CRM-DQ-176]
    statement: >-
      Console Recently Merged and management details require merge-read authority, and record version history
      provides merge entries linking to their outcomes.
    kind: permission
    enforced_at:
      - console
    must_prove: true
    provenance: test
    source: 'react-console:acceptance/crm/playwright/journeys/merging/CRM-ACC-0266.spec.ts#CRM-ACC-0266'
    origin: 'services-crm:docs/merging/experience/functional-requirements.md#AUD-2'
  - id: BR-CAP-CRM-DQ-019-10
    proved_by: []
    statement: 'Workspace exports include merges, absorbed originals and their aliases.'
    kind: policy
    enforced_at:
      - service
    must_prove: false
    provenance: observed
    source: 'services-crm:modules/merges/export/merges.dataset.ts:mergesDataset'
    origin: none
  - id: BR-CAP-CRM-DQ-019-11
    proved_by: []
    statement: >-
      Merging has no undo operation; repairing a mistake requires survivor edits or record recreation from
      retained originals, and the console communicates that limit.
    kind: policy
    enforced_at:
      - console
    must_prove: false
    provenance: documented
    source: 'services-crm:docs/merging/architecture.md#7.4 What can and cannot be undone'
    origin: 'services-crm:docs/merging/experience/functional-requirements.md#GEN-8'
scenarios:
  - id: SC-CAP-CRM-DQ-019-01
    given: Two contacts have been merged successfully.
    when: A colleague with record-read authority opens the survivor's merged-from history.
    then: They see merge attribution and absorbed originals without needing merge-management permission.
    provenance: test
    source: >-
      services-crm:modules/merges/tests/e2e/merged-from-history.e2e.spec.js#answers the reader the merge’s
      outcome and the absorbed record as it was
  - id: SC-CAP-CRM-DQ-019-02
    given: Several people have requested merges.
    when: 'An administrator filters history by type, status, author and date.'
    then: >-
      Entries identify the records and attribution, with details showing retained, moved and discarded
      information.
    provenance: test
    source: 'react-console:acceptance/crm/playwright/journeys/merging/CRM-ACC-0266.spec.ts#CRM-ACC-0266'
edge_cases: []
constraints: []
depends_on:
  - CAP-CRM-DQ-016
related:
  - CAP-CRM-DQ-011
  - CAP-CRM-DQ-018
  - CAP-CRM-ENT-016
journeys:
  - JNY-CRM-DQ-006
open_questions:
  - OQ-CRM-DQ-002
evidence:
  - repository: services-crm
    source_sha: a8d1364f1dd44b723bb5f9acba12f983e9ec8d69
    paths:
      - docs/merging/architecture.md
      - docs/merging/decisions.md
      - docs/merging/experience/functional-requirements.md
      - docs/milestones/CRM-M4-duplicates-and-merge.md
      - docs/milestones/CRM-M6-access-and-audit.md
      - modules/merges/db/record-merges.table.ts
      - modules/merges/export/merges.dataset.ts
      - modules/merges/tests/e2e/merged-from-history.e2e.spec.js
      - modules/merges/tests/e2e/merges.e2e.spec.js
      - modules/merges/tests/integration/db/record-merges.table.integration.spec.js
      - modules/merges/tests/integration/services/merges/merge-outcome.integration.spec.js
      - modules/merges/tests/integration/services/merges/merged-from-history.integration.spec.js
      - modules/merges/tests/integration/services/merges/tenant-merge-history.integration.spec.js
    note: 'Static examination connects rule claims to implementation, declared checks and the cited tests.'
  - repository: react-console
    source_sha: baf6dae382d6f41dce976c7f848667ccc37e076f
    paths:
      - acceptance/crm/playwright/journeys/merging/CRM-ACC-0266.spec.ts
    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-DAT-001, TC-DAT-002, TC-DAT-003, TC-LOG-001, TC-LOG-002, TC-LOG-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, TC-TEN-004]
exercised_by: [FAS-CRM-DQ-05-01, FAS-CRM-DQ-05-02, FAS-CRM-DQ-05-03, FAS-CRM-DQ-05-04, FAS-CRM-DQ-05-05]
suites: [TST-CRM-DQ-176, TST-CRM-DQ-181, TST-CRM-DQ-183]
---

# Inspect merge outcomes and attribution

## Purpose

Staff can understand who requested a merge and what information and connections it changed.

## How It Works

Merge-authorized readers open Recently Merged and filter the workspace history. Each entry identifies the participating records and requester in readable terms. Detail views preserve the original records and the survivor as written. Field outcomes explain the winning, losing and gap-filling sources. They retain decisions and related-record actions for later inspection. A record reader can inspect the successful merges that made that record without merge-management authority. Management-only details remain excluded from that narrower response. Aliases connect earlier absorbed identities to the same history. Merge records persist for the workspace lifetime and cannot be erased by ordinary application operations. The product should implement the promised removal of one person's original values on a privacy request. A merge itself is irreversible; repair uses ordinary editing or recreation.

## Relationships

Execution produces attempts and permanent outcomes. Alias resolution joins an absorbed identity to the survivor's history. Platform owns audit pointers and workspace export delivery.
