---
id: STATE-PFM-ELG-004
title: Bulk run lifecycle
object: DOM-PFM-ELG-003
product_area: platform
module: eligibility
revision: 1
status: draft
design_intent: proposed
implementation_evidence: partially-observed
source_sha:
  services-platform: ad3f6a6582843008ed0f5a17b131878d15829af1
states:
  - name: queued
    meaning: Submission created the run and job; subject evaluation has not begun.
  - name: running
    meaning: The job evaluates subjects and commits pages in sequence.
  - name: succeeded
    meaning: >-
      Evaluation completed and its retained results or export are available
      until intended expiry.
  - name: failed
    meaning: >-
      Execution failed or reconciliation marked abandoned work failed; dependent
      simulation also fails.
  - name: cancelled
    meaning: >-
      Execution was stopped; the lifecycle supports this status without an
      exposed cancellation operation.
  - name: expired
    meaning: >-
      The lifecycle’s retention end; expiry helpers exist without a deployed
      cleanup schedule.
transitions:
  - from: queued
    to: running
    trigger: Population job enters evaluation
    guard: The run and job committed together and the job started after commit.
    side_effects:
      - Begin page evaluation
    who: Population job
    provenance: observed
    source: >-
      services-platform:modules/eligibility/services/population/population-workflow.ts:populationWorkflow
  - from: running
    to: running
    trigger: Population page callback
    guard: The run cursor still matches the page’s starting cursor.
    side_effects:
      - Commit counts and retained subjects with the cursor
      - Write page diagnostics
    who: Population job
    provenance: observed
    source: >-
      services-platform:modules/eligibility/services/population/population-run.ts:evaluatePopulationPage
  - from: running
    to: succeeded
    trigger: Population completion after the final page
    guard: All subject pages completed.
    side_effects:
      - Calculate deltas
      - Produce an optional export
      - Set intended ninety-day run expiry
      - Complete simulation impact
    who: Population job
    provenance: observed
    source: >-
      services-platform:modules/eligibility/services/population/population-run.ts:finishPopulationRun
  - from: running
    to: failed
    trigger: >-
      Task exception, unallowed million-subject limit or abandoned-job
      settlement
    guard: >-
      Failure settlement applies to the job, including unsupported
      million-subject growth.
    side_effects:
      - Fail the dependent simulation
      - Emit execution failure metrics
    who: Population job or job reconciler
    provenance: observed
    source: >-
      services-platform:modules/eligibility/services/population/population-failure.ts:failPopulationRunOfJob
  - from: queued
    to: failed
    trigger: Queued job failure or abandonment
    guard: The queued job is settled as failed or abandoned.
    side_effects:
      - Fail its dependent simulation
    who: Job reconciler
    provenance: observed
    source: 'services-platform:modules/eligibility/lifecycle.ts:RUN_TRANSITIONS'
  - from: succeeded
    to: expired
    trigger: Run or simulation expiry helper invocation
    guard: >-
      The settled result exceeded its retention; automatic invocation is not
      deployed.
    side_effects:
      - Remove retained results through the maintenance helper
    who: No deployed schedule calls it
    provenance: observed
    source: 'services-platform:docs/debt/eligibility-population-deployment.md'
  - from: failed
    to: expired
    trigger: Settled-run expiry helper invocation
    guard: >-
      The settled result exceeded retention; automatic invocation is not
      deployed.
    side_effects:
      - Remove expired results
    who: No deployed schedule calls it
    provenance: observed
    source: 'services-platform:modules/eligibility/lifecycle.ts:RUN_TRANSITIONS'
  - from: cancelled
    to: expired
    trigger: Cancelled-run expiry helper invocation
    guard: >-
      The settled result exceeded retention; automatic invocation is not
      deployed.
    side_effects:
      - Remove expired results
    who: No deployed schedule calls it
    provenance: observed
    source: 'services-platform:modules/eligibility/lifecycle.ts:RUN_TRANSITIONS'
  - from: queued
    to: cancelled
    trigger: Cancellation lifecycle action without a route
    guard: 'The lifecycle permits cancellation, without a caller operation.'
    side_effects: []
    who: Nobody today
    provenance: observed
    source: 'services-platform:modules/eligibility/lifecycle.ts:RUN_TRANSITIONS'
  - from: running
    to: cancelled
    trigger: Cancellation lifecycle action without a route
    guard: 'The lifecycle permits cancellation, without a caller operation.'
    side_effects: []
    who: Nobody today
    provenance: observed
    source: 'services-platform:modules/eligibility/lifecycle.ts:RUN_TRANSITIONS'
invalid:
  - from: succeeded
    to: running
    why: >-
      Settled runs do not restart; retries use the current running or settled
      result.
  - from: expired
    to: succeeded
    why: Expiry has no outgoing transition.
  - from: failed
    to: succeeded
    why: Failure cannot be changed to success by restarting the same run.
concurrency: >-
  Page evaluation can repeat, but a locked cursor guard commits its counts only
  once. Restarted execution resumes at the stored cursor. Reserved task
  concurrency is two; separate interactive starts create separate runs.
invariants:
  - INV-DOM-PFM-ELG-003-07
  - INV-DOM-PFM-ELG-003-08
evidence:
  - >-
    services-platform at ad3f6a6: modules/eligibility/lifecycle.ts;
    services/population/population-run.ts, population-workflow.ts,
    population-failure.ts; services/simulation/; docs/eligibility.md §14, §15;
    docs/debt/eligibility-population-deployment.md;
    docs/milestones/PLAT-M12-eligibility-who-qualifies.md (Proposed).
---
# Bulk run lifecycle

## The Lifecycle

```mermaid
stateDiagram-v2
  queued --> running
  running --> succeeded
  running --> failed
  queued --> failed
  succeeded --> expired
  failed --> expired
  cancelled --> expired
  queued --> cancelled
  running --> cancelled
```

## Transitions Explained

This state model describes population-run execution, including a simulation’s underlying comparison run. Failed runs keep already committed page data. Cancellation and automatic retention cleanup are not available deployed behaviors.

## What Cannot Happen

Settled runs do not restart; retries use the current running or settled result. Expiry has no outgoing transition. Failure cannot be changed to success by restarting the same run.

## Concurrency and Timing

Page evaluation can repeat, but a locked cursor guard commits its counts only once. Restarted execution resumes at the stored cursor. Reserved task concurrency is two; separate interactive starts create separate runs.
