---
id: STATE-COM-ORD-008
title: Entitlement lifecycle
object: DOM-COM-ORD-004
product_area: commerce
module: orders
revision: 1
status: draft
design_intent: proposed
implementation_evidence: observed
source_sha:
  services-commerce: c8b66a98e2490617aec38ba5c8165dd9bd0a8f9b
states:
  - name: active
    meaning: Consumption is available when the window and allowance permit it.
  - name: revoked
    meaning: 'Cancellation, enforcement or staff ended availability without removing uses.'
  - name: expired
    meaning: The background pass recorded that the validity end has passed.
transitions:
  - from: active
    to: revoked
    trigger: 'A cancellation, enforcement suspension or reasoned staff action revokes availability.'
    guard: The current grant must be active.
    side_effects:
      - retain revocation time and cause-qualified explanation
      - append purchased-benefit revocation history
      - retain the reasoned benefit intervention record
    who: 'System (cancellation, enforcement) or staff with the revoke permission'
    provenance: test
    source: >-
      services-commerce:modules/entitlements/tests/e2e/entitlements.e2e.spec.js#revokes the line’s grant with
      the reason, refuses the download 409 entitlement_not_active, and writes the history
  - from: revoked
    to: active
    trigger: Enforcement restoration revisits its own revocation.
    guard: The recorded reason has the enforcement cause and validity has not ended.
    side_effects:
      - append restored-benefit history
    who: System (enforcement restore)
    provenance: observed
    source: 'services-commerce:modules/entitlements/services/register/grant-handler.ts:enforceForObligation'
  - from: revoked
    to: expired
    trigger: Restoration finds the previously enforced grant beyond its validity end.
    guard: The end of the window has passed.
    side_effects: []
    who: System (enforcement restore)
    provenance: observed
    source: 'services-commerce:modules/entitlements/services/register/grant-handler.ts:enforceForObligation'
  - from: active
    to: expired
    trigger: The expiry pass finds an active grant past its end.
    guard: Status and elapsed validity are rechecked.
    side_effects: []
    who: System (entitlement sweep)
    provenance: observed
    source: 'services-commerce:modules/entitlements/services/register/entitlement-sweeper.ts:sweepEntitlements'
invalid:
  - from: expired
    to: revoked
    why: Staff revocation only accepts active grants.
  - from: expired
    to: active
    why: Ending validity cannot be undone by reopening the expired grant.
concurrency: >-
  Consumption locks eligible grants and checks their windows directly. Scheduled expiry only records the ended
  state and can lag if an earlier shared-sweeper pass fails.
invariants:
  - INV-DOM-COM-ORD-004-04
  - INV-DOM-COM-ORD-004-05
  - INV-DOM-COM-ORD-004-06
evidence:
  - >-
    services-commerce at c8b66a98: modules/entitlements/db/entitlements.table.ts;
    services/register/grant-handler.ts, revocation.ts, entitlement-sweeper.ts, entitlement-events.ts;
    services/entitlements/entitlement-interventions.ts.
---

# Entitlement lifecycle

## The Lifecycle

```mermaid
stateDiagram-v2
  [*] --> active: granted at delivery or by staff
  active --> revoked: cancellation, enforcement or staff
  revoked --> active: enforcement restored
  revoked --> expired: restored after the window
  active --> expired: window passed
```

## Transitions Explained

Grant creation begins active availability. Staff, line cancellation and enforcement can revoke it without erasing use history. Enforcement restoration can reinstate its own revocation or record expiry if the validity end has passed.

## What Cannot Happen

Staff and cancellation revocations are not restored by the enforcement path. Expired windows do not reopen. Exhausting an allowance leaves the grant active, so restoring a use can make it drawable again.

## Concurrency and Timing

Consumption locks eligible grants and checks their windows directly. Scheduled expiry only records the ended state and can lag if an earlier shared-sweeper pass fails.
