Skip to content

Survivorship

After matching identifies which records belong to the same entity, survivorship determines the canonical value for each field. When three sources say different things about the same customer, survivorship picks the winner.

The Conflict Problem

You've matched these three records as the same person:

FieldCRM (Salesforce)Billing (Stripe)Support (Zendesk)
nameJohn SmithJon SmithJ. Smith
email[email protected][email protected][email protected]
phone555-0100null555-0100
companyAcme IncAcme IncorporatedAcme
titleVP EngineeringnullVP of Eng
revenuenull$50,000null
plannullEnterprisenull
tags[prospect][paying][active, vip]
citySan FranciscoSan FranciscoSF
updated_at2026-01-152026-02-012026-01-20

Which "name" goes in the golden record? What about "tags"? Survivorship answers these questions field by field.

Source Priority

The most common strategy. You rank your sources by trustworthiness, and the highest-ranked source with a non-null value wins.

How It Works

  1. Sources are ranked in order of priority (first = highest)
  2. For each field, check sources in priority order
  3. The first non-null value becomes the golden record value

Example

With ranking [crm, billing, support]:

FieldCRMBillingSupportWinnerWhy
nameJohn SmithJon SmithJ. SmithJohn SmithCRM is #1 and non-null
phone555-0100null555-0100555-0100CRM is #1 and non-null
revenuenull$50,000null$50,000CRM null → Billing is next
plannullEnterprisenullEnterpriseCRM null → Billing is next

YAML Config

yaml
survivorship:
  default: source_priority
  source_ranking: [crm, billing, support]

When to Use

  • You have a clear "system of record" for most fields
  • Data quality varies significantly between sources
  • You want predictable, deterministic results

Most Recent

The value with the most recent timestamp wins. Best for fields that change over time (title, address, phone).

How It Works

  1. Each source record has a timestamp field (e.g., updated_at)
  2. For each field, the value from the record with the latest timestamp wins
  3. Null values are skipped — the most recent non-null value wins

Example

FieldCRM (Jan 15)Billing (Feb 1)Support (Jan 20)WinnerWhy
nameJohn SmithJon SmithJ. SmithJon SmithBilling is most recent
titleVP EngineeringnullVP of EngVP of EngSupport is more recent than CRM (Billing null)
citySan FranciscoSan FranciscoSFSan FranciscoBilling is most recent

YAML Config

yaml
survivorship:
  default: most_recent

When to Use

  • Fields that change frequently (job title, address, phone number)
  • All sources have reliable timestamps
  • You want the "latest known truth"

Most Complete

The longest or most complete value wins. Best for fields where more detail is better (company name, address).

How It Works

  1. For string fields: the longest non-null value wins
  2. For arrays: the value with the most elements wins
  3. Ties are broken by source priority (if configured) or alphabetical order

Example

FieldCRMBillingSupportWinnerWhy
companyAcme IncAcme IncorporatedAcmeAcme IncorporatedLongest (18 chars)
nameJohn SmithJon SmithJ. SmithJohn SmithLongest (10 chars)
titleVP EngineeringnullVP of EngVP EngineeringLongest (14 chars)

YAML Config

yaml
survivorship:
  default: most_complete

When to Use

  • Company names where abbreviation vs. full name varies
  • Address fields where some sources truncate
  • Any field where more detail = better quality

Aggregate

Instead of picking one value, combine values from all sources. Six aggregate functions are available:

FunctionDescriptionInput → Output
unionCombine all unique values[a, b] + [b, c] → [a, b, c]
intersectionKeep only values present in all sources[a, b] + [b, c] → [b]
maxHighest numeric value100, 200, 150 → 200
minLowest numeric value100, 200, 150 → 100
sumTotal across sources100, 200, 150 → 450
avgAverage across sources100, 200, 150 → 150

Example

FieldCRMBillingSupportFunctionResult
tags[prospect][paying][active, vip]union[prospect, paying, active, vip]
revenuenull$50,000nullmax$50,000

YAML Config

yaml
survivorship:
  default: source_priority
  source_ranking: [crm, billing, support]
  overrides:
    - field: tags
      strategy: aggregate
      function: union
    - field: revenue
      strategy: aggregate
      function: max

When to Use

  • union: Tags, labels, categories — keep everything
  • intersection: Shared attributes across sources — only keep agreements
  • max/min: Revenue, scores — use the extreme value
  • sum: Quantities, counts — total across sources
  • avg: Ratings, scores — average across sources

Field-Level Overrides

In practice, you'll use a different strategy for different fields. Set a global default and override specific fields:

yaml
survivorship:
  default: source_priority
  source_ranking: [crm, billing, support]
  overrides:
    - field: email
      strategy: most_recent
    - field: title
      strategy: most_recent
    - field: company
      strategy: most_complete
    - field: tags
      strategy: aggregate
      function: union
    - field: revenue
      strategy: aggregate
      function: max

This says:

  • Most fields: Use the CRM value (source priority)
  • email, title: Use the most recent value (these change over time)
  • company: Use the most complete value (longest name wins)
  • tags: Combine all tags from all sources
  • revenue: Use the highest revenue figure

Worked Example: Golden Record

Let's build a complete golden record from the three-source example at the top of this page.

Input Records

FieldCRM (Salesforce)Billing (Stripe)Support (Zendesk)
nameJohn SmithJon SmithJ. Smith
email[email protected][email protected][email protected]
phone555-0100null555-0100
companyAcme IncAcme IncorporatedAcme
titleVP EngineeringnullVP of Eng
revenuenull$50,000null
plannullEnterprisenull
tags[prospect][paying][active, vip]
citySan FranciscoSan FranciscoSF
updated_at2026-01-152026-02-012026-01-20

Survivorship Config

yaml
survivorship:
  default: source_priority
  source_ranking: [crm, billing, support]
  overrides:
    - field: email
      strategy: most_recent
    - field: title
      strategy: most_recent
    - field: company
      strategy: most_complete
    - field: tags
      strategy: aggregate
      function: union
    - field: revenue
      strategy: aggregate
      function: max

Result: Golden Record

FieldGolden ValueStrategySource
nameJohn Smithsource_priorityCRM (#1, non-null)
email[email protected]most_recentBilling (Feb 1 — all same anyway)
phone555-0100source_priorityCRM (#1, non-null)
companyAcme Incorporatedmost_completeBilling (longest: 18 chars)
titleVP of Engmost_recentSupport (Jan 20 — Billing null, Support > CRM)
revenue$50,000aggregate(max)Billing (only non-null)
planEnterprisesource_priorityBilling (CRM null → #2)
tags[prospect, paying, active, vip]aggregate(union)All sources combined
citySan Franciscosource_priorityCRM (#1, non-null)

Each field used the strategy best suited to its semantics:

  • name, phone, city, plan → source priority (CRM is the system of record)
  • email, title → most recent (these fields change over time)
  • company → most complete ("Acme Incorporated" beats "Acme Inc" and "Acme")
  • tags → aggregate union (combine all labels)
  • revenue → aggregate max (use the highest known figure)

Next Steps

The identity and delegation layer for AI agents.