---
id: STATE-MBR-MEM-008
title: Billing run action outcome
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: planned
    meaning: The action is eligible for its first execution attempt.
  - name: done
    meaning: 'Its order, communication request or local drop effect completed.'
  - name: skipped
    meaning: >-
      Current facts leave no applicable work, including later coverage or a
      missing recipient.
  - name: stale
    meaning: 'The reviewed term changed or disappeared, preventing the planned effect.'
  - name: failed
    meaning: A supported refusal was recorded with its reason.
transitions:
  - from: planned
    to: done
    trigger: Execution performs the planned effect.
    guard: The reviewed term remains current and the effect succeeds.
    side_effects:
      - >-
        Retain the resulting order or communication reference, or record
        successful drop.
    who: Billing run execution job
    provenance: test
    source: >-
      services-membership:modules/billing/tests/integration/billing-runs.integration.spec.ts#executes
      on the jobs engine: one order per renewing candidate
  - from: planned
    to: skipped
    trigger: Execution finds no applicable effect.
    guard: >-
      Later coverage prevents ordering, or a communication recipient is
      unavailable.
    side_effects:
      - Record the skipped reason.
    who: Billing run execution job
    provenance: test
    source: >-
      services-membership:tests/acceptance/billing/MBR-ACC-0418.acceptance.ts#MBR-ACC-0418
  - from: planned
    to: stale
    trigger: The candidate no longer matches the reviewed version.
    guard: The term or owning holding disappeared or the term version changed.
    side_effects:
      - Record stale outcome without performing the effect.
    who: Billing run execution job
    provenance: test
    source: >-
      services-membership:modules/billing/tests/integration/billing-runs.integration.spec.ts#refuses
      as stale an action whose term changed after planning
  - from: planned
    to: failed
    trigger: A supported operation refuses the work.
    guard: >-
      The handler recognizes the refusal instead of throwing an unexpected
      error.
    side_effects:
      - Store the refusal code and bounded explanation.
    who: Billing run execution job
    provenance: observed
    source: >-
      services-membership:modules/billing/services/execution/execute-action.ts:executeOrder
invalid:
  - from: done
    to: planned
    why: No supported reset reopens a settled action.
  - from: failed
    to: planned
    why: >-
      A failed action remains settled; another billing batch supplies a new
      action.
concurrency: >-
  Notice and drop settle in their database transaction. Order preparation checks
  under lock, then placement runs outside that transaction and settlement
  follows; duplicate prevention relies on the stable Commerce order key.
invariants:
  - INV-DOM-MBR-MEM-005-03
  - INV-DOM-MBR-MEM-005-05
  - INV-DOM-MBR-MEM-005-06
  - INV-DOM-MBR-MEM-005-07
evidence:
  - >-
    services-membership at 5994c270: modules/billing/db/billing-vocabularies.ts
    (BILLING_ACTION_STATUSES); services/execution/execute-action.ts,
    billing-notices.ts
---

# Billing run action outcome

## The Lifecycle

```mermaid
stateDiagram-v2
  state planned
  state done
  state skipped
  state stale
  state failed
  planned --> done
  planned --> skipped
  planned --> stale
  planned --> failed
```

## Transitions Explained

Each action starts planned and settles into an outcome. Done confirms its requested effect; skipped records that current facts need no work. Stale protects the reviewed term version, while failed records a supported refusal.

## What Cannot Happen

Settled rows have no normal reset to planned. Executing the same run again skips those outcomes rather than repeating their effects.

## Concurrency and Timing

Notice and drop settle in their database transaction. Order preparation checks under lock, then placement runs outside that transaction and settlement follows; duplicate prevention relies on the stable Commerce order key.
