---
id: ATS-CRM-ACT-001
scope: CAP-CRM-ACT-001
product_area: crm
module: activities-tasks
revision: 3
status: proposed
approved_by: null
approved_at: null
source_sha:
  services-crm: a8d1364f1dd44b723bb5f9acba12f983e9ec8d69
  react-console: baf6dae382d6f41dce976c7f848667ccc37e076f
  rhythm-v2-docs: 18a49edf30ee6bda18b159b65a2b91e093ea713d
scenarios:
- id: ATS-CRM-ACT-001-01
  title: Reject invalid activity link sets
  level: api
  proves:
  - BR-CAP-CRM-ACT-001-01
  preconditions: Workspace contact and organization fixtures are available.
  steps: Submit empty, ambiguous, repeated and 201-entry link sets.
  expected: Each request identifies invalid links and leaves no activity.
  negative: true
  data_needs: Each run creates and isolates the records it needs.
  bound_to:
  - services-crm:modules/activities/tests/integration/services/persistence/activities.integration.spec.js#refuses
    an activity linked to nothing
  - services-crm:modules/activities/tests/integration/services/persistence/activities.integration.spec.js#refuses
    a link that names both a contact and an organization
  - services-crm:modules/activities/tests/integration/services/persistence/activities.integration.spec.js#refuses
    a record linked twice
  - services-crm:modules/activities/tests/integration/services/persistence/activities.integration.spec.js#refuses
    more than 200 links
  - services-crm:modules/activities/tests/integration/db/activities.table.integration.spec.js#refuses
    a link to a contact and an organization at once
  - TST-CRM-ACT-007
  - TST-CRM-ACT-003
  provenance: test
  source: services-crm:modules/activities/tests/integration/services/persistence/activities.integration.spec.js#refuses
    an activity linked to nothing
  category: validation
  binding_scope: Each registered suite contributes the assertions named by the retained file bindings;
    a compound scenario can require several suites. Conformance remains unverified.
- id: ATS-CRM-ACT-001-02
  title: Default a primary link and reject competing primaries
  level: api
  proves:
  - BR-CAP-CRM-ACT-001-02
  preconditions: Two workspace contacts can be linked.
  steps: Save with neither primary, then with both marked primary.
  expected: The first link becomes primary in the valid save; the conflicting save fails.
  negative: true
  data_needs: Each run creates and isolates the records it needs.
  bound_to:
  - services-crm:modules/activities/tests/integration/services/persistence/activities.integration.spec.js#makes
    the first link the primary one when none says it is
  - services-crm:modules/activities/tests/integration/services/persistence/activities.integration.spec.js#refuses
    two primary links
  - services-crm:modules/activities/tests/integration/db/activities.table.integration.spec.js#refuses
    a second primary link of one activity
  - TST-CRM-ACT-007
  - TST-CRM-ACT-003
  provenance: test
  source: services-crm:modules/activities/tests/integration/services/persistence/activities.integration.spec.js#makes
    the first link the primary one when none says it is
  category: rule
  binding_scope: Each registered suite contributes the assertions named by the retained file bindings;
    a compound scenario can require several suites. Conformance remains unverified.
- id: ATS-CRM-ACT-001-03
  title: Inspect primary selection and persist an API correction
  level: browser
  proves:
  - BR-CAP-CRM-ACT-001-02
  preconditions: A contact has an organization available for linking.
  steps: Inspect the form primary controls, then select the organization through the API and inspect stored
    links.
  expected: The API correction makes the organization primary; the historical browser assertion separately
    checks whether the form exposes that choice.
  negative: false
  data_needs: Each run creates and isolates the records it needs.
  bound_to:
  - react-console:lib/activities/links.test.ts#makes a chosen contact or organization the one primary
    link
  - react-console:acceptance/crm/playwright/journeys/cross-application/CRM-ACC-0691.spec.ts#CRM-ACC-0691
  - TST-CRM-ACT-082
  - TST-CRM-ACT-035
  provenance: test
  source: react-console:lib/activities/links.test.ts#makes a chosen contact or organization the one primary
    link
  category: interaction
  binding_note: The helper unit assertion proves link selection. The historical browser journey performs
    the stored primary correction through the API and soft-asserts a missing form control; it does not
    execute today’s primary button.
  binding_scope: Each registered suite contributes the assertions named by the retained file bindings;
    a compound scenario can require several suites. Conformance remains unverified.
- id: ATS-CRM-ACT-001-04
  title: Reject unavailable types for new interactions
  level: api
  proves:
  - BR-CAP-CRM-ACT-001-03
  preconditions: An activity type is inactive.
  steps: Create an activity with that type.
  expected: The service identifies the unavailable type and refuses creation.
  negative: true
  data_needs: Each run creates and isolates the records it needs.
  bound_to:
  - services-crm:modules/activities/tests/integration/services/persistence/activities.integration.spec.js#refuses
    an inactive type for a new activity
  - services-crm:modules/activities/tests/integration/services/persistence/activities.integration.spec.js#refuses
    a type the tenant does not have
  - TST-CRM-ACT-007
  provenance: test
  source: services-crm:modules/activities/tests/integration/services/persistence/activities.integration.spec.js#refuses
    an inactive type for a new activity
  category: validation
  binding_scope: Each registered suite contributes the assertions named by the retained file bindings;
    a compound scenario can require several suites. Conformance remains unverified.
- id: ATS-CRM-ACT-001-05
  title: Apply field modes without forbidding hidden attendee links
  level: unit
  proves:
  - BR-CAP-CRM-ACT-001-04
  - BR-CAP-CRM-ACT-001-16
  preconditions: Types cover hidden and required modes.
  steps: Evaluate hidden values, absent required values, a scheduled call and contacts with attendees
    hidden.
  expected: Invalid details fail; the scheduled call needs no completed-result fields and hidden attendee
    links remain valid.
  negative: true
  data_needs: Each run creates and isolates the records it needs.
  bound_to:
  - services-crm:modules/activities/tests/unit/services/activities/field-modes.spec.js#refuses a hidden
    direction that is present
  - services-crm:modules/activities/tests/unit/services/activities/field-modes.spec.js#refuses a required
    outcome that a completed activity lacks
  - services-crm:modules/activities/tests/unit/services/activities/field-modes.spec.js#asks a scheduled
    activity for no required outcome or duration, those being what came of it
  - 'services-crm:modules/activities/tests/integration/services/persistence/activities.integration.spec.js#refuses
    a hidden field: a note with a direction'
  - 'services-crm:modules/activities/tests/e2e/activities.e2e.spec.js#refuses a hidden field the type
    does not take: 400 naming it'
  - services-crm:modules/activities/tests/unit/services/activities/field-modes.spec.js#refuses nothing
    about the links when attendees are hidden
  - TST-CRM-ACT-013
  - TST-CRM-ACT-007
  - TST-CRM-ACT-002
  provenance: test
  source: services-crm:modules/activities/tests/unit/services/activities/field-modes.spec.js#refuses a
    hidden direction that is present
  category: validation
  binding_scope: Each registered suite contributes the assertions named by the retained file bindings;
    a compound scenario can require several suites. Conformance remains unverified.
- id: ATS-CRM-ACT-001-06
  title: Require an additional contact attendee
  level: api
  proves:
  - BR-CAP-CRM-ACT-001-05
  preconditions: The chosen type requires attendees.
  steps: Log an activity with only a primary contact.
  expected: The request identifies the missing attendee links.
  negative: true
  data_needs: Each run creates and isolates the records it needs.
  bound_to:
  - services-crm:modules/activities/tests/integration/services/persistence/activities.integration.spec.js#asks
    for an attendee besides the primary record when the type requires attendees
  - TST-CRM-ACT-007
  provenance: test
  source: services-crm:modules/activities/tests/integration/services/persistence/activities.integration.spec.js#asks
    for an attendee besides the primary record when the type requires attendees
  category: validation
  binding_scope: Each registered suite contributes the assertions named by the retained file bindings;
    a compound scenario can require several suites. Conformance remains unverified.
- id: ATS-CRM-ACT-001-07
  title: Validate outcomes against type and active selection
  level: api
  proves:
  - BR-CAP-CRM-ACT-001-06
  preconditions: Two types and a deactivated outcome exist.
  steps: Try a foreign outcome and an inactive outcome, then retain a prior inactive selection.
  expected: New invalid selections fail while an existing inactive outcome can remain.
  negative: true
  data_needs: Each run creates and isolates the records it needs.
  bound_to:
  - services-crm:modules/activities/tests/integration/services/persistence/activities.integration.spec.js#refuses
    an outcome of another type
  - services-crm:modules/activities/tests/integration/services/persistence/activities.integration.spec.js#refuses
    a deactivated outcome for a new activity
  - services-crm:modules/activities/tests/integration/services/persistence/activities.integration.spec.js#keeps
    a deactivated outcome on an activity that already has it
  - services-crm:modules/activities/tests/integration/db/activities.table.integration.spec.js#refuses
    an outcome of another type, by the three-column key
  - TST-CRM-ACT-007
  - TST-CRM-ACT-003
  provenance: test
  source: services-crm:modules/activities/tests/integration/services/persistence/activities.integration.spec.js#refuses
    an outcome of another type
  category: validation
  binding_scope: Each registered suite contributes the assertions named by the retained file bindings;
    a compound scenario can require several suites. Conformance remains unverified.
- id: ATS-CRM-ACT-001-08
  title: Report time and numeric boundary failures
  level: api
  proves:
  - BR-CAP-CRM-ACT-001-07
  preconditions: A valid active type is available.
  steps: Send an earlier end, durations outside zero to 1,440 and a 501-character subject.
  expected: Each refusal names the relevant field.
  negative: true
  data_needs: Each run creates and isolates the records it needs.
  bound_to:
  - services-crm:modules/activities/tests/integration/services/persistence/activities.integration.spec.js#refuses
    an end before the start
  - services-crm:modules/activities/tests/integration/services/persistence/activities.integration.spec.js#refuses
    a duration below 0 minutes, naming the field
  - services-crm:modules/activities/tests/integration/services/persistence/activities.integration.spec.js#refuses
    a duration above 1440 minutes, naming the field
  - services-crm:modules/activities/tests/integration/services/persistence/activities.integration.spec.js#refuses
    a subject of more than 500 characters, naming the field
  - TST-CRM-ACT-007
  provenance: test
  source: services-crm:modules/activities/tests/integration/services/persistence/activities.integration.spec.js#refuses
    an end before the start
  category: boundary
  binding_scope: Each registered suite contributes the assertions named by the retained file bindings;
    a compound scenario can require several suites. Conformance remains unverified.
- id: ATS-CRM-ACT-001-09
  title: Clean note content and reject excessive retained text
  level: unit
  proves:
  - BR-CAP-CRM-ACT-001-08
  preconditions: The sanitizer and a valid activity fixture are available.
  steps: Supply unsafe markup, empty markup and more than 100,000 retained characters.
  expected: Unsafe content disappears, empty content becomes empty, and excessive content fails by field.
  negative: true
  data_needs: Each run creates and isolates the records it needs.
  bound_to:
  - services-crm:modules/activities/tests/unit/services/activities/activity-body.spec.js#drops a script
    and its content
  - services-crm:modules/activities/tests/unit/services/activities/activity-body.spec.js#drops an event
    handler and an inline style
  - 'services-crm:modules/activities/tests/unit/services/activities/activity-body.spec.js#drops a javascript:
    link but keeps its text'
  - services-crm:modules/activities/tests/unit/services/activities/activity-body.spec.js#answers null
    for a body of nothing but markup and whitespace
  - services-crm:modules/activities/tests/integration/services/persistence/activities.integration.spec.js#refuses
    a body over 100000 characters once sanitised, naming body, and writes nothing
  - 'services-crm:modules/activities/tests/e2e/activities.e2e.spec.js#refuses a body over 100000 characters
    once sanitised: 400 naming body'
  - TST-CRM-ACT-012
  - TST-CRM-ACT-007
  - TST-CRM-ACT-002
  provenance: test
  source: services-crm:modules/activities/tests/unit/services/activities/activity-body.spec.js#drops a
    script and its content
  category: boundary
  binding_scope: Each registered suite contributes the assertions named by the retained file bindings;
    a compound scenario can require several suites. Conformance remains unverified.
- id: ATS-CRM-ACT-001-10
  title: Apply defaults for person and machine callers
  level: api
  proves:
  - BR-CAP-CRM-ACT-001-09
  preconditions: A type declares a default duration.
  steps: Create with only required details as a user and as a job.
  expected: Type and clock defaults apply; the job-created activity has no default user owner.
  negative: false
  data_needs: Each run creates and isolates the records it needs.
  bound_to:
  - services-crm:modules/activities/tests/integration/services/persistence/activities.integration.spec.js#defaults
    the status, the time and the owner from the type, the clock and the caller
  - services-crm:modules/activities/tests/integration/services/persistence/activities.integration.spec.js#defaults
    a type’s duration on a create that states none
  - services-crm:modules/activities/tests/integration/services/persistence/activities.integration.spec.js#gives
    the activity no owner when the caller is not a user
  - TST-CRM-ACT-007
  provenance: test
  source: services-crm:modules/activities/tests/integration/services/persistence/activities.integration.spec.js#defaults
    the status, the time and the owner from the type, the clock and the caller
  category: rule
  binding_scope: Each registered suite contributes the assertions named by the retained file bindings;
    a compound scenario can require several suites. Conformance remains unverified.
- id: ATS-CRM-ACT-001-11
  title: Recover one activity from repeated creation
  level: api
  proves:
  - BR-CAP-CRM-ACT-001-11
  preconditions: A client selects a valid time-ordered activity identifier.
  steps: Repeat identical creates, race them, and submit different content under the same identifier.
  expected: Identical deliveries retain one activity and follow-up; differing content conflicts.
  negative: true
  data_needs: Each run creates and isolates the records it needs.
  bound_to:
  - services-crm:modules/activities/tests/integration/services/persistence/activities.create-retries.integration.spec.js#makes
    one activity
  - services-crm:modules/activities/tests/integration/services/persistence/activities.create-retries.integration.spec.js#answers
    the retry with the activity the first attempt made, as a read answers it
  - services-crm:modules/activities/tests/integration/services/persistence/activities.create-retries.integration.spec.js#refuses
    it as a conflict (409), naming the id
  - react-console:acceptance/crm/playwright/journeys/cross-application/CRM-ACC-0729.spec.ts#CRM-ACC-0729
  - TST-CRM-ACT-006
  - TST-CRM-ACT-069
  provenance: test
  source: services-crm:modules/activities/tests/integration/services/persistence/activities.create-retries.integration.spec.js#makes
    one activity
  category: concurrency
  binding_scope: Each registered suite contributes the assertions named by the retained file bindings;
    a compound scenario can require several suites. Conformance remains unverified.
- id: ATS-CRM-ACT-001-12
  title: Retain import attribution and unique external references
  level: api
  proves:
  - BR-CAP-CRM-ACT-001-12
  preconditions: An import origin and external reference are supplied.
  steps: Create an imported activity, repeat its external reference and edit the original.
  expected: Origin persists and duplicate external references fail.
  negative: true
  data_needs: Each run creates and isolates the records it needs.
  bound_to:
  - services-crm:modules/activities/tests/integration/services/persistence/activities.integration.spec.js#records
    sys_origin and sys_external_id from the source it is given
  - services-crm:modules/activities/tests/integration/services/persistence/activities.integration.spec.js#keeps
    the origin it was created with
  - services-crm:modules/activities/tests/integration/db/activities.table.integration.spec.js#refuses
    a second activity of the tenant under the same external id
  - TST-CRM-ACT-007
  - TST-CRM-ACT-003
  provenance: test
  source: services-crm:modules/activities/tests/integration/services/persistence/activities.integration.spec.js#records
    sys_origin and sys_external_id from the source it is given
  category: invariant
  binding_scope: Each registered suite contributes the assertions named by the retained file bindings;
    a compound scenario can require several suites. Conformance remains unverified.
- id: ATS-CRM-ACT-001-13
  title: Reject activity custom field values
  level: api
  proves:
  - BR-CAP-CRM-ACT-001-13
  preconditions: An active type permits a valid activity.
  steps: Include custom field values in the save.
  expected: The API rejects the unsupported custom-field property.
  negative: true
  data_needs: Each run creates and isolates the records it needs.
  bound_to:
  - 'services-crm:modules/activities/tests/e2e/activities.e2e.spec.js#refuses a custom field value, an
    activity having no custom fields (R2-ARCH-001): 400 naming custom_fields'
  - services-crm:modules/activities/tests/e2e/activities.e2e.spec.js#answers an activity with no custom_fields
    property
  - TST-CRM-ACT-002
  provenance: test
  source: 'services-crm:modules/activities/tests/e2e/activities.e2e.spec.js#refuses a custom field value,
    an activity having no custom fields (R2-ARCH-001): 400 naming custom_fields'
  category: validation
  binding_scope: Each registered suite contributes the assertions named by the retained file bindings;
    a compound scenario can require several suites. Conformance remains unverified.
- id: ATS-CRM-ACT-001-14
  title: Shared logging survives correction and creates one follow-up
  category: interaction
  level: api
  proves:
  - BR-CAP-CRM-ACT-001-02
  - BR-CAP-CRM-ACT-002-09
  - BR-CAP-CRM-ACT-003-04
  - BR-CAP-CRM-ACT-005-05
  preconditions: Two contacts and an organization are linked to one interaction; the type suggests follow-up
    work.
  steps: Log with a follow-up, then correct the primary selection and remove one secondary link. Read
    both remaining timelines, the removed timeline and the task.
  expected: The remaining records show the corrected shared entry once, the removed context omits it,
    and the original follow-up remains a single task.
  negative: false
  data_needs: Run-owned records in an isolated workspace; fixed clock for calendar checks.
  bound_to: []
  provenance: proposed
  source: services-crm:modules/activities/tests/integration/services/persistence/activities.integration.spec.js#makes
    the first link the primary one when none says it is; services-crm:modules/activities/tests/integration/services/persistence/activities.integration.spec.js#writes
    nothing when the follow-up task is refused; 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; services-crm:modules/activities/tests/integration/services/persistence/activities.queries.integration.spec.js#shows
    the activity linked to three contacts and an organization once on each of the four timelines
  exercises:
  - CAP-CRM-ACT-001
  - CAP-CRM-ACT-002
  - CAP-CRM-ACT-003
  - CAP-CRM-ACT-005
  related:
  - CAP-CRM-ACT-002
  - CAP-CRM-ACT-003
  - CAP-CRM-ACT-005
- id: ATS-CRM-ACT-001-15
  title: Clear ownership after the creation default
  category: rule
  level: api
  proves:
  - BR-CAP-CRM-ACT-001-17
  preconditions: A user can create and update an activity.
  steps: Create once with ownership omitted and once with empty ownership; edit each to clear ownership
    and read back.
  expected: Both initial records name the caller as owner; the later edits retain empty ownership.
  negative: false
  data_needs: Run-owned records in an isolated workspace; fixed clock for calendar checks.
  bound_to: []
  provenance: proposed
  source: services-crm:modules/activities/services/persistence/activities.ts:activityValuesOf
- id: ATS-CRM-ACT-001-16
  title: Collect field problems and keep both records absent
  category: failure
  level: api
  proves:
  - BR-CAP-CRM-ACT-001-15
  - BR-CAP-CRM-ACT-002-09
  preconditions: The type requires direction and outcome; a follow-up is requested.
  steps: Submit completed work missing both required details and inspect validation and database counts.
  expected: The refusal identifies both fields and neither activity nor task is retained.
  negative: false
  data_needs: Run-owned records in an isolated workspace; fixed clock for calendar checks.
  bound_to: []
  provenance: proposed
  source: services-crm:modules/activities/services/persistence/activities.ts:saveNewActivity
evidence:
- 'services-crm at a8d1364f1dd44b723bb5f9acba12f983e9ec8d69: scenario sources, executable assertions and
  local dependency boundaries are inspected.'
- 'react-console at baf6dae382d6f41dce976c7f848667ccc37e076f: scoped component tests and browser journey
  assertions are inspected.'
coverage:
  rule: covered
  transition: 'gap: FND-CRM-ACT-068'
  validation: covered
  permission: 'gap: FND-CRM-ACT-068'
  edge: 'gap: FND-CRM-ACT-068'
  failure: covered
  boundary: covered
  concurrency: covered
  invariant: covered
  interaction: covered
coverage_obligations:
  finding: FND-CRM-ACT-068
  unproved_rules: []
  permission_matrix:
    keys:
    - crm.activities.create
    remaining: Complete allow/refuse combinations, including each console guard and each API operation.
  execution_note: Covered means a scenario is specified; it does not mean that scenario has executed or
    every variant has an executable binding.
related_coverage:
- capability: CAP-CRM-ACT-002
  scenarios:
  - ATS-CRM-ACT-001-14
  finding: FND-CRM-ACT-068
- capability: CAP-CRM-ACT-003
  scenarios:
  - ATS-CRM-ACT-001-14
  finding: FND-CRM-ACT-068
- capability: CAP-CRM-ACT-005
  scenarios:
  - ATS-CRM-ACT-001-14
  finding: FND-CRM-ACT-068
permission_coverage:
- key: crm.activities.create
  finding: FND-CRM-ACT-068
  note: The finding covers unproved operation and surface combinations; a permission-category scenario
    is not a complete permission matrix.
---

# Log one interaction for all related people and organizations: Capability Test Specification

## Coverage

Category coverage counts specified proof. Unbound cases remain proposed; registered assertions do not establish a passing run.

| Rule | Proof Scenario Or Finding |
|---|---|
| `BR-CAP-CRM-ACT-001-01` | `ATS-CRM-ACT-001-01` |
| `BR-CAP-CRM-ACT-001-02` | `ATS-CRM-ACT-001-02`, `ATS-CRM-ACT-001-03`, `ATS-CRM-ACT-001-14` |
| `BR-CAP-CRM-ACT-001-03` | `ATS-CRM-ACT-001-04` |
| `BR-CAP-CRM-ACT-001-04` | `ATS-CRM-ACT-001-05` |
| `BR-CAP-CRM-ACT-001-05` | `ATS-CRM-ACT-001-06` |
| `BR-CAP-CRM-ACT-001-06` | `ATS-CRM-ACT-001-07` |
| `BR-CAP-CRM-ACT-001-07` | `ATS-CRM-ACT-001-08` |
| `BR-CAP-CRM-ACT-001-08` | `ATS-CRM-ACT-001-09` |
| `BR-CAP-CRM-ACT-001-09` | `ATS-CRM-ACT-001-10` |
| `BR-CAP-CRM-ACT-001-11` | `ATS-CRM-ACT-001-11` |
| `BR-CAP-CRM-ACT-001-12` | `ATS-CRM-ACT-001-12` |
| `BR-CAP-CRM-ACT-001-13` | `ATS-CRM-ACT-001-13` |
| `BR-CAP-CRM-ACT-001-15` | `ATS-CRM-ACT-001-16` |
| `BR-CAP-CRM-ACT-001-16` | `ATS-CRM-ACT-001-05` |
| `BR-CAP-CRM-ACT-001-17` | `ATS-CRM-ACT-001-15` |

## Interactions With Related Capabilities

Two contacts and an organization are linked to one interaction; the type suggests follow-up work. Log with a follow-up, then correct the primary selection and remove one secondary link. Read both remaining timelines, the removed timeline and the task.

The interaction scenario names the capabilities and rules it exercises. The coverage finding retains incomplete permission combinations and failure variants.
