---
id: ATS-CRM-DQ-009
scope: CAP-CRM-DQ-009
product_area: crm
module: data-quality
revision: 1
status: proposed
source_sha:
  services-crm: a8d1364f1dd44b723bb5f9acba12f983e9ec8d69
  react-console: baf6dae382d6f41dce976c7f848667ccc37e076f
scenarios:
  - id: ATS-CRM-DQ-009-01
    title: Manual confirmation creates a full-score decision
    level: api
    proves:
      - BR-CAP-CRM-DQ-009-01
    preconditions: Two existing records have no candidate.
    steps: Confirm their shared identity with a note.
    expected: >-
      The result is manual and confirmed at 100 with the reviewer and note in
      its reason.
    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/persistence/duplicate-candidates.integration.spec.js#is
      confirmed, manual and at full score: certainty, not a computation
    category: rule
    execution_sources:
      - >-
        services-crm:modules/duplicates/tests/integration/services/persistence/duplicate-candidates.integration.spec.js#is
        confirmed, manual and at full score: certainty, not a computation
      - >-
        services-crm:modules/duplicates/tests/integration/services/persistence/duplicate-candidates.integration.spec.js#carries
        one reason, naming the person who said so and what they said
  - id: ATS-CRM-DQ-009-02
    title: Confirmation replaces an earlier dismissal in place
    level: api
    proves:
      - BR-CAP-CRM-DQ-009-02
    preconditions: An existing pair is dismissed.
    steps: Manually confirm it.
    expected: >-
      The same identity becomes confirmed at full score, removes dismissal and
      retains the human reason.
    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/persistence/duplicate-candidates.integration.spec.js#is
      the same candidate, confirmed in place
    category: transition
    execution_sources:
      - >-
        services-crm:modules/duplicates/tests/integration/services/persistence/duplicate-candidates.integration.spec.js#is
        the same candidate, confirmed in place
      - >-
        services-crm:modules/duplicates/tests/integration/services/persistence/duplicate-candidates.integration.spec.js#takes
        the dismissal off, the person having just overruled it
      - >-
        services-crm:modules/duplicates/tests/integration/services/persistence/duplicate-candidates.integration.spec.js#carries
        the full score and the person’s own reason, not the weak evidence it had
  - id: ATS-CRM-DQ-009-03
    title: Confirmation rejects invalid participants
    level: api
    proves:
      - BR-CAP-CRM-DQ-009-03
    preconditions: Prepare one record and an unavailable identity.
    steps: 'Submit one participant, repeated participants and an absent participant.'
    expected: Invalid cardinality is rejected and unavailable records return not found.
    negative: true
    data_needs: The existing scenario setup supplies the required records.
    bound_to:
      - TST-CRM-DQ-182
      - TST-CRM-DQ-180
    provenance: test
    source: >-
      services-crm:modules/duplicates/tests/e2e/duplicates.e2e.spec.js#refuses a
      manual pair that does not name two records (400)
    category: validation
    execution_sources:
      - >-
        services-crm:modules/duplicates/tests/e2e/duplicates.e2e.spec.js#refuses
        a manual pair that does not name two records (400)
      - >-
        services-crm:modules/duplicates/tests/e2e/duplicates.e2e.spec.js#refuses
        a manual pair naming a record the tenant does not have (404)
      - >-
        services-crm:modules/duplicates/tests/integration/services/persistence/duplicate-candidates.integration.spec.js#refuses
        a pair of one record with itself
  - id: ATS-CRM-DQ-009-04
    title: Readers cannot confirm duplicates
    level: api
    proves:
      - BR-CAP-CRM-DQ-009-04
    preconditions: Use a duplicate reader without review authority.
    steps: Submit manual confirmation.
    expected: The request is refused.
    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 that reader saying two records are the same
    category: permission
    execution_sources:
      - >-
        services-crm:modules/duplicates/tests/e2e/duplicates.e2e.spec.js#answers
        403 to that reader saying two records are the same
  - id: ATS-CRM-DQ-009-05
    title: >-
      Observe open becoming confirmed after a reviewer confirms an existing open
      comparison
    category: transition
    level: api
    proves:
      - BR-CAP-CRM-DQ-009-02
    transition:
      model: STATE-CRM-DQ-001
      index: 7
      from: open
      to: confirmed
      guard: >-
        Review authority and two different existing records of one type are
        required.
      side_effects:
        - assign full score and the human explanation
        - exclude the confirmed pair from groups
    preconditions: >-
      Arrange open standing with the transition guard satisfied: Review
      authority and two different existing records of one type are required.
    steps: A reviewer confirms an existing open comparison.
    expected: >-
      Read the confirmed standing and inspect the associated changes: assign
      full score and the human explanation; exclude the confirmed pair from
      groups.
    negative: false
    data_needs: >-
      Fixtures for open, the guard and the affected records; a fixed clock for
      time-dependent changes.
    source: >-
      services-crm:modules/duplicates/tests/integration/services/persistence/duplicate-candidates.integration.spec.js#takes
      the dismissal off, the person having just overruled it
    design_sources:
      - STATE-CRM-DQ-001
    note: >-
      The design supplies this transition obligation. A runtime binding requires
      assertions for its guard, destination and associated writes in one
      sequence.
    bound_to: []
    provenance: proposed
    execution_sources: []
  - id: ATS-CRM-DQ-009-06
    title: >-
      Observe dismissed becoming confirmed after a reviewer confirms a
      previously rejected comparison
    category: transition
    level: api
    proves:
      - BR-CAP-CRM-DQ-009-02
    transition:
      model: STATE-CRM-DQ-001
      index: 8
      from: dismissed
      to: confirmed
      guard: Review authority is required.
      side_effects:
        - clear the former dismissal
        - record the human confirmation
    preconditions: >-
      Arrange dismissed standing with the transition guard satisfied: Review
      authority is required.
    steps: A reviewer confirms a previously rejected comparison.
    expected: >-
      Read the confirmed standing and inspect the associated changes: clear the
      former dismissal; record the human confirmation.
    negative: false
    data_needs: >-
      Fixtures for dismissed, the guard and the affected records; a fixed clock
      for time-dependent changes.
    source: >-
      services-crm:modules/duplicates/tests/integration/services/persistence/duplicate-candidates.integration.spec.js#takes
      the dismissal off, the person having just overruled it
    design_sources:
      - STATE-CRM-DQ-001
    note: >-
      The design supplies this transition obligation. A runtime binding requires
      assertions for its guard, destination and associated writes in one
      sequence.
    bound_to: []
    provenance: proposed
    execution_sources: []
  - id: ATS-CRM-DQ-009-07
    title: >-
      Observe absent becoming confirmed after a reviewer identifies an unstored
      duplicate pair
    category: transition
    level: api
    proves:
      - BR-CAP-CRM-DQ-009-01
    transition:
      model: STATE-CRM-DQ-001
      index: 9
      from: absent
      to: confirmed
      guard: Review authority is required.
      side_effects:
        - create a manual full-score confirmation without grouping
    preconditions: >-
      Arrange absent standing with the transition guard satisfied: Review
      authority is required.
    steps: A reviewer identifies an unstored duplicate pair.
    expected: >-
      Read the confirmed standing and inspect the associated changes: create a
      manual full-score confirmation without grouping.
    negative: false
    data_needs: >-
      Fixtures for absent, the guard and the affected records; a fixed clock for
      time-dependent changes.
    source: >-
      services-crm:modules/duplicates/tests/integration/services/persistence/duplicate-candidates.integration.spec.js#is
      confirmed, manual and at full score: certainty, not a computation
    design_sources:
      - STATE-CRM-DQ-001
    note: >-
      The design supplies this transition obligation. A runtime binding requires
      assertions for its guard, destination and associated writes in one
      sequence.
    bound_to: []
    provenance: proposed
    execution_sources: []
  - id: ATS-CRM-DQ-009-08
    title: A reviewer can confirm without merge authority
    category: rule
    level: browser
    proves:
      - BR-CAP-CRM-DQ-009-06
    preconditions: >-
      A reviewer lacking both record-merge permissions and two records with no
      detected comparison.
    steps: >-
      Use the console confirmation picker, confirm the pair and add another
      existing record to the reviewed selection.
    expected: >-
      Confirmation is available independently of merging. This proposed
      customer-surface obligation has no executable binding.
    negative: true
    data_needs: Run-owned records and caller permissions that distinguish the two cases.
    source: FND-CRM-DQ-012
    design_sources:
      - CAP-CRM-DQ-009
    bound_to: []
    provenance: proposed
    execution_sources: []
  - id: ATS-CRM-DQ-009-09
    title: Human confirmation settles review before planning
    category: interaction
    level: api
    proves:
      - BR-CAP-CRM-DQ-009-01
      - BR-CAP-CRM-DQ-009-02
      - BR-CAP-CRM-DQ-009-03
      - BR-CAP-CRM-DQ-009-04
      - BR-CAP-CRM-DQ-009-06
    exercises:
      - CAP-CRM-DQ-009
      - CAP-CRM-DQ-007
      - CAP-CRM-DQ-012
    workflow_sources:
      - WF-CRM-DQ-004
    preconditions: >-
      Run-owned contact and organization records, the relevant staff permissions
      and the related state described by the sequence.
    steps: >-
      Confirm an open pair and a dismissed pair, read their groups, then prepare
      the confirmed records for a merge.
    expected: >-
      Confirmation updates the existing pair and group membership; planning
      operates on the same two records.
    negative: false
    data_needs: >-
      An isolated workspace with related records and fixed timestamps; owned
      participant failure injection where requested.
    source: CAP-CRM-DQ-009; CAP-CRM-DQ-007; CAP-CRM-DQ-012; WF-CRM-DQ-004
    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/tests/e2e/duplicates.e2e.spec.js
      - >-
        modules/duplicates/tests/integration/services/persistence/duplicate-candidates.integration.spec.js
    note: >-
      Bindings identify authored proof; empty bindings remain proposed and
      findings record known limitations.
coverage:
  rule: covered
  transition: covered
  validation: covered
  permission: covered
  edge: 'gap: FND-CRM-DQ-060'
  failure: 'gap: FND-CRM-DQ-060'
  boundary: 'gap: FND-CRM-DQ-060'
  concurrency: 'gap: FND-CRM-DQ-060'
  invariant: 'gap: FND-CRM-DQ-060'
  interaction: covered
coverage_notes:
  edge: >-
    No complete scenario currently isolates this category; the finding lists the
    remaining proof obligation.
  failure: >-
    No complete scenario currently isolates this category; the finding lists the
    remaining proof obligation.
  boundary: >-
    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.
  invariant: >-
    No complete scenario currently isolates this category; the finding lists the
    remaining proof obligation.
permission_coverage:
  - key: crm.duplicates.review
    scenario_ids:
      - ATS-CRM-DQ-009-04
    finding: FND-CRM-DQ-060
proof_matrix:
  - rule: BR-CAP-CRM-DQ-009-01
    scenarios:
      - ATS-CRM-DQ-009-01
      - ATS-CRM-DQ-009-07
      - ATS-CRM-DQ-009-09
  - rule: BR-CAP-CRM-DQ-009-02
    scenarios:
      - ATS-CRM-DQ-009-02
      - ATS-CRM-DQ-009-05
      - ATS-CRM-DQ-009-06
      - ATS-CRM-DQ-009-09
  - rule: BR-CAP-CRM-DQ-009-03
    scenarios:
      - ATS-CRM-DQ-009-03
      - ATS-CRM-DQ-009-09
  - rule: BR-CAP-CRM-DQ-009-04
    scenarios:
      - ATS-CRM-DQ-009-04
      - ATS-CRM-DQ-009-09
  - rule: BR-CAP-CRM-DQ-009-06
    scenarios:
      - ATS-CRM-DQ-009-08
      - ATS-CRM-DQ-009-09
interaction_coverage:
  related:
    - CAP-CRM-DQ-007
    - CAP-CRM-DQ-012
  workflow_sources:
    - WF-CRM-DQ-004
  scenarios:
    - ATS-CRM-DQ-009-09
---

# Record a duplicate that matching missed: 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-009-01` | `ATS-CRM-DQ-009-01`, `ATS-CRM-DQ-009-07`, `ATS-CRM-DQ-009-09` |
| `BR-CAP-CRM-DQ-009-02` | `ATS-CRM-DQ-009-02`, `ATS-CRM-DQ-009-05`, `ATS-CRM-DQ-009-06`, `ATS-CRM-DQ-009-09` |
| `BR-CAP-CRM-DQ-009-03` | `ATS-CRM-DQ-009-03`, `ATS-CRM-DQ-009-09` |
| `BR-CAP-CRM-DQ-009-04` | `ATS-CRM-DQ-009-04`, `ATS-CRM-DQ-009-09` |
| `BR-CAP-CRM-DQ-009-06` | `ATS-CRM-DQ-009-08`, `ATS-CRM-DQ-009-09` |

## Interactions With Related Capabilities

Confirm an open pair and a dismissed pair, read their groups, then prepare the confirmed records for a merge.

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.
