---
id: STATE-PFM-DJE-004
title: Data run lifecycle
object: DOM-PFM-DJE-005
product_area: platform
module: data-job-engine
revision: 1
status: draft
design_intent: proposed
implementation_evidence: observed
source_sha:
  services-platform: ad3f6a6582843008ed0f5a17b131878d15829af1
states:
  - name: registered
    meaning: 'The package and ordered datasets are saved, with no child submissions yet.'
  - name: running
    meaning: Staff-driven passes poll active datasets and submit eligible work.
  - name: paused
    meaning: Further submissions are held while existing child jobs continue.
  - name: succeeded
    meaning: >-
      All steps have ended succeeded or finally blocked; readiness may still
      report issues.
  - name: failed
    meaning: >-
      A dataset failure settles the parent and skips unsubmitted work while
      retaining the load.
  - name: cancelled
    meaning: >-
      The parent ends after child cancellation requests and skips pending work;
      completed writes remain.
transitions:
  - from: registered
    to: running
    trigger: Start package execution
    guard: The caller may drive remaining work
    side_effects:
      - save the start time and submit dependency-free datasets
    who: Staff member with the data-run permission
    provenance: observed
    source: >-
      services-platform:modules/data-jobs/services/runs/run-driver.ts:startDataRun
  - from: running
    to: paused
    trigger: Hold further dataset submission
    guard: The parent is running
    side_effects:
      - leave existing child jobs unchanged
    who: Staff member with the data-run permission
    provenance: observed
    source: >-
      services-platform:modules/data-jobs/services/runs/run-driver.ts:pauseDataRun
  - from: paused
    to: running
    trigger: Continue package execution
    guard: The parent is paused and the caller may drive remaining work
    side_effects:
      - advance one execution pass
    who: Staff member with the data-run permission
    provenance: observed
    source: >-
      services-platform:modules/data-jobs/services/runs/run-driver.ts:resumeDataRun
  - from: running
    to: succeeded
    trigger: Settle completed package work
    guard: Every dataset is succeeded or finally blocked
    side_effects:
      - save finish time while retaining readiness blockers
    who: 'Run-driving start, resume or read request'
    provenance: observed
    source: >-
      services-platform:modules/data-jobs/services/runs/run-driver.ts:advanceDataRun
  - from: running
    to: failed
    trigger: Settle a failed dataset
    guard: At least one step is failed
    side_effects:
      - name the failed dataset and skip pending steps
    who: 'Run-driving start, resume or read request'
    provenance: test
    source: >-
      services-crm:modules/data-jobs/tests/integration/services/jobs/bulk-data-job-failure.integration.spec.js#fails
      the data job, so its status read answers failed and a Data Run polling it
      stops
  - from: registered
    to: cancelled
    trigger: Abandon an unstarted package
    guard: The parent is registered
    side_effects:
      - skip pending datasets
    who: Staff member with the data-run permission
    provenance: observed
    source: >-
      services-platform:modules/data-jobs/services/persistence/data-runs.ts:DATA_RUN_TRANSITIONS
  - from: running
    to: cancelled
    trigger: Abandon active package work
    guard: The caller is authorized for active datasets
    side_effects:
      - >-
        request child cancellation; ignore logged non-access errors; skip
        pending datasets
    who: Staff member with the data-run permission
    provenance: observed
    source: >-
      services-platform:modules/data-jobs/services/runs/run-driver.ts:cancelDataRun
  - from: paused
    to: cancelled
    trigger: Abandon paused package work
    guard: The parent is paused and child-call authority is available
    side_effects:
      - request child cancellation and skip pending datasets
    who: Staff member with the data-run permission
    provenance: observed
    source: >-
      services-platform:modules/data-jobs/services/persistence/data-runs.ts:DATA_RUN_TRANSITIONS
invalid:
  - from: succeeded
    to: running
    why: A completed package needs a new registration for another attempt.
  - from: failed
    to: running
    why: Failed work cannot resume; recovery uses a reset and new run.
  - from: cancelled
    to: running
    why: Cancellation is terminal for the run.
  - from: registered
    to: paused
    why: Pause applies only to a running run.
  - from: running
    to: registered
    why: The lifecycle has no return to its initial registration state.
concurrency: >-
  State writes lock and validate the parent, but execution passes hold no lock
  across remote submissions. Concurrent readers can create duplicate child work,
  and an unrecorded remote success can be resubmitted. Existing unfinished
  package rows are locked during registration, without a unique constraint for
  concurrent absence checks.
invariants:
  - INV-DOM-PFM-DJE-005-05
  - INV-DOM-PFM-DJE-005-06
  - INV-DOM-PFM-DJE-005-07
evidence:
  - >-
    services-platform at ad3f6a65:
    modules/data-jobs/services/runs/run-driver.ts;
    services/persistence/data-runs.ts (DATA_RUN_TRANSITIONS, setDataRunState,
    registerDataRun); db/data-runs.table.ts; docs/data-jobs/data-runs.md.
---

# Data Run Lifecycle

## The Lifecycle

```mermaid
stateDiagram-v2
  [*] --> registered
  registered --> running: start package execution
  running --> paused: hold further dataset submission
  paused --> running: continue package execution
  running --> succeeded: settle completed package work
  running --> failed: settle a failed dataset
  registered --> cancelled: abandon an unstarted package
  running --> cancelled: abandon active package work
  paused --> cancelled: abandon paused package work
```

## Transitions Explained

Start can begin registered work or take up paused work. Resume specifically requires paused state. Each running read can poll jobs and submit eligible datasets. Parent success includes finally blocked steps, making readiness a separate result. Pause leaves child jobs active; cancellation asks them to stop before settling the parent.

## What Cannot Happen

Final runs do not restart. Pausing a registered run is refused. Neither failure nor cancellation compensates the load.

## Concurrency and Timing

There is no background driver or saved staff token. Concurrent passes and failed child bookkeeping can duplicate submissions. Logged cancellation errors can leave child jobs active after the parent has ended.
