---
id: ATS-PFM-DJE-004
scope: CAP-PFM-DJE-004
product_area: platform
module: data-job-engine
revision: 2
status: proposed
approved_by: null
approved_at: null
source_sha:
  macroservice-libraries: 54536a441935c6e09fdb7f96f0bec71c52ba4e03
  services-crm: a8d1364f1dd44b723bb5f9acba12f983e9ec8d69
  react-console: baf6dae382d6f41dce976c7f848667ccc37e076f
scenarios:
  - id: ATS-PFM-DJE-004-01
    title: Final-state transitions are constrained
    level: unit
    proves:
      - BR-CAP-PFM-DJE-004-01
    preconditions: Use the declared state transition model.
    steps:
      - do: Check outgoing transitions from every final state.
        expect: Only the allowed blocked-item retry can leave a completed state.
        provenance: test
        source: >-
          macroservice-libraries:packages/data-jobs/src/data-job-states.spec.ts#leaves every final
          state with nowhere to go, but for the retry of blocked items the plan allows
    expected: Only the allowed blocked-item retry can leave a completed state.
    negative: true
    data_needs: No additional fixture is needed.
    bound_to:
      - TST-PFM-DJE-014
    provenance: test
    source: >-
      macroservice-libraries:packages/data-jobs/src/data-job-states.spec.ts#leaves every final state
      with nowhere to go, but for the retry of blocked items the plan allows
    category: transition
    binding_evidence:
      - >-
        macroservice-libraries:packages/data-jobs/src/data-job-states.spec.ts#leaves every final
        state with nowhere to go, but for the retry of blocked items the plan allows
      - >-
        macroservice-libraries:packages/data-jobs/src/data-job-states.spec.ts#never resumes a
        cancelled job, and never cancels a finished one
  - id: ATS-PFM-DJE-004-02
    title: Cancellation waits for work already in flight
    level: api
    proves:
      - BR-CAP-PFM-DJE-004-02
    preconditions: Start a job with an executing batch.
    steps:
      - do: Request cancellation during processing.
        expect: 'The batch settles, further work stops, and cancelled totals include unattempted items.'
        provenance: test
        source: >-
          services-crm:modules/data-jobs/tests/integration/services/jobs/contact-data-jobs.integration.spec.js#ends
          the job cancelled, not failed, once the batch it waited for has finished
    expected: 'The batch settles, further work stops, and cancelled totals include unattempted items.'
    negative: false
    data_needs: A collection of 500 contacts.
    bound_to:
      - TST-PFM-DJE-117
      - TST-PFM-DJE-101
    provenance: test
    source: >-
      services-crm:modules/data-jobs/tests/integration/services/jobs/contact-data-jobs.integration.spec.js#ends
      the job cancelled, not failed, once the batch it waited for has finished
    category: concurrency
    binding_evidence:
      - >-
        services-crm:modules/data-jobs/tests/integration/services/jobs/contact-data-jobs.integration.spec.js#ends
        the job cancelled, not failed, once the batch it waited for has finished
      - >-
        services-crm:modules/data-jobs/tests/integration/services/jobs/contact-data-jobs.integration.spec.js#reports
        what the running batch committed and what the cancel kept from running
      - >-
        react-console:acceptance/data-jobs/playwright/journeys/foundations/DJE-ACC-0006.spec.ts#DJE-ACC-0006
  - id: ATS-PFM-DJE-004-03
    title: Resume recovers a paused file job
    level: api
    proves:
      - BR-CAP-PFM-DJE-004-03
    preconditions: Pause a file job before its source is read.
    steps:
      - do: Resume its processing.
        expect: The job proceeds to completion.
        provenance: test
        source: >-
          macroservice-libraries:packages/data-jobs/src/tests/integration/bulk-data-jobs.integration.spec.ts#holds
          a job paused before its source was read, and runs it to the end once resumed
    expected: The job proceeds to completion.
    negative: false
    data_needs: A short input file.
    bound_to:
      - TST-PFM-DJE-024
    provenance: test
    source: >-
      macroservice-libraries:packages/data-jobs/src/tests/integration/bulk-data-jobs.integration.spec.ts#holds
      a job paused before its source was read, and runs it to the end once resumed
    category: transition
    binding_evidence:
      - >-
        macroservice-libraries:packages/data-jobs/src/tests/integration/bulk-data-jobs.integration.spec.ts#holds
        a job paused before its source was read, and runs it to the end once resumed
      - >-
        macroservice-libraries:packages/data-jobs/src/tests/integration/bulk-data-jobs.integration.spec.ts#holds
        a job paused between planning and admission, and finishes it after the resume
  - id: ATS-PFM-DJE-004-04
    title: Retry recovers dependencies but refuses invalid input
    level: api
    proves:
      - BR-CAP-PFM-DJE-004-04
    preconditions: Prepare a completed job with blocked children and another with rejections.
    steps:
      - do: Load the missing parent and retry each job.
        expect: The children apply; the rejection-only job refuses retry.
        provenance: test
        source: >-
          macroservice-libraries:packages/data-jobs/src/tests/integration/keyed-data-jobs.integration.spec.ts#blocks
          the child, and a retry after the parent is loaded applies it and finishes the job
    expected: The children apply; the rejection-only job refuses retry.
    negative: true
    data_needs: Parent and dependent input files.
    bound_to:
      - TST-PFM-DJE-029
      - TST-PFM-DJE-120
    provenance: test
    source: >-
      macroservice-libraries:packages/data-jobs/src/tests/integration/keyed-data-jobs.integration.spec.ts#blocks
      the child, and a retry after the parent is loaded applies it and finishes the job
    category: edge
    binding_evidence:
      - >-
        macroservice-libraries:packages/data-jobs/src/tests/integration/keyed-data-jobs.integration.spec.ts#blocks
        the child, and a retry after the parent is loaded applies it and finishes the job
      - >-
        macroservice-libraries:packages/data-jobs/src/tests/integration/keyed-data-jobs.integration.spec.ts#refuses
        to retry a job whose refusals are not blocked items, because correcting records is a new job
      - >-
        services-crm:modules/data-jobs/tests/integration/services/jobs/contact-update-versions.integration.spec.js#refuses
        a retry of the finished job rather than writing over the edit
  - id: ATS-PFM-DJE-004-05
    title: Applied rollback prevents retry
    level: api
    proves:
      - BR-CAP-PFM-DJE-004-05
    preconditions: Prepare a job with blocked items and an applied rollback.
    steps:
      - do: Invoke retry on the original job.
        expect: The service refuses retry after rollback.
        provenance: test
        source: >-
          macroservice-libraries:packages/data-jobs/src/tests/integration/rollback-and-retry.integration.spec.ts#refuses
          to retry a job that has been rolled back, so its blocked rows are not written after the
          undo
    expected: The service refuses retry after rollback.
    negative: true
    data_needs: No additional fixture is needed.
    bound_to:
      - TST-PFM-DJE-032
      - TST-PFM-DJE-012
    provenance: test
    source: >-
      macroservice-libraries:packages/data-jobs/src/tests/integration/rollback-and-retry.integration.spec.ts#refuses
      to retry a job that has been rolled back, so its blocked rows are not written after the undo
    category: interaction
    binding_evidence:
      - >-
        macroservice-libraries:packages/data-jobs/src/tests/integration/rollback-and-retry.integration.spec.ts#refuses
        to retry a job that has been rolled back, so its blocked rows are not written after the undo
      - >-
        macroservice-libraries:packages/data-jobs/src/data-job-actions.spec.ts#does not offer Retry
        once a rollback has been applied, and still does while one is only planned
  - id: ATS-PFM-DJE-004-06
    title: Unauthorized users cannot control a job
    level: browser
    proves:
      - BR-CAP-PFM-DJE-004-06
    preconditions: 'Use read-only, ordinary-user and administrator-without-bulk personas.'
    steps:
      - do: Inspect Data Imports and attempt job controls under each identity.
        expect: The controls are absent and backend calls are refused.
        provenance: proposed
        source: >-
          react-console:acceptance/crm/playwright/journeys/data-operations/CRM-ACC-0664.spec.ts#CRM-ACC-0664
    expected: The controls are absent and backend calls are refused.
    negative: true
    data_needs: The specified permission personas.
    bound_to: []
    provenance: proposed
    source: >-
      react-console:acceptance/crm/playwright/journeys/data-operations/CRM-ACC-0664.spec.ts#CRM-ACC-0664
    category: permission
    removed_binding_evidence:
      - >-
        react-console:acceptance/crm/playwright/journeys/data-operations/CRM-ACC-0664.spec.ts#CRM-ACC-0664
  - id: ATS-PFM-DJE-004-07
    title: Workflow failure settles durable job state
    level: api
    proves:
      - BR-CAP-PFM-DJE-004-07
    preconditions: Prepare a file job whose workflow failed after partial admission.
    steps:
      - do: Invoke failure handling twice.
        expect: The first call fails the job and abandons unstarted work; the repeat adds no changes.
        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
    expected: The first call fails the job and abandons unstarted work; the repeat adds no changes.
    negative: true
    data_needs: No additional fixture is needed.
    bound_to:
      - TST-PFM-DJE-113
      - TST-PFM-DJE-024
    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
    category: failure
    binding_evidence:
      - >-
        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
      - >-
        services-crm:modules/data-jobs/tests/integration/services/jobs/bulk-data-job-failure.integration.spec.js#abandons
        every batch no worker had started, and counts their items as not attempted
      - >-
        macroservice-libraries:packages/data-jobs/src/tests/integration/bulk-data-jobs.integration.spec.ts#fails
        a job whose workflow died after admitting part of it, and abandons every batch no worker had
        started
  - id: ATS-PFM-DJE-004-08
    title: Cancellation accounts for settled and abandoned work
    category: interaction
    level: api
    exercises:
      - CAP-PFM-DJE-003
      - CAP-PFM-DJE-004
    proves:
      - BR-CAP-PFM-DJE-003-01
      - BR-CAP-PFM-DJE-004-02
    preconditions: Prepare a multi-batch job and hold one batch in flight.
    steps:
      - do: >-
          Cancel while that batch is active, let it settle, and inspect receipts and unattempted
          positions.
        expect: >-
          The active batch may commit once; later batches do not start and the job settles cancelled
          with unattempted work counted.
        provenance: proposed
        source: >-
          services-crm:modules/data-jobs/tests/integration/services/queue/data-job-worker.integration.spec.js#changes
          each contact once between them, whichever delivery got there first;
          services-crm:modules/data-jobs/tests/integration/services/jobs/contact-data-jobs.integration.spec.js#ends
          the job cancelled, not failed, once the batch it waited for has finished
    expected: >-
      The active batch may commit once; later batches do not start and the job settles cancelled
      with unattempted work counted.
    negative: false
    data_needs: Prepare a multi-batch job and hold one batch in flight.
    bound_to: []
    provenance: proposed
    source: >-
      services-crm:modules/data-jobs/tests/integration/services/queue/data-job-worker.integration.spec.js#changes
      each contact once between them, whichever delivery got there first;
      services-crm:modules/data-jobs/tests/integration/services/jobs/contact-data-jobs.integration.spec.js#ends
      the job cancelled, not failed, once the batch it waited for has finished
  - id: ATS-PFM-DJE-004-09
    title: Applied restoration prevents reopening original blocked work
    category: interaction
    level: api
    exercises:
      - CAP-PFM-DJE-004
      - CAP-PFM-DJE-008
    proves:
      - BR-CAP-PFM-DJE-004-05
      - BR-CAP-PFM-DJE-008-01
      - BR-CAP-PFM-DJE-008-09
    preconditions: Finish an update with reversible changes and blocked input.
    steps:
      - do: >-
          Plan a restoration, verify planning alone leaves retry available, apply the restoration,
          and attempt retry of the original.
        expect: Only application of restoration prevents later retry; restored values stay intact.
        provenance: proposed
        source: >-
          macroservice-libraries:packages/data-jobs/src/tests/integration/rollback-and-retry.integration.spec.ts#refuses
          to retry a job that has been rolled back, so its blocked rows are not written after the
          undo;
          services-crm:modules/data-jobs/tests/integration/services/jobs/contact-update-rollback.integration.spec.js#plans
          it already validated, because planning a rollback IS validating it;
          macroservice-libraries:packages/data-jobs/README.md#Rolling a job back
    expected: Only application of restoration prevents later retry; restored values stay intact.
    negative: false
    data_needs: Finish an update with reversible changes and blocked input.
    bound_to: []
    provenance: proposed
    source: >-
      macroservice-libraries:packages/data-jobs/src/tests/integration/rollback-and-retry.integration.spec.ts#refuses
      to retry a job that has been rolled back, so its blocked rows are not written after the undo;
      services-crm:modules/data-jobs/tests/integration/services/jobs/contact-update-rollback.integration.spec.js#plans
      it already validated, because planning a rollback IS validating it;
      macroservice-libraries:packages/data-jobs/README.md#Rolling a job back
  - id: ATS-PFM-DJE-004-10
    title: Dependency arrival makes retained input retryable
    category: interaction
    level: api
    exercises:
      - CAP-PFM-DJE-004
      - CAP-PFM-DJE-012
    proves:
      - BR-CAP-PFM-DJE-004-04
      - BR-CAP-PFM-DJE-012-04
    preconditions: Load a child whose required parent key is absent.
    steps:
      - do: >-
          Inspect the blocked result, load the parent, and retry the child job without another
          upload.
        expect: >-
          The retained child input applies after its parent exists without duplicating earlier
          successful writes.
        provenance: proposed
        source: >-
          macroservice-libraries:packages/data-jobs/src/tests/integration/keyed-data-jobs.integration.spec.ts#refuses
          to retry a job whose refusals are not blocked items, because correcting records is a new
          job;
          macroservice-libraries:packages/data-jobs/src/tests/integration/keyed-data-jobs.integration.spec.ts#blocks
          the child, and a retry after the parent is loaded applies it and finishes the job
    expected: >-
      The retained child input applies after its parent exists without duplicating earlier
      successful writes.
    negative: false
    data_needs: Load a child whose required parent key is absent.
    bound_to: []
    provenance: proposed
    source: >-
      macroservice-libraries:packages/data-jobs/src/tests/integration/keyed-data-jobs.integration.spec.ts#refuses
      to retry a job whose refusals are not blocked items, because correcting records is a new job;
      macroservice-libraries:packages/data-jobs/src/tests/integration/keyed-data-jobs.integration.spec.ts#blocks
      the child, and a retry after the parent is loaded applies it and finishes the job
evidence:
  - >-
    Reviewed evidence: macroservice-libraries (54536a44): src/data-job-states.ts, job-control.ts,
    data-job-actions.ts, fail-bulk-data-job.ts; tests data-job-states.spec.ts,
    data-job-actions.spec.ts, bulk-data-jobs.integration.spec.ts,
    keyed-data-jobs.integration.spec.ts, rollback-and-retry.integration.spec.ts.
  - >-
    Reviewed evidence: services-crm (a8d1364f): docs/data-jobs.md (What a job may be asked now);
    tests contact-data-jobs.integration.spec.js, bulk-data-job-failure.integration.spec.js.
  - >-
    Reviewed evidence: react-console (baf6dae3): lib/api/data-jobs/rules.ts;
    components/data-management/data-jobs/job-actions.tsx;
    acceptance/data-jobs/playwright/journeys/foundations/DJE-ACC-0006.spec.ts.
  - >-
    Testing back-fill: related capability rules, domain invariants, state transitions and crossing
    workflows at the pinned source revisions.
coverage:
  rule: 'gap: FND-PFM-DJE-064'
  transition: 'gap: FND-PFM-DJE-064'
  validation: 'gap: FND-PFM-DJE-064'
  permission: covered
  edge: covered
  failure: covered
  boundary: 'gap: FND-PFM-DJE-064'
  concurrency: covered
  invariant: 'gap: FND-PFM-DJE-064'
  interaction: covered
coverage_notes:
  transition: >-
    Selected lifecycle examples do not cover every applicable object and batch transition. The
    linked finding retains the remaining matrix.
  execution: >-
    Covered means a specification scenario exists. Proposed scenarios and registered suites with no
    run result do not establish executed conformance.
related:
  - CAP-PFM-DJE-003
  - CAP-PFM-DJE-008
  - CAP-PFM-DJE-012
workflows:
  - WF-PFM-DJE-004
coverage_evidence:
  - rule: BR-CAP-PFM-DJE-004-01
    scenarios:
      - ATS-PFM-DJE-004-01
    provenance: proposed
    source: >-
      macroservice-libraries:packages/data-jobs/src/data-job-states.spec.ts#leaves every final state
      with nowhere to go, but for the retry of blocked items the plan allows
  - rule: BR-CAP-PFM-DJE-004-02
    scenarios:
      - ATS-PFM-DJE-004-02
      - ATS-PFM-DJE-004-08
    provenance: proposed
    source: >-
      services-crm:modules/data-jobs/tests/integration/services/jobs/contact-data-jobs.integration.spec.js#ends
      the job cancelled, not failed, once the batch it waited for has finished
  - rule: BR-CAP-PFM-DJE-004-03
    scenarios:
      - ATS-PFM-DJE-004-03
    provenance: proposed
    source: >-
      macroservice-libraries:packages/data-jobs/src/tests/integration/bulk-data-jobs.integration.spec.ts#holds
      a job paused before its source was read, and runs it to the end once resumed
  - rule: BR-CAP-PFM-DJE-004-04
    scenarios:
      - ATS-PFM-DJE-004-04
      - ATS-PFM-DJE-004-10
    provenance: proposed
    source: >-
      macroservice-libraries:packages/data-jobs/src/tests/integration/keyed-data-jobs.integration.spec.ts#refuses
      to retry a job whose refusals are not blocked items, because correcting records is a new job
  - rule: BR-CAP-PFM-DJE-004-05
    scenarios:
      - ATS-PFM-DJE-004-05
      - ATS-PFM-DJE-004-09
    provenance: proposed
    source: >-
      macroservice-libraries:packages/data-jobs/src/tests/integration/rollback-and-retry.integration.spec.ts#refuses
      to retry a job that has been rolled back, so its blocked rows are not written after the undo
  - rule: BR-CAP-PFM-DJE-004-06
    scenarios:
      - ATS-PFM-DJE-004-06
    provenance: proposed
    source: 'services-crm:docs/data-jobs.md#What a job may be asked now: `actions` (D-39)'
  - rule: BR-CAP-PFM-DJE-004-07
    scenarios:
      - ATS-PFM-DJE-004-07
    provenance: proposed
    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
---

# Interrupt a job and recover its unfinished work: Capability Test Specification

## Coverage

The structured coverage rows link required rules to their scenarios. A covered category has a defined check; executable coverage and successful execution require separate evidence. The category map keeps incomplete lifecycle matrices and other missing checks visible as findings.

## Interactions With Related Capabilities

Cancellation accounts for settled and abandoned work. Applied restoration prevents reopening original blocked work. Dependency arrival makes retained input retryable. The interaction scenarios use the related capabilities' rule references and identify the shared fixture and observable outcome.
