---
id: ATS-MBR-MEM-007
scope: CAP-MBR-MEM-007
product_area: membership
module: memberships
revision: 2
status: proposed
approved_by: null
approved_at: null
source_sha:
  services-membership: 5994c270e8a37a30f848e99ba5b5ee6b87c08893
  react-console: baf6dae382d6f41dce976c7f848667ccc37e076f
scenarios:
  - id: ATS-MBR-MEM-007-01
    title: Refuse affiliations outside affiliation-bound programs
    level: api
    proves:
      - BR-CAP-MBR-MEM-007-01
    preconditions: An identity-bound program has a membership term.
    steps:
      - do: Name units during term creation and later attempt a direct addition.
        expect: 'Creation and addition are refused, and no affiliation is saved.'
        provenance: test
        source:
          - >-
            services-membership:tests/acceptance/affiliations/MBR-ACC-0263.acceptance.ts#MBR-ACC-0263:
            Ending a member's only chapter is refused, a cancelled term's
            chapters cannot be touched, and a program that does not bind by
            affiliation refuses chapters twice over
    expected: 'Creation and addition are refused, and no affiliation is saved.'
    negative: true
    data_needs: >-
      Membership terms, dated affiliation rows, unit settings and
      operation-specific callers or connections.
    bound_to:
      - TST-MBR-MEM-047
    provenance: test
    source: >-
      services-membership:tests/acceptance/affiliations/MBR-ACC-0263.acceptance.ts#MBR-ACC-0263:
      Ending a member's only chapter is refused, a cancelled term's chapters
      cannot be touched, and a program that does not bind by affiliation refuses
      chapters twice over
    category: validation
    binding_evidence:
      - suite: TST-MBR-MEM-047
        source: >-
          services-membership:tests/acceptance/affiliations/MBR-ACC-0263.acceptance.ts#MBR-ACC-0263:
          Ending a member's only chapter is refused, a cancelled term's chapters
          cannot be touched, and a program that does not bind by affiliation
          refuses chapters twice over
  - id: ATS-MBR-MEM-007-02
    title: Refuse inactive or disallowed unit selections
    level: api
    proves:
      - BR-CAP-MBR-MEM-007-02
    preconditions: >-
      The structure includes a region, inactive chapter and disallowed unit
      type.
    steps:
      - do: >-
          Attempt additions for each ineligible unit and inspect retained valid
          rows.
        expect: Each invalid selection is refused; valid existing affiliations remain.
        provenance: test
        source:
          - >-
            services-membership:modules/memberships/tests/integration/services/affiliations.integration.spec.ts#refuses
            a unit whose type takes no member affiliation (a region)
          - >-
            services-membership:tests/acceptance/affiliations/MBR-ACC-0262.acceptance.ts#MBR-ACC-0262:
            A coordinator's wrong additions are each refused with the rule's own
            code and the valid chapters already added are kept
    expected: Each invalid selection is refused; valid existing affiliations remain.
    negative: true
    data_needs: >-
      Membership terms, dated affiliation rows, unit settings and
      operation-specific callers or connections.
    bound_to:
      - TST-MBR-MEM-024
      - TST-MBR-MEM-046
    provenance: test
    source: >-
      services-membership:modules/memberships/tests/integration/services/affiliations.integration.spec.ts#refuses
      a unit whose type takes no member affiliation (a region)
    category: validation
    binding_evidence:
      - suite: TST-MBR-MEM-024
        source: >-
          services-membership:modules/memberships/tests/integration/services/affiliations.integration.spec.ts#refuses
          a unit whose type takes no member affiliation (a region)
      - suite: TST-MBR-MEM-046
        source: >-
          services-membership:tests/acceptance/affiliations/MBR-ACC-0262.acceptance.ts#MBR-ACC-0262:
          A coordinator's wrong additions are each refused with the rule's own
          code and the valid chapters already added are kept
  - id: ATS-MBR-MEM-007-03
    title: Enforce effective minimum and maximum counts
    level: api
    proves:
      - BR-CAP-MBR-MEM-007-03
    preconditions: Regular requires a chapter; Student permits only one.
    steps:
      - do: >-
          Create with no required chapter, add beyond a maximum, end the sole
          required chapter, then end one of two.
        expect: >-
          Minimum and maximum violations fail; removing one of two permitted
          chapters succeeds.
        provenance: test
        source:
          - >-
            services-membership:modules/memberships/tests/unit/unit-rules.spec.ts#refuses
            fewer affiliations of a type than its minimum from the day the
            operation takes effect
          - >-
            services-membership:modules/memberships/tests/unit/unit-rules.spec.ts#refuses
            more affiliations of a type on a day than its maximum
          - >-
            services-membership:modules/memberships/tests/unit/unit-rules.spec.ts#leaves
            a shortfall before the operation’s day alone
          - >-
            services-membership:modules/memberships/tests/integration/services/affiliations.integration.spec.ts#refuses
            a Regular term with no chapter: the package needs one (unit_minimum)
          - >-
            services-membership:modules/memberships/tests/integration/services/affiliations.integration.spec.ts#refuses
            a second chapter on a Student term: the package allows one
            (unit_maximum)
          - >-
            services-membership:modules/memberships/tests/integration/services/affiliations.integration.spec.ts#refuses
            to end a Regular term’s only chapter (unit_minimum), and ends one of
            two
    expected: >-
      Minimum and maximum violations fail; removing one of two permitted
      chapters succeeds.
    negative: true
    data_needs: >-
      Membership terms, dated affiliation rows, unit settings and
      operation-specific callers or connections.
    bound_to:
      - TST-MBR-MEM-038
      - TST-MBR-MEM-024
    provenance: test
    source: >-
      services-membership:modules/memberships/tests/unit/unit-rules.spec.ts#refuses
      fewer affiliations of a type than its minimum from the day the operation
      takes effect
    category: boundary
    binding_evidence:
      - suite: TST-MBR-MEM-038
        source: >-
          services-membership:modules/memberships/tests/unit/unit-rules.spec.ts#refuses
          fewer affiliations of a type than its minimum from the day the
          operation takes effect
      - suite: TST-MBR-MEM-038
        source: >-
          services-membership:modules/memberships/tests/unit/unit-rules.spec.ts#refuses
          more affiliations of a type on a day than its maximum
      - suite: TST-MBR-MEM-038
        source: >-
          services-membership:modules/memberships/tests/unit/unit-rules.spec.ts#leaves
          a shortfall before the operation’s day alone
      - suite: TST-MBR-MEM-024
        source: >-
          services-membership:modules/memberships/tests/integration/services/affiliations.integration.spec.ts#refuses
          a Regular term with no chapter: the package needs one (unit_minimum)
      - suite: TST-MBR-MEM-024
        source: >-
          services-membership:modules/memberships/tests/integration/services/affiliations.integration.spec.ts#refuses
          a second chapter on a Student term: the package allows one
          (unit_maximum)
      - suite: TST-MBR-MEM-024
        source: >-
          services-membership:modules/memberships/tests/integration/services/affiliations.integration.spec.ts#refuses
          to end a Regular term’s only chapter (unit_minimum), and ends one of
          two
  - id: ATS-MBR-MEM-007-04
    title: Limit simultaneous primary designations
    level: unit
    proves:
      - BR-CAP-MBR-MEM-007-04
      - INV-DOM-MBR-MEM-003-06
    preconditions: >-
      Two overlapping rows share a unit type with configurable multiple-primary
      allowance.
    steps:
      - do: >-
          Validate the overlapping primary set with the allowance disabled and
          enabled.
        expect: >-
          A primary conflict is reported when multiple primaries are forbidden,
          and the enabled allowance accepts the set.
        provenance: test
        source:
          - >-
            services-membership:modules/memberships/tests/unit/unit-rules.spec.ts#refuses
            two primaries of one type on a day unless the type allows several
    expected: >-
      A primary conflict is reported when multiple primaries are forbidden, and
      the enabled allowance accepts the set.
    negative: true
    data_needs: >-
      Membership terms, dated affiliation rows, unit settings and
      operation-specific callers or connections.
    bound_to:
      - TST-MBR-MEM-038
    provenance: test
    source: >-
      services-membership:modules/memberships/tests/unit/unit-rules.spec.ts#refuses
      two primaries of one type on a day unless the type allows several
    category: invariant
    binding_evidence:
      - suite: TST-MBR-MEM-038
        source: >-
          services-membership:modules/memberships/tests/unit/unit-rules.spec.ts#refuses
          two primaries of one type on a day unless the type allows several
  - id: ATS-MBR-MEM-007-05
    title: Reject overlapping ties to the same unit
    level: api
    proves:
      - BR-CAP-MBR-MEM-007-05
      - INV-DOM-MBR-MEM-003-04
    preconditions: The term already holds a chapter for the requested period.
    steps:
      - do: Attempt to add the existing chapter over overlapping dates.
        expect: The request reports affiliation overlap without saving another tie.
        provenance: test
        source:
          - >-
            services-membership:modules/memberships/tests/integration/services/affiliations.integration.spec.ts#refuses
            the same unit twice on a day of a term (affiliation_overlap)
    expected: The request reports affiliation overlap without saving another tie.
    negative: true
    data_needs: >-
      Membership terms, dated affiliation rows, unit settings and
      operation-specific callers or connections.
    bound_to:
      - TST-MBR-MEM-024
    provenance: test
    source: >-
      services-membership:modules/memberships/tests/integration/services/affiliations.integration.spec.ts#refuses
      the same unit twice on a day of a term (affiliation_overlap)
    category: invariant
    binding_evidence:
      - suite: TST-MBR-MEM-024
        source: >-
          services-membership:modules/memberships/tests/integration/services/affiliations.integration.spec.ts#refuses
          the same unit twice on a day of a term (affiliation_overlap)
  - id: ATS-MBR-MEM-007-06
    title: Route dues-bearing changes through an amendment
    level: api
    proves:
      - BR-CAP-MBR-MEM-007-06
    preconditions: >-
      Some chapters have package-specific or catch-all dues products, while
      another has none.
    steps:
      - do: 'Request dues-bearing additions, then add the chapter without dues.'
        expect: >-
          Dues-bearing requests identify the amendment requirement; the no-dues
          addition succeeds beside the existing primary.
        provenance: test
        source:
          - >-
            services-membership:modules/memberships/tests/integration/services/affiliations.integration.spec.ts#refuses
            to add a chapter that sells dues for the package, naming the
            Commerce amendment (requires_amendment)
          - >-
            services-membership:modules/memberships/tests/integration/services/affiliations.integration.spec.ts#adds
            a chapter that sells no dues from today, not primary beside the
            term’s primary
          - >-
            services-membership:tests/acceptance/affiliations/MBR-ACC-0266.acceptance.ts#MBR-ACC-0266:
            A chapter that charges dues for the member's package cannot be added
            or moved into from the console, until its dues product is switched
            off
    expected: >-
      Dues-bearing requests identify the amendment requirement; the no-dues
      addition succeeds beside the existing primary.
    negative: true
    data_needs: >-
      Membership terms, dated affiliation rows, unit settings and
      operation-specific callers or connections.
    bound_to:
      - TST-MBR-MEM-024
      - TST-MBR-MEM-050
    provenance: test
    source: >-
      services-membership:modules/memberships/tests/integration/services/affiliations.integration.spec.ts#refuses
      to add a chapter that sells dues for the package, naming the Commerce
      amendment (requires_amendment)
    category: interaction
    binding_evidence:
      - suite: TST-MBR-MEM-024
        source: >-
          services-membership:modules/memberships/tests/integration/services/affiliations.integration.spec.ts#refuses
          to add a chapter that sells dues for the package, naming the Commerce
          amendment (requires_amendment)
      - suite: TST-MBR-MEM-024
        source: >-
          services-membership:modules/memberships/tests/integration/services/affiliations.integration.spec.ts#adds
          a chapter that sells no dues from today, not primary beside the term’s
          primary
      - suite: TST-MBR-MEM-050
        source: >-
          services-membership:tests/acceptance/affiliations/MBR-ACC-0266.acceptance.ts#MBR-ACC-0266:
          A chapter that charges dues for the member's package cannot be added
          or moved into from the console, until its dues product is switched off
  - id: ATS-MBR-MEM-007-07
    title: Distinguish omitted renewal ties from an empty list
    level: api
    proves:
      - BR-CAP-MBR-MEM-007-07
    preconditions: >-
      A Regular term holds Atlanta and Savannah and the next package still
      requires a chapter.
    steps:
      - do: >-
          Create the first term with named units, renew without affiliations,
          and separately renew with an explicit empty list.
        expect: >-
          The first period has its named units; omission inherits them; an empty
          list fails the package minimum and saves no new term.
        provenance: test
        source:
          - >-
            services-membership:modules/memberships/tests/integration/services/affiliations.integration.spec.ts#writes
            a staff term’s chapters from its first day, the first of the type
            the primary
          - >-
            services-membership:modules/memberships/tests/integration/services/affiliations.integration.spec.ts#carries
            the previous term’s chapters into a staff renewal that names none,
            as inherited
          - >-
            services-membership:tests/acceptance/affiliations/MBR-ACC-0271.acceptance.ts#MBR-ACC-0271:
            A staff renewal carries Jo's chapters into the new term, a renewal
            with an empty list carries nothing, and corrections and terminations
            keep every row inside its term
    expected: >-
      The first period has its named units; omission inherits them; an empty
      list fails the package minimum and saves no new term.
    negative: false
    data_needs: >-
      Membership terms, dated affiliation rows, unit settings and
      operation-specific callers or connections.
    bound_to:
      - TST-MBR-MEM-024
      - TST-MBR-MEM-054
    provenance: test
    source: >-
      services-membership:modules/memberships/tests/integration/services/affiliations.integration.spec.ts#writes
      a staff term’s chapters from its first day, the first of the type the
      primary
    category: interaction
    binding_evidence:
      - suite: TST-MBR-MEM-024
        source: >-
          services-membership:modules/memberships/tests/integration/services/affiliations.integration.spec.ts#writes
          a staff term’s chapters from its first day, the first of the type the
          primary
      - suite: TST-MBR-MEM-024
        source: >-
          services-membership:modules/memberships/tests/integration/services/affiliations.integration.spec.ts#carries
          the previous term’s chapters into a staff renewal that names none, as
          inherited
      - suite: TST-MBR-MEM-054
        source: >-
          services-membership:tests/acceptance/affiliations/MBR-ACC-0271.acceptance.ts#MBR-ACC-0271:
          A staff renewal carries Jo's chapters into the new term, a renewal
          with an empty list carries nothing, and corrections and terminations
          keep every row inside its term
  - id: ATS-MBR-MEM-007-08
    title: End or withdraw a row while preserving transfer lineage
    level: api
    proves:
      - BR-CAP-MBR-MEM-007-08
    preconditions: >-
      The fixture includes an ordinary row, a never-started row and a
      transferred row with a continuation.
    steps:
      - do: >-
          Shorten an ordinary row, withdraw a never-started row, and attempt
          withdrawal of the continued row.
        expect: >-
          Ending retains its shortened row; withdrawal removes the unused row;
          the continued row remains and the refusal identifies its continuation.
        provenance: test
        source:
          - >-
            services-membership:modules/memberships/tests/integration/services/affiliation-withdrawal-continued.integration.spec.ts#refuses
            to withdraw the continued row, naming the affiliation that continues
            it, and keeps the row
          - >-
            services-membership:modules/memberships/tests/integration/services/affiliation-withdrawal-continued.integration.spec.ts#still
            ends the continued row on a day it held
          - >-
            services-membership:tests/acceptance/affiliations/MBR-ACC-0264.acceptance.ts#MBR-ACC-0264:
            Withdrawing a chapter that never held deletes the row but the
            versions keep it; an end must shorten; the reason on an end is
            accepted and lost
    expected: >-
      Ending retains its shortened row; withdrawal removes the unused row; the
      continued row remains and the refusal identifies its continuation.
    negative: false
    data_needs: >-
      Membership terms, dated affiliation rows, unit settings and
      operation-specific callers or connections.
    bound_to:
      - TST-MBR-MEM-022
      - TST-MBR-MEM-048
    provenance: test
    source: >-
      services-membership:modules/memberships/tests/integration/services/affiliation-withdrawal-continued.integration.spec.ts#refuses
      to withdraw the continued row, naming the affiliation that continues it,
      and keeps the row
    category: transition
    binding_evidence:
      - suite: TST-MBR-MEM-022
        source: >-
          services-membership:modules/memberships/tests/integration/services/affiliation-withdrawal-continued.integration.spec.ts#refuses
          to withdraw the continued row, naming the affiliation that continues
          it, and keeps the row
      - suite: TST-MBR-MEM-022
        source: >-
          services-membership:modules/memberships/tests/integration/services/affiliation-withdrawal-continued.integration.spec.ts#still
          ends the continued row on a day it held
      - suite: TST-MBR-MEM-048
        source: >-
          services-membership:tests/acceptance/affiliations/MBR-ACC-0264.acceptance.ts#MBR-ACC-0264:
          Withdrawing a chapter that never held deletes the row but the versions
          keep it; an end must shorten; the reason on an end is accepted and
          lost
  - id: ATS-MBR-MEM-007-09
    title: Move primary designation across overlapping rows
    level: api
    proves:
      - BR-CAP-MBR-MEM-007-09
    preconditions: 'Atlanta and Savannah overlap on one term, with Atlanta currently primary.'
    steps:
      - do: Make Savannah primary and inspect both rows’ complete spans.
        expect: >-
          Savannah becomes primary and the overlapping Atlanta row loses its
          flag for its whole span.
        provenance: test
        source:
          - >-
            services-membership:modules/memberships/tests/integration/services/affiliations.integration.spec.ts#makes
            an affiliation the primary of its type and the other one no longer
    expected: >-
      Savannah becomes primary and the overlapping Atlanta row loses its flag
      for its whole span.
    negative: false
    data_needs: >-
      Membership terms, dated affiliation rows, unit settings and
      operation-specific callers or connections.
    bound_to:
      - TST-MBR-MEM-024
    provenance: test
    source: >-
      services-membership:modules/memberships/tests/integration/services/affiliations.integration.spec.ts#makes
      an affiliation the primary of its type and the other one no longer
    category: transition
    binding_evidence:
      - suite: TST-MBR-MEM-024
        source: >-
          services-membership:modules/memberships/tests/integration/services/affiliations.integration.spec.ts#makes
          an affiliation the primary of its type and the other one no longer
  - id: ATS-MBR-MEM-007-10
    title: Reject an outdated affiliation version
    level: api
    proves:
      - BR-CAP-MBR-MEM-007-10
    preconditions: An affiliation row has changed since the caller read it.
    steps:
      - do: Submit an ending or primary change with the older row version.
        expect: >-
          The request reports a version mismatch and does not overwrite the
          current row.
        provenance: test
        source:
          - >-
            services-membership:modules/memberships/tests/integration/services/affiliations.integration.spec.ts#refuses
            an affiliation change read at an older version (version_mismatch)
    expected: >-
      The request reports a version mismatch and does not overwrite the current
      row.
    negative: true
    data_needs: >-
      Membership terms, dated affiliation rows, unit settings and
      operation-specific callers or connections.
    bound_to:
      - TST-MBR-MEM-024
    provenance: test
    source: >-
      services-membership:modules/memberships/tests/integration/services/affiliations.integration.spec.ts#refuses
      an affiliation change read at an older version (version_mismatch)
    category: concurrency
    binding_evidence:
      - suite: TST-MBR-MEM-024
        source: >-
          services-membership:modules/memberships/tests/integration/services/affiliations.integration.spec.ts#refuses
          an affiliation change read at an older version (version_mismatch)
  - id: ATS-MBR-MEM-007-11
    title: Serialize affiliation selection against unit merging
    level: api
    proves:
      - BR-CAP-MBR-MEM-007-11
    preconditions: Two database connections operate on the same active unit.
    steps:
      - do: >-
          Hold the unit’s merge lock while adding; separately hold its
          affiliation share lock while requesting the merge lock.
        expect: >-
          The add blocks and rejects the committed merged status; the merge lock
          blocks while the share lock is held.
        provenance: test
        source:
          - >-
            services-membership:modules/memberships/tests/integration/services/affiliation-add-concurrency.integration.spec.ts#waits
            for a merge in flight and is then refused, because the unit it read
            is merged
          - >-
            services-membership:modules/memberships/tests/integration/services/affiliation-add-concurrency.integration.spec.ts#makes
            a merge wait for an add in flight, so the merge’s plan sees the add
            committed
    expected: >-
      The add blocks and rejects the committed merged status; the merge lock
      blocks while the share lock is held.
    negative: false
    data_needs: >-
      Membership terms, dated affiliation rows, unit settings and
      operation-specific callers or connections.
    bound_to:
      - TST-MBR-MEM-021
    provenance: test
    source: >-
      services-membership:modules/memberships/tests/integration/services/affiliation-add-concurrency.integration.spec.ts#waits
      for a merge in flight and is then refused, because the unit it read is
      merged
    category: concurrency
    binding_evidence:
      - suite: TST-MBR-MEM-021
        source: >-
          services-membership:modules/memberships/tests/integration/services/affiliation-add-concurrency.integration.spec.ts#waits
          for a merge in flight and is then refused, because the unit it read is
          merged
      - suite: TST-MBR-MEM-021
        source: >-
          services-membership:modules/memberships/tests/integration/services/affiliation-add-concurrency.integration.spec.ts#makes
          a merge wait for an add in flight, so the merge’s plan sees the add
          committed
  - id: ATS-MBR-MEM-007-12
    title: Return each member once in chapter and ancestor rosters
    level: api
    proves:
      - BR-CAP-MBR-MEM-007-12
    preconditions: >-
      Jo holds chapter affiliations to Atlanta and Savannah within one
      hierarchy.
    steps:
      - do: >-
          Read each chapter, its ancestors with descendants, the ancestor
          without descendants and the unrelated Western Region.
        expect: >-
          Chapter and ancestor results include Jo once; an ancestor’s own roster
          without descendants and the Western Region exclude her.
        provenance: test
        source:
          - >-
            services-membership:tests/e2e/s05-multiple-chapters.e2e.spec.ts#returns
            Jo in the Atlanta and in the Savannah roster
          - >-
            services-membership:tests/e2e/s05-multiple-chapters.e2e.spec.ts#returns
            Jo once in the Southeast Zone, Eastern Region and National rosters
          - >-
            services-membership:tests/e2e/s05-multiple-chapters.e2e.spec.ts#stores
            no affiliation above a chapter: the zone’s own roster, without its
            descendants, has no Jo
          - >-
            services-membership:tests/e2e/s05-multiple-chapters.e2e.spec.ts#returns
            Jo in no roster of the Western Region
    expected: >-
      Chapter and ancestor results include Jo once; an ancestor’s own roster
      without descendants and the Western Region exclude her.
    negative: false
    data_needs: >-
      Membership terms, dated affiliation rows, unit settings and
      operation-specific callers or connections.
    bound_to:
      - TST-MBR-MEM-248
    provenance: test
    source: >-
      services-membership:tests/e2e/s05-multiple-chapters.e2e.spec.ts#returns Jo
      in the Atlanta and in the Savannah roster
    category: interaction
    binding_evidence:
      - suite: TST-MBR-MEM-248
        source: >-
          services-membership:tests/e2e/s05-multiple-chapters.e2e.spec.ts#returns
          Jo in the Atlanta and in the Savannah roster
      - suite: TST-MBR-MEM-248
        source: >-
          services-membership:tests/e2e/s05-multiple-chapters.e2e.spec.ts#returns
          Jo once in the Southeast Zone, Eastern Region and National rosters
      - suite: TST-MBR-MEM-248
        source: >-
          services-membership:tests/e2e/s05-multiple-chapters.e2e.spec.ts#stores
          no affiliation above a chapter: the zone’s own roster, without its
          descendants, has no Jo
      - suite: TST-MBR-MEM-248
        source: >-
          services-membership:tests/e2e/s05-multiple-chapters.e2e.spec.ts#returns
          Jo in no roster of the Western Region
  - id: ATS-MBR-MEM-007-13
    title: Carry ending chapters into an undated renewal
    category: interaction
    level: api
    proves:
      - BR-CAP-MBR-MEM-002-02
      - BR-CAP-MBR-MEM-007-07
    interacts_with:
      - CAP-MBR-MEM-002
    workflows:
      - WF-MBR-MEM-002
    relies_on:
      - ATS-MBR-MEM-002-02
      - ATS-MBR-MEM-007-07
    preconditions: A principal holding has a current term with permitted chapters.
    steps:
      - do: >-
          Renew without a chapter list, then try a separate renewal with an
          empty list under a required minimum.
        expect: >-
          Omission creates inherited chapter rows on the new term; the
          empty-list attempt leaves no additional term.
        provenance: proposed
        source: &ref_0
          - >-
            services-membership:modules/memberships/tests/integration/services/staff-operations.integration.spec.ts#adds
            a renewal continuing the latest term when no dates are given
          - >-
            services-membership:modules/memberships/tests/integration/services/affiliations.integration.spec.ts#writes
            a staff term’s chapters from its first day, the first of the type
            the primary
    expected: >-
      Omission creates inherited chapter rows on the new term; the empty-list
      attempt leaves no additional term.
    negative: false
    data_needs: >-
      An isolated workspace with the specified membership, package, chapter and
      partner-port fixtures.
    bound_to: []
    provenance: proposed
    source: *ref_0
  - id: ATS-MBR-MEM-007-14
    title: Keep child chapter coverage inside mirrored periods
    category: interaction
    level: api
    proves:
      - BR-CAP-MBR-MEM-006-07
      - BR-CAP-MBR-MEM-007-03
    interacts_with:
      - CAP-MBR-MEM-006
    workflows:
      - WF-MBR-MEM-002
    relies_on:
      - ATS-MBR-MEM-006-07
      - ATS-MBR-MEM-007-03
    preconditions: >-
      A child mirrors an organizational period and has allowed chapter
      connections.
    steps:
      - do: >-
          Shorten the parental period, then inspect the child period and its
          dated chapter answer.
        expect: >-
          Child coverage contracts with its source and no chapter answer extends
          beyond the contracted child period.
        provenance: proposed
        source: &ref_1
          - >-
            services-membership:modules/memberships/tests/integration/services/organization-children.integration.spec.ts#re-mirrors
            the children when the parent’s end is corrected: a child never
            outlasts the parent
          - >-
            services-membership:modules/memberships/tests/unit/unit-rules.spec.ts#refuses
            fewer affiliations of a type than its minimum from the day the
            operation takes effect
    expected: >-
      Child coverage contracts with its source and no chapter answer extends
      beyond the contracted child period.
    negative: false
    data_needs: >-
      An isolated workspace with the specified membership, package, chapter and
      partner-port fixtures.
    bound_to: []
    provenance: proposed
    source: *ref_1
  - id: ATS-MBR-MEM-007-15
    title: Protect transfer lineage when ending its predecessor
    category: interaction
    level: api
    proves:
      - BR-CAP-MBR-MEM-007-08
      - BR-CAP-MBR-MEM-008-01
    interacts_with:
      - CAP-MBR-MEM-008
    workflows:
      - WF-MBR-MEM-009
    relies_on:
      - ATS-MBR-MEM-007-08
      - ATS-MBR-MEM-008-01
    preconditions: An affiliation has a successor created by transfer.
    steps:
      - do: 'Attempt to withdraw the predecessor, then end it on a day it held.'
        expect: >-
          Withdrawal is refused naming the successor; an allowed end preserves
          the lineage.
        provenance: proposed
        source: &ref_2
          - >-
            services-membership:modules/memberships/tests/integration/services/affiliation-withdrawal-continued.integration.spec.ts#refuses
            to withdraw the continued row, naming the affiliation that continues
            it, and keeps the row
          - >-
            services-membership:modules/memberships/tests/integration/services/affiliations.integration.spec.ts#transfers
            to a chapter that sells no dues: the old row ends the day before,
            the new one continues it as primary
    expected: >-
      Withdrawal is refused naming the successor; an allowed end preserves the
      lineage.
    negative: false
    data_needs: >-
      An isolated workspace with the specified membership, package, chapter and
      partner-port fixtures.
    bound_to: []
    provenance: proposed
    source: *ref_2
  - id: ATS-MBR-MEM-007-16
    title: Make selected chapter dues part of the checkout plan
    category: interaction
    level: api
    proves:
      - BR-CAP-MBR-MEM-007-06
      - BR-CAP-MBR-MEM-009-07
    interacts_with:
      - CAP-MBR-MEM-009
    workflows: []
    relies_on:
      - ATS-MBR-MEM-007-06
      - ATS-MBR-MEM-009-07
    preconditions: A package permits a chapter that sells dues.
    steps:
      - do: >-
          Prepare the package without its selected chapter dues line, then
          include the dues line and fulfil the placed purchase.
        expect: >-
          The incomplete checkout is refused; the completed checkout creates the
          paid chapter affiliation.
        provenance: proposed
        source: &ref_3
          - >-
            services-membership:modules/memberships/tests/integration/services/affiliations.integration.spec.ts#refuses
            to add a chapter that sells dues for the package, naming the
            Commerce amendment (requires_amendment)
          - >-
            services-membership:modules/commerce-participant/tests/integration/participant.integration.spec.ts#plans
            a join: kind, service period from the package rule, the dues
            chapter, audience new, a sql claim, no amount
    expected: >-
      The incomplete checkout is refused; the completed checkout creates the
      paid chapter affiliation.
    negative: false
    data_needs: >-
      An isolated workspace with the specified membership, package, chapter and
      partner-port fixtures.
    bound_to: []
    provenance: proposed
    source: *ref_3
  - id: ATS-MBR-MEM-007-17
    title: Scope expiry attention through current chapters
    category: interaction
    level: api
    proves:
      - BR-CAP-MBR-MEM-007-12
      - BR-CAP-MBR-MEM-014-04
    interacts_with:
      - CAP-MBR-MEM-014
    workflows:
      - WF-MBR-MEM-002
    relies_on:
      - ATS-MBR-MEM-007-12
      - ATS-MBR-MEM-014-04
    preconditions: Publication is enabled for a member with two chapters sharing ancestors.
    steps:
      - do: Sweep for approaching expiry and inspect the published item scope.
        expect: >-
          The item reaches the selected chapters and their ancestors before the
          workspace scope.
        provenance: proposed
        source: &ref_4
          - >-
            services-membership:tests/e2e/s05-multiple-chapters.e2e.spec.ts#returns
            Jo in the Atlanta and in the Savannah roster
          - >-
            services-membership:modules/memberships/tests/integration/services/expiring-memberships.integration.spec.ts#scopes
            the item by the membership’s chapter and its ancestors, most
            specific first, then the tenant
    expected: >-
      The item reaches the selected chapters and their ancestors before the
      workspace scope.
    negative: false
    data_needs: >-
      An isolated workspace with the specified membership, package, chapter and
      partner-port fixtures.
    bound_to: []
    provenance: proposed
    source: *ref_4
  - id: ATS-MBR-MEM-007-18
    title: Check every affected chapter before a primary change
    category: interaction
    level: api
    proves:
      - BR-CAP-MBR-MEM-007-09
      - BR-CAP-MBR-MEM-015-07
    interacts_with:
      - CAP-MBR-MEM-015
    workflows:
      - WF-MBR-MEM-009
    relies_on:
      - ATS-MBR-MEM-007-09
      - ATS-MBR-MEM-015-06
    preconditions: An officer reaches only one of a member’s two chapters.
    steps:
      - do: >-
          Try to make that chapter primary when the other would lose its flag,
          then repeat as an officer reaching both.
        expect: >-
          The first request changes neither row; the second can change the
          primary designation.
        provenance: proposed
        source: &ref_5
          - >-
            services-membership:modules/memberships/tests/integration/services/affiliations.integration.spec.ts#makes
            an affiliation the primary of its type and the other one no longer
          - >-
            services-membership:modules/memberships/tests/integration/services/unit-scope.integration.spec.ts#refuses
            the Atlanta officer ending Jo’s Savannah row, out_of_scope naming
            Savannah
    expected: >-
      The first request changes neither row; the second can change the primary
      designation.
    negative: false
    data_needs: >-
      An isolated workspace with the specified membership, package, chapter and
      partner-port fixtures.
    bound_to: []
    provenance: proposed
    source: *ref_5
evidence:
  - >-
    services-membership at 5994c270e8a37a30f848e99ba5b5ee6b87c08893: reviewed
    affiliation schemas and operations, unit-count calculation, deferred binding
    checks, dated listing and the cited integration, acceptance and concurrency
    assertions.
  - >-
    rhythm-v2-docs:specs/membership/memberships/design/: domain objects, state
    models and workflows reviewed for coverage.
coverage:
  rule: 'gap: FND-MBR-MEM-089'
  transition: 'gap: FND-MBR-MEM-089'
  validation: covered
  permission: 'gap: FND-MBR-MEM-089'
  edge: 'gap: FND-MBR-MEM-089'
  failure: 'gap: FND-MBR-MEM-089'
  boundary: covered
  concurrency: covered
  invariant: 'gap: FND-MBR-MEM-089'
  interaction: covered
coverage_notes:
  transition: >-
    The scenarios do not enumerate every applicable object transition; the
    finding preserves the remaining transition matrix.
  permission: >-
    The finding records named permissions without a complete positive and
    negative proof.
  invariant: >-
    Existing invariant examples do not cover every applicable domain-object
    constraint.
  interaction: >-
    Every related capability and each cross-capability workflow has an explicit
    composite scenario. Unbound composites remain proposed.
---

# Maintain dated chapter and section affiliations: Capability Test Specification

## Coverage

| Rule | Scenario or Finding |
|---|---|
| `BR-CAP-MBR-MEM-007-01` | `ATS-MBR-MEM-007-01` |
| `BR-CAP-MBR-MEM-007-02` | `ATS-MBR-MEM-007-02` |
| `BR-CAP-MBR-MEM-007-03` | `ATS-MBR-MEM-007-03`, `ATS-MBR-MEM-007-14` |
| `BR-CAP-MBR-MEM-007-04` | `ATS-MBR-MEM-007-04` |
| `BR-CAP-MBR-MEM-007-05` | `ATS-MBR-MEM-007-05` |
| `BR-CAP-MBR-MEM-007-06` | `ATS-MBR-MEM-007-06`, `ATS-MBR-MEM-007-16` |
| `BR-CAP-MBR-MEM-007-07` | `ATS-MBR-MEM-007-07`, `ATS-MBR-MEM-007-13` |
| `BR-CAP-MBR-MEM-007-08` | `ATS-MBR-MEM-007-08`, `ATS-MBR-MEM-007-15` |
| `BR-CAP-MBR-MEM-007-09` | `ATS-MBR-MEM-007-09`, `ATS-MBR-MEM-007-18` |
| `BR-CAP-MBR-MEM-007-10` | `ATS-MBR-MEM-007-10` |
| `BR-CAP-MBR-MEM-007-11` | `ATS-MBR-MEM-007-11` |
| `BR-CAP-MBR-MEM-007-12` | `ATS-MBR-MEM-007-12`, `ATS-MBR-MEM-007-17` |
| `BR-CAP-MBR-MEM-007-13` | no scenario: `FND-MBR-MEM-023` |
| `BR-CAP-MBR-MEM-007-14` | no scenario: `FND-MBR-MEM-022` |

## Interactions With Related Capabilities

The interaction cases test how a shared holding, period, chapter connection or recorded change affects related work. Each case names its related capabilities and workflows in frontmatter. A composite case remains proposed until executable assertions establish every part of its expected outcome.
