---
id: STATE-MBR-MEM-007
title: Billing run lifecycle
object: DOM-MBR-MEM-005
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: draft
    meaning: The batch exists without a candidate plan.
  - name: planned
    meaning: Candidate actions and their reviewed versions are available.
  - name: executing
    meaning: An execution job is assigned to process this batch.
  - name: executed
    meaning: Execution has settled the available planned actions.
  - name: cancelled
    meaning: The batch was stopped before execution while retaining its plan.
transitions:
  - from: draft
    to: planned
    trigger: Staff or a recurring occurrence plans a draft.
    guard: The submitted run version is current.
    side_effects:
      - 'Classify candidates, insert keyed actions and update plan statistics.'
    who: Membership administrator; the recurring schedule
    provenance: test
    source: >-
      services-membership:modules/billing/tests/unit/run-plan.spec.ts#counts the
      candidates, their classes, the exclusions and the planned actions
  - from: planned
    to: planned
    trigger: Staff replan a planned batch.
    guard: The submitted version matches the locked run.
    side_effects:
      - Add absent actions without resetting settled rows.
    who: Membership administrator
    provenance: test
    source: >-
      services-membership:modules/billing/tests/unit/run-plan.spec.ts#counts the
      candidates, their classes, the exclusions and the planned actions
  - from: planned
    to: executing
    trigger: Staff or configured recurring work starts execution.
    guard: The run is planned and its version matches.
    side_effects:
      - Create the assigned job in the transaction and start it after commit.
    who: Membership administrator; the recurring schedule
    provenance: observed
    source: >-
      services-membership:modules/billing/services/runs/billing-run-operations.ts:executeRun
  - from: executing
    to: executed
    trigger: The job completes its finish step.
    guard: Its execution slice has processed available planned work.
    side_effects:
      - Recount outcomes and finish the job and run.
    who: Durable jobs engine
    provenance: observed
    source: >-
      services-membership:modules/billing/services/execution/billing-run-workflow.ts
      (FinishRun)
  - from: executing
    to: planned
    trigger: The execution failure consequence runs.
    guard: The batch still belongs to this failed job and remains executing.
    side_effects:
      - Retain settled actions and return the run to planned.
    who: Durable jobs engine
    provenance: unknown
    source: FND-MBR-MEM-048
  - from: executed
    to: executing
    trigger: Staff execute a completed batch again.
    guard: The current version is supplied.
    side_effects:
      - Create another job that normally finds no planned work.
    who: Membership administrator
    provenance: observed
    source: >-
      services-membership:modules/billing/services/execution/billing-run-workflow.ts
      (header)
  - from: draft
    to: cancelled
    trigger: Staff cancel an untouched draft.
    guard: The run version is current.
    side_effects:
      - Mark the batch cancelled.
    who: Membership administrator
    provenance: test
    source: >-
      services-membership:tests/acceptance/billing/MBR-ACC-0406.acceptance.ts#MBR-ACC-0406
  - from: planned
    to: cancelled
    trigger: Staff cancel a planned batch.
    guard: Its version is current and execution has not started.
    side_effects:
      - Keep the stored plan for inspection.
    who: Membership administrator
    provenance: test
    source: >-
      services-membership:tests/acceptance/billing/MBR-ACC-0406.acceptance.ts#MBR-ACC-0406
invalid:
  - from: executing
    to: cancelled
    why: Cancellation accepts only draft or planned batches.
  - from: cancelled
    to: planned
    why: Planning rejects a cancelled batch.
  - from: draft
    to: executing
    why: Execution requires a planned or previously executed batch.
concurrency: >-
  Run operations compare a version while holding the row lock. Failure recovery
  checks job ownership before changing state. No deployed reconciler recovers an
  execution job that never starts.
invariants:
  - INV-DOM-MBR-MEM-005-04
evidence:
  - >-
    services-membership at 5994c270: modules/billing/db/billing-vocabularies.ts;
    services/runs/billing-run-operations.ts;
    services/execution/billing-run-workflow.ts, billing-run-failure.ts
---

# Billing run lifecycle

## The Lifecycle

```mermaid
stateDiagram-v2
  state draft
  state planned
  state executing
  state executed
  state cancelled
  draft --> planned
  planned --> planned
  planned --> executing
  executing --> executed
  executed --> executing
  draft --> cancelled
  planned --> cancelled
```

## Transitions Explained

A draft is planned before execution. Replanning adds absent action keys without resetting settled ones. Execution creates a job and finishes the batch after processing; the failure consequence can return its assigned batch to planned.

## What Cannot Happen

Executing batches cannot be cancelled or replanned. Cancelled plans have no resume operation, and drafts cannot execute. Re-executing an executed batch is permitted but normally finds no planned actions.

## Concurrency and Timing

Run operations compare a version while holding the row lock. Failure recovery checks job ownership before changing state. No deployed reconciler recovers an execution job that never starts.
