---
id: CAP-PFM-DJE-002
title: Review a change before approving its application
feature: FEAT-PFM-DJE-01
product_area: platform
module: data-job-engine
revision: 1
status: draft
product_intent: confirmed
implementation_evidence: observed
supersedes:
  - RUL-DJE-ENG-006
source_sha:
  macroservice-libraries: 54536a441935c6e09fdb7f96f0bec71c52ba4e03
  services-crm: a8d1364f1dd44b723bb5f9acba12f983e9ec8d69
  services-platform: ad3f6a6582843008ed0f5a17b131878d15829af1
  react-console: baf6dae382d6f41dce976c7f848667ccc37e076f
intent_sources:
  - 'services-platform:docs/milestones/plans/PLAT-M19-plan.md#A1'
  - 'services-platform:docs/milestones/plans/PLAT-M19-plan.md#S19'
  - 'services-platform:docs/milestones/plans/PLAT-M19-plan.md#3. How it works for the user'
purpose: >-
  An administrator can inspect a proposed interactive change and approve the saved impact before records
  are written.
outcomes:
  - Validation reports planned outcomes without changing the target records.
  - Approval identifies the impact the administrator reviewed.
  - An expired preview requires a new validation.
concepts:
  - CON-PFM-DJE-001
actors:
  - ACT-PFM-035
  - ACT-PFM-036
surfaces:
  - console
  - api
preconditions: []
postconditions: []
permissions:
  - key: crm.contacts.bulk
    where_checked: api
    scope: tenant
  - key: crm.contacts.update
    where_checked: api
    scope: tenant
  - key: crm.organizations.bulk
    where_checked: api
    scope: tenant
  - key: platform.custom-fields.bulk
    where_checked: api
    scope: tenant
rules:
  - id: BR-CAP-PFM-DJE-002-01
    proved_by: [ATS-PFM-DJE-001-11, ATS-PFM-DJE-002-01, ATS-PFM-DJE-002-06, ATS-PFM-DJE-002-07, ATS-PFM-DJE-006-08, TST-PFM-DJE-117]
    statement: >-
      Validation runs the operation’s prevalidation checks and reports planned impact and refusals
      without saving changes to the target records.
    kind: lifecycle
    enforced_at:
      - service
    must_prove: true
    provenance: test
    source: >-
      services-crm:modules/data-jobs/tests/integration/services/jobs/contact-data-jobs.integration.spec.js#changes
      nothing while it is validating
    origin: 'services-platform:docs/milestones/plans/PLAT-M19-plan.md#3. How it works for the user'
  - id: BR-CAP-PFM-DJE-002-02
    proved_by: [ATS-PFM-DJE-001-11, ATS-PFM-DJE-002-02, ATS-PFM-DJE-002-06, ATS-PFM-DJE-002-07, ATS-PFM-DJE-002-08, ATS-PFM-DJE-002-09, ATS-PFM-DJE-006-08, ATS-PFM-DJE-007-09, ATS-PFM-DJE-009-12, TST-PFM-DJE-116, TST-PFM-DJE-117]
    statement: >-
      Approval of a validated job must echo its impact fingerprint; an omitted or mismatched fingerprint
      is refused without leaving the validated state.
    kind: validation
    enforced_at:
      - service
    must_prove: true
    provenance: test
    source: >-
      services-crm:modules/data-jobs/tests/integration/services/jobs/contact-data-jobs.integration.spec.js#refuses
      an apply of the validated update whose digest is not the one the validation answered
    origin: none
  - id: BR-CAP-PFM-DJE-002-03
    proved_by: [ATS-PFM-DJE-002-03]
    statement: >-
      A preview remains applicable for 24 hours after validation; a later apply attempt expires the job
      and requires a fresh validation.
    kind: lifecycle
    enforced_at:
      - service
    must_prove: true
    provenance: observed
    source: 'macroservice-libraries:packages/data-jobs/src/job-control.ts:applyValidatedJob'
    origin: 'services-platform:docs/milestones/plans/PLAT-M19-plan.md#A1'
  - id: BR-CAP-PFM-DJE-002-04
    proved_by: [ATS-PFM-DJE-002-04, TST-PFM-DJE-110]
    statement: The apply action refuses a job that has not completed validation.
    kind: validation
    enforced_at:
      - service
    must_prove: true
    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
    origin: none
  - id: BR-CAP-PFM-DJE-002-05
    proved_by: [ATS-PFM-DJE-002-05, TST-PFM-DJE-015]
    statement: >-
      The job combines batch impacts by adding change totals, deletion counts for each affected
      collection and blocked counts for each reason.
    kind: calculation
    enforced_at:
      - service
    must_prove: true
    provenance: test
    source: >-
      macroservice-libraries:packages/data-jobs/src/define-data-operation.spec.ts#adds the counts, which
      is what makes a digest speak for every batch and not the last one
    origin: none
  - id: BR-CAP-PFM-DJE-002-06
    proved_by: []
    statement: >-
      CRM file jobs apply directly and the console describes that limitation; Platform can validate
      uploaded datasets containing at most 500 records.
    kind: policy
    enforced_at:
      - service
      - console
    must_prove: false
    provenance: observed
    source: >-
      services-crm:modules/data-jobs/aws/api/bulk-data-jobs.schemas.ts;
      services-platform:modules/data-jobs/services/jobs/custom-field-data-jobs.ts:submitPlatformDataJob;
      react-console:components/data-management/data-jobs/new/step-validate.tsx
    origin: none
  - id: BR-CAP-PFM-DJE-002-07
    proved_by: []
    statement: >-
      A validated job’s detail supplies the impact fingerprint and any typed deletion phrase; list rows
      indicate only whether a fingerprint is available.
    kind: policy
    enforced_at:
      - api
    must_prove: false
    provenance: documented
    source: 'services-crm:docs/data-jobs.md#Listing a tenant''s jobs'
    origin: none
scenarios:
  - id: SC-CAP-PFM-DJE-002-01
    given: A proposed twelve-contact change contains one invalid value.
    when: The administrator requests validation.
    then: 'The preview identifies eleven planned changes and one coded refusal, without changing the contacts.'
    provenance: documented
    source: 'services-platform:docs/milestones/plans/PLAT-M19-plan.md#3. How it works for the user'
  - id: SC-CAP-PFM-DJE-002-02
    given: A job completed validation the previous day.
    when: An administrator attempts approval after 25 hours.
    then: Rhythm expires the job and refuses the apply request.
    provenance: documented
    source: 'services-platform:docs/milestones/plans/PLAT-M19-plan.md#S19'
edge_cases: []
constraints: []
depends_on: []
related:
  - CAP-PFM-DJE-001
  - CAP-PFM-DJE-006
  - CAP-PFM-DJE-007
journeys:
  - JNY-PFM-DJE-002
open_questions: []
evidence:
  - >-
    Reviewed evidence: macroservice-libraries (54536a44): README.md (Deleting records; Versions);
    src/job-control.ts, data-job-request.ts, define-data-operation.ts (mergeDataJobImpacts),
    data-job-config.ts (validationExpiryHours).
  - >-
    Reviewed evidence: services-crm (a8d1364f): docs/data-jobs.md (What a job is; Listing a tenant's
    jobs); tests contact-data-jobs.integration.spec.js, configuration-data-jobs.integration.spec.js,
    organization-update.e2e.spec.js.
  - >-
    Reviewed evidence: services-platform (ad3f6a65): docs/milestones/plans/PLAT-M19-plan.md (A1, S19),
    PLAT-M21-plan.md (walkthrough).
  - >-
    Reviewed evidence: react-console (baf6dae3):
    components/data-management/data-jobs/new/step-validate.tsx;
    acceptance/crm/journeys/data-operations/CRM-ACC-0662.
controls: [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-LOG-004, TC-LOG-005, TC-PI-001, TC-PI-003, 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]
exercised_by: [FAS-PFM-DJE-01-01, FAS-PFM-DJE-01-04]
suites: [TST-PFM-DJE-015, TST-PFM-DJE-110, TST-PFM-DJE-116, TST-PFM-DJE-117]
---

# Review a change before approving its application

## Purpose

An administrator can inspect a proposed interactive change and approve the saved impact before records are written.

## How It Works

An administrator submits an interactive change for validation. Rhythm saves the proposed outcomes and combines their impact across batches. Validation leaves the target records intact. The administrator reviews that report before choosing Apply. Approval sends back the report’s fingerprint and cannot substitute another impact. A job submitted directly for application cannot use that approval action. Preview expiry is checked when someone acts on the job, so an old list row can still display Validated. CRM file imports run directly, whereas Platform offers bounded uploaded-dataset validation. The product should make file preview limits clear before staff submit a file.

## Relationships

- Job submission preserves the input being reviewed.
- Version protection handles edits between preview and application.
- Destructive changes require this approval stage.
