---
id: CAP-PFM-DJE-006
title: Preserve intervening edits during bulk changes
feature: FEAT-PFM-DJE-02
product_area: platform
module: data-job-engine
revision: 1
status: draft
product_intent: confirmed
implementation_evidence: observed
supersedes:
  - RUL-DJE-ENG-007
  - RUL-DJE-ENG-010
source_sha:
  macroservice-libraries: 54536a441935c6e09fdb7f96f0bec71c52ba4e03
  services-crm: a8d1364f1dd44b723bb5f9acba12f983e9ec8d69
  react-console: baf6dae382d6f41dce976c7f848667ccc37e076f
intent_sources:
  - 'services-crm:docs/milestones/CRM-M7-data-operations.md#D-37'
  - 'services-crm:docs/milestones/CRM-M7-data-operations.md#D-38'
  - 'services-platform:docs/milestones/plans/PLAT-M19-plan.md#A4'
  - 'services-platform:docs/milestones/plans/PLAT-M19-plan.md#S05'
purpose: >-
  Administrators can review conflicts before replacing information that another person changed while a
  job waited.
outcomes:
  - Intervening changes are preserved and identified for review.
  - Conflicted input can be validated again against current records.
  - Producer deliveries respect staff changes under the default policy.
concepts:
  - CON-PFM-DJE-001
  - CON-PFM-DJE-004
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: service
    scope: record
  - key: crm.organizations.update
    where_checked: service
    scope: record
rules:
  - id: BR-CAP-PFM-DJE-006-01
    proved_by: [ATS-PFM-DJE-002-07, ATS-PFM-DJE-006-01, ATS-PFM-DJE-006-02, ATS-PFM-DJE-006-08, ATS-PFM-DJE-006-09, ATS-PFM-DJE-008-09, TST-PFM-DJE-085, TST-PFM-DJE-120]
    statement: >-
      Validation captures versions for eligible identifier-based changes, omitting contact changes
      already satisfied by current values; application preserves intervening edits as conflicts and
      processes the remaining records.
    kind: policy
    enforced_at:
      - service
    must_prove: true
    provenance: observed
    source: >-
      services-crm:modules/data-jobs/tests/integration/services/jobs/contact-update-versions.integration.spec.js#skips
      the contact that changed after the validation as a named conflict;
      services-crm:modules/data-jobs/services/operations/contact-update.ts:prevalidate
    origin: 'services-crm:docs/milestones/CRM-M7-data-operations.md#D-37'
  - id: BR-CAP-PFM-DJE-006-02
    proved_by: [ATS-PFM-DJE-006-03]
    statement: >-
      An input record’s explicit expected version takes precedence over a captured version; a mismatch
      reports a version conflict with the last editor and time, without exposing values.
    kind: policy
    enforced_at:
      - service
    must_prove: true
    provenance: documented
    source: 'services-crm:docs/data-jobs.md#What each contact''s outcome can be'
    origin: 'services-crm:docs/milestones/CRM-M7-data-operations.md#D-37'
  - id: BR-CAP-PFM-DJE-006-03
    proved_by: [ATS-PFM-DJE-006-04, TST-PFM-DJE-120]
    statement: >-
      A contact already holding the requested values reports applied and unchanged even when another edit
      advanced its version.
    kind: policy
    enforced_at:
      - service
    must_prove: true
    provenance: test
    source: >-
      services-crm:modules/data-jobs/tests/integration/services/jobs/contact-update-versions.integration.spec.js#applies
      the contact whose colleague made the very change the job asks for, rather than calling it a
      conflict
    origin: 'services-crm:docs/milestones/CRM-M7-data-operations.md#D-37'
  - id: BR-CAP-PFM-DJE-006-04
    proved_by: [ATS-PFM-DJE-006-02, ATS-PFM-DJE-006-05, TST-PFM-DJE-085, TST-PFM-DJE-120]
    statement: >-
      Conflict revalidation creates a linked validation of just the conflicted input at current versions;
      unfinished jobs, jobs without conflicts, file jobs and rollbacks refuse it.
    kind: lifecycle
    enforced_at:
      - service
    must_prove: true
    provenance: test
    source: >-
      services-crm:modules/data-jobs/tests/integration/services/jobs/contact-update-versions.integration.spec.js#makes
      the revalidation a new validation of the one conflicted contact, linked to the job it corrects
    origin: 'services-crm:docs/milestones/CRM-M7-data-operations.md#D-37'
  - id: BR-CAP-PFM-DJE-006-05
    proved_by: [ATS-PFM-DJE-006-06, ATS-PFM-DJE-006-10, ATS-PFM-DJE-012-13, TST-PFM-DJE-029, TST-PFM-DJE-066]
    statement: >-
      Under reject policy, a keyed update checks the version last written by its producer and preserves
      later staff edits as conflicts; overwrite policy permits replacement unless an explicit expected
      version prevents it.
    kind: policy
    enforced_at:
      - service
    must_prove: true
    provenance: test
    source: >-
      macroservice-libraries:packages/data-jobs/src/tests/integration/keyed-data-jobs.integration.spec.ts#refuses
      the delivery as a conflict and leaves the record alone
    origin: 'services-crm:docs/milestones/CRM-M7-data-operations.md#D-38'
  - id: BR-CAP-PFM-DJE-006-06
    proved_by: [ATS-PFM-DJE-006-07, TST-PFM-DJE-030]
    statement: >-
      A keyed patch below the applied producer revision is stale and skipped; a patch at the same
      revision can supply a further part of that revision.
    kind: policy
    enforced_at:
      - service
    must_prove: true
    provenance: observed
    source: 'macroservice-libraries:packages/data-jobs/src/keyed-item-decision.ts:decideKeyedItem'
    origin: 'services-crm:docs/milestones/CRM-M7-data-operations.md#D-38'
  - id: BR-CAP-PFM-DJE-006-07
    proved_by: [ATS-PFM-DJE-006-10, ATS-PFM-DJE-012-13]
    statement: >-
      The crosswalk retains the version the producer actually wrote rather than adopting a later
      staff-edited version.
    kind: invariant
    enforced_at:
      - service
      - database
    must_prove: false
    provenance: documented
    source: 'macroservice-libraries:packages/data-jobs/README.md#Keyed writes and the ID crosswalk'
    origin: 'services-crm:docs/milestones/CRM-M7-data-operations.md#D-38'
  - id: BR-CAP-PFM-DJE-006-08
    proved_by: []
    statement: >-
      File-job protection uses producer crosswalk versions and explicit expected versions instead of a
      validation snapshot.
    kind: invariant
    enforced_at:
      - service
    must_prove: false
    provenance: documented
    source: >-
      macroservice-libraries:packages/data-jobs/README.md#Versions: captured at validation, verified at
      application
    origin: none
scenarios:
  - id: SC-CAP-PFM-DJE-006-01
    given: An administrator previews title changes for 35 contacts before a colleague edits one.
    when: They approve the job and then revalidate its conflict.
    then: >-
      Thirty-four contacts change initially; the conflict identifies the editor and time, and a
      separately approved revalidation can change the remaining contact.
    provenance: test
    source: 'react-console:acceptance/data-jobs/playwright/journeys/dialogs/DJE-ACC-0103.spec.ts#DJE-ACC-0103'
edge_cases: []
constraints: []
depends_on: []
related:
  - CAP-PFM-DJE-002
  - CAP-PFM-DJE-008
  - CAP-PFM-DJE-012
journeys:
  - JNY-PFM-DJE-002
  - JNY-PFM-DJE-005
open_questions: []
evidence:
  - >-
    Reviewed evidence: macroservice-libraries (54536a44): README.md (Versions; Keyed writes);
    src/version-capture.ts, revalidate-data-job-conflicts.ts, keyed-item-decision.ts; tests
    version-capture.integration.spec.ts, keyed-data-jobs.integration.spec.ts,
    keyed-patches.integration.spec.ts.
  - >-
    Reviewed evidence: services-crm (a8d1364f): docs/data-jobs.md (Concurrent edits);
    services/operations/captured-versions.ts, version-conflicts.ts; tests
    contact-update-versions.integration.spec.js, organization-update-versions.integration.spec.js,
    organization-update-conflicts.integration.spec.js.
  - >-
    Reviewed evidence: react-console (baf6dae3):
    acceptance/data-jobs/playwright/journeys/dialogs/DJE-ACC-0103.spec.ts;
    acceptance/crm/journeys/data-operations/CRM-ACC-0651, 0667.
controls: [TC-AVL-001, TC-AVL-004, TC-AZ-001, TC-AZ-002, TC-AZ-003, TC-AZ-004, TC-DAT-001, TC-DAT-003, TC-LOG-004, TC-LOG-005, TC-MON-001, 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]
exercised_by: [FAS-PFM-DJE-02-01, FAS-PFM-DJE-02-03, FAS-PFM-DJE-02-04, FAS-PFM-DJE-02-05]
suites: [TST-PFM-DJE-029, TST-PFM-DJE-030, TST-PFM-DJE-066, TST-PFM-DJE-085, TST-PFM-DJE-120]
---

# Preserve intervening edits during bulk changes

## Purpose

Administrators can review conflicts before replacing information that another person changed while a job waited.

## How It Works

An administrator previews an interactive change before applying it. For eligible changes, Rhythm retains the record versions used by validation. A later edit prevents the job from silently replacing that record. The remaining records can still proceed. A contact already holding the desired values needs no further write and is reported unchanged. Staff can create a new validation for the conflicted records and review their current state. This is a correction job rather than a retry of the original input. Producer deliveries use crosswalk versions to protect edits between files. An overwrite policy explicitly changes that protection, while a record’s supplied expected version remains binding.

## Relationships

- Preview supplies eligible version snapshots.
- Rollback uses a related safeguard for later field edits.
- Producer-key imports supply crosswalk versions for recurring deliveries.
