---
id: WF-MBR-MEM-004
title: Terminate or cancel a term and close what follows it
trigger: >-
  Staff request closure, or a billing drop calls termination with its configured
  reason.
product_area: membership
module: memberships
revision: 1
status: draft
design_intent: proposed
implementation_evidence: observed
inference: []
source_sha:
  services-membership: 5994c270e8a37a30f848e99ba5b5ee6b87c08893
  react-console: baf6dae382d6f41dce976c7f848667ccc37e076f
implements:
  - CAP-MBR-MEM-003
  - CAP-MBR-MEM-006
  - CAP-MBR-MEM-013
  - CAP-MBR-MEM-014
  - CAP-MBR-MEM-020
moves:
  - STATE-MBR-MEM-003
  - STATE-MBR-MEM-005
  - STATE-MBR-MEM-011
  - STATE-MBR-MEM-013
crosses:
  - SVC-MBR-MEM-memberships
  - SVC-MBR-MEM-billing
  - SVC-MBR-MEM-events
idempotency: >-
  Staff repeats meet a stale version after success. A billing action records its
  result with the drop and does not attempt a settled action again.
concurrency: >-
  The owning membership lock and term version order closure against other term
  changes.
hops:
  - 'n': 1
    actor_or_service: Membership staff or a billing run
    action: >-
      Lock the holding, compare the term version and validate a termination
      reason.
    anchor: >-
      services-membership:modules/memberships/services/operations/staff-operations.ts:terminateTerm
    seam: sync
    on_failure: Reject a stale version or a reason outside its permitted use.
    left_inconsistent: No partial local change remains.
    observer: Staff result or billing action refusal
    provenance: observed
    source: >-
      services-membership:modules/memberships/services/operations/staff-operations.ts:terminateTerm
  - 'n': 2
    actor_or_service: Memberships service
    action: >-
      Cancel coverage effective on or before its first day; otherwise terminate
      it and shorten the end when necessary.
    anchor: >-
      services-membership:modules/memberships/services/operations/staff-operations.ts:terminateTerm
    seam: sync
    on_failure: An error aborts the transaction and reverses its writes.
    left_inconsistent: No partial local change remains.
    observer: Caller-visible API result
    provenance: test
    source: >-
      services-membership:modules/events/tests/integration/business-events.integration.spec.ts#states
      membership.term.cancelled, not terminated, for a term that had n
  - 'n': 3
    actor_or_service: Memberships service
    action: >-
      Bound affiliations to the revised term, write closure events and resolve
      enabled expiry attention.
    anchor: >-
      services-membership:modules/memberships/services/attention/expiring-memberships.ts:resolveExpiringOnClose
    seam: sync
    on_failure: 'If enabled attention resolution refuses, abort the business transaction.'
    left_inconsistent: No partial local change remains.
    observer: Caller-visible API result
    provenance: observed
    source: >-
      services-membership:modules/memberships/services/operations/staff-operations.ts:terminateTerm
  - 'n': 4
    actor_or_service: Memberships service
    action: >-
      Propagate closure to source-linked grant and child periods with their
      business events.
    anchor: >-
      services-membership:modules/memberships/services/operations/staff-operations.ts:followParent
    seam: sync
    on_failure: An error aborts the transaction and reverses its writes.
    left_inconsistent: No partial local change remains.
    observer: Caller-visible API result
    provenance: test
    source: >-
      services-membership:tests/acceptance/memberships/MBR-ACC-0182.acceptance.ts#MBR-ACC-0182
  - 'n': 5
    actor_or_service: Change-events consumer
    action: >-
      After commit, deliver the termination to Committees when its receiver is
      configured.
    anchor: >-
      services-membership:modules/events/services/handlers/committees-membership-events.ts:committeesMembershipEventsHandler
    seam: event
    on_failure: >-
      Report failed delivery for retry and eventual dead-letter isolation with
      an alarm.
    left_inconsistent: >-
      Membership closure is durable while appointment changes can remain
      pending.
    observer: Dead-letter alarm and appointment records
    provenance: test
    source: >-
      services-membership:modules/events/tests/integration/change-events-dispatch.integration.spec.ts#gives
      Committees the business event’s own id
branches:
  - >-
    A late billing drop retains the already elapsed term dates and records the
    decision separately.
waits:
  - >-
    Configured Committees delivery can wait through retries and has no
    guaranteed completion interval.
evidence:
  - >-
    services-membership at 5994c270:
    modules/memberships/services/operations/staff-operations.ts;
    services/attention/expiring-memberships.ts;
    modules/billing/services/execution/execute-action.ts:drop;
    modules/events/services/handlers/*
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]
---

# Terminate or cancel a term and close what follows it

## What It Does

Staff and billing end coverage through the same closure path. Started periods become terminated; unstarted periods become cancelled, and linked coverage follows the result.

## The Flow

```mermaid
flowchart TD
  H1["Lock the holding, compare the term version and validate a termination reason"]
  H2["Cancel coverage effective on or before its first day; otherwise terminate it and shorten the end when necessary"]
  H1 --> H2
  H3["Bound affiliations to the revised term, write closure events and resolve enabled expiry attention"]
  H2 --> H3
  H4["Propagate closure to source-linked grant and child periods with their business events"]
  H3 --> H4
  H5["After commit, deliver the termination to Committees when its receiver is configured"]
  H4 --> H5
```

## When Something Fails

Local refusal restores the previous state through rollback. Configured Committees delivery is separate: failure leaves membership closed while the receiver has not acted, and repeated queue failure reaches the dead-letter queue. A new period is needed to restore closed coverage.

## Open Design Questions

A late lapse communicates the period’s last day, which can precede the detection date substantially.
