---
id: CAP-MBR-MEM-008
title: Preserve member connections through transfers and unit merges
feature: FEAT-MBR-MEM-02
product_area: membership
module: memberships
revision: 1
status: draft
product_intent: confirmed
implementation_evidence: partially-observed
supersedes:
  - 'inventory:CAP-MBR-AFF-006'
  - 'inventory:CAP-MBR-AFF-011'
source_sha:
  services-membership: 5994c270e8a37a30f848e99ba5b5ee6b87c08893
  react-console: baf6dae382d6f41dce976c7f848667ccc37e076f
intent_sources:
  - 'services-membership:README.md#2026-10-18 — Final acceptance (decision 1: "Build the move now")'
  - 'services-membership:docs/migrations/unit-merge/README.md'
purpose: >-
  Staff move a member’s affiliation or merge units while retaining the dated relationships needed for rosters
  and history.
outcomes:
  - Transfers retain the connection between the ending row and its successor.
  - 'Merges account for current, future, duplicate and closed affiliations.'
  - Dated roster and officer views follow the resulting relationships.
concepts:
  - CON-MBR-MEM-003
actors:
  - ACT-MBR-007
  - ACT-MBR-009
  - ACT-MBR-006
surfaces:
  - console
  - api
permissions:
  - key: membership.affiliations.manage
    where_checked: api
    scope: record
  - key: membership.structure.manage
    where_checked: api
    scope: tenant
rules:
  - id: BR-CAP-MBR-MEM-008-01
    proved_by: [ATS-MBR-MEM-007-15, ATS-MBR-MEM-008-01, ATS-MBR-MEM-008-10, ATS-MBR-MEM-020-13, TST-MBR-MEM-024, TST-MBR-MEM-049]
    statement: >-
      A transfer ends the original affiliation on the preceding day and creates a successor on the effective
      date with its primary flag, end and lineage, recording a transfer event.
    kind: lifecycle
    enforced_at:
      - service
    must_prove: true
    provenance: observed
    source: >-
      services-membership:modules/memberships/services/affiliations/affiliation-operations.ts:writeAffiliationTransfer
    origin: none
  - id: BR-CAP-MBR-MEM-008-02
    proved_by: [ATS-MBR-MEM-008-02, ATS-MBR-MEM-008-11, TST-MBR-MEM-024, TST-MBR-MEM-249]
    statement: >-
      A direct transfer into a unit with applicable active dues is refused and identifies the Commerce
      component-change amendment required to carry the charge.
    kind: policy
    enforced_at:
      - service
    must_prove: true
    provenance: test
    source: >-
      services-membership:tests/e2e/s06-midterm-transfer.e2e.spec.ts#refuses the console’s transfer 409
      requires_amendment, naming the component_change amendment
    origin: none
  - id: BR-CAP-MBR-MEM-008-03
    proved_by: [ATS-MBR-MEM-008-03, TST-MBR-MEM-249]
    statement: >-
      Dated rosters reflect the old and new units on their respective dates and retain membership in any
      shared ancestor reached by another affiliation.
    kind: calculation
    enforced_at:
      - service
    must_prove: true
    provenance: test
    source: >-
      services-membership:tests/e2e/s06-midterm-transfer.e2e.spec.ts#takes Jo out of Atlanta’s roster from
      2027-01-01 and into the Pacific Zone’s, keeping them in the Southeast Zone’s through Savannah
    origin: none
  - id: BR-CAP-MBR-MEM-008-04
    proved_by: [ATS-MBR-MEM-008-04, TST-MBR-MEM-023, TST-MBR-MEM-037, TST-MBR-MEM-060]
    statement: >-
      A merge transfers begun affiliations, repoints future affiliations, ends or withdraws overlaps with the
      survivor, and leaves closed or cancelled-period affiliations unchanged.
    kind: lifecycle
    enforced_at:
      - service
    must_prove: true
    provenance: observed
    source: >-
      services-membership:modules/memberships/services/affiliations/unit-merge.ts:decideMergedTerm,
      writeDecision
    origin: >-
      Andrew 2026-10-18, guided build acceptance decision 1
      (services-membership:docs/migrations/unit-merge/README.md)
  - id: BR-CAP-MBR-MEM-008-05
    proved_by: [ATS-MBR-MEM-008-05]
    statement: >-
      A merge plan refuses affiliations requiring a different survivor type or introducing a unit-rule problem
      absent before the merge, identifying affected memberships before writes occur.
    kind: validation
    enforced_at:
      - service
    must_prove: true
    provenance: observed
    source: 'services-membership:modules/memberships/services/affiliations/unit-merge.ts:decideMergedTerm'
    origin: >-
      Andrew 2026-10-18, guided build acceptance decision 1
      (services-membership:docs/migrations/unit-merge/README.md)
  - id: BR-CAP-MBR-MEM-008-06
    proved_by: [ATS-MBR-MEM-008-06]
    statement: >-
      Identity-bound memberships move to the survivor unless a principal membership’s owner already holds that
      program in the surviving identity unit, which produces a merge refusal.
    kind: lifecycle
    enforced_at:
      - service
    must_prove: true
    provenance: observed
    source: 'services-membership:modules/memberships/services/affiliations/unit-merge.ts:decideIdentityBound'
    origin: >-
      Andrew 2026-10-18, guided build acceptance decision 1
      (services-membership:docs/migrations/unit-merge/README.md)
  - id: BR-CAP-MBR-MEM-008-07
    proved_by: [ATS-MBR-MEM-008-07, TST-MBR-MEM-256]
    statement: 'Any affiliation naming a unit, including a closed historical row, prevents deletion of that unit.'
    kind: invariant
    enforced_at:
      - service
      - database
    must_prove: true
    provenance: test
    source: >-
      services-membership:tests/e2e/s13-unit-merge.e2e.spec.ts#refuses to delete Savannah while affiliations
      name it (unit_has_affiliations)
    origin: none
  - id: BR-CAP-MBR-MEM-008-08
    proved_by: [ATS-MBR-MEM-008-08, ATS-MBR-MEM-008-12, ATS-MBR-MEM-015-12, TST-MBR-MEM-256]
    statement: 'After a merge, the survivor’s officers can read moved members through their new in-scope affiliations.'
    kind: policy
    enforced_at:
      - service
    must_prove: true
    provenance: test
    source: >-
      services-membership:tests/e2e/s13-unit-merge.e2e.spec.ts#shows Alex Pat now, with Pat’s Atlanta
      affiliation in scope
    origin: none
  - id: BR-CAP-MBR-MEM-008-09
    proved_by: []
    statement: >-
      The product should publish transfer-equivalent business events for every merge ending, withdrawal and
      repointing.
    kind: policy
    enforced_at:
      - service
    must_prove: true
    provenance: unknown
    source: FND-MBR-MEM-028
    origin: none
  - id: BR-CAP-MBR-MEM-008-10
    proved_by: []
    statement: >-
      The product should retain a current primary designation when a primary affiliation merges into an
      existing nonprimary survivor affiliation.
    kind: invariant
    enforced_at:
      - service
    must_prove: true
    provenance: unknown
    source: FND-MBR-MEM-027
    origin: none
  - id: BR-CAP-MBR-MEM-008-11
    proved_by: []
    statement: >-
      Merging affiliations carries no dues line or payment and leaves the merged unit’s dues products for a
      separate finance decision.
    kind: policy
    enforced_at:
      - service
    must_prove: false
    provenance: documented
    source: 'services-membership:docs/migrations/unit-merge/README.md#The behaviour'
    origin: none
  - id: BR-CAP-MBR-MEM-008-12
    proved_by: [ATS-MBR-MEM-008-09, TST-MBR-MEM-252]
    statement: >-
      Reparenting a chapter changes no affiliation row; current rosters use the new tree while past-date
      ancestry uses the historical tree.
    kind: policy
    enforced_at:
      - service
    must_prove: true
    provenance: observed
    source: >-
      services-membership:modules/memberships/services/reads/membership-views.ts:membershipFiltersOf;
      tests/e2e/s09-restructuring.e2e.spec.ts#rewrites no affiliation: Jo’s row is the same row, version and
      unit
    origin: none
scenarios:
  - id: SC-CAP-MBR-MEM-008-01
    given: 'Pat belongs only to Savannah, while Jo belongs to both Savannah and Atlanta.'
    when: An administrator merges Savannah into Atlanta today.
    then: 'Pat continues in Atlanta, Jo’s duplicate Savannah tie ends, and today’s Savannah roster has no members.'
    provenance: observed
    source: >-
      services-membership:modules/memberships/services/affiliations/unit-merge.ts:decideMergedTerm,
      writeDecision
  - id: SC-CAP-MBR-MEM-008-02
    given: Open chapter affiliations would have to move into a survivor of another unit type.
    when: Staff request the incompatible merge.
    then: The refusal leaves the units and affiliation rows unchanged and identifies the affected memberships.
    provenance: test
    source: >-
      services-membership:modules/memberships/tests/integration/services/affiliations-unit-merge.integration.spec.ts#leaves
      the tree and the affiliations unchanged
edge_cases: []
constraints: []
depends_on:
  - CAP-MBR-MEM-007
related:
  - CAP-MBR-MEM-009
  - CAP-MBR-MEM-015
journeys:
  - JNY-MBR-MEM-006
open_questions:
  - OQ-MBR-MEM-002
evidence:
  - repository: services-membership
    source_sha: 5994c270e8a37a30f848e99ba5b5ee6b87c08893
    paths:
      - modules/memberships/services/affiliations/affiliation-operations.ts
      - modules/memberships/services/affiliations/unit-merge.ts
      - modules/memberships/tests/unit/unit-merge.spec.ts
      - modules/memberships/tests/integration/services/affiliations-unit-merge.integration.spec.ts
      - modules/memberships/tests/integration/services/identity-unit-merge.integration.spec.ts
      - tests/e2e/s06-midterm-transfer.e2e.spec.ts
      - tests/e2e/s09-restructuring.e2e.spec.ts
      - tests/e2e/s13-unit-merge.e2e.spec.ts
      - docs/migrations/unit-merge/README.md
controls: [TC-AVL-002, TC-AVL-003, TC-AVL-004, TC-AZ-001, TC-AZ-002, TC-AZ-003, TC-AZ-004, TC-AZ-006, TC-CHG-001, TC-CHG-002, TC-CHG-003, TC-CHG-004, TC-CRY-001, TC-CRY-002, TC-CRY-003, TC-DAT-001, TC-DAT-002, TC-DAT-003, TC-DAT-004, TC-DAT-007, 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-MON-004, TC-PI-001, TC-PI-002, TC-PI-003, TC-PI-004, TC-PI-005, TC-PRV-001, TC-PRV-002, TC-SEC-001, TC-SEC-004, TC-TEN-001, TC-TEN-002, TC-TEN-003, TC-TEN-004]
exercised_by: [FAS-MBR-MEM-02-02, FAS-MBR-MEM-02-03, FAS-MBR-MEM-02-04, FAS-MBR-MEM-02-05]
suites: [TST-MBR-MEM-023, TST-MBR-MEM-024, TST-MBR-MEM-037, TST-MBR-MEM-049, TST-MBR-MEM-060, TST-MBR-MEM-249, TST-MBR-MEM-252, TST-MBR-MEM-256]
---

# Preserve member connections through transfers and unit merges

## Purpose

A member relocation and an association’s unit merger both change where membership is held. Staff need a dated account of that change so the current roster does not erase earlier connections.

## How It Works

Staff transfer an individual affiliation by choosing a target and effective date. The operation checks the proposed resulting set before writing the change. Dues-bearing targets require the purchase-related path rather than a direct staff transfer. An administrator instead uses a unit merge to account for every affected affiliation together. The merge plan distinguishes a move from removal of an overlapping survivor tie. Future ties can change their unit in place because they have not yet held in the old unit. Staff inspect the merge’s counts and each affected membership’s lifecycle record. Identity-bound memberships are considered alongside the affiliation rows. Missing publication for some merge actions and loss of a primary flag onto an existing survivor remain findings.

## Relationships

- Dated affiliations supply the rows and effective rules for transfers and merge planning.
- Organizational structure owns the unit merge and reparenting operations that invoke this membership work.
- Membership purchases supply the amendment route needed for dues-bearing changes.
