---
id: DOM-MBR-MEM-005
title: Billing Run
realises: CON-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
owned_by: SVC-MBR-MEM-billing
readable_by: []
lifecycle: STATE-MBR-MEM-007
custom_fields: none
identity: >-
  Runs and reusable configurations receive stable identifiers. A recurring
  configuration has at most one run for each occurrence date, and each run has a
  unique action key comprising kind, reminder number and term.
attributes:
  - name: template
    kind: reference
    required: false
    computed: false
    notes: >-
      Template filters, action settings and drop reason are copied onto a new
      run, preserving its configuration.
  - name: program
    kind: reference
    required: true
    computed: false
    notes: The program determines the population of ending terms to consider.
  - name: end-date range
    kind: date
    required: true
    computed: false
    notes: The run selects term ends within an ordered inclusive date range.
  - name: as of
    kind: date
    required: false
    computed: false
    notes: >-
      This planning business date classifies candidates and supplies the
      effective date for drops.
  - name: filters and actions
    kind: collection
    required: true
    computed: false
    notes: >-
      Bounded documents specify included types, packages and member flags,
      together with orders, notices, reminders and drops.
  - name: drop reason
    kind: reference
    required: false
    computed: false
    notes: Drops require a configured reason applicable to termination.
  - name: status
    kind: enum
    required: true
    computed: false
    notes: >-
      The run progresses through draft, planned, executing, executed and
      cancelled.
  - name: statistics
    kind: collection
    required: false
    computed: true
    notes: 'Statistics summarize candidate classes, exclusions and action outcomes.'
  - name: planned actions
    kind: collection
    required: false
    computed: false
    notes: >-
      An action stores its candidate, kind, reminder index, reviewed term
      version, result and any order or communication reference.
  - name: execution job
    kind: reference
    required: false
    computed: false
    notes: The job reference connects the run to durable execution steps and events.
  - name: recurring run
    kind: collection
    required: false
    computed: false
    notes: >-
      A recurring configuration identifies its template, local schedule,
      selection offsets, active flag and automatic execution preference.
  - name: version
    kind: number
    required: true
    computed: true
    notes: >-
      Run operations and recurring changes compare the caller’s version with the
      locked current record.
relationships:
  - to: DOM-MBR-MEM-002
    cardinality: one-to-many
    ownership: Actions reference selected terms and preserve the reviewed version.
    cross_service: false
  - to: DOM-MBR-MEM-001
    cardinality: one-to-many
    ownership: >-
      Action selection reads suspension, origin and member preferences from the
      referenced holding.
    cross_service: false
invariants:
  - id: INV-DOM-MBR-MEM-005-01
    statement: Selection bounds and recurring offset bounds must be ordered.
    enforced_at:
      - database
    provenance: observed
    source: >-
      services-membership:modules/billing/db/billing-runs.table.ts:billing_runs_range_check;
      modules/billing/db/recurring-billing-runs.table.ts:recurring_billing_runs_offsets_check
  - id: INV-DOM-MBR-MEM-005-02
    statement: >-
      One recurring configuration cannot create two runs for the same local
      occurrence date.
    enforced_at:
      - database
    provenance: observed
    source: >-
      services-membership:modules/billing/db/billing-runs.table.ts:billing_runs_occurrence_uidx
  - id: INV-DOM-MBR-MEM-005-03
    statement: >-
      A run cannot contain duplicate actions for the same kind, reminder index
      and candidate term.
    enforced_at:
      - database
    provenance: observed
    source: >-
      services-membership:modules/billing/db/billing-run-actions.table.ts:billing_run_actions_key_uidx
  - id: INV-DOM-MBR-MEM-005-04
    statement: >-
      Planning, execution and cancellation require a current version and a
      permitted run state.
    enforced_at:
      - service
    provenance: test
    source: >-
      services-membership:tests/acceptance/billing/MBR-ACC-0406.acceptance.ts#MBR-ACC-0406
  - id: INV-DOM-MBR-MEM-005-05
    statement: >-
      Only planned actions are attempted; local database effects settle with
      their action, while order placement settles afterward.
    enforced_at:
      - service
    provenance: test
    source: >-
      services-membership:modules/billing/tests/integration/billing-runs.integration.spec.ts#refuses
      as stale an action whose term changed after planning
  - id: INV-DOM-MBR-MEM-005-06
    statement: >-
      A candidate whose term version differs from the plan becomes stale without
      performing the action.
    enforced_at:
      - service
    provenance: test
    source: >-
      services-membership:modules/billing/tests/integration/billing-runs.integration.spec.ts#refuses
      as stale an action whose term changed after planning
  - id: INV-DOM-MBR-MEM-005-07
    statement: >-
      Order placement uses a stable action-based key so a cooperating Commerce
      port recognizes repeats.
    enforced_at:
      - service
    provenance: observed
    source: >-
      services-membership:modules/billing/services/execution/execute-action.ts:executeOrder
  - id: INV-DOM-MBR-MEM-005-08
    statement: A dropping template must reference a reason valid for term termination.
    enforced_at:
      - service
    provenance: test
    source: >-
      services-membership:tests/acceptance/billing/MBR-ACC-0402.acceptance.ts#MBR-ACC-0402
  - id: INV-DOM-MBR-MEM-005-09
    statement: >-
      Concurrent recurring changes at the same version allow one winner and
      reject the stale writer.
    enforced_at:
      - service
    provenance: test
    source: >-
      services-membership:modules/billing/tests/integration/recurring-billing-run-concurrency.integration.spec.ts#applies
      one of two changes made at the same version
physical:
  - membership.billing_templates
  - membership.billing_runs
  - membership.billing_run_actions
  - membership.recurring_billing_runs
  - membership.billing_run_jobs
  - membership.billing_run_job_steps
  - membership.billing_run_job_events
  - membership.schedules
  - membership.schedule_runs
evidence:
  - >-
    services-membership at 5994c270: modules/billing/db/*.table.ts,
    billing-vocabularies.ts; services/planning/run-plan.ts,
    billing-documents.ts; services/runs/billing-run-operations.ts;
    services/execution/*; services/recurring/recurring-billing-runs.ts;
    services/configuration/billing-template-records.ts.
---

# Billing Run

## What It Models

A billing run is a reviewable batch of renewal work for one program and end-date range. It separates selection from execution so staff can inspect the proposed work before placing orders, requesting notices or dropping lapsed periods. Templates and recurring schedules reuse that configuration.

## Identity and Attributes

The run copies configuration and stores the planning date, statistics and candidate actions. Each action preserves the term version that staff reviewed. Recurring configuration calculates selection dates from each local occurrence and can request automatic execution.

## Relationships

Actions reference memberships and their candidate terms. Commerce owns resulting orders, and Platform owns requested communications. The run keeps references and outcomes for accountability.

## Invariants

Uniqueness protects recurring occurrences and action keys. Version and status checks protect run changes, while stale-term checks protect execution. Notice and drop effects commit with their result; order placement crosses a separate transaction boundary and relies on the order key.

## How It Is Stored and Shared

Billing owns templates, runs, actions, recurring configuration and execution records. Durable jobs process actions in slices. The Membership schedule dispatcher delivers recurring occurrences. These records declare no custom fields.

## Open Design Questions

Commerce placement is a refusing stub, and notice purposes are not connected to sending. Organization recipients remain undecided. An execution job that never starts has no deployed reconciler to return the run to a usable state.
