---
id: ATS-CRM-DQ-004
scope: CAP-CRM-DQ-004
product_area: crm
module: data-quality
revision: 1
status: proposed
source_sha:
  services-crm: a8d1364f1dd44b723bb5f9acba12f983e9ec8d69
  react-console: baf6dae382d6f41dce976c7f848667ccc37e076f
scenarios:
  - id: ATS-CRM-DQ-004-01
    title: Draft results honor confidence and exclude the edited record
    level: api
    proves:
      - BR-CAP-CRM-DQ-004-01
      - BR-CAP-CRM-DQ-004-02
    preconditions: >-
      Prepare many draft look-alikes, its own saved record and a very-high rule
      floor.
    steps: Request the draft check.
    expected: >-
      No more than five ranked matches appear, excluding self and below-floor
      candidates.
    negative: false
    data_needs: The existing scenario setup supplies the required records.
    bound_to:
      - TST-CRM-DQ-180
    provenance: test
    source: >-
      services-crm:modules/duplicates/tests/integration/services/detection/duplicate-checks.integration.spec.js#answers
      at most the five a form shows, however many the tenant holds
    category: boundary
    execution_sources:
      - >-
        services-crm:modules/duplicates/tests/integration/services/detection/duplicate-checks.integration.spec.js#answers
        at most the five a form shows, however many the tenant holds
      - >-
        services-crm:modules/duplicates/tests/integration/services/detection/duplicate-checks.integration.spec.js#does
        not answer the record itself, a record never being its own duplicate
      - >-
        services-crm:modules/duplicates/tests/integration/services/detection/duplicate-checks.integration.spec.js#answers
        no record, the pair scoring 70 and the tenant asking for 90
  - id: ATS-CRM-DQ-004-02
    title: Checking does not create review work
    level: api
    proves:
      - BR-CAP-CRM-DQ-004-04
    preconditions: A draft resembles an existing contact.
    steps: Check the draft and read candidates afterwards.
    expected: The review queue retains its earlier contents.
    negative: false
    data_needs: The existing scenario setup supplies the required records.
    bound_to:
      - TST-CRM-DQ-182
    provenance: test
    source: >-
      services-crm:modules/duplicates/tests/e2e/duplicates.e2e.spec.js#writes
      nothing: the draft is not a record, so the queue is as it was
    category: invariant
    execution_sources:
      - >-
        services-crm:modules/duplicates/tests/e2e/duplicates.e2e.spec.js#writes
        nothing: the draft is not a record, so the queue is as it was
  - id: ATS-CRM-DQ-004-03
    title: Draft checking requires duplicate-read authority
    level: api
    proves:
      - BR-CAP-CRM-DQ-004-05
    preconditions: Use a caller with no duplicate permission.
    steps: Submit a check request.
    expected: Access is denied.
    negative: true
    data_needs: The existing scenario setup supplies the required records.
    bound_to:
      - TST-CRM-DQ-182
    provenance: test
    source: >-
      services-crm:modules/duplicates/tests/e2e/duplicates.e2e.spec.js#answers
      403 to a caller with no duplicates permission at all
    category: permission
    execution_sources:
      - >-
        services-crm:modules/duplicates/tests/e2e/duplicates.e2e.spec.js#answers
        403 to a caller with no duplicates permission at all
  - id: ATS-CRM-DQ-004-04
    title: Overrides validate reasons and commit with creation
    level: api
    proves:
      - BR-CAP-CRM-DQ-004-06
      - BR-CAP-CRM-DQ-004-07
    preconditions: A blocking rule refuses the intended create.
    steps: >-
      Try absent and blank reasons, no rule, a failing audit write and then a
      valid override.
    expected: >-
      Invalid fields are named, an audit failure leaves no contact and the valid
      create retains one attributed override record.
    negative: true
    data_needs: The existing scenario setup supplies the required records.
    bound_to:
      - TST-CRM-DQ-180
    provenance: test
    source: >-
      services-crm:modules/duplicates/tests/integration/services/persistence/duplicate-block-overrides.integration.spec.js#refuses
      an override with no reason, naming the field
    category: failure
    execution_sources:
      - >-
        services-crm:modules/duplicates/tests/integration/services/persistence/duplicate-block-overrides.integration.spec.js#refuses
        an override with no reason, naming the field
      - >-
        services-crm:modules/duplicates/tests/integration/services/persistence/duplicate-block-overrides.integration.spec.js#refuses
        an override naming no rule, naming the field
      - >-
        services-crm:modules/duplicates/tests/integration/services/persistence/duplicate-block-overrides.integration.spec.js#leaves
        no contact behind, the record and its audit sharing one transaction
      - >-
        services-crm:modules/duplicates/tests/integration/services/persistence/duplicate-block-overrides.integration.spec.js#records
        the override in the create, about the record the create made
  - id: ATS-CRM-DQ-004-05
    title: Override records cannot be duplicated or updated
    level: api
    proves:
      - BR-CAP-CRM-DQ-004-07
      - BR-CAP-CRM-DQ-004-08
    preconditions: A record already has a block override.
    steps: Insert another override and attempt an application update.
    expected: Both writes are refused.
    negative: true
    data_needs: The existing scenario setup supplies the required records.
    bound_to:
      - TST-CRM-DQ-180
    provenance: test
    source: >-
      services-crm:modules/duplicates/tests/integration/services/persistence/duplicate-block-overrides.integration.spec.js#refuses
      a second override of the same record, a record being created once
    category: invariant
    execution_sources:
      - >-
        services-crm:modules/duplicates/tests/integration/services/persistence/duplicate-block-overrides.integration.spec.js#refuses
        a second override of the same record, a record being created once
      - >-
        services-crm:modules/duplicates/tests/integration/services/persistence/duplicate-block-overrides.integration.spec.js#is
        not rewritable by the application, which holds no UPDATE on the audit
  - id: ATS-CRM-DQ-004-06
    title: Organization exceptions use the same accountable boundary
    level: api
    proves:
      - BR-CAP-CRM-DQ-004-10
    preconditions: Configure an organization blocker and an existing match.
    steps: 'Create ordinarily, then override with authority and a reason.'
    expected: >-
      Ordinary creation identifies the blocking match; the authorized exception
      creates an audited organization.
    negative: false
    data_needs: The existing scenario setup supplies the required records.
    bound_to:
      - TST-CRM-DQ-182
    provenance: test
    source: >-
      services-crm:modules/duplicates/tests/e2e/organization-block-rules.e2e.spec.js#refuses
      an ordinary user’s create 409 possible_duplicate, naming the held
      organization
    category: permission
    execution_sources:
      - >-
        services-crm:modules/duplicates/tests/e2e/organization-block-rules.e2e.spec.js#refuses
        an ordinary user’s create 409 possible_duplicate, naming the held
        organization
      - >-
        services-crm:modules/duplicates/tests/e2e/organization-block-rules.e2e.spec.js#audits
        the override with its reason, its rule and the organization it was let
        past
  - id: ATS-CRM-DQ-004-07
    title: The form displays suggestions only for a useful draft
    level: browser
    proves:
      - BR-CAP-CRM-DQ-004-01
      - BR-CAP-CRM-DQ-004-04
    preconditions: Prepare an existing member.
    steps: 'Enter matching details, then remove the name.'
    expected: >-
      Up to five suggestions appear without writes, and the nameless form shows
      no suggestions.
    negative: false
    data_needs: The existing scenario setup supplies the required records.
    bound_to:
      - TST-CRM-DQ-176
    provenance: test
    source: >-
      react-console:acceptance/crm/playwright/journeys/merging/CRM-ACC-0243.spec.ts#CRM-ACC-0243
    category: rule
    execution_sources:
      - >-
        react-console:acceptance/crm/playwright/journeys/merging/CRM-ACC-0243.spec.ts#CRM-ACC-0243
  - id: ATS-CRM-DQ-004-08
    title: Unsupported check record types are rejected
    level: api
    proves:
      - BR-CAP-CRM-DQ-004-13
    preconditions: Use an authorized duplicate reader.
    steps: Request a draft check for an unsupported record type.
    expected: The API returns an invalid-request refusal naming the type.
    negative: true
    data_needs: Use the records and caller described in this scenario.
    bound_to:
      - TST-CRM-DQ-182
    provenance: test
    source: 'services-crm:modules/duplicates/aws/api/duplicates.routes.ts:objectTypeOf'
    category: validation
    execution_sources:
      - >-
        services-crm:modules/duplicates/tests/e2e/duplicates.e2e.spec.js#refuses
        a record type detection does not run over, naming the segment (400)
  - id: ATS-CRM-DQ-004-09
    title: Checking a draft leaves the review queue empty
    category: invariant
    level: api
    proves:
      - INV-DOM-CRM-DQ-001-09
    preconditions: >-
      One stored contact and a matching unsaved draft without any review
      comparisons.
    steps: Check the draft and read comparisons for the existing contact.
    expected: The draft has a suggestion but the stored comparison list is still empty.
    negative: false
    data_needs: >-
      Records, versions and caller contexts owned by the run; transaction
      failure injection when the invariant concerns rollback.
    bound_to:
      - TST-CRM-DQ-182
    source: >-
      services-crm:modules/duplicates/tests/e2e/duplicates.e2e.spec.js#writes
      nothing: the draft is not a record, so the queue is as it was
    design_sources:
      - DOM-CRM-DQ-001
    execution_sources:
      - >-
        services-crm:modules/duplicates/tests/e2e/duplicates.e2e.spec.js#writes
        nothing: the draft is not a record, so the queue is as it was
    provenance: test
  - id: ATS-CRM-DQ-004-10
    title: Exception-write failure removes the attempted new contact
    category: invariant
    level: api
    proves:
      - INV-DOM-CRM-DQ-001-10
    preconditions: >-
      A blocked creation that is authorized for an exception; fail its exception
      write.
    steps: Attempt creation and inspect contacts and exception rows after failure.
    expected: Neither the new contact nor its exception record remains.
    negative: false
    data_needs: >-
      Records, versions and caller contexts owned by the run; transaction
      failure injection when the invariant concerns rollback.
    bound_to:
      - TST-CRM-DQ-180
    source: >-
      services-crm:modules/duplicates/tests/integration/services/persistence/duplicate-block-overrides.integration.spec.js#leaves
      no contact behind, the record and its audit sharing one transaction
    design_sources:
      - DOM-CRM-DQ-001
    execution_sources:
      - >-
        services-crm:modules/duplicates/tests/integration/services/persistence/duplicate-block-overrides.integration.spec.js#leaves
        no contact behind, the record and its audit sharing one transaction
    provenance: test
  - id: ATS-CRM-DQ-004-11
    title: The override form follows the server’s authority decision
    category: permission
    level: browser
    proves:
      - BR-CAP-CRM-DQ-004-11
    preconditions: >-
      The same blocked draft viewed by an ordinary creator and the appropriate
      override holder.
    steps: >-
      Submit the draft in each context; inspect the available action and attempt
      confirmation with an empty reason.
    expected: >-
      Only the override holder receives Create Anyway, and an empty explanation
      prevents authorized confirmation.
    negative: true
    data_needs: Run-owned records and caller permissions that distinguish the two cases.
    source: >-
      react-console:components/records/create/duplicate-block-refusal.tsx:onCreateAnyway
    design_sources:
      - CAP-CRM-DQ-004
    bound_to: []
    provenance: proposed
    execution_sources: []
  - id: ATS-CRM-DQ-004-12
    title: Creation and its exception share a decision boundary
    category: interaction
    level: api
    proves:
      - BR-CAP-CRM-DQ-004-01
      - BR-CAP-CRM-DQ-004-02
      - BR-CAP-CRM-DQ-004-04
      - BR-CAP-CRM-DQ-004-05
      - BR-CAP-CRM-DQ-004-06
      - BR-CAP-CRM-DQ-004-07
      - BR-CAP-CRM-DQ-004-08
      - BR-CAP-CRM-DQ-004-10
      - BR-CAP-CRM-DQ-004-13
      - BR-CAP-CRM-DQ-004-11
    exercises:
      - CAP-CRM-DQ-004
      - CAP-CRM-ENT-001
      - CAP-CRM-ENT-002
    workflow_sources:
      - WF-CRM-DQ-003
      - WF-CRM-DQ-009
    preconditions: >-
      Run-owned contact and organization records, the relevant staff permissions
      and the related state described by the sequence.
    steps: >-
      Try blocked contact and organization creates as an ordinary creator, then
      as the respective override holder with a reason. Inject an exception-write
      failure on another attempt.
    expected: >-
      Refusal, authorized creation and rollback match the named rules; the
      exception identifies the record created.
    negative: false
    data_needs: >-
      An isolated workspace with related records and fixed timestamps; owned
      participant failure injection where requested.
    source: >-
      CAP-CRM-DQ-004; CAP-CRM-ENT-001; CAP-CRM-ENT-002; WF-CRM-DQ-003;
      WF-CRM-DQ-009
    note: >-
      This cumulative seam scenario remains proposed until one executable
      sequence establishes all of its outcomes.
    bound_to: []
    provenance: proposed
    workflow_coverage_note: >-
      The workflows identify the handoffs under review. Separate assertions
      leave recovery and failure ordering unproved; the capability coverage
      finding records that limit.
    execution_sources: []
evidence:
  - repository: services-crm
    source_sha: a8d1364f1dd44b723bb5f9acba12f983e9ec8d69
    paths:
      - modules/duplicates/aws/api/duplicates.routes.ts
      - modules/duplicates/tests/e2e/duplicates.e2e.spec.js
      - modules/duplicates/tests/e2e/organization-block-rules.e2e.spec.js
      - >-
        modules/duplicates/tests/integration/services/detection/duplicate-checks.integration.spec.js
      - >-
        modules/duplicates/tests/integration/services/persistence/duplicate-block-overrides.integration.spec.js
    note: >-
      Bindings identify authored proof; empty bindings remain proposed and
      findings record known limitations.
  - repository: react-console
    source_sha: baf6dae382d6f41dce976c7f848667ccc37e076f
    paths:
      - acceptance/crm/playwright/journeys/merging/CRM-ACC-0243.spec.ts
    note: >-
      Bindings identify authored proof; empty bindings remain proposed and
      findings record known limitations.
coverage:
  rule: covered
  transition: 'gap: FND-CRM-DQ-055'
  validation: covered
  permission: covered
  edge: 'gap: FND-CRM-DQ-055'
  failure: covered
  boundary: covered
  concurrency: 'gap: FND-CRM-DQ-055'
  invariant: covered
  interaction: covered
coverage_notes:
  transition: >-
    No complete scenario currently isolates this category; the finding lists the
    remaining proof obligation.
  edge: >-
    No complete scenario currently isolates this category; the finding lists the
    remaining proof obligation.
  concurrency: >-
    No complete scenario currently isolates this category; the finding lists the
    remaining proof obligation.
permission_coverage:
  - key: crm.duplicates.read
    scenario_ids:
      - ATS-CRM-DQ-004-03
      - ATS-CRM-DQ-004-06
      - ATS-CRM-DQ-004-11
    finding: FND-CRM-DQ-055
  - key: crm.contacts.create-despite-duplicate-block
    scenario_ids:
      - ATS-CRM-DQ-004-03
      - ATS-CRM-DQ-004-06
      - ATS-CRM-DQ-004-11
    finding: FND-CRM-DQ-055
  - key: crm.organizations.create-despite-duplicate-block
    scenario_ids:
      - ATS-CRM-DQ-004-03
      - ATS-CRM-DQ-004-06
      - ATS-CRM-DQ-004-11
    finding: FND-CRM-DQ-055
proof_matrix:
  - rule: BR-CAP-CRM-DQ-004-01
    scenarios:
      - ATS-CRM-DQ-004-01
      - ATS-CRM-DQ-004-07
      - ATS-CRM-DQ-004-12
  - rule: BR-CAP-CRM-DQ-004-02
    scenarios:
      - ATS-CRM-DQ-004-01
      - ATS-CRM-DQ-004-12
  - rule: BR-CAP-CRM-DQ-004-04
    scenarios:
      - ATS-CRM-DQ-004-02
      - ATS-CRM-DQ-004-07
      - ATS-CRM-DQ-004-12
  - rule: BR-CAP-CRM-DQ-004-05
    scenarios:
      - ATS-CRM-DQ-004-03
      - ATS-CRM-DQ-004-12
  - rule: BR-CAP-CRM-DQ-004-06
    scenarios:
      - ATS-CRM-DQ-004-04
      - ATS-CRM-DQ-004-12
  - rule: BR-CAP-CRM-DQ-004-07
    scenarios:
      - ATS-CRM-DQ-004-04
      - ATS-CRM-DQ-004-05
      - ATS-CRM-DQ-004-12
  - rule: BR-CAP-CRM-DQ-004-08
    scenarios:
      - ATS-CRM-DQ-004-05
      - ATS-CRM-DQ-004-12
  - rule: BR-CAP-CRM-DQ-004-10
    scenarios:
      - ATS-CRM-DQ-004-06
      - ATS-CRM-DQ-004-12
  - rule: BR-CAP-CRM-DQ-004-11
    scenarios:
      - ATS-CRM-DQ-004-11
      - ATS-CRM-DQ-004-12
  - rule: BR-CAP-CRM-DQ-004-13
    scenarios:
      - ATS-CRM-DQ-004-08
      - ATS-CRM-DQ-004-12
interaction_coverage:
  related:
    - CAP-CRM-ENT-001
    - CAP-CRM-ENT-002
  workflow_sources:
    - WF-CRM-DQ-003
    - WF-CRM-DQ-009
  scenarios:
    - ATS-CRM-DQ-004-12
---

# Check drafts and account for block overrides: Capability Test Specification

## Coverage

The rule matrix names the authored checks. A covered category means that a scenario exists; it does not report a passing execution. The coverage notes and findings identify missing checks, while execution sources retain the exact assertions inspected.

| Required Rule | Scenarios |
|---|---|
| `BR-CAP-CRM-DQ-004-01` | `ATS-CRM-DQ-004-01`, `ATS-CRM-DQ-004-07`, `ATS-CRM-DQ-004-12` |
| `BR-CAP-CRM-DQ-004-02` | `ATS-CRM-DQ-004-01`, `ATS-CRM-DQ-004-12` |
| `BR-CAP-CRM-DQ-004-04` | `ATS-CRM-DQ-004-02`, `ATS-CRM-DQ-004-07`, `ATS-CRM-DQ-004-12` |
| `BR-CAP-CRM-DQ-004-05` | `ATS-CRM-DQ-004-03`, `ATS-CRM-DQ-004-12` |
| `BR-CAP-CRM-DQ-004-06` | `ATS-CRM-DQ-004-04`, `ATS-CRM-DQ-004-12` |
| `BR-CAP-CRM-DQ-004-07` | `ATS-CRM-DQ-004-04`, `ATS-CRM-DQ-004-05`, `ATS-CRM-DQ-004-12` |
| `BR-CAP-CRM-DQ-004-08` | `ATS-CRM-DQ-004-05`, `ATS-CRM-DQ-004-12` |
| `BR-CAP-CRM-DQ-004-10` | `ATS-CRM-DQ-004-06`, `ATS-CRM-DQ-004-12` |
| `BR-CAP-CRM-DQ-004-11` | `ATS-CRM-DQ-004-11`, `ATS-CRM-DQ-004-12` |
| `BR-CAP-CRM-DQ-004-13` | `ATS-CRM-DQ-004-08`, `ATS-CRM-DQ-004-12` |

## Interactions With Related Capabilities

Try blocked contact and organization creates as an ordinary creator, then as the respective override holder with a reason. Inject an exception-write failure on another attempt.

These sequences test the handoffs named in the interaction coverage record. A proposed sequence remains unbound until an executable run checks its combined outcome; component assertions alone leave that obligation open.
