---
id: ATS-PFM-MTD-017
scope: CAP-PFM-MTD-017
product_area: platform
module: metadata
revision: 2
status: proposed
source_sha:
  services-platform: ad3f6a6582843008ed0f5a17b131878d15829af1
  react-console: baf6dae382d6f41dce976c7f848667ccc37e076f
scenarios:
  - id: ATS-PFM-MTD-017-01
    title: Type vocabulary rejects unsupported choices
    level: api
    proves:
      - BR-CAP-PFM-MTD-017-01
    preconditions: Relationship creation is available.
    steps:
      - do: 'Submit unknown cardinality, delete policies, missing labels and invalid keys.'
        provenance: test
        source: >-
          services-platform:modules/associations/tests/e2e/associations.e2e.spec.js#answers 400 to an unknown
          cardinality, naming the three
    expected: Each request identifies its invalid choice without storing the type.
    negative: true
    data_needs: Relationship creation is available.
    bound_to:
      - >-
        services-platform:modules/associations/tests/e2e/associations.e2e.spec.js#answers 400 to a
        64-character type id in the service’s id grammar
      - >-
        services-platform:modules/associations/tests/e2e/associations.e2e.spec.js#answers 400 to a blank
        forward label as required
      - >-
        services-platform:modules/associations/tests/e2e/associations.e2e.spec.js#answers 400 to an unknown
        cardinality, naming the three
      - >-
        services-platform:modules/associations/tests/e2e/associations.e2e.spec.js#answers 400 to an unknown
        delete rule, naming the three
      - >-
        services-platform:modules/associations/tests/integration/services/persistence/association-types.integration.spec.js#refuses
        an id already in use in the tenant
      - TST-PFM-MTD-036
      - TST-PFM-MTD-041
    provenance: test
    source: >-
      services-platform:modules/associations/tests/e2e/associations.e2e.spec.js#answers 400 to an unknown
      cardinality, naming the three
    category: validation
    assertions:
      - expect: Each request identifies its invalid choice without storing the type.
        provenance: test
        source: >-
          services-platform:modules/associations/tests/e2e/associations.e2e.spec.js#answers 400 to an unknown
          cardinality, naming the three
  - id: ATS-PFM-MTD-017-02
    title: Endpoints must be supported and available
    level: api
    proves:
      - BR-CAP-PFM-MTD-017-02
    preconditions: 'An active object, a draft and registered Contacts exist.'
    steps:
      - do: Create types to each and a same-type contact relationship.
        provenance: test
        source: >-
          services-platform:modules/associations/tests/e2e/associations.e2e.spec.js#answers 400 to a type of a
          draft custom object, naming it as not active
    expected: 'Supported endpoints work, drafts and missing types fail and same-type relationships are accepted.'
    negative: true
    data_needs: 'An active object, a draft and registered Contacts exist.'
    bound_to:
      - >-
        services-platform:modules/associations/tests/e2e/associations.e2e.spec.js#creates a type to an active
        custom object of the tenant
      - >-
        services-platform:modules/associations/tests/e2e/associations.e2e.spec.js#answers 400 to a type of a
        draft custom object, naming it as not active
      - >-
        services-platform:modules/associations/tests/integration/services/persistence/association-types.integration.spec.js#refuses
        an object the registry does not have
      - >-
        services-platform:modules/associations/tests/integration/services/persistence/associations.integration.spec.js#accepts
        two contacts of a same-object type (Contact mentors Contact)
      - TST-PFM-MTD-036
      - TST-PFM-MTD-041
      - TST-PFM-MTD-045
    provenance: test
    source: >-
      services-platform:modules/associations/tests/e2e/associations.e2e.spec.js#answers 400 to a type of a
      draft custom object, naming it as not active
    category: interaction
    assertions:
      - expect: 'Supported endpoints work, drafts and missing types fail and same-type relationships are accepted.'
        provenance: test
        source: >-
          services-platform:modules/associations/tests/e2e/associations.e2e.spec.js#answers 400 to a type of a
          draft custom object, naming it as not active
  - id: ATS-PFM-MTD-017-03
    title: Cascade definitions cannot delete native records
    level: browser
    proves:
      - BR-CAP-PFM-MTD-017-03
      - BR-CAP-PFM-MTD-017-10
      - INV-DOM-PFM-MTD-006-02
    preconditions: API and console relationship editors are available.
    steps:
      - do: 'Define a native-target cascade, missing label and duplicate identity.'
        provenance: test
        source: >-
          react-console:acceptance/custom-objects/playwright/journeys/PLAT-M6-S02.spec.ts#PLAT-M6-S02: a
          relationship type with a missing label, a cascade onto contacts or a duplicate id is refused and
          nothing is saved
    expected: Each invalid definition fails with an explanation and nothing is saved.
    negative: true
    data_needs: API and console relationship editors are available.
    bound_to:
      - >-
        services-platform:modules/associations/tests/integration/services/persistence/association-types.integration.spec.js#refuses
        a cascade that would delete a native record, writing nothing
      - >-
        react-console:acceptance/custom-objects/playwright/journeys/PLAT-M6-S02.spec.ts#PLAT-M6-S02: a
        relationship type with a missing label, a cascade onto contacts or a duplicate id is refused and
        nothing is saved
      - TST-PFM-MTD-041
      - TST-PFM-MTD-016
    provenance: test
    source: >-
      react-console:acceptance/custom-objects/playwright/journeys/PLAT-M6-S02.spec.ts#PLAT-M6-S02: a
      relationship type with a missing label, a cascade onto contacts or a duplicate id is refused and nothing
      is saved
    category: validation
    assertions:
      - expect: Each invalid definition fails with an explanation and nothing is saved.
        provenance: test
        source: >-
          react-console:acceptance/custom-objects/playwright/journeys/PLAT-M6-S02.spec.ts#PLAT-M6-S02: a
          relationship type with a missing label, a cascade onto contacts or a duplicate id is refused and
          nothing is saved
  - id: ATS-PFM-MTD-017-04
    title: Type shape and occupied primary settings are protected
    level: api
    proves:
      - BR-CAP-PFM-MTD-017-04
      - INV-DOM-PFM-MTD-006-01
    preconditions: A type has an open primary link.
    steps:
      - do: 'Change its cardinality, endpoint, dating or primary support and attempt stale relabelling.'
        provenance: test
        source: >-
          services-platform:modules/associations/tests/integration/services/persistence/association-types.integration.spec.js#refuses
          a change of cardinality, the shape of a type being immutable, and leaves the row as it was
    expected: 'Immutable, occupied and stale changes fail; valid versioned relabelling succeeds.'
    negative: true
    data_needs: A type has an open primary link.
    bound_to:
      - >-
        services-platform:modules/associations/tests/integration/services/persistence/association-types.integration.spec.js#refuses
        a change of cardinality, the shape of a type being immutable, and leaves the row as it was
      - >-
        services-platform:modules/associations/tests/integration/services/persistence/association-types.integration.spec.js#refuses
        a change of the to object
      - >-
        services-platform:modules/associations/tests/integration/services/persistence/association-types.integration.spec.js#refuses
        turning the primary off while an open association of the type is primary
      - >-
        services-platform:modules/associations/tests/integration/services/persistence/association-types.integration.spec.js#refuses
        a stale version and leaves the row as it was
      - TST-PFM-MTD-041
    provenance: test
    source: >-
      services-platform:modules/associations/tests/integration/services/persistence/association-types.integration.spec.js#refuses
      a change of cardinality, the shape of a type being immutable, and leaves the row as it was
    category: concurrency
    assertions:
      - expect: 'Immutable, occupied and stale changes fail; valid versioned relabelling succeeds.'
        provenance: test
        source: >-
          services-platform:modules/associations/tests/integration/services/persistence/association-types.integration.spec.js#refuses
          a change of cardinality, the shape of a type being immutable, and leaves the row as it was
  - id: ATS-PFM-MTD-017-05
    title: Used types retire without discarding links
    level: api
    proves:
      - BR-CAP-PFM-MTD-017-05
    preconditions: One type has links and another is unused.
    steps:
      - do: Remove both and try a new link under the retired type.
        provenance: test
        source: >-
          services-platform:modules/associations/tests/integration/services/persistence/association-types.integration.spec.js#deactivates
          a type an association names instead of deleting it
    expected: 'The unused type is deleted, the used type deactivates and new links are refused.'
    negative: true
    data_needs: One type has links and another is unused.
    bound_to:
      - >-
        services-platform:modules/associations/tests/integration/services/persistence/association-types.integration.spec.js#deletes
        a type no association names, and says so
      - >-
        services-platform:modules/associations/tests/integration/services/persistence/association-types.integration.spec.js#deactivates
        a type an association names instead of deleting it
      - >-
        services-platform:modules/associations/tests/integration/services/persistence/association-types.integration.spec.js#refuses
        a new association of a deactivated type
      - TST-PFM-MTD-041
    provenance: test
    source: >-
      services-platform:modules/associations/tests/integration/services/persistence/association-types.integration.spec.js#deactivates
      a type an association names instead of deleting it
    category: transition
    assertions:
      - expect: 'The unused type is deleted, the used type deactivates and new links are refused.'
        provenance: test
        source: >-
          services-platform:modules/associations/tests/integration/services/persistence/association-types.integration.spec.js#deactivates
          a type an association names instead of deleting it
  - id: ATS-PFM-MTD-017-06
    title: Owner dependencies prevent type retirement
    level: browser
    proves:
      - BR-CAP-PFM-MTD-017-06
      - INV-DOM-PFM-MTD-006-03
    preconditions: Live and archived custom objects use owner types.
    steps:
      - do: 'Retire them, change the owner settings and retry retirement and revival.'
        provenance: test
        source: >-
          services-platform:modules/associations/tests/integration/services/persistence/association-types.integration.spec.js#refuses
          deactivating the type of one object, naming it by its label and what to change first
    expected: Dependencies identify every affected object; removing ownership allows retirement and revival succeeds.
    negative: true
    data_needs: Live and archived custom objects use owner types.
    bound_to:
      - >-
        services-platform:modules/associations/tests/integration/services/persistence/association-types.integration.spec.js#refuses
        deactivating the type of one object, naming it by its label and what to change first
      - >-
        services-platform:modules/associations/tests/integration/services/persistence/association-types.integration.spec.js#names
        every object that uses the type as its owner, whatever its status, by label
      - >-
        services-platform:modules/associations/tests/integration/services/persistence/association-types.integration.spec.js#deactivates
        the type once no object names it as its owner, and revives it whatever objects name it
      - >-
        react-console:acceptance/custom-objects/playwright/journeys/PLAT-M6-S09.spec.ts#PLAT-M6-S09: a
        relationship type is relabelled, retired, revived and removed, and Boat's owner type cannot be retired
      - TST-PFM-MTD-041
      - TST-PFM-MTD-023
    provenance: test
    source: >-
      services-platform:modules/associations/tests/integration/services/persistence/association-types.integration.spec.js#refuses
      deactivating the type of one object, naming it by its label and what to change first
    category: interaction
    assertions:
      - expect: >-
          Dependencies identify every affected object; removing ownership allows retirement and revival
          succeeds.
        provenance: test
        source: >-
          services-platform:modules/associations/tests/integration/services/persistence/association-types.integration.spec.js#refuses
          deactivating the type of one object, naming it by its label and what to change first
  - id: ATS-PFM-MTD-017-07
    title: Type audit records configuration actions
    level: api
    proves:
      - BR-CAP-PFM-MTD-017-09
    preconditions: Relationship-type administration is available.
    steps:
      - do: 'Create, relabel, deactivate and delete types and inspect the trail.'
        provenance: test
        source: >-
          services-platform:modules/associations/tests/integration/services/persistence/association-types.integration.spec.js#records
          a delete and a deactivation in the security trail, each by its action
    expected: Audit actions identify changes by field name.
    negative: false
    data_needs: Relationship-type administration is available.
    bound_to:
      - >-
        services-platform:modules/associations/tests/integration/services/persistence/association-types.integration.spec.js#records
        the create in the security trail, with the changed fields by name
      - >-
        services-platform:modules/associations/tests/integration/services/persistence/association-types.integration.spec.js#records
        a delete and a deactivation in the security trail, each by its action
      - TST-PFM-MTD-041
    provenance: test
    source: >-
      services-platform:modules/associations/tests/integration/services/persistence/association-types.integration.spec.js#records
      a delete and a deactivation in the security trail, each by its action
    category: rule
    assertions:
      - expect: Audit actions identify changes by field name.
        provenance: test
        source: >-
          services-platform:modules/associations/tests/integration/services/persistence/association-types.integration.spec.js#records
          a delete and a deactivation in the security trail, each by its action
  - id: ATS-PFM-MTD-017-08
    title: Ordinary users cannot administer types
    level: browser
    proves:
      - BR-CAP-PFM-MTD-017-10
    preconditions: Standard and read-only staff use the console.
    steps:
      - do: Look for relationship-type configuration.
        provenance: test
        source: >-
          react-console:acceptance/custom-objects/playwright/journeys/PLAT-M6-S12.spec.ts#PLAT-M6-S12: a
          standard user links, ends and removes but has no Relationship Types screen, and a read-only
          colleague sees no actions
    expected: Neither receives the administration screen.
    negative: true
    data_needs: Standard and read-only staff use the console.
    bound_to:
      - >-
        react-console:acceptance/custom-objects/playwright/journeys/PLAT-M6-S12.spec.ts#PLAT-M6-S12: a
        standard user links, ends and removes but has no Relationship Types screen, and a read-only colleague
        sees no actions
      - TST-PFM-MTD-026
    provenance: test
    source: >-
      react-console:acceptance/custom-objects/playwright/journeys/PLAT-M6-S12.spec.ts#PLAT-M6-S12: a standard
      user links, ends and removes but has no Relationship Types screen, and a read-only colleague sees no
      actions
    category: permission
    assertions:
      - expect: Neither receives the administration screen.
        provenance: test
        source: >-
          react-console:acceptance/custom-objects/playwright/journeys/PLAT-M6-S12.spec.ts#PLAT-M6-S12: a
          standard user links, ends and removes but has no Relationship Types screen, and a read-only
          colleague sees no actions
  - id: ATS-PFM-MTD-017-09
    title: A relationship policy controls link creation and deletion
    category: interaction
    level: api
    exercises:
      - CAP-PFM-MTD-017
      - CAP-PFM-MTD-009
      - CAP-PFM-MTD-018
      - CAP-PFM-MTD-019
    proves:
      - BR-CAP-PFM-MTD-017-06
      - BR-CAP-PFM-MTD-018-01
      - BR-CAP-PFM-MTD-019-01
    preconditions: An active custom object has a restricting relationship type and a compatible endpoint.
    steps:
      - do: >-
          Create a link, try removing its protected endpoint, retire the used type after clearing any owner
          dependency and attempt another link.
        provenance: proposed
        source: &ref_0
          - >-
            services-platform:modules/associations/tests/integration/services/persistence/association-types.integration.spec.js#refuses
            deactivating the type of one object, naming it by its label and what to change first
          - >-
            services-platform:modules/associations/tests/integration/services/persistence/associations.integration.spec.js#refuses
            a record associated with itself
          - >-
            services-platform:modules/associations/tests/integration/db/apply-endpoint-deletion.integration.spec.js#answers
            what endpointDeletionOutcome says for an open association on the to side under restrict
    expected: 'Compare the deletion refusal, retained connection and new-link refusal.'
    negative: false
    data_needs: An active custom object has a restricting relationship type and a compatible endpoint.
    bound_to: []
    provenance: proposed
    source: *ref_0
    assertions:
      - expect: 'Compare the deletion refusal, retained connection and new-link refusal.'
        provenance: proposed
        source: *ref_0
evidence:
  - >-
    services-platform at ad3f6a6582843008ed0f5a17b131878d15829af1: the association type specs named in each
    scenario.
  - 'react-console at baf6dae382d6f41dce976c7f848667ccc37e076f: Playwright PLAT-M6-S02, S09, S12.'
  - >-
    Codex testing back-fill: pinned capability, domain object, state model and workflow obligations reviewed;
    existing bound test files and exact case titles checked.
coverage:
  rule: covered
  transition: covered
  validation: covered
  permission: covered
  edge: 'gap: FND-PFM-MTD-079'
  failure: 'gap: FND-PFM-MTD-079'
  boundary: 'gap: FND-PFM-MTD-079'
  concurrency: covered
  invariant: 'gap: FND-PFM-MTD-079'
  interaction: covered
coverage_obligations:
  - rule: BR-CAP-PFM-MTD-017-01
    scenarios:
      - ATS-PFM-MTD-017-01
    finding: null
    provenance: documented
    source: specs/platform/metadata/planning/capabilities/CAP-PFM-MTD-017-define-how-two-kinds-of-record-relate.md
  - rule: BR-CAP-PFM-MTD-017-02
    scenarios:
      - ATS-PFM-MTD-017-02
    finding: null
    provenance: documented
    source: specs/platform/metadata/planning/capabilities/CAP-PFM-MTD-017-define-how-two-kinds-of-record-relate.md
  - rule: BR-CAP-PFM-MTD-017-03
    scenarios:
      - ATS-PFM-MTD-017-03
    finding: null
    provenance: documented
    source: specs/platform/metadata/planning/capabilities/CAP-PFM-MTD-017-define-how-two-kinds-of-record-relate.md
  - rule: BR-CAP-PFM-MTD-017-04
    scenarios:
      - ATS-PFM-MTD-017-04
    finding: null
    provenance: documented
    source: specs/platform/metadata/planning/capabilities/CAP-PFM-MTD-017-define-how-two-kinds-of-record-relate.md
  - rule: BR-CAP-PFM-MTD-017-05
    scenarios:
      - ATS-PFM-MTD-017-05
    finding: null
    provenance: documented
    source: specs/platform/metadata/planning/capabilities/CAP-PFM-MTD-017-define-how-two-kinds-of-record-relate.md
  - rule: BR-CAP-PFM-MTD-017-06
    scenarios:
      - ATS-PFM-MTD-017-06
      - ATS-PFM-MTD-017-09
    finding: null
    provenance: documented
    source: specs/platform/metadata/planning/capabilities/CAP-PFM-MTD-017-define-how-two-kinds-of-record-relate.md
  - rule: BR-CAP-PFM-MTD-017-07
    scenarios: []
    finding: FND-PFM-MTD-079
    provenance: documented
    source: specs/platform/metadata/planning/capabilities/CAP-PFM-MTD-017-define-how-two-kinds-of-record-relate.md
  - rule: BR-CAP-PFM-MTD-017-08
    scenarios: []
    finding: FND-PFM-MTD-079
    provenance: documented
    source: specs/platform/metadata/planning/capabilities/CAP-PFM-MTD-017-define-how-two-kinds-of-record-relate.md
  - rule: BR-CAP-PFM-MTD-017-09
    scenarios:
      - ATS-PFM-MTD-017-07
    finding: null
    provenance: documented
    source: specs/platform/metadata/planning/capabilities/CAP-PFM-MTD-017-define-how-two-kinds-of-record-relate.md
  - rule: BR-CAP-PFM-MTD-017-10
    scenarios:
      - ATS-PFM-MTD-017-03
      - ATS-PFM-MTD-017-08
    finding: null
    provenance: documented
    source: specs/platform/metadata/planning/capabilities/CAP-PFM-MTD-017-define-how-two-kinds-of-record-relate.md
interactions:
  - with: CAP-PFM-MTD-009
    scenarios:
      - ATS-PFM-MTD-017-09
    finding: null
    provenance: proposed
    source: specs/platform/metadata/planning/capabilities/CAP-PFM-MTD-017-define-how-two-kinds-of-record-relate.md
  - with: CAP-PFM-MTD-018
    scenarios:
      - ATS-PFM-MTD-017-09
    finding: null
    provenance: proposed
    source: specs/platform/metadata/planning/capabilities/CAP-PFM-MTD-017-define-how-two-kinds-of-record-relate.md
  - with: CAP-PFM-MTD-019
    scenarios:
      - ATS-PFM-MTD-017-09
    finding: null
    provenance: proposed
    source: specs/platform/metadata/planning/capabilities/CAP-PFM-MTD-017-define-how-two-kinds-of-record-relate.md
---

# Define Meaningful Record Relationships: Capability Test Specification

## Coverage

- Obligation 01: 1 scenario cite this obligation.
- Obligation 02: 1 scenario cite this obligation.
- Obligation 03: 1 scenario cite this obligation.
- Obligation 04: 1 scenario cite this obligation.
- Obligation 05: 1 scenario cite this obligation.
- Obligation 06: 2 scenarios cite this obligation.
- Obligation 07: The coverage finding records the missing scenario.
- Obligation 08: The coverage finding records the missing scenario.
- Obligation 09: 1 scenario cite this obligation.
- Obligation 10: 2 scenarios cite this obligation.

Category coverage identifies the kind of proof present. Detailed transition, permission and invariant obligations and unbound proposals remain in the coverage finding until their individual cases are accounted for.

## Interactions With Related Capabilities

Type lifecycle and deletion policy remain effective at their consuming operations. The structured interaction rows identify the related capabilities exercised and any remaining gap. Cross-capability workflow seams remain subject to the detailed coverage audit.
