---
id: CAP-MBR-STR-003
title: Combine units and continue their memberships
feature: FEAT-MBR-STR-01
product_area: membership
module: structure
revision: 1
status: draft
product_intent: proposed
implementation_evidence: observed
supersedes:
  - react-console acceptance inventory CAP-MBR-STR-006
source_sha:
  services-membership: 5994c270e8a37a30f848e99ba5b5ee6b87c08893
  react-console: baf6dae382d6f41dce976c7f848667ccc37e076f
intent_sources:
  - >-
    services-membership:docs/migrations/unit-merge/README.md#P2c: a unit merge moves its members' affiliations
    (Andrew's decision of 2026-10-18, guided build acceptance decision 1: build the move now)
purpose: An administrator combines two units so eligible children and memberships continue under one survivor.
outcomes:
  - Eligible memberships continue under the surviving unit through one coordinated merge.
  - The result identifies financial and organizational records requiring follow-up.
concepts:
  - CON-MBR-STR-001
  - CON-MBR-STR-002
actors:
  - ACT-MBR-001
surfaces:
  - api
preconditions: []
postconditions: []
permissions:
  - key: membership.structure.manage
    where_checked: api
    scope: tenant
  - key: membership.application.access
    where_checked: api
    scope: tenant
rules:
  - id: BR-CAP-MBR-STR-003-01
    proved_by: [ATS-MBR-STR-003-01, TST-MBR-STR-010, TST-MBR-STR-078]
    statement: >-
      A merge requires an active survivor outside the source unit’s own branch, and rejects a source already
      marked merged.
    kind: validation
    enforced_at:
      - service
    must_prove: true
    provenance: test
    source: >-
      services-membership:modules/structure/tests/unit/services/tree-edits.spec.ts#the tree edits › merge ›
      refuses a survivor below the merged unit
    origin: none
  - id: BR-CAP-MBR-STR-003-02
    proved_by: [ATS-MBR-STR-002-13, ATS-MBR-STR-003-02, TST-MBR-STR-006, TST-MBR-STR-078]
    statement: >-
      All source children relocate to the survivor subject to placement checks, with the complete merge rolled
      back if any child cannot move.
    kind: invariant
    enforced_at:
      - service
    must_prove: true
    provenance: test
    source: >-
      services-membership:modules/structure/tests/integration/services/persistence/organizational-units.integration.spec.ts#organizational
      units in the database › merge › moves the children under the survivor, marks the unit merged and lists
      what it left
    origin: none
  - id: BR-CAP-MBR-STR-003-03
    proved_by: [ATS-MBR-STR-003-03, TST-MBR-STR-006, TST-MBR-STR-077]
    statement: The source unit receives merged status and a reference to its survivor.
    kind: lifecycle
    enforced_at:
      - service
      - database
    must_prove: true
    provenance: test
    source: >-
      services-membership:modules/structure/tests/integration/services/persistence/organizational-units.integration.spec.ts#organizational
      units in the database › merge › moves the children under the survivor, marks the unit merged and lists
      what it left
    origin: none
  - id: BR-CAP-MBR-STR-003-04
    proved_by: [ATS-MBR-STR-003-04, ATS-MBR-STR-003-08, ATS-MBR-STR-004-07, TST-MBR-STR-099]
    statement: >-
      Effective affiliations transfer or end when the member already overlaps the survivor; unstarted
      affiliations are re-pointed or withdrawn, and earlier closed periods and cancelled terms remain
      unchanged.
    kind: policy
    enforced_at:
      - service
    must_prove: true
    provenance: documented
    source: 'services-membership:docs/migrations/unit-merge/README.md#The behaviour'
    origin: >-
      services-membership:docs/migrations/unit-merge/README.md#P2c: a unit merge moves its members'
      affiliations (Andrew's decision of 2026-10-18, guided build acceptance decision 1: build the move now)
  - id: BR-CAP-MBR-STR-003-05
    proved_by: [ATS-MBR-STR-003-05, TST-MBR-STR-008, TST-MBR-STR-010]
    statement: >-
      Any newly introduced affiliation-rule violation rejects the complete merge and identifies affected
      memberships and rules.
    kind: validation
    enforced_at:
      - service
    must_prove: true
    provenance: test
    source: >-
      services-membership:modules/structure/tests/integration/services/tree/unit-merge.integration.spec.ts#the
      tree edits affiliations bind › a merge an affiliation cannot follow › is refused 409
      affiliations_not_movable, naming the membership and unit_minimum
    origin: >-
      services-membership:docs/migrations/unit-merge/README.md#P2c: a unit merge moves its members'
      affiliations (Andrew's decision of 2026-10-18, guided build acceptance decision 1: build the move now)
  - id: BR-CAP-MBR-STR-003-06
    proved_by: [ATS-MBR-STR-003-06, TST-MBR-STR-003]
    statement: >-
      Identity-bound memberships replace the source identity with the survivor, with a conflict rejected when
      the owner already holds the survivor’s membership.
    kind: policy
    enforced_at:
      - service
    must_prove: true
    provenance: test
    source: >-
      services-membership:modules/memberships/tests/integration/services/identity-unit-merge.integration.spec.ts#a
      unit merge moves the identity of identity-bound memberships › the merge of Macon into Atlanta › makes
      Atlanta the identity of Kim’s membership, at the next version
    origin: none
  - id: BR-CAP-MBR-STR-003-07
    proved_by: [ATS-MBR-STR-003-09, ATS-MBR-STR-007-08, ATS-MBR-STR-008-07, TST-MBR-STR-077]
    statement: >-
      The merge retains dues products, financial settings, organization links and committee attachments on the
      source and identifies follow-up work.
    kind: policy
    enforced_at:
      - service
    must_prove: false
    provenance: test
    source: >-
      services-membership:modules/structure/tests/integration/services/persistence/organizational-units.integration.spec.ts#organizational
      units in the database › merge › moves the children under the survivor, marks the unit merged and lists
      what it left
    origin: none
  - id: BR-CAP-MBR-STR-003-08
    proved_by: []
    statement: >-
      A merge defaults to today, accepts an earlier effective date and rejects future dates; an omitted reason
      is generated from the source and survivor.
    kind: validation
    enforced_at:
      - api
      - service
    must_prove: false
    provenance: observed
    source: 'services-membership:modules/structure/services/tree/tree-edits.ts:mergeUnit'
    origin: none
  - id: BR-CAP-MBR-STR-003-09
    proved_by: [ATS-MBR-STR-003-07, TST-MBR-STR-077]
    statement: >-
      Merged units reject moves, detail replacements, deactivation and further merges, while their links,
      financial settings and dues products remain separately writable.
    kind: lifecycle
    enforced_at:
      - service
    must_prove: true
    provenance: observed
    source: >-
      services-membership:modules/structure/services/persistence/organizational-units.ts:updateOrganizationalUnit
    origin: none
  - id: BR-CAP-MBR-STR-003-10
    proved_by: []
    statement: 'Merging leaves the source’s parent, current tree placement and open parent-history period unchanged.'
    kind: policy
    enforced_at:
      - service
    must_prove: false
    provenance: observed
    source: 'services-membership:modules/structure/services/tree/tree-edits.ts:mergeUnit'
    origin: none
  - id: BR-CAP-MBR-STR-003-11
    proved_by: []
    statement: Each relocated child publishes a parent-change event identifying the merged source.
    kind: policy
    enforced_at:
      - service
    must_prove: false
    provenance: test
    source: >-
      services-membership:modules/structure/tests/unit/services/tree-edits.spec.ts#the tree edits › merge ›
      states membership.unit.reparented for each child that moved under the survivor, naming the merged unit
    origin: none
  - id: BR-CAP-MBR-STR-003-12
    proved_by: []
    statement: An inactive source can merge into an active survivor.
    kind: policy
    enforced_at:
      - service
    must_prove: false
    provenance: observed
    source: 'services-membership:modules/structure/services/tree/tree-edits.ts:mergeUnit'
    origin: none
scenarios:
  - id: SC-CAP-MBR-STR-003-01
    given: The association decides to absorb Savannah Chapter into Atlanta.
    when: Staff submit Savannah’s merge with Atlanta as survivor.
    then: The eligible section and memberships continue at Atlanta while Savannah retains merged status.
    provenance: test
    source: >-
      services-membership:tests/e2e/s13-unit-merge.e2e.spec.ts#a unit merge moves its members: Savannah into
      Atlanta › merges Savannah, counting one affiliation moved and one ended on the survivor
edge_cases:
  - id: SC-CAP-MBR-STR-003-02
    given: The combination would introduce a shortfall against a member’s package minimum.
    when: Staff attempt the unit combination.
    then: The complete operation fails and all earlier records remain intact.
    provenance: test
    source: >-
      services-membership:modules/structure/tests/integration/services/tree/unit-merge.integration.spec.ts#the
      tree edits affiliations bind › a merge an affiliation cannot follow › is refused 409
      affiliations_not_movable, naming the membership and unit_minimum
constraints: []
depends_on:
  - CAP-MBR-STR-002
related:
  - CAP-MBR-STR-004
  - CAP-MBR-STR-008
journeys:
  - JNY-MBR-STR-003
open_questions:
  - OQ-MBR-STR-001
evidence:
  - 'services-membership: Examination of the merge in the tree edits and the merge affiliation step it calls.'
  - 'services-membership: Examination of merge integration tests, the unit tier and scenario 13.'
  - 'services-membership: Examination of the unit-merge and structure records.'
  - 'services-membership:modules/memberships/tests/integration/services/identity-unit-merge.integration.spec.ts'
  - 'services-membership:modules/structure/services/persistence/organizational-units.ts'
  - 'services-membership:modules/structure/services/tree/tree-edits.ts'
  - >-
    services-membership:modules/structure/tests/integration/services/persistence/organizational-units.integration.spec.ts
  - 'services-membership:modules/structure/tests/integration/services/tree/unit-merge.integration.spec.ts'
  - 'services-membership:modules/structure/tests/unit/services/tree-edits.spec.ts'
  - 'services-membership:tests/e2e/s13-unit-merge.e2e.spec.ts'
controls: [TC-AVL-002, TC-AVL-003, TC-AVL-004, TC-AZ-001, TC-AZ-002, TC-AZ-003, TC-AZ-004, TC-AZ-005, 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-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-STR-01-03, FAS-MBR-STR-01-05, FAS-MBR-STR-02-03]
suites: [TST-MBR-STR-003, TST-MBR-STR-006, TST-MBR-STR-008, TST-MBR-STR-010, TST-MBR-STR-077, TST-MBR-STR-078, TST-MBR-STR-099]
---

# Combine units and continue their memberships

## Purpose

An administrator combines two units so eligible children and memberships continue under one survivor.

## How It Works

An administrator identifies the unit being absorbed and the unit that survives. The service checks the survivor and plans the affected membership changes before applying the merge. A new membership-rule conflict blocks the entire operation. Child units move through the structural placement checks. Affiliations already effective can continue through replacement periods on the survivor. An affiliation that has not started instead changes its unit in place, or is withdrawn when the member already belongs to the survivor. Identity-bound memberships also change their identifying unit when that change has no conflicting holding. The source is marked merged and retains its relationship to the survivor. Financial and organization records remain on the source for separate resolution. Staff review the returned leftovers before treating the combination as operationally complete. The product should settle whether the merged source remains in the current tree.

## Relationships

- Child relocation relies on the placement and restructuring capability.
- The memberships module supplies affiliation and membership-identity changes.
- Unit finance and organization links require separate follow-up after merging.
