---
id: WF-PFM-DJE-003
title: Approve a validated job
trigger: A caller approves an existing validated job.
product_area: platform
module: data-job-engine
revision: 1
status: draft
design_intent: confirmed
origin: >-
  services-platform:docs/proposals/rhythm-data-job-engine-plan.md §6.6
  validate-only then apply and §13.2 hard deletes (approved 2026-10-12);
  PLAT-M19 CRM-Q10 (typed delete confirmation)
implementation_evidence: observed
inference: []
source_sha:
  macroservice-libraries: 54536a441935c6e09fdb7f96f0bec71c52ba4e03
  services-crm: a8d1364f1dd44b723bb5f9acba12f983e9ec8d69
  services-platform: ad3f6a6582843008ed0f5a17b131878d15829af1
  react-console: baf6dae382d6f41dce976c7f848667ccc37e076f
implements:
  - CAP-PFM-DJE-002
  - CAP-PFM-DJE-007
  - CAP-PFM-DJE-009
moves:
  - STATE-PFM-DJE-001
  - STATE-PFM-DJE-002
crosses:
  - SVC-PFM-DJE-crm-data-jobs
  - SVC-PFM-DJE-data-jobs
  - SVC-PFM-DJE-engine
hops:
  - 'n': 1
    actor_or_service: Console or integration
    action: 'Read the preview’s impact, digest and any deletion phrase.'
    anchor: >-
      services-crm:modules/data-jobs/services/jobs/contact-data-jobs.ts:readDataJob
    seam: sync
    on_failure: Return the job’s current read result or read refusal.
    left_inconsistent: Reading does not queue application.
    observer: The person reading the preview.
    provenance: documented
    source: 'services-crm:docs/data-jobs.md#Listing a tenant''s jobs'
  - 'n': 2
    actor_or_service: Apply route
    action: Require route authority and the collection’s record category.
    anchor: 'services-crm:modules/data-jobs/aws/api/data-jobs.routes.ts:dataJobsRoutes'
    seam: sync
    on_failure: Return forbidden access or concealed missing-job results.
    left_inconsistent: No application work is created.
    observer: The request response exposes the result.
    provenance: test
    source: >-
      services-crm:modules/data-jobs/tests/integration/services/jobs/configuration-data-jobs.integration.spec.js#is
      not found by the apply, so a validated job of contacts cannot be started
      from here
  - 'n': 3
    actor_or_service: Engine job control
    action: 'Lock the job and check state, deadline, digest and any typed phrase.'
    anchor: >-
      macroservice-libraries:packages/data-jobs/src/job-control.ts:applyValidatedJob
    seam: sync
    on_failure: >-
      Return named digest or confirmation refusals; late approval commits expiry
      and raises an illegal-operation conflict.
    left_inconsistent: An expired preview stays final and requires new validation.
    observer: >-
      The caller receives the conflict response, including any available reason
      code.
    provenance: test
    source: >-
      services-crm:modules/data-jobs/tests/e2e/organization-update.e2e.spec.js#refuses
      the apply of a job that was never validated with 409, because an apply is
      the approval of a validation
  - 'n': 4
    actor_or_service: Engine job control
    action: Requeue preserved input for apply and recompute finished progress.
    anchor: >-
      macroservice-libraries:packages/data-jobs/src/job-control.ts:applyValidatedJob
    seam: queue
    on_failure: Roll back the approval transaction.
    left_inconsistent: A failed transaction leaves the preview unchanged.
    observer: Inspection shows the application waiting for processing.
    provenance: observed
    source: >-
      macroservice-libraries:packages/data-jobs/src/job-control.ts:applyValidatedJob
  - 'n': 5
    actor_or_service: Batches
    action: >-
      Prevalidate again and compare captured versions while applying eligible
      items.
    anchor: 'macroservice-libraries:packages/data-jobs/src/version-capture.ts'
    seam: queue
    on_failure: Report changed records as conflicts or domain refusals.
    left_inconsistent: Newer values remain on conflicted records.
    observer: Refusals page; conflict revalidation is offered.
    provenance: test
    source: >-
      services-crm:modules/data-jobs/tests/integration/services/jobs/organization-delete.integration.spec.js#refuses
      the one the contact now belongs to as a conflict, because the delete
      approved was another one
idempotency: >-
  Once queued, the job no longer accepts the same approval. Preview refusals
  remain refusals during apply rather than silently becoming new eligible work.
concurrency: >-
  Approval checks and requeue share a job-locked transaction. Captured record
  versions protect later application against intervening edits.
branches:
  - Platform processes approved batches inside the current request.
  - Rollback plans use the same approval protocol with their own digest.
waits:
  - >-
    Approval is available through the recorded 24-hour window; expiry is
    action-driven.
evidence:
  - >-
    macroservice-libraries at 54536a44: src/job-control.ts, hard-delete.ts,
    data-job-request.ts (impactDigest), version-capture.ts.
  - >-
    services-crm at a8d1364f: aws/api/data-jobs.routes.ts (apply route),
    tests/integration/services/jobs/contact-delete.integration.spec.js.
  - >-
    react-console at baf6dae3:
    components/data-management/data-jobs/new/confirm-apply-dialog.tsx;
    lib/api/data-jobs/rules.ts (dataJobApplyOptions).
controls: [TC-AVL-004, TC-AVL-005, TC-AZ-001, TC-AZ-002, TC-AZ-003, TC-AZ-004, TC-DAT-001, TC-DAT-002, TC-DAT-003, TC-DAT-004, TC-IAM-001, TC-IAM-002, TC-IAM-004, TC-IAM-005, TC-IAM-006, TC-LOG-002, TC-LOG-003, TC-LOG-004, TC-LOG-005, TC-MON-001, TC-MON-002, TC-PI-001, TC-PI-002, TC-PI-003, TC-PI-004, TC-PI-005, TC-PRV-001, TC-PRV-002, TC-TEN-001, TC-TEN-002, TC-TEN-003, TC-VEN-001, TC-VEN-002, TC-VEN-003]
---

# Approve A Validated Job

## What It Does

Approval moves preserved preview input back into execution after checking the saved impact digest and approval window. Deletion adds a typed confirmation, and batch application checks current record conditions again.

## The Flow

```mermaid
flowchart TD
  H1["Console or integration"] --> H2
  H2["Apply route"] --> H3
  H3["Engine job control"] --> H4
  H4["Engine job control"] --> H5
  H5["Batches"]
```

## When Something Fails

A refused approval does not start application, except that late approval records expiry. Application can still produce conflicts or domain refusals after successful approval, leaving protected records and prior commits intact.

## Open Design Questions

The recorded findings identify the remaining limits; this examination does not authorize stronger behavior or change the planning rules.
