---
id: WF-PFM-MTD-009
title: Move links and references when CRM merges duplicates
trigger: Platform contributes relationship and reference work to CRM’s merge transaction.
product_area: platform
module: metadata
revision: 1
status: draft
design_intent: confirmed
origin: 'PLAT-M6 assumption A3 and D4 (Andrew, 2026-10-21: move reference fields to the survivor), plan approved
  2026-10-21 (services-platform:docs/milestones/plans/PLAT-M6-plan.md); services-platform:docs/record-merge-participant.md
  (the participant contract)'
implementation_evidence: observed
inference: []
source_sha:
  services-platform: ad3f6a6582843008ed0f5a17b131878d15829af1
implements:
- CAP-PFM-MTD-019
- CAP-PFM-MTD-014
moves:
- STATE-PFM-MTD-010
crosses:
- SVC-PFM-MTD-associations
- SVC-PFM-MTD-custom-objects
idempotency: Planning is read-only and shares collision decisions with apply. Reapplication after success has no
  remaining duplicate endpoints, while touched rows remain in the owner transaction.
concurrency: Planning is read-only and shares collision decisions with apply. Reapplication after success has no
  remaining duplicate endpoints, while touched rows remain in the owner transaction.
hops:
- n: 1
  actor_or_service: CRM merge worker
  action: The merge contract asks Platform to plan survivor and duplicate effects inside the owner’s merge transaction.
  anchor: services-platform:docs/record-merge-participant.md#Four functions, called inside CRM's transaction
  seam: sync
  on_failure: A reported blocker prevents application before writes begin.
  left_inconsistent: Planning makes no business changes.
  observer: The initiating person or service and its operation logs.
  provenance: documented
  source: services-platform:docs/record-merge-participant.md#Four functions, called inside CRM's transaction
- n: 2
  actor_or_service: Platform merge plan function
  action: Platform counts link moves, collision endings and redirected custom-reference values and returns readable
    summaries.
  anchor: services-platform:lib/record-merge/platform-references.ts
  seam: sync
  on_failure: Stop the merge plan if the participant cannot provide an answer.
  left_inconsistent: The plan remains read-only.
  observer: The initiating person or service and its operation logs.
  provenance: test
  source: services-platform:modules/associations/tests/integration/db/associations-merge.integration.spec.js#counts
    the associations held by m, and says how many end inst
- n: 3
  actor_or_service: Platform merge apply function
  action: Apply moves duplicate endpoints to the survivor, ends colliding or self-links on the bounded merge date,
    clears extra primary and redirects reference values.
  anchor: services-platform:lib/record-merge/platform-references.ts
  seam: sync
  on_failure: Any failed statement rolls back with the owner’s merge transaction.
  left_inconsistent: No participant move commits independently of the merge.
  observer: The initiating person or service and its operation logs.
  provenance: test
  source: services-platform:modules/associations/tests/integration/db/associations-merge.integration.spec.js#ends
    m’s association that repeats s’s, giving it s’s id, and
- n: 4
  actor_or_service: Database history capture
  action: Commit-time history captures departed and added links and reference values under the merge attribution.
  anchor: services-platform:docs/record-history.md#The two streams
  seam: sync
  on_failure: Reject commit without actor or source context.
  left_inconsistent: The merge and its revisions roll back together.
  observer: The initiating person or service and its operation logs.
  provenance: test
  source: 'services-platform:modules/custom-objects/tests/integration/db/custom-object-records-merge.integration.spec.js#attributes
    the change to the merge: its source, it'
- n: 5
  actor_or_service: CRM
  action: The documented owner contract publishes the merge event; Platform emits no events for link moves or merge
    endings.
  anchor: services-platform:docs/business-events.md#6. Decisions and departures
  seam: event
  on_failure: This hop states the external contract rather than a verified owner call site.
  left_inconsistent: Link-event subscribers receive no announcement for these merge changes.
  observer: Event delivery monitoring and the retained ledger.
  provenance: documented
  source: services-platform:docs/debt/merge-association-events.md
branches: []
waits: []
evidence:
- 'services-platform at ad3f6a65: docs/record-merge-participant.md; lib/record-merge/platform-references.ts; docs/associations.md
  §7; docs/custom-objects.md §24 (a CRM merge moves reference properties); modules/associations/tests/integration/db/associations-merge.integration.spec.js;
  modules/custom-objects/tests/integration/db/custom-object-records-merge.integration.spec.js'
controls: [TC-AVL-005, TC-AZ-001, TC-AZ-002, TC-AZ-003, TC-AZ-004, TC-DAT-001, TC-DAT-002, TC-DAT-003, TC-DAT-004, TC-IAM-001, TC-IAM-002, TC-IAM-004, TC-IAM-005, TC-LOG-002, TC-LOG-003, TC-LOG-004, TC-LOG-005, TC-MON-001, TC-PI-001, TC-PI-002, TC-PI-003, TC-PI-005, TC-PRV-001, TC-PRV-002, TC-TEN-001, TC-TEN-002, TC-TEN-003, TC-TEN-004, TC-VEN-001, TC-VEN-002, TC-VEN-003]
---

# Move links and references when CRM merges duplicates

## What It Does

Platform contributes relationship and reference work to CRM’s merge transaction. Planning explains the effects, and application redirects duplicates to the survivor while resolving collisions.

## The Flow

```mermaid
sequenceDiagram
  participant CRM as CRM merge (one transaction)
  participant Plan as Platform plan function
  participant Apply as Platform apply function
  participant Hist as History capture
  CRM->>Plan: plan survivor and duplicates
  Plan-->>CRM: counts and sentences, blockers
  CRM->>Apply: apply
  Apply->>Apply: move links, end collisions, clear extra primary, redirect references
  Apply-->>CRM: actions taken
  CRM->>Hist: commit, revisions attributed to the merge
```

## When Something Fails

A reported blocker prevents application before writes begin. Planning makes no business changes. Stop the merge plan if the participant cannot provide an answer. The plan remains read-only. Reject commit without actor or source context. The merge and its revisions roll back together. This hop states the external contract rather than a verified owner call site. Link-event subscribers receive no announcement for these merge changes.

## Open Design Questions

Event support for moved or merge-ended connections remains unresolved.
