---
id: STATE-MBR-MEM-002
title: Membership Commerce fence
object: DOM-MBR-MEM-001
product_area: membership
module: memberships
revision: 1
status: draft
design_intent: proposed
implementation_evidence: partially-observed
source_sha:
  services-membership: 5994c270e8a37a30f848e99ba5b5ee6b87c08893
  react-console: baf6dae382d6f41dce976c7f848667ccc37e076f
states:
  - name: unfenced
    meaning: Purchase work has no outstanding Commerce fence.
  - name: cancellation_pending
    meaning: A claimed cancellation blocks competing purchase work until completion.
  - name: amendment_pending
    meaning: >-
      A claimed amendment holds the membership, but amendment completion is
      unavailable.
  - name: renewal_pending
    meaning: >-
      The vocabulary includes a renewal fence that no current owner function
      writes.
transitions:
  - from: unfenced
    to: cancellation_pending
    trigger: Commerce claims a line cancellation.
    guard: The owner function finds the referenced Membership term.
    side_effects:
      - Store the cancellation document alongside its fence.
    who: 'Commerce, through the owner function'
    provenance: test
    source: >-
      services-membership:tests/e2e/commerce-cancellation.e2e.spec.ts#fences the
      membership in TX-K, refusing a competing purchase meanwhile
  - from: cancellation_pending
    to: unfenced
    trigger: The cancellation obligation completes.
    guard: The obligation identifies the claimed cancellation.
    side_effects:
      - Close the period and clear its cancellation fence.
    who: 'Commerce, through cancel'
    provenance: test
    source: >-
      services-membership:tests/e2e/commerce-cancellation.e2e.spec.ts#terminates
      the term the day before the effective date, ends its chapter, clears the
      fence
  - from: unfenced
    to: amendment_pending
    trigger: Commerce claims a line amendment.
    guard: The owner function resolves the referenced term.
    side_effects:
      - Store the amendment reference and pending fence.
    who: 'Commerce, through the owner function'
    provenance: observed
    source: >-
      services-membership:db/migrations/20261018044117_commerce_participant.sql:commerce_claim_change
invalid:
  - from: amendment_pending
    to: unfenced
    why: No implemented amendment-completion operation clears this fence.
  - from: unfenced
    to: renewal_pending
    why: Current owner functions do not write the declared renewal fence.
concurrency: >-
  Claims share Commerce’s transaction and take the holding lock. Preparation
  rejects fenced work, while fulfilment treats an outstanding fence as
  retryable.
invariants:
  - INV-DOM-MBR-MEM-001-11
evidence:
  - >-
    services-membership at 5994c270: modules/terms/db/holding-columns.ts
    (COMMERCE_FENCES); db/migrations/20261018044117_commerce_participant.sql;
    services/prepare/eligibility.ts; services/cancellation/cancellation.ts
---

# Membership Commerce fence

## The Lifecycle

```mermaid
stateDiagram-v2
  state unfenced
  state cancellation_pending
  state amendment_pending
  state renewal_pending
  unfenced --> cancellation_pending
  cancellation_pending --> unfenced
  unfenced --> amendment_pending
```

## Transitions Explained

Commerce claims a document and records its fence while cancellation or amendment is pending. Cancellation completion clears its fence. The renewal fence is vocabulary only; pending renewal detection instead reads a pending term.

## What Cannot Happen

Amendment execution is refused and supplies no normal fence-clearing path. A declared renewal fence is not evidence that a writer exists.

## Concurrency and Timing

Claims share Commerce’s transaction and take the holding lock. Preparation rejects fenced work, while fulfilment treats an outstanding fence as retryable.
