---
id: ATS-COM-CAT-001
scope: CAP-COM-CAT-001
product_area: commerce
module: catalog
revision: 2
status: proposed
source_sha:
  services-commerce: c8b66a98e2490617aec38ba5c8165dd9bd0a8f9b
  react-console: baf6dae382d6f41dce976c7f848667ccc37e076f
scenarios:
  - id: ATS-COM-CAT-001-01
    title: Policy money fields reject incomplete or unsupported choices
    level: api
    proves:
      - BR-CAP-COM-CAT-001-01
      - BR-CAP-COM-CAT-001-02
      - INV-DOM-COM-CAT-001-01
    preconditions: A unit supports USD alone
    steps: Attempt creation without currency and with EUR
    expected: Both requests fail on the relevant field and leave no policy
    negative: true
    data_needs: Accounting business unit with currencies
    bound_to:
      - TST-COM-CAT-030
    provenance: test
    source: >-
      services-commerce:modules/configuration/tests/e2e/ordering-profiles.e2e.spec.js#answers 400 to
      a profile without a business unit or without a currency: the two money facts a profile always
      has
    category: validation
    binding_evidence:
      - >-
        services-commerce:modules/configuration/tests/e2e/ordering-profiles.e2e.spec.js#answers 400
        to a profile without a business unit or without a currency: the two money facts a profile
        always has
      - >-
        services-commerce:modules/configuration/tests/e2e/ordering-profiles.e2e.spec.js#answers 400
        currency_not_supported_by_business_unit to a currency the business unit does not transact in
    step_evidence:
      - do: Attempt creation without currency and with EUR
        provenance: test
        source: >-
          services-commerce:modules/configuration/tests/e2e/ordering-profiles.e2e.spec.js#answers
          400 to a profile without a business unit or without a currency: the two money facts a
          profile always has
    assertions:
      - expect: Both requests fail on the relevant field and leave no policy
        provenance: test
        source: >-
          services-commerce:modules/configuration/tests/e2e/ordering-profiles.e2e.spec.js#answers
          400 to a profile without a business unit or without a currency: the two money facts a
          profile always has
  - id: ATS-COM-CAT-001-02
    title: Merchant-account eligibility and connection failure take different paths
    level: unit
    proves:
      - BR-CAP-COM-CAT-001-03
    preconditions: Accounting provides account fixtures and an unavailable response
    steps: >-
      Submit wrong-unit, inactive, wrong-currency and unknown accounts, then simulate connection
      failure
    expected: >-
      Invalid accounts fail field validation; connection failure permits saving with a logged
      warning
    negative: true
    data_needs: Fixture Accounting accounts
    bound_to:
      - TST-COM-CAT-043
    provenance: test
    source: >-
      services-commerce:modules/configuration/tests/unit/persistence/ordering-profile-merchant-account.spec.js#is
      refused 400 merchant_account_not_eligible when the account belongs to another business unit
    category: failure
    binding_evidence:
      - >-
        services-commerce:modules/configuration/tests/unit/persistence/ordering-profile-merchant-account.spec.js#is
        refused 400 merchant_account_not_eligible when the account belongs to another business unit
      - >-
        services-commerce:modules/configuration/tests/unit/persistence/ordering-profile-merchant-account.spec.js#is
        let through, logged, when Accounting is unreachable
    step_evidence:
      - do: >-
          Submit wrong-unit, inactive, wrong-currency and unknown accounts, then simulate connection
          failure
        provenance: test
        source: >-
          services-commerce:modules/configuration/tests/unit/persistence/ordering-profile-merchant-account.spec.js#is
          refused 400 merchant_account_not_eligible when the account belongs to another business
          unit
    assertions:
      - expect: >-
          Invalid accounts fail field validation; connection failure permits saving with a logged
          warning
        provenance: test
        source: >-
          services-commerce:modules/configuration/tests/unit/persistence/ordering-profile-merchant-account.spec.js#is
          refused 400 merchant_account_not_eligible when the account belongs to another business
          unit
  - id: ATS-COM-CAT-001-03
    title: Card-range validation identifies missing or reversed bounds
    level: api
    proves:
      - BR-CAP-COM-CAT-001-04
      - INV-DOM-COM-CAT-001-07
    preconditions: Range-based acceptance is selected
    steps: Omit each bound in turn and reverse their order
    expected: Each invalid range fails with the affected bound identified
    negative: true
    data_needs: none
    bound_to:
      - TST-COM-CAT-030
    provenance: test
    source: >-
      services-commerce:modules/configuration/tests/e2e/ordering-profiles.e2e.spec.js#answers 400 to
      a within_range acceptance without its minimum, naming card_minimum_total_minor, with or
      without the maximum (0755)
    category: validation
    binding_evidence:
      - >-
        services-commerce:modules/configuration/tests/e2e/ordering-profiles.e2e.spec.js#answers 400
        to a within_range acceptance without its minimum, naming card_minimum_total_minor, with or
        without the maximum (0755)
      - >-
        services-commerce:modules/configuration/tests/e2e/ordering-profiles.e2e.spec.js#answers 400
        to an inverted card range, naming the field, not the database rule, and saves nothing
        (DEF-COM-0866)
    step_evidence:
      - do: Omit each bound in turn and reverse their order
        provenance: test
        source: >-
          services-commerce:modules/configuration/tests/e2e/ordering-profiles.e2e.spec.js#answers
          400 to a within_range acceptance without its minimum, naming card_minimum_total_minor,
          with or without the maximum (0755)
    assertions:
      - expect: Each invalid range fails with the affected bound identified
        provenance: test
        source: >-
          services-commerce:modules/configuration/tests/e2e/ordering-profiles.e2e.spec.js#answers
          400 to a within_range acceptance without its minimum, naming card_minimum_total_minor,
          with or without the maximum (0755)
  - id: ATS-COM-CAT-001-04
    title: Database enforcement rejects unsupported payment windows
    level: api
    proves:
      - BR-CAP-COM-CAT-001-05
      - INV-DOM-COM-CAT-001-08
    preconditions: A policy row is ready for insertion
    steps: Insert zero-minute and eight-day windows
    expected: Both inserts fail their window constraint
    negative: true
    data_needs: none
    bound_to:
      - TST-COM-CAT-033
    provenance: test
    source: >-
      services-commerce:modules/configuration/tests/integration/db/configuration-records.table.integration.spec.js#refuses
      a tender window outside one minute to a week, by ordering_profiles_tender_window_minutes_check
    category: boundary
    binding_evidence:
      - >-
        services-commerce:modules/configuration/tests/integration/db/configuration-records.table.integration.spec.js#refuses
        a tender window outside one minute to a week, by
        ordering_profiles_tender_window_minutes_check
    step_evidence:
      - do: Insert zero-minute and eight-day windows
        provenance: test
        source: >-
          services-commerce:modules/configuration/tests/integration/db/configuration-records.table.integration.spec.js#refuses
          a tender window outside one minute to a week, by
          ordering_profiles_tender_window_minutes_check
    assertions:
      - expect: Both inserts fail their window constraint
        provenance: test
        source: >-
          services-commerce:modules/configuration/tests/integration/db/configuration-records.table.integration.spec.js#refuses
          a tender window outside one minute to a week, by
          ordering_profiles_tender_window_minutes_check
  - id: ATS-COM-CAT-001-05
    title: Policy payment lists reject blanks and duplicates
    level: unit
    proves:
      - BR-CAP-COM-CAT-001-07
    preconditions: Policy requests contain editable payment lists
    steps: Replace with an empty collection option and create with a repeated payment method
    expected: Validation identifies each offending entry
    negative: true
    data_needs: none
    bound_to:
      - TST-COM-CAT-041
      - TST-COM-CAT-035
    provenance: test
    source: >-
      services-commerce:modules/configuration/tests/unit/api/blank-ordering-profile-ids.spec.js#refuses
      an empty entry in collection_option_ids on a replacement 400, naming the field
    category: validation
    binding_evidence:
      - >-
        services-commerce:modules/configuration/tests/unit/api/blank-ordering-profile-ids.spec.js#refuses
        an empty entry in collection_option_ids on a replacement 400, naming the field
      - >-
        services-commerce:modules/configuration/tests/integration/services/persistence/ordering-profiles.integration.spec.js#refuses
        a payment method named twice, 400 payment_method_repeated (the seam for Accounting’s list,
        D-10)
    step_evidence:
      - do: Replace with an empty collection option and create with a repeated payment method
        provenance: test
        source: >-
          services-commerce:modules/configuration/tests/unit/api/blank-ordering-profile-ids.spec.js#refuses
          an empty entry in collection_option_ids on a replacement 400, naming the field
    assertions:
      - expect: Validation identifies each offending entry
        provenance: test
        source: >-
          services-commerce:modules/configuration/tests/unit/api/blank-ordering-profile-ids.spec.js#refuses
          an empty entry in collection_option_ids on a replacement 400, naming the field
  - id: ATS-COM-CAT-001-06
    title: Default designation transfers without disappearing
    level: api
    proves:
      - BR-CAP-COM-CAT-001-09
      - INV-DOM-COM-CAT-001-02
    preconditions: The workspace initially has no policies
    steps: 'Create two policies, designate the second and attempt to clear its default flag'
    expected: Creation selects the first; transfer selects only the second; clearing the flag fails
    negative: true
    data_needs: none
    bound_to:
      - TST-COM-CAT-035
      - TST-COM-CAT-030
    provenance: test
    source: >-
      services-commerce:modules/configuration/tests/integration/services/persistence/ordering-profiles.integration.spec.js#makes
      a second profile no default, and one stating is_tenant_default the default in place of the
      first, in one transaction
    category: invariant
    binding_evidence:
      - >-
        services-commerce:modules/configuration/tests/integration/services/persistence/ordering-profiles.integration.spec.js#makes
        a second profile no default, and one stating is_tenant_default the default in place of the
        first, in one transaction
      - >-
        services-commerce:modules/configuration/tests/e2e/ordering-profiles.e2e.spec.js#answers 400
        to a replacement that drops the tenant default flag from the default, and moves it when
        another states it
    step_evidence:
      - do: 'Create two policies, designate the second and attempt to clear its default flag'
        provenance: test
        source: >-
          services-commerce:modules/configuration/tests/integration/services/persistence/ordering-profiles.integration.spec.js#makes
          a second profile no default, and one stating is_tenant_default the default in place of the
          first, in one transaction
    assertions:
      - expect: Creation selects the first; transfer selects only the second; clearing the flag fails
        provenance: test
        source: >-
          services-commerce:modules/configuration/tests/integration/services/persistence/ordering-profiles.integration.spec.js#makes
          a second profile no default, and one stating is_tenant_default the default in place of the
          first, in one transaction
  - id: ATS-COM-CAT-001-07
    title: References retain default and store policies
    level: api
    proves:
      - BR-CAP-COM-CAT-001-10
      - BR-CAP-COM-CAT-001-11
      - INV-DOM-COM-CAT-001-03
      - INV-DOM-COM-CAT-001-05
    preconditions: Workspace and application defaults and a store policy exist
    steps: >-
      Deactivate the application default and delete referenced policies, then remove the store
      reference
    expected: >-
      Default and store refusals identify their dependencies; the unreferenced store policy can be
      deleted
    negative: true
    data_needs: A store under a policy
    bound_to:
      - TST-COM-CAT-035
      - TST-COM-CAT-030
    provenance: test
    source: >-
      services-commerce:modules/configuration/tests/integration/services/persistence/ordering-profiles.integration.spec.js#refuses
      making an application default inactive, 409 profile_is_default naming the application, and
      deactivates it once no default names it (D31)
    category: transition
    binding_evidence:
      - >-
        services-commerce:modules/configuration/tests/integration/services/persistence/ordering-profiles.integration.spec.js#refuses
        making an application default inactive, 409 profile_is_default naming the application, and
        deactivates it once no default names it (D31)
      - >-
        services-commerce:modules/configuration/tests/e2e/ordering-profiles.e2e.spec.js#answers 409
        naming the store while a store sells under the profile, then 200 once the store is gone
    step_evidence:
      - do: >-
          Deactivate the application default and delete referenced policies, then remove the store
          reference
        provenance: test
        source: >-
          services-commerce:modules/configuration/tests/integration/services/persistence/ordering-profiles.integration.spec.js#refuses
          making an application default inactive, 409 profile_is_default naming the application, and
          deactivates it once no default names it (D31)
    assertions:
      - expect: >-
          Default and store refusals identify their dependencies; the unreferenced store policy can
          be deleted
        provenance: test
        source: >-
          services-commerce:modules/configuration/tests/integration/services/persistence/ordering-profiles.integration.spec.js#refuses
          making an application default inactive, 409 profile_is_default naming the application, and
          deactivates it once no default names it (D31)
  - id: ATS-COM-CAT-001-08
    title: Stale policy replacement preserves the current record
    level: api
    proves:
      - BR-CAP-COM-CAT-001-13
    preconditions: The saved policy has advanced to version two
    steps: Submit the earlier version for replacement
    expected: A conflict preserves version two
    negative: true
    data_needs: none
    bound_to:
      - TST-COM-CAT-030
    provenance: test
    source: >-
      services-commerce:modules/configuration/tests/e2e/ordering-profiles.e2e.spec.js#answers 409 to
      a stale version
    category: concurrency
    binding_evidence:
      - >-
        services-commerce:modules/configuration/tests/e2e/ordering-profiles.e2e.spec.js#answers 409
        to a stale version
    step_evidence:
      - do: Submit the earlier version for replacement
        provenance: test
        source: >-
          services-commerce:modules/configuration/tests/e2e/ordering-profiles.e2e.spec.js#answers
          409 to a stale version
    assertions:
      - expect: A conflict preserves version two
        provenance: test
        source: >-
          services-commerce:modules/configuration/tests/e2e/ordering-profiles.e2e.spec.js#answers
          409 to a stale version
  - id: ATS-COM-CAT-001-09
    title: Policy writes refuse a read-only caller
    level: api
    proves:
      - BR-CAP-COM-CAT-001-15
    preconditions: A caller has policy read authority alone
    steps: 'Attempt policy creation, replacement and removal'
    expected: Permission refusals preserve the records
    negative: true
    data_needs: Read-exclusively persona
    bound_to:
      - TST-COM-CAT-028
    provenance: test
    source: >-
      services-commerce:modules/configuration/tests/e2e/configuration-security.e2e.spec.js#is
      refused the creates, 403 permission_missing
    category: permission
    binding_evidence:
      - >-
        services-commerce:modules/configuration/tests/e2e/configuration-security.e2e.spec.js#is
        refused the creates, 403 permission_missing
      - >-
        services-commerce:modules/configuration/tests/e2e/configuration-security.e2e.spec.js#is
        refused the replacements, 403 permission_missing, the records unchanged
    step_evidence:
      - do: 'Attempt policy creation, replacement and removal'
        provenance: test
        source: >-
          services-commerce:modules/configuration/tests/e2e/configuration-security.e2e.spec.js#is
          refused the creates, 403 permission_missing
    assertions:
      - expect: Permission refusals preserve the records
        provenance: test
        source: >-
          services-commerce:modules/configuration/tests/e2e/configuration-security.e2e.spec.js#is
          refused the creates, 403 permission_missing
  - id: ATS-COM-CAT-001-10
    title: Policy summary reflects a saved card-range edit
    level: browser
    proves:
      - BR-CAP-COM-CAT-001-04
      - AS-JNY-COM-CAT-001-01
    preconditions: The console runs against Commerce mock data
    steps: 'Create and view a policy, edit its card range and save'
    expected: The returned view summarizes the revised range
    negative: false
    data_needs: Console mock
    bound_to:
      - TST-COM-CAT-005
    provenance: test
    source: >-
      react-console:e2e/mock/commerce-checkout-policies.mock.spec.ts#create a policy, read its
      summary on the view, edit the card range, save, and see it on the view
    category: rule
    binding_evidence:
      - >-
        react-console:e2e/mock/commerce-checkout-policies.mock.spec.ts#create a policy, read its
        summary on the view, edit the card range, save, and see it on the view
    step_evidence:
      - do: 'Create and view a policy, edit its card range and save'
        provenance: test
        source: >-
          react-console:e2e/mock/commerce-checkout-policies.mock.spec.ts#create a policy, read its
          summary on the view, edit the card range, save, and see it on the view
    assertions:
      - expect: The returned view summarizes the revised range
        provenance: test
        source: >-
          react-console:e2e/mock/commerce-checkout-policies.mock.spec.ts#create a policy, read its
          summary on the view, edit the card range, save, and see it on the view
  - id: ATS-COM-CAT-001-11
    title: A placed sale retains the policy values it used
    category: rule
    level: api
    proves:
      - BR-CAP-COM-CAT-001-14
    preconditions: A placed order retains a policy snapshot.
    steps: >-
      Read the retained settlement, card, invoice and fee-product values; edit the policy; read the
      retained values again.
    expected: The retained values match the first read and differ from the edited policy.
    negative: false
    data_needs: Run-owned workspace and records; fixed clock where dates are exercised.
    bound_to: []
    provenance: proposed
    source:
      - >-
        services-commerce:modules/configuration/tests/integration/services/persistence/ordering-profiles.queries.integration.spec.js#snapshotOf
        freezes the settlement, card, invoicing, fee-product and quote rules an order carries (22
        §9), nothing else
    step_evidence:
      - do: >-
          Read the retained settlement, card, invoice and fee-product values; edit the policy; read
          the retained values again.
        provenance: proposed
        source:
          - >-
            services-commerce:modules/configuration/tests/integration/services/persistence/ordering-profiles.queries.integration.spec.js#snapshotOf
            freezes the settlement, card, invoicing, fee-product and quote rules an order carries
            (22 §9), nothing else
    assertions:
      - expect: The retained values match the first read and differ from the edited policy.
        provenance: proposed
        source:
          - >-
            services-commerce:modules/configuration/tests/integration/services/persistence/ordering-profiles.queries.integration.spec.js#snapshotOf
            freezes the settlement, card, invoicing, fee-product and quote rules an order carries
            (22 §9), nothing else
  - id: ATS-COM-CAT-001-12
    title: Policy protection refuses the protected write
    category: invariant
    level: api
    proves:
      - BR-CAP-COM-CAT-001-16
    preconditions: Separate otherwise editable records use full protection and deletion-only protection.
    steps: >-
      Replace and delete the fully protected record, then replace and delete the deletion-only
      protected record; reread both.
    expected: >-
      The full-protection requests refuse; the deletion-only replacement succeeds and removal
      refuses; refused writes preserve the stored record.
    negative: true
    data_needs: Run-owned workspace and records; fixed clock where dates are exercised.
    bound_to: []
    provenance: proposed
    source:
      - 'services-commerce:modules/configuration/services/persistence/ordering-profiles.ts'
    step_evidence:
      - do: >-
          Replace and delete the fully protected record, then replace and delete the deletion-only
          protected record; reread both.
        provenance: proposed
        source:
          - 'services-commerce:modules/configuration/services/persistence/ordering-profiles.ts'
    assertions:
      - expect: >-
          The full-protection requests refuse; the deletion-only replacement succeeds and removal
          refuses; refused writes preserve the stored record.
        provenance: proposed
        source:
          - 'services-commerce:modules/configuration/services/persistence/ordering-profiles.ts'
  - id: ATS-COM-CAT-001-13
    title: Changing the default changes fallback selection
    category: interaction
    level: api
    proves:
      - BR-CAP-COM-CAT-001-09
      - BR-CAP-COM-CAT-002-03
    preconditions: Two active policies and no application default exist.
    steps: >-
      Resolve the fallback, transfer the workspace default, resolve again and attempt to disable the
      selected policy.
    expected: The new policy is selected and cannot be disabled while retained as default.
    negative: false
    data_needs: Run-owned workspace and records; fixed clock where dates are exercised.
    bound_to: []
    provenance: proposed
    source:
      - >-
        services-commerce:modules/configuration/tests/integration/services/persistence/ordering-profiles.integration.spec.js#makes
        a second profile no default, and one stating is_tenant_default the default in place of the
        first, in one transaction
      - >-
        services-commerce:modules/configuration/tests/e2e/ordering-profiles.e2e.spec.js#resolves a
        context: the profile it names (explicit), else its application’s default, else the tenant
        default
    exercises:
      - CAP-COM-CAT-001
      - CAP-COM-CAT-002
    workflows:
      - WF-COM-CAT-001
    step_evidence:
      - do: >-
          Resolve the fallback, transfer the workspace default, resolve again and attempt to disable
          the selected policy.
        provenance: proposed
        source:
          - >-
            services-commerce:modules/configuration/tests/integration/services/persistence/ordering-profiles.integration.spec.js#makes
            a second profile no default, and one stating is_tenant_default the default in place of
            the first, in one transaction
          - >-
            services-commerce:modules/configuration/tests/e2e/ordering-profiles.e2e.spec.js#resolves
            a context: the profile it names (explicit), else its application’s default, else the
            tenant default
    assertions:
      - expect: The new policy is selected and cannot be disabled while retained as default.
        provenance: proposed
        source:
          - >-
            services-commerce:modules/configuration/tests/integration/services/persistence/ordering-profiles.integration.spec.js#makes
            a second profile no default, and one stating is_tenant_default the default in place of
            the first, in one transaction
          - >-
            services-commerce:modules/configuration/tests/e2e/ordering-profiles.e2e.spec.js#resolves
            a context: the profile it names (explicit), else its application’s default, else the
            tenant default
  - id: ATS-COM-CAT-001-14
    title: A store retains its checkout policy
    category: interaction
    level: api
    proves:
      - BR-CAP-COM-CAT-001-11
      - BR-CAP-COM-CAT-003-01
    preconditions: A store uses an otherwise unreferenced policy.
    steps: Request policy deletion; move the store to another valid policy; repeat deletion.
    expected: The first deletion identifies the store; the second removes the now-unreferenced policy.
    negative: false
    data_needs: Run-owned workspace and records; fixed clock where dates are exercised.
    bound_to: []
    provenance: proposed
    source:
      - >-
        services-commerce:modules/configuration/tests/e2e/ordering-profiles.e2e.spec.js#answers 409
        naming the store while a store sells under the profile, then 200 once the store is gone
      - >-
        services-commerce:modules/configuration/tests/e2e/stores.e2e.spec.js#answers 400 to an
        ordering profile the tenant does not have, naming the property
    exercises:
      - CAP-COM-CAT-001
      - CAP-COM-CAT-003
    workflows: []
    step_evidence:
      - do: Request policy deletion; move the store to another valid policy; repeat deletion.
        provenance: proposed
        source:
          - >-
            services-commerce:modules/configuration/tests/e2e/ordering-profiles.e2e.spec.js#answers
            409 naming the store while a store sells under the profile, then 200 once the store is
            gone
          - >-
            services-commerce:modules/configuration/tests/e2e/stores.e2e.spec.js#answers 400 to an
            ordering profile the tenant does not have, naming the property
    assertions:
      - expect: The first deletion identifies the store; the second removes the now-unreferenced policy.
        provenance: proposed
        source:
          - >-
            services-commerce:modules/configuration/tests/e2e/ordering-profiles.e2e.spec.js#answers
            409 naming the store while a store sells under the profile, then 200 once the store is
            gone
          - >-
            services-commerce:modules/configuration/tests/e2e/stores.e2e.spec.js#answers 400 to an
            ordering profile the tenant does not have, naming the property
  - id: ATS-COM-CAT-001-15
    title: Checkout policy activation and default designation is exercised across every declared move
    category: transition
    level: api
    proves:
      - BR-CAP-COM-CAT-001-09
      - BR-CAP-COM-CAT-001-10
      - BR-CAP-COM-CAT-001-11
      - BR-CAP-COM-CAT-001-13
      - BR-CAP-COM-CAT-001-16
    preconditions: >-
      Independent run-owned records start in each declared origin state; guarded variants omit one
      required condition at a time.
    steps: >-
      For each transition case, establish the origin, apply its trigger with the guard satisfied,
      read the resulting state and side effects, then repeat on a separate record with a required
      guard absent.
    expected: >-
      Every allowed case reaches its stated destination and retains its declared side effects;
      failed guards preserve the originating record except for the separately documented partial
      offer action.
    negative: true
    data_needs: Run-owned workspace and records; fixed clock where dates are exercised.
    bound_to: []
    provenance: proposed
    source:
      - >-
        rhythm-v2-docs:specs/commerce/catalog/design/state-models/STATE-COM-CAT-001-checkout-policy-activation-and-default.md#STATE-COM-CAT-001
      - >-
        services-commerce:modules/configuration/tests/integration/services/persistence/ordering-profiles.integration.spec.js#makes
        a second profile no default, and one stating is_tenant_default the default in place of the
        first, in one transaction
      - >-
        services-commerce:modules/configuration/tests/e2e/ordering-profiles.e2e.spec.js#removes an
        application default left out of the document, the tenant default kept when null
      - >-
        services-commerce:modules/configuration/tests/integration/services/persistence/ordering-profiles.integration.spec.js#refuses
        making an application default inactive, 409 profile_is_default naming the application, and
        deactivates it once no default names it (D31)
      - 'services-commerce:modules/configuration/services/persistence/ordering-profiles.ts'
      - >-
        services-commerce:modules/configuration/tests/e2e/ordering-profiles.e2e.spec.js#answers 409
        naming the store while a store sells under the profile, then 200 once the store is gone
      - 'services-commerce:modules/configuration/services/persistence/ordering-profiles.ts'
    state_model: STATE-COM-CAT-001
    transition_cases:
      - from: active
        to: active default
        trigger: >-
          Creation establishes the first default, or staff select this policy in the defaults
          document.
        guard: The selected policy must be active in this workspace.
        provenance: proposed
        source:
          - >-
            services-commerce:modules/configuration/tests/integration/services/persistence/ordering-profiles.integration.spec.js#makes
            a second profile no default, and one stating is_tenant_default the default in place of
            the first, in one transaction
          - >-
            rhythm-v2-docs:specs/commerce/catalog/design/state-models/STATE-COM-CAT-001-checkout-policy-activation-and-default.md#STATE-COM-CAT-001
      - from: active default
        to: active
        trigger: Staff transfer the workspace designation or remove the remaining application selections.
        guard: Workspace default removal requires another active policy to receive the designation.
        provenance: proposed
        source:
          - >-
            services-commerce:modules/configuration/tests/e2e/ordering-profiles.e2e.spec.js#removes
            an application default left out of the document, the tenant default kept when null
          - >-
            rhythm-v2-docs:specs/commerce/catalog/design/state-models/STATE-COM-CAT-001-checkout-policy-activation-and-default.md#STATE-COM-CAT-001
      - from: active
        to: inactive
        trigger: A replacement disables policy activity.
        guard: >-
          The read version must match, full protection must be absent and no default may retain the
          policy.
        provenance: proposed
        source:
          - >-
            services-commerce:modules/configuration/tests/integration/services/persistence/ordering-profiles.integration.spec.js#refuses
            making an application default inactive, 409 profile_is_default naming the application,
            and deactivates it once no default names it (D31)
          - >-
            rhythm-v2-docs:specs/commerce/catalog/design/state-models/STATE-COM-CAT-001-checkout-policy-activation-and-default.md#STATE-COM-CAT-001
      - from: inactive
        to: active
        trigger: A replacement enables policy activity.
        guard: The policy version must match and update protection must allow the write.
        provenance: proposed
        source:
          - 'services-commerce:modules/configuration/services/persistence/ordering-profiles.ts'
          - >-
            rhythm-v2-docs:specs/commerce/catalog/design/state-models/STATE-COM-CAT-001-checkout-policy-activation-and-default.md#STATE-COM-CAT-001
      - from: active
        to: deleted
        trigger: An authorized delete requests removal.
        guard: >-
          Protection, default selection and retained store or sale references must all permit
          removal.
        provenance: proposed
        source:
          - >-
            services-commerce:modules/configuration/tests/e2e/ordering-profiles.e2e.spec.js#answers
            409 naming the store while a store sells under the profile, then 200 once the store is
            gone
          - >-
            rhythm-v2-docs:specs/commerce/catalog/design/state-models/STATE-COM-CAT-001-checkout-policy-activation-and-default.md#STATE-COM-CAT-001
      - from: inactive
        to: deleted
        trigger: An authorized delete requests removal.
        guard: No protection or retained reference may block removal.
        provenance: proposed
        source:
          - 'services-commerce:modules/configuration/services/persistence/ordering-profiles.ts'
          - >-
            rhythm-v2-docs:specs/commerce/catalog/design/state-models/STATE-COM-CAT-001-checkout-policy-activation-and-default.md#STATE-COM-CAT-001
    step_evidence:
      - do: >-
          For each transition case, establish the origin, apply its trigger with the guard
          satisfied, read the resulting state and side effects, then repeat on a separate record
          with a required guard absent.
        provenance: proposed
        source:
          - >-
            rhythm-v2-docs:specs/commerce/catalog/design/state-models/STATE-COM-CAT-001-checkout-policy-activation-and-default.md#STATE-COM-CAT-001
          - >-
            services-commerce:modules/configuration/tests/integration/services/persistence/ordering-profiles.integration.spec.js#makes
            a second profile no default, and one stating is_tenant_default the default in place of
            the first, in one transaction
          - >-
            services-commerce:modules/configuration/tests/e2e/ordering-profiles.e2e.spec.js#removes
            an application default left out of the document, the tenant default kept when null
          - >-
            services-commerce:modules/configuration/tests/integration/services/persistence/ordering-profiles.integration.spec.js#refuses
            making an application default inactive, 409 profile_is_default naming the application,
            and deactivates it once no default names it (D31)
          - 'services-commerce:modules/configuration/services/persistence/ordering-profiles.ts'
          - >-
            services-commerce:modules/configuration/tests/e2e/ordering-profiles.e2e.spec.js#answers
            409 naming the store while a store sells under the profile, then 200 once the store is
            gone
          - 'services-commerce:modules/configuration/services/persistence/ordering-profiles.ts'
    assertions:
      - expect: >-
          Every allowed case reaches its stated destination and retains its declared side effects;
          failed guards preserve the originating record except for the separately documented partial
          offer action.
        provenance: proposed
        source:
          - >-
            rhythm-v2-docs:specs/commerce/catalog/design/state-models/STATE-COM-CAT-001-checkout-policy-activation-and-default.md#STATE-COM-CAT-001
          - >-
            services-commerce:modules/configuration/tests/integration/services/persistence/ordering-profiles.integration.spec.js#makes
            a second profile no default, and one stating is_tenant_default the default in place of
            the first, in one transaction
          - >-
            services-commerce:modules/configuration/tests/e2e/ordering-profiles.e2e.spec.js#removes
            an application default left out of the document, the tenant default kept when null
          - >-
            services-commerce:modules/configuration/tests/integration/services/persistence/ordering-profiles.integration.spec.js#refuses
            making an application default inactive, 409 profile_is_default naming the application,
            and deactivates it once no default names it (D31)
          - 'services-commerce:modules/configuration/services/persistence/ordering-profiles.ts'
          - >-
            services-commerce:modules/configuration/tests/e2e/ordering-profiles.e2e.spec.js#answers
            409 naming the store while a store sells under the profile, then 200 once the store is
            gone
          - 'services-commerce:modules/configuration/services/persistence/ordering-profiles.ts'
  - id: ATS-COM-CAT-001-16
    title: Reserved policy identities refuse before saving
    category: invariant
    level: api
    proves:
      - INV-DOM-COM-CAT-001-06
      - BR-CAP-COM-CAT-001-08
    preconditions: An otherwise valid policy request can supply its own identity.
    steps: >-
      Create using each reserved identity in mixed case and with surrounding spaces, then create
      using a distinct ordinary identity.
    expected: Reserved attempts fail without a record; the distinct ordinary identity can be saved.
    negative: true
    data_needs: Run-owned workspace and records; fixed clock where dates are exercised.
    bound_to: []
    provenance: proposed
    source:
      - >-
        services-commerce:modules/configuration/tests/unit/persistence/ordering-profile-rules.spec.js#refuses
        a reserved id whatever its case and surrounding spaces
      - >-
        rhythm-v2-docs:specs/commerce/catalog/design/objects/DOM-COM-CAT-001-checkout-policy.md#DOM-COM-CAT-001
    verification_note: >-
      This design references the invariant; executable binding awaits an assertion-by-assertion
      comparison with this complete scenario.
    step_evidence:
      - do: >-
          Create using each reserved identity in mixed case and with surrounding spaces, then create
          using a distinct ordinary identity.
        provenance: proposed
        source:
          - >-
            services-commerce:modules/configuration/tests/unit/persistence/ordering-profile-rules.spec.js#refuses
            a reserved id whatever its case and surrounding spaces
          - >-
            rhythm-v2-docs:specs/commerce/catalog/design/objects/DOM-COM-CAT-001-checkout-policy.md#DOM-COM-CAT-001
    assertions:
      - expect: Reserved attempts fail without a record; the distinct ordinary identity can be saved.
        provenance: proposed
        source:
          - >-
            services-commerce:modules/configuration/tests/unit/persistence/ordering-profile-rules.spec.js#refuses
            a reserved id whatever its case and surrounding spaces
          - >-
            rhythm-v2-docs:specs/commerce/catalog/design/objects/DOM-COM-CAT-001-checkout-policy.md#DOM-COM-CAT-001
  - id: ATS-COM-CAT-001-17
    title: Policy snapshots keep only the required order settings
    category: invariant
    level: api
    proves:
      - INV-DOM-COM-CAT-001-09
      - BR-CAP-COM-CAT-001-14
    preconditions: 'A complete policy includes money, timing, card, invoice and fee-product fields.'
    steps: >-
      Build the retained policy snapshot, compare its fields with the source values and verify that
      unrelated display and reference fields are absent.
    expected: >-
      The snapshot contains the settlement, card, invoice, fee-product and quote settings and
      excludes unrelated policy fields.
    negative: true
    data_needs: Run-owned workspace and records; fixed clock where dates are exercised.
    bound_to: []
    provenance: proposed
    source:
      - >-
        services-commerce:modules/configuration/tests/integration/services/persistence/ordering-profiles.queries.integration.spec.js#snapshotOf
        freezes the settlement, card, invoicing, fee-product and quote rules an order carries (22
        §9), nothing else
      - >-
        rhythm-v2-docs:specs/commerce/catalog/design/objects/DOM-COM-CAT-001-checkout-policy.md#DOM-COM-CAT-001
    verification_note: >-
      This design references the invariant; executable binding awaits an assertion-by-assertion
      comparison with this complete scenario.
    step_evidence:
      - do: >-
          Build the retained policy snapshot, compare its fields with the source values and verify
          that unrelated display and reference fields are absent.
        provenance: proposed
        source:
          - >-
            services-commerce:modules/configuration/tests/integration/services/persistence/ordering-profiles.queries.integration.spec.js#snapshotOf
            freezes the settlement, card, invoicing, fee-product and quote rules an order carries
            (22 §9), nothing else
          - >-
            rhythm-v2-docs:specs/commerce/catalog/design/objects/DOM-COM-CAT-001-checkout-policy.md#DOM-COM-CAT-001
    assertions:
      - expect: >-
          The snapshot contains the settlement, card, invoice, fee-product and quote settings and
          excludes unrelated policy fields.
        provenance: proposed
        source:
          - >-
            services-commerce:modules/configuration/tests/integration/services/persistence/ordering-profiles.queries.integration.spec.js#snapshotOf
            freezes the settlement, card, invoicing, fee-product and quote rules an order carries
            (22 §9), nothing else
          - >-
            rhythm-v2-docs:specs/commerce/catalog/design/objects/DOM-COM-CAT-001-checkout-policy.md#DOM-COM-CAT-001
evidence:
  - 'Pinned service inputs: test sources in scenario bindings'
  - 'Pinned console inputs: console sources in scenario bindings'
  - >-
    rhythm-v2-docs:specs/commerce/catalog/planning/capabilities/CAP-COM-CAT-001-define-how-each-kind-of-sale-is-billed-and-paid.md#CAP-COM-CAT-001
  - >-
    rhythm-v2-docs:specs/commerce/catalog/design/workflows/WF-COM-CAT-001-save-a-checkout-policy-against-accounting-s.md#WF-COM-CAT-001
product_intent: proposed
coverage:
  rule: covered
  transition: covered
  validation: covered
  permission: covered
  edge: 'gap: FND-COM-CAT-055'
  failure: covered
  boundary: covered
  concurrency: covered
  invariant: covered
  interaction: covered
coverage_notes:
  edge: >-
    No complete edge scenario is established by this back-fill; the finding records the missing
    proof.
  concurrency: >-
    A stale-write example covers version conflict; overlapping operations and external effects
    require separate proof.
permission_coverage:
  - key: commerce.ordering-profiles.read
    coverage: 'gap: FND-COM-CAT-055'
    reason: >-
      Existing permission examples cover selected personas, not the independent allow and deny
      matrix for every named key.
    provenance: unknown
    source:
      - 'rhythm-v2-docs:specs/commerce/catalog/FINDINGS.md#FND-COM-CAT-055'
  - key: commerce.ordering-profiles.create
    coverage: 'gap: FND-COM-CAT-055'
    reason: >-
      Existing permission examples cover selected personas, not the independent allow and deny
      matrix for every named key.
    provenance: unknown
    source:
      - 'rhythm-v2-docs:specs/commerce/catalog/FINDINGS.md#FND-COM-CAT-055'
  - key: commerce.ordering-profiles.update
    coverage: 'gap: FND-COM-CAT-055'
    reason: >-
      Existing permission examples cover selected personas, not the independent allow and deny
      matrix for every named key.
    provenance: unknown
    source:
      - 'rhythm-v2-docs:specs/commerce/catalog/FINDINGS.md#FND-COM-CAT-055'
  - key: commerce.ordering-profiles.delete
    coverage: 'gap: FND-COM-CAT-055'
    reason: >-
      Existing permission examples cover selected personas, not the independent allow and deny
      matrix for every named key.
    provenance: unknown
    source:
      - 'rhythm-v2-docs:specs/commerce/catalog/FINDINGS.md#FND-COM-CAT-055'
  - key: commerce.ordering-profiles.bulk
    coverage: 'gap: FND-COM-CAT-055'
    reason: >-
      Existing permission examples cover selected personas, not the independent allow and deny
      matrix for every named key.
    provenance: unknown
    source:
      - 'rhythm-v2-docs:specs/commerce/catalog/FINDINGS.md#FND-COM-CAT-055'
---

# Configure reusable sale-processing policies: Capability Test Specification

## Coverage

| Rule | Proof Scenario or Gap |
|---|---|
| `BR-CAP-COM-CAT-001-01` | `ATS-COM-CAT-001-01` |
| `BR-CAP-COM-CAT-001-02` | `ATS-COM-CAT-001-01` |
| `BR-CAP-COM-CAT-001-03` | `ATS-COM-CAT-001-02` |
| `BR-CAP-COM-CAT-001-04` | `ATS-COM-CAT-001-03`, `ATS-COM-CAT-001-10` |
| `BR-CAP-COM-CAT-001-05` | `ATS-COM-CAT-001-04` |
| `BR-CAP-COM-CAT-001-07` | `ATS-COM-CAT-001-05` |
| `BR-CAP-COM-CAT-001-09` | `ATS-COM-CAT-001-06`, `ATS-COM-CAT-001-13`, `ATS-COM-CAT-001-15` |
| `BR-CAP-COM-CAT-001-10` | `ATS-COM-CAT-001-07`, `ATS-COM-CAT-001-15` |
| `BR-CAP-COM-CAT-001-11` | `ATS-COM-CAT-001-07`, `ATS-COM-CAT-001-14`, `ATS-COM-CAT-001-15` |
| `BR-CAP-COM-CAT-001-13` | `ATS-COM-CAT-001-08`, `ATS-COM-CAT-001-15` |
| `BR-CAP-COM-CAT-001-14` | `ATS-COM-CAT-001-11`, `ATS-COM-CAT-001-17` |
| `BR-CAP-COM-CAT-001-15` | `ATS-COM-CAT-001-09` |
| `BR-CAP-COM-CAT-001-16` | `ATS-COM-CAT-001-12`, `ATS-COM-CAT-001-15` |

## Interactions With Related Capabilities

Changing the default changes fallback selection. A store retains its checkout policy.

Coverage describes specified proof. A binding names the existing assertions that contribute to it; proposed designs remain unexecuted.
