---
id: STATE-PFM-OPS-004
title: Licence override lifecycle
product_area: platform
module: operations
revision: 1
status: draft
object: DOM-PFM-OPS-003
design_intent: confirmed
origin: >-
  services-platform:docs/proposals/application-access-and-entitlements.md#10 Decisions (built and accepted by
  Andrew 2026-10-15)
implementation_evidence: observed
source_sha:
  services-platform: ad3f6a6582843008ed0f5a17b131878d15829af1
states:
  - name: scheduled
    meaning: 'The decision exists, but its start instant has not arrived.'
  - name: in force
    meaning: The unrevoked decision is inside its effective period.
  - name: ended
    meaning: 'The end instant has arrived, leaving a historical decision without current effect.'
  - name: revoked
    meaning: 'Staff recorded withdrawal, ending the decision’s effect while preserving its account.'
transitions:
  - from: scheduled
    to: in force
    trigger: The read clock reaches the decision start.
    guard: No withdrawal has been recorded.
    side_effects:
      - No writer runs; the resolver now includes the decision.
    who: 'nobody: derived from the clock'
    provenance: test
    source: >-
      services-platform:modules/licensing/tests/unit/availability/application-availability.spec.ts#is not in
      force at the instant it ends, so a replacement starting there leaves no overlap
  - from: in force
    to: ended
    trigger: The read clock reaches the decision end.
    guard: The decision has a finite end.
    side_effects:
      - No writer or refresh runs; cached access follows expiry.
    who: 'nobody: derived from the clock'
    provenance: test
    source: >-
      services-platform:modules/licensing/tests/unit/availability/application-availability.spec.ts#is not in
      force at the instant it ends, so a replacement starting there leaves no overlap
  - from: in force
    to: revoked
    trigger: Authorized staff withdraw an active decision.
    guard: The decision has not been withdrawn already.
    side_effects:
      - Write withdrawal author and time together.
      - Attempt security-history insertion after commit.
      - Request refresh only if the preceding work succeeds.
    who: Rhythm staff
    provenance: test
    source: >-
      services-platform:modules/licensing/tests/e2e/licensing.e2e.spec.js#refuses to withdraw the same
      override twice, with 409
  - from: scheduled
    to: revoked
    trigger: Staff withdraw a future decision.
    guard: The future decision has not been withdrawn already.
    side_effects:
      - Record withdrawal and attempt the same history and refresh work.
    who: Rhythm staff
    provenance: observed
    source: 'services-platform:modules/licensing/services/persistence/licence-overrides.ts:revokeLicenceOverride'
  - from: ended
    to: revoked
    trigger: Staff withdraw a decision whose period has already ended.
    guard: The historical decision has not been withdrawn already.
    side_effects:
      - 'Record withdrawal and attempt history and refresh, without changing current commercial coverage.'
    who: Rhythm staff
    provenance: observed
    source: 'services-platform:modules/licensing/services/persistence/licence-overrides.ts:revokeLicenceOverride'
invalid:
  - from: revoked
    to: in force
    why: Withdrawal cannot be reversed; any replacement is another decision.
  - from: revoked
    to: revoked
    why: A second withdrawal produces conflict and no refresh request.
  - from: ended
    to: in force
    why: There is no period-edit operation; further coverage needs a new override.
concurrency: >-
  A conditional unrevoked-row update admits one withdrawal. Several effective decisions can coexist; active
  withholds win, and current or grace contract coverage is reported before staff grants.
invariants:
  - INV-DOM-PFM-OPS-003-03
  - INV-DOM-PFM-OPS-003-04
  - INV-DOM-PFM-OPS-003-05
evidence:
  - >-
    services-platform at ad3f6a6: modules/licensing/db/licence-overrides.table.ts,
    services/persistence/licence-overrides.ts, services/enablement/grant-licence-override.ts,
    services/availability/application-availability.ts; docs/licensing.md §3.
  - >-
    codex examination 2026-10-23: checked the pinned source anchors, planning references and enforcement
    boundaries; unresolved limits are recorded in module findings.
---

# Licence override lifecycle

## The Lifecycle

```mermaid
stateDiagram-v2
  [*] --> scheduled: future decision
  [*] --> in_force: effective decision
  scheduled --> in_force: start reached
  in_force --> ended: end reached
  scheduled --> revoked: staff withdrawal
  in_force --> revoked: staff withdrawal
  ended --> revoked: staff withdrawal
  ended --> [*]
  revoked --> [*]
```

## Transitions Explained

A decision’s commercial standing follows its start and end instants without scheduled writes. The start is inclusive and the end exclusive. Staff withdrawal is the persisted change and records the withdrawing person with the time. Its history and refresh work happen after the decision write.

## What Cannot Happen

There is no operation to edit, extend or restore an existing override. A repeat withdrawal is a conflict. Expired and withdrawn decisions remain in staff history while the workspace exists.

## Concurrency and Timing

Natural expiry requests no cache refresh, so cached authority can outlast the instant of commercial expiry within its lifetime. Conditional withdrawal admits only one competing request.
