---
id: SVC-CRM-DQ-merges
title: Merges Service Module
product_area: crm
module: data-quality
repository: services-crm
source_module: modules/merges
revision: 1
status: draft
design_intent: proposed
implementation_evidence: observed
inference: []
source_sha:
  services-crm: a8d1364f1dd44b723bb5f9acba12f983e9ec8d69
owns:
  - DOM-CRM-DQ-003
  - DOM-CRM-DQ-004
does_not_own:
  - >-
    Entities owns ordinary record saves, deletes and record endpoints; merging
    uses those services alongside its own reference and parent preparation.
  - Application participants remain responsible for their own reference changes.
  - >-
    Platform owns portal accounts and relinking, job infrastructure, audit
    storage and event catalogue delivery.
  - >-
    The duplicates module owns pair decisions carried or removed during
    execution.
operations:
  - operation_id: getMergesHealth
    intent: Report module health and deployed build information.
    access: public
    permission: 'none: public health route'
    realises: []
    published_to_submissions: 'not published: reports deployment health and captures no business request.'
  - operation_id: createMergePlan
    intent: >-
      Create a preview for two to ten same-type participants, choosing the
      recommendation when no survivor is supplied.
    access: console
    permission: >-
      any of crm.contacts.merge, crm.contacts.read, crm.organizations.merge,
      crm.organizations.read admits; the handler requires the merge and read
      keys of the plan record type
    realises:
      - CAP-CRM-DQ-012
      - CAP-CRM-DQ-013
      - CAP-CRM-DQ-014
      - CAP-CRM-DQ-015
      - CAP-CRM-DQ-017
    published_to_submissions: >-
      not published: an administrative merge of existing records with a reviewed
      preview, not an intake capture.
  - operation_id: listMergePlans
    intent: >-
      Page unfinished plans of the requested type, defaulting to those started
      by the caller and ordered by modification.
    access: console
    permission: >-
      any of crm.contacts.merge, crm.contacts.read, crm.organizations.merge,
      crm.organizations.read admits; the handler requires the merge and read
      keys of the plan record type
    realises:
      - CAP-CRM-DQ-012
    published_to_submissions: >-
      not published: reads or reports existing review state and accepts no
      captured business request.
  - operation_id: getMergeLimits
    intent: >-
      Report the current participant and write ceilings for callers qualified to
      plan either type.
    access: console
    permission: >-
      any of crm.contacts.merge, crm.contacts.read, crm.organizations.merge,
      crm.organizations.read admits; the handler requires a complete read and
      merge pair for at least one record type
    realises:
      - CAP-CRM-DQ-012
    published_to_submissions: >-
      not published: reads or reports existing review state and accepts no
      captured business request.
  - operation_id: getMergePlan
    intent: >-
      Recompute an open plan against current records, store changed results and
      include recent attempts.
    access: console
    permission: >-
      any of crm.contacts.merge, crm.contacts.read, crm.organizations.merge,
      crm.organizations.read admits; the handler requires the merge and read
      keys of the plan record type
    realises:
      - CAP-CRM-DQ-012
      - CAP-CRM-DQ-013
    published_to_submissions: >-
      not published: reads or reports existing review state and accepts no
      captured business request.
  - operation_id: updateMergePlan
    intent: >-
      Apply participant, survivor and answer edits under optimistic version
      control and refresh the preview.
    access: console
    permission: >-
      any of crm.contacts.merge, crm.contacts.read, crm.organizations.merge,
      crm.organizations.read admits; the handler requires the merge and read
      keys of the plan record type
    realises:
      - CAP-CRM-DQ-013
      - CAP-CRM-DQ-014
      - CAP-CRM-DQ-017
    published_to_submissions: >-
      not published: an administrative merge of existing records with a reviewed
      preview, not an intake capture.
  - operation_id: validateMergePlan
    intent: Refresh and store the current preview for pre-confirmation review.
    access: console
    permission: >-
      any of crm.contacts.merge, crm.contacts.read, crm.organizations.merge,
      crm.organizations.read admits; the handler requires the merge and read
      keys of the plan record type
    realises:
      - CAP-CRM-DQ-013
    published_to_submissions: >-
      not published: reads or reports existing review state and accepts no
      captured business request.
  - operation_id: executeMergePlan
    intent: >-
      Validate execution approval and readiness, then commit an attempt and
      durable job or return the existing attempt.
    access: console
    permission: >-
      any of crm.contacts.merge, crm.contacts.read, crm.organizations.merge,
      crm.organizations.read admits; the handler requires the merge and read
      keys of the plan record type
    realises:
      - CAP-CRM-DQ-016
      - CAP-CRM-DQ-017
      - CAP-CRM-DQ-018
    published_to_submissions: >-
      not published: an administrative merge of existing records with a reviewed
      preview, not an intake capture.
  - operation_id: listRecordMerges
    intent: >-
      Page workspace merge history with successes as the default and supported
      filters; record-specific history instead follows lineage.
    access: console
    permission: crm.merges.read
    realises:
      - CAP-CRM-DQ-019
    published_to_submissions: >-
      not published: reads or reports existing review state and accepts no
      captured business request.
  - operation_id: getRecordMerge
    intent: 'Read one attempt’s standing, failure context and associated job.'
    access: console
    permission: crm.merges.read
    realises:
      - CAP-CRM-DQ-016
      - CAP-CRM-DQ-019
    published_to_submissions: >-
      not published: reads or reports existing review state and accepts no
      captured business request.
  - operation_id: getRecordMergeDetails
    intent: >-
      Read original and resulting values, applied decisions, reference actions
      and validation for an attempt.
    access: console
    permission: crm.merges.read
    realises:
      - CAP-CRM-DQ-019
    published_to_submissions: >-
      not published: reads or reports existing review state and accepts no
      captured business request.
  - operation_id: listMergesIntoRecord
    intent: >-
      Page successful merged-from history for an authorized record reader,
      resolving an absorbed identity to its survivor.
    access: console
    permission: >-
      crm.contacts.read or crm.organizations.read for the path record type,
      reaching the record; crm.merges.read widens nothing here
    realises:
      - CAP-CRM-DQ-019
    published_to_submissions: >-
      not published: reads or reports existing review state and accepts no
      captured business request.
  - operation_id: getMergeIntoRecord
    intent: >-
      Read a successful lineage outcome under record-read authority, exposing
      sensitive audit details only with merge-read authority.
    access: console
    permission: >-
      crm.contacts.read or crm.organizations.read for the path record type;
      crm.merges.read widens the details
    realises:
      - CAP-CRM-DQ-019
    published_to_submissions: >-
      not published: reads or reports existing review state and accepts no
      captured business request.
  - operation_id: getMergedRecordAlias
    intent: >-
      Resolve an absorbed identity to destination, merge and time, or return
      not-found when no alias exists.
    access: console
    permission: crm.merges.read
    realises:
      - CAP-CRM-DQ-018
    published_to_submissions: >-
      not published: an identity lookup for integrations and links, not a
      capture.
events:
  - name: crm.contact.merged business event
    direction: produced
    when: >-
      Successful contact execution writes this event within the business
      transaction.
    payload_summary: >-
      Saved survivor values and absorbed contact identities with requester
      attribution and merge correlation.
  - name: record.merged audit pointer
    direction: produced
    when: >-
      Successful execution writes a pointer for each participant in the business
      transaction.
    payload_summary: >-
      The merge and survivor identities and the participant’s retained or
      absorbed role.
  - name: contact and organization change events
    direction: produced
    when: >-
      Ordinary survivor save and participant deletes capture their normal
      changed-record events.
    payload_summary: Owner save or delete context correlated to the merge.
  - name: crm.organization.merged business event
    direction: produced
    when: Organization merging does not declare or publish this catalogue entry.
    payload_summary: There is no emitted organization-merge payload.
jobs:
  - >-
    The durable record_merge workflow publishes definitions, runs one
    fifteen-minute merge task and has a failure task, within a twenty-one-minute
    workflow limit.
  - >-
    Five-minute reconciliation settles unresolved merge execution and performs
    overdue-plan expiry.
integrations:
  - system: Other applications (participant functions)
    direction: outbound
    contract: >-
      Installed application plan and apply functions are discovered through
      catalogue and execute grants; CRM calls them inside its transaction,
      requiring Platform for contacts.
  - system: Platform jobs API and monitoring
    direction: outbound
    contract: >-
      The submitted job exposes engine root, step and event data through
      customer-scoped monitoring views.
consistency:
  - rule: CRM and application-owned merge changes share one business transaction.
    kind: transactional
    compensation: >-
      Business failure rolls back all changes; separate settlement records the
      attempt and reopens an eligible plan.
  - rule: 'Submission commits its attempt, job and executing-plan marker together.'
    kind: transactional
    compensation: >-
      Reconciliation can settle a lost workflow start as failure and reopen the
      eligible plan.
  - rule: The contact announcement is persisted with successful merging.
    kind: transactional
    compensation: >-
      Delivery follows commit and can lag without announcing a rolled-back
      merge.
  - rule: >-
      Search, region and duplicate evidence refresh through owner change
      handling.
    kind: eventual
    compensation: >-
      Queue recovery belongs to each handler and does not roll back the
      committed merge.
  - rule: An open-plan read can persist a refreshed preview.
    kind: transactional
    compensation: >-
      Optimistic version checks reject a losing writer without replacing the
      newer preview.
evidence:
  - >-
    services-crm at a8d1364f: modules/merges/aws/api/merges.routes.ts (route
    declarations), merged-record-routes.ts, merges.schemas.ts, merges.mapper.ts;
    aws/merges.module.ts; aws/logic/*.lambda.ts; services/**; db/*.table.ts;
    aws/crm.service.ts (ContactsPermissions, OrganizationsPermissions,
    MergesReadPermission); aws/lambda/JOB_RECONCILER.ts; docs/merging/api.md,
    architecture.md.
controls: [TC-AVL-004, TC-AZ-001, TC-AZ-002, TC-AZ-003, TC-AZ-004, TC-AZ-005, TC-AZ-006, TC-DAT-001, TC-DAT-002, TC-DAT-003, TC-DAT-004, TC-DAT-005, TC-IAM-001, TC-IAM-002, TC-IAM-004, TC-IAM-005, TC-IAM-006, TC-LOG-001, TC-LOG-002, TC-LOG-003, TC-LOG-004, TC-LOG-005, TC-MON-001, TC-MON-002, TC-PI-001, TC-PI-002, TC-PI-003, TC-PI-004, TC-PI-005, TC-PRV-001, TC-PRV-002, TC-TEN-001, TC-TEN-002, TC-TEN-003, TC-TEN-004]
---

# Merges Service Module

## What This Service Is For

The merges module prepares reviewed combinations and executes them as durable attempts. It retains original values and absorbed identities so staff and integrations can explain the result after participant deletion.

## Boundary

Plans, attempt history, job records and aliases belong here. Ordinary survivor saves and absorbed deletes call Entities; merge persistence also moves affiliations and references and prepares organization hierarchy. Application-owned functions apply changes outside CRM ownership.

## Operations in Words

Type-specific read and merge permission pairs authorize planning and execution. Merge-read authority controls workspace history and aliases, while record-scoped lineage operations use the record’s read authority and selectively expose additional audit detail.

## Events and Jobs

Contact merging writes a committed business event; organization merging currently writes none. Participant audit pointers and ordinary record events share the successful transaction. Job reporting begins before execution and maps the outcome to watched steps afterward.

## Consistency Guarantees

Business changes are atomic, with failure recorded separately after rollback. Task reporting, announcement delivery and derived projections can lag that outcome. Each operation declares its unpublished Submissions status.
