---
id: CAP-CRM-ACT-003
title: Correct or delete an activity with protection against stale edits
feature: FEAT-CRM-ACT-01
product_area: crm
module: activities-tasks
revision: 2
status: draft
product_intent: proposed
implementation_evidence: observed
supersedes:
  - react-console acceptance inventory CAP-CRM-ACT-002
source_sha:
  services-crm: a8d1364f1dd44b723bb5f9acba12f983e9ec8d69
  react-console: baf6dae382d6f41dce976c7f848667ccc37e076f
intent_sources:
  - 'services-crm:docs/milestones/CRM-M8-activities-and-tasks.md#E-09'
  - 'services-crm:docs/milestones/CRM-M1-contacts-and-organizations.md#D-05'
  - 'services-crm:docs/migrations/activities/README.md#D9'
purpose: Staff amend an interaction without overwriting a newer correction.
outcomes:
  - Changes limited to the intended details
  - Conflicts that preserve newer work
  - Shared entries editable by authorized colleagues
concepts:
  - CON-CRM-ACT-001
actors:
  - ACT-CRM-001
  - ACT-CRM-004
surfaces:
  - console
  - api
  - job
preconditions:
  - The workspace contains the activity being changed.
postconditions:
  - >-
    The save advances the activity version, or deletion removes the activity and
    its links.
permissions:
  - key: crm.activities.read
    where_checked: api
    scope: tenant
  - key: crm.activities.update
    where_checked: api
    scope: tenant
  - key: crm.activities.delete
    where_checked: api
    scope: tenant
  - key: crm.activities.update
    where_checked: console
    scope: tenant
  - key: crm.activities.delete
    where_checked: console
    scope: tenant
rules:
  - id: BR-CAP-CRM-ACT-003-01
    proved_by: [ATS-CRM-ACT-003-01, ATS-CRM-ACT-003-09, TST-CRM-ACT-002, TST-CRM-ACT-007]
    statement: >-
      An edit must use the version read, and a stale version causes a conflict
      without changing the activity.
    kind: validation
    enforced_at:
      - api
      - service
    must_prove: true
    provenance: test
    source: >-
      services-crm:modules/activities/tests/e2e/activities.e2e.spec.js#refuses a
      replace of a version it has moved on from: 409
    origin: 'services-crm:docs/milestones/CRM-M1-contacts-and-organizations.md#D-05'
  - id: BR-CAP-CRM-ACT-003-02
    proved_by: [ATS-CRM-ACT-003-02, TST-CRM-ACT-002]
    statement: >-
      A partial edit changes only named properties, clearing those explicitly
      set to empty and preserving the rest.
    kind: policy
    enforced_at:
      - api
      - service
    must_prove: true
    provenance: test
    source: >-
      services-crm:modules/activities/tests/e2e/activities.e2e.spec.js#leaves
      every property the patch omits as it was: duration, end, body, external
      id, owner and links
    origin: 'services-crm:docs/milestones/CRM-M8-activities-and-tasks.md#E-09'
  - id: BR-CAP-CRM-ACT-003-03
    proved_by: [ATS-CRM-ACT-003-03, TST-CRM-ACT-002, TST-CRM-ACT-036]
    statement: >-
      A complete replacement must include every required replacement property,
      and missing properties cause a field-specific refusal without a write.
    kind: validation
    enforced_at:
      - api
    must_prove: true
    provenance: test
    source: >-
      services-crm:modules/activities/tests/e2e/activities.e2e.spec.js#refuses a
      replacement missing a property: 400 naming it
    origin: 'services-crm:docs/milestones/CRM-M8-activities-and-tasks.md#E-09'
  - id: BR-CAP-CRM-ACT-003-04
    proved_by: [ATS-CRM-ACT-001-14, ATS-CRM-ACT-003-04, ATS-CRM-ACT-006-04, TST-CRM-ACT-007]
    statement: >-
      Replacing activity links matches them by related record, preserving the
      existing link for each record retained in the set.
    kind: policy
    enforced_at:
      - service
    must_prove: true
    provenance: test
    source: >-
      services-crm:modules/activities/tests/integration/services/persistence/activities.integration.spec.js#replaces
      the links as a set on update, keeping the row of a record still linked
    origin: none
  - id: BR-CAP-CRM-ACT-003-05
    proved_by: [ATS-CRM-ACT-003-05, ATS-CRM-ACT-008-10, TST-CRM-ACT-007, TST-CRM-ACT-044]
    statement: >-
      An activity can retain its deactivated type or outcome during correction,
      but cannot switch to an inactive type.
    kind: policy
    enforced_at:
      - service
    must_prove: true
    provenance: test
    source: >-
      services-crm:modules/activities/tests/integration/services/persistence/activities.integration.spec.js#keeps
      an inactive type on an activity that already has it
    origin: none
  - id: BR-CAP-CRM-ACT-003-06
    proved_by: [ATS-CRM-ACT-003-06, TST-CRM-ACT-007]
    statement: >-
      An update lock blocks edits, and a deletion lock or full lock blocks
      deletion.
    kind: validation
    enforced_at:
      - service
    must_prove: true
    provenance: test
    source: >-
      services-crm:modules/activities/tests/integration/services/persistence/activities.integration.spec.js#refuses
      a locked activity
    origin: 'services-crm:docs/milestones/CRM-M8-activities-and-tasks.md#D-08'
  - id: BR-CAP-CRM-ACT-003-07
    proved_by: [ATS-CRM-ACT-003-07, ATS-CRM-ACT-004-05, TST-CRM-ACT-002, TST-CRM-ACT-007]
    statement: >-
      Deleting an activity also deletes its links and attachment records, and
      another deletion reports it absent.
    kind: lifecycle
    enforced_at:
      - service
      - database
    must_prove: true
    provenance: test
    source: >-
      services-crm:modules/activities/tests/integration/services/persistence/activities.integration.spec.js#removes
      the activity and its links
    origin: none
  - id: BR-CAP-CRM-ACT-003-08
    proved_by: [ATS-CRM-ACT-003-08, TST-CRM-ACT-061]
    statement: >-
      The corresponding activity permissions permit edits and deletion
      regardless of ownership; activity deletion is a user-tier permission,
      whereas contact deletion is an administrator-tier permission.
    kind: permission
    enforced_at:
      - api
    must_prove: true
    provenance: observed
    source: 'services-crm:aws/crm.service.ts:ActivitiesPermissions'
    origin: none
    note: >-
      This source is an implementation decision record, so it does not confirm
      Product authority for the rule.
  - id: BR-CAP-CRM-ACT-003-09
    proved_by: []
    statement: Editing an activity preserves its original source classification.
    kind: invariant
    enforced_at:
      - service
    must_prove: true
    provenance: test
    source: >-
      services-crm:modules/activities/tests/integration/services/persistence/activities.integration.spec.js#keeps
      the origin it was created with
    origin: none
  - id: BR-CAP-CRM-ACT-003-10
    proved_by: []
    statement: >-
      After an ambiguous edit response, the console reads the activity and
      reports success only if the saved values match the submitted change.
    kind: policy
    enforced_at:
      - console
    must_prove: false
    provenance: test
    source: >-
      react-console:lib/activities/retry-safe-writes.test.ts#is saved when its
      answer is lost but the activity holds what was sent
    origin: 'services-crm:docs/milestones/CRM-M8-activities-and-tasks.md#D-43'
  - id: BR-CAP-CRM-ACT-003-11
    proved_by: []
    statement: >-
      Deleting an activity removes its import mappings, allowing a subsequent
      import of that source item to create a new activity.
    kind: lifecycle
    enforced_at:
      - service
    must_prove: true
    provenance: observed
    source: >-
      services-crm:modules/activities/services/persistence/activities.ts:deleteActivity
    origin: none
scenarios:
  - id: SC-CAP-CRM-ACT-003-01
    given: Two editors read the same call version.
    when: Save one correction and then submit the other editor’s correction.
    then: The later stale save is rejected and the first correction remains.
    provenance: test
    source: >-
      react-console:acceptance/crm/playwright/journeys/cross-application/CRM-ACC-0693.spec.ts#CRM-ACC-0693
  - id: SC-CAP-CRM-ACT-003-02
    given: An integration prepares a meeting replacement.
    when: Omit duration from the complete replacement.
    then: The request names the missing duration and retains the earlier meeting.
    provenance: test
    source: >-
      react-console:acceptance/crm/playwright/journeys/cross-application/CRM-ACC-0692.spec.ts#CRM-ACC-0692
edge_cases: []
constraints: []
depends_on:
  - CAP-CRM-ACT-001
related:
  - CAP-CRM-ACT-004
  - CAP-CRM-ACT-006
  - CAP-CRM-ACT-019
journeys:
  - JNY-CRM-ACT-001
open_questions: []
evidence:
  - >-
    services-crm at a8d1364f1dd44b723bb5f9acba12f983e9ec8d69: Independently
    reviewed declarations, behavior and assertions identified in this
    capability’s row citations.
  - >-
    react-console at baf6dae382d6f41dce976c7f848667ccc37e076f: Independently
    reviewed declarations, behavior and assertions identified in this
    capability’s row citations.
controls: [TC-AZ-001, TC-AZ-002, TC-AZ-003, TC-AZ-004, TC-AZ-006, 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-PRV-003, TC-TEN-001, TC-TEN-002, TC-TEN-003]
exercised_by: [FAS-CRM-ACT-01-03, FAS-CRM-ACT-01-04, FAS-CRM-ACT-01-06, FAS-CRM-ACT-02-02, FAS-CRM-ACT-02-03]
suites: [TST-CRM-ACT-002, TST-CRM-ACT-007, TST-CRM-ACT-036, TST-CRM-ACT-044, TST-CRM-ACT-061]
---

# Correct or delete an activity with protection against stale edits

## Purpose

Staff amend an interaction without overwriting a newer correction.

## How It Works

A coordinator opens an activity from the record timeline. The editor sends the changed details with the version it read. Rhythm checks that version before accepting the correction. A conflict requires the coordinator to reload and reconcile the newer record. An integration using a complete replacement must provide the complete replacement content. The console handles an uncertain save response by checking the stored record. Existing deactivated selections can remain during a correction. Deletion removes the activity’s local links and attachment records. The relevant lock can prevent either correction or deletion.

## Relationships

- Activity logging defines the shared record being corrected.
- Activity history presents the resulting revisions.
- Attachment handling releases the files associated with a deleted entry.
