---
id: WF-MBR-MEM-002
title: 'Add a staff term to renew, reinstate or rejoin'
trigger: Staff request another period without an order and explain the entry.
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-002
  - CAP-MBR-MEM-006
  - CAP-MBR-MEM-007
  - CAP-MBR-MEM-014
moves:
  - STATE-MBR-MEM-001
  - STATE-MBR-MEM-003
  - STATE-MBR-MEM-011
crosses:
  - SVC-MBR-MEM-memberships
  - SVC-MBR-MEM-events
idempotency: >-
  A request key recognizes retries. Explicit dates collide on overlap when
  repeated without a key; undated repeat requests can calculate successive
  periods and both succeed.
concurrency: >-
  The holding lock orders its term writes. It does not order concurrent
  additions to different exclusive programs owned by the same person.
hops:
  - 'n': 1
    actor_or_service: Membership staff through the API
    action: >-
      Lock the principal holding and validate the selected active type and
      package.
    anchor: >-
      services-membership:modules/memberships/services/operations/staff-operations.ts:addTerm
    seam: sync
    on_failure: Return the relevant validation or conflict refusal before committing.
    left_inconsistent: No partial local change remains.
    observer: Caller-visible API result
    provenance: observed
    source: >-
      services-membership:modules/memberships/services/operations/staff-operations.ts:addTerm,
      refuseChild
  - 'n': 2
    actor_or_service: Memberships service
    action: >-
      Calculate the next dates and classify the event using the previous
      effective period and allowed continuity gap.
    anchor: >-
      services-membership:modules/memberships/services/operations/term-events.ts:termEventOf
    seam: sync
    on_failure: Reject the operation before committing any writes.
    left_inconsistent: No partial local change remains.
    observer: Caller-visible API result
    provenance: test
    source: >-
      services-membership:modules/memberships/tests/unit/term-events.spec.ts#is
      a rejoin for a term starting after the reinstatement window
  - 'n': 3
    actor_or_service: Memberships service
    action: >-
      Commit the period and lifecycle and business events; resolve a renewal
      alert when enabled.
    anchor: >-
      services-membership:modules/memberships/services/operations/term-writes.ts:writeCommittedTerm
    seam: sync
    on_failure: Report conflicting coverage and roll back the new period and events.
    left_inconsistent: No partial local change remains.
    observer: Caller-visible API result
    provenance: observed
    source: >-
      services-membership:modules/memberships/services/attention/expiring-memberships.ts:resolveExpiringOnCommit
  - 'n': 4
    actor_or_service: Memberships service
    action: >-
      Insert requested units or inherit the previous period’s ending
      affiliations that remain allowed.
    anchor: >-
      services-membership:modules/memberships/services/affiliations/affiliation-operations.ts:carriedAffiliations
    seam: sync
    on_failure: Return the violated unit rule and commit no changes.
    left_inconsistent: No partial local change remains.
    observer: Caller-visible API result
    provenance: observed
    source: >-
      services-membership:modules/memberships/services/affiliations/affiliation-operations.ts:writeTermAffiliations,
      carriedAffiliations
  - 'n': 5
    actor_or_service: Memberships service
    action: >-
      Apply renewed grants, derive organizational children and refresh standing
      and continuity caches.
    anchor: >-
      services-membership:modules/memberships/services/operations/staff-operations.ts:addTerm
    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: observed
    source: >-
      services-membership:modules/memberships/services/membership-caches.ts:recomputeMembershipCache
branches:
  - >-
    A continuity-breaking rejoin creates another episode without resetting the
    original join date.
  - >-
    Another period can choose a different type or package belonging to the same
    program.
waits: []
evidence:
  - >-
    services-membership at 5994c270:
    modules/memberships/services/operations/staff-operations.ts, term-writes.ts,
    term-events.ts; services/affiliations/affiliation-operations.ts;
    services/membership-caches.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-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]
---

# Add a staff term to renew, reinstate or rejoin

## What It Does

Staff add coverage to an existing principal holding. Period calculation identifies renewal, reinstatement or rejoin and carries permitted chapters into the new period.

## The Flow

```mermaid
flowchart TD
  H1["Lock the principal holding and validate the selected active type and package"]
  H2["Calculate the next dates and classify the event using the previous effective period and allowed continuity gap"]
  H1 --> H2
  H3["Commit the period and lifecycle and business events; resolve a renewal alert when enabled"]
  H2 --> H3
  H4["Insert requested units or inherit the previous period’s ending affiliations that remain allowed"]
  H3 --> H4
  H5["Apply renewed grants, derive organizational children and refresh standing and continuity caches"]
  H4 --> H5
```

## When Something Fails

All local effects share one transaction, so refusal preserves the earlier holding. Two concurrent undated renewals can both book periods, and independent program locks leave the existing exclusivity race unresolved.

## Open Design Questions

Product needs a repeat-request policy for undated renewals and a decision on locking exclusive holdings by owner.
