---
id: ATS-COM-CAT-019
scope: CAP-COM-CAT-019
product_area: commerce
module: catalog
revision: 2
status: proposed
source_sha:
  services-commerce: c8b66a98e2490617aec38ba5c8165dd9bd0a8f9b
  react-console: baf6dae382d6f41dce976c7f848667ccc37e076f
scenarios:
  - id: ATS-COM-CAT-019-01
    title: Recommendation parameters match the selected kind
    level: unit
    proves:
      - BR-CAP-COM-CAT-019-01
      - INV-DOM-COM-CAT-006-01
    preconditions: Rule inputs can vary their kind and parameters
    steps: Omit add-on products and add a parameter belonging to another kind
    expected: Both inputs fail with the parameter path identified
    negative: true
    data_needs: none
    bound_to:
      - TST-COM-CAT-151
      - TST-COM-CAT-136
    provenance: test
    source: >-
      services-commerce:modules/recommendations/tests/unit/rule-rules.spec.js#refuses an add_on rule
      with no products, parameters_invalid, naming the path
    category: validation
    binding_evidence:
      - >-
        services-commerce:modules/recommendations/tests/unit/rule-rules.spec.js#refuses an add_on
        rule with no products, parameters_invalid, naming the path
      - >-
        services-commerce:modules/recommendations/tests/unit/rule-rules.spec.js#refuses a parameter
        the kind does not take
      - >-
        services-commerce:modules/recommendations/tests/e2e/recommendation-rules.e2e.spec.js#refuses
        an add_on rule with no products, 400 parameters_invalid
    step_evidence:
      - do: Omit add-on products and add a parameter belonging to another kind
        provenance: test
        source: >-
          services-commerce:modules/recommendations/tests/unit/rule-rules.spec.js#refuses an add_on
          rule with no products, parameters_invalid, naming the path
    assertions:
      - expect: Both inputs fail with the parameter path identified
        provenance: test
        source: >-
          services-commerce:modules/recommendations/tests/unit/rule-rules.spec.js#refuses an add_on
          rule with no products, parameters_invalid, naming the path
  - id: ATS-COM-CAT-019-02
    title: Placement bindings respect supported kinds and caps
    level: api
    proves:
      - BR-CAP-COM-CAT-019-02
      - INV-DOM-COM-CAT-006-02
    preconditions: Store placements are registered
    steps: Bind an unsupported kind and exceed a placement’s offer cap
    expected: Both bindings fail
    negative: true
    data_needs: none
    bound_to:
      - TST-COM-CAT-136
      - TST-COM-CAT-138
    provenance: test
    source: >-
      services-commerce:modules/recommendations/tests/e2e/recommendation-rules.e2e.spec.js#refuses a
      binding to a placement that shows no such kind, 400 placement_unsupported
    category: boundary
    binding_evidence:
      - >-
        services-commerce:modules/recommendations/tests/e2e/recommendation-rules.e2e.spec.js#refuses
        a binding to a placement that shows no such kind, 400 placement_unsupported
      - >-
        services-commerce:modules/recommendations/tests/e2e/recommendation-rules.e2e.spec.js#refuses
        a cap above the placement’s, 400 max_offers_exceeds_placement
      - >-
        services-commerce:modules/recommendations/tests/integration/db/recommendations-tables.table.integration.spec.js#refuses
        a cap of zero or above ten on a placement and on a binding
    step_evidence:
      - do: Bind an unsupported kind and exceed a placement’s offer cap
        provenance: test
        source: >-
          services-commerce:modules/recommendations/tests/e2e/recommendation-rules.e2e.spec.js#refuses
          a binding to a placement that shows no such kind, 400 placement_unsupported
    assertions:
      - expect: Both bindings fail
        provenance: test
        source: >-
          services-commerce:modules/recommendations/tests/e2e/recommendation-rules.e2e.spec.js#refuses
          a binding to a placement that shows no such kind, 400 placement_unsupported
  - id: ATS-COM-CAT-019-03
    title: Deferred recommendation kinds retain different availability
    level: api
    proves:
      - BR-CAP-COM-CAT-019-04
    preconditions: Rule creation can select application flow or membership savings
    steps: Create both forms
    expected: Flow action fails and membership-savings configuration is stored
    negative: true
    data_needs: none
    bound_to:
      - TST-COM-CAT-136
      - TST-COM-CAT-151
    provenance: test
    source: >-
      services-commerce:modules/recommendations/tests/e2e/recommendation-rules.e2e.spec.js#refuses a
      rule whose action is start_journey, 409 action_unavailable: the journeys are R3’s
    category: edge
    binding_evidence:
      - >-
        services-commerce:modules/recommendations/tests/e2e/recommendation-rules.e2e.spec.js#refuses
        a rule whose action is start_journey, 409 action_unavailable: the journeys are R3’s
      - >-
        services-commerce:modules/recommendations/tests/unit/rule-rules.spec.js#accepts a
        membership_savings rule’s parameters whole, for R1 to read
    step_evidence:
      - do: Create both forms
        provenance: test
        source: >-
          services-commerce:modules/recommendations/tests/e2e/recommendation-rules.e2e.spec.js#refuses
          a rule whose action is start_journey, 409 action_unavailable: the journeys are R3’s
    assertions:
      - expect: Flow action fails and membership-savings configuration is stored
        provenance: test
        source: >-
          services-commerce:modules/recommendations/tests/e2e/recommendation-rules.e2e.spec.js#refuses
          a rule whose action is start_journey, 409 action_unavailable: the journeys are R3’s
  - id: ATS-COM-CAT-019-04
    title: Recommendation activation requires binding and capacity
    level: api
    proves:
      - BR-CAP-COM-CAT-019-05
      - AS-JNY-COM-CAT-006-01
      - INV-DOM-COM-CAT-006-03
    preconditions: Bound and unbound rules and a full placement exist
    steps: 'Exercise lifecycle changes, unbound activation and a twenty-sixth active rule'
    expected: Supported moves succeed while missing binding and excess capacity fail
    negative: true
    data_needs: none
    bound_to:
      - TST-COM-CAT-136
      - TST-COM-CAT-148
    provenance: test
    source: >-
      services-commerce:modules/recommendations/tests/e2e/recommendation-rules.e2e.spec.js#moves
      through active, paused, active, ended, archived
    category: transition
    binding_evidence:
      - >-
        services-commerce:modules/recommendations/tests/e2e/recommendation-rules.e2e.spec.js#moves
        through active, paused, active, ended, archived
      - >-
        services-commerce:modules/recommendations/tests/e2e/recommendation-rules.e2e.spec.js#refuses
        to activate a rule bound to no placement, 409 no_placement
      - >-
        services-commerce:modules/recommendations/tests/integration/services/persistence/recommendation-rules.integration.spec.js#refuses
        the twenty-sixth active rule of one placement, too_many_active_rules, naming the placement
    step_evidence:
      - do: 'Exercise lifecycle changes, unbound activation and a twenty-sixth active rule'
        provenance: test
        source: >-
          services-commerce:modules/recommendations/tests/e2e/recommendation-rules.e2e.spec.js#moves
          through active, paused, active, ended, archived
    assertions:
      - expect: Supported moves succeed while missing binding and excess capacity fail
        provenance: test
        source: >-
          services-commerce:modules/recommendations/tests/e2e/recommendation-rules.e2e.spec.js#moves
          through active, paused, active, ended, archived
  - id: ATS-COM-CAT-019-05
    title: Presentation locks substance but permits message editing
    level: api
    proves:
      - BR-CAP-COM-CAT-019-06
      - INV-DOM-COM-CAT-006-04
    preconditions: A rule has already produced a presentation
    steps: Change its products and then its message
    expected: Locked substance fails and the message saves
    negative: true
    data_needs: A presentation
    bound_to:
      - TST-COM-CAT-141
      - TST-COM-CAT-148
    provenance: test
    source: >-
      services-commerce:modules/recommendations/tests/integration/services/persistence/offer-presentations.integration.spec.js#locks
      the rule once the first presentation is written
    category: invariant
    binding_evidence:
      - >-
        services-commerce:modules/recommendations/tests/integration/services/persistence/offer-presentations.integration.spec.js#locks
        the rule once the first presentation is written
      - >-
        services-commerce:modules/recommendations/tests/integration/services/persistence/recommendation-rules.integration.spec.js#refuses
        the substance of a locked rule, rule_locked, naming the columns, while the message stays
        editable
    step_evidence:
      - do: Change its products and then its message
        provenance: test
        source: >-
          services-commerce:modules/recommendations/tests/integration/services/persistence/offer-presentations.integration.spec.js#locks
          the rule once the first presentation is written
    assertions:
      - expect: Locked substance fails and the message saves
        provenance: test
        source: >-
          services-commerce:modules/recommendations/tests/integration/services/persistence/offer-presentations.integration.spec.js#locks
          the rule once the first presentation is written
  - id: ATS-COM-CAT-019-06
    title: Names and holdouts remain deterministic
    level: unit
    proves:
      - BR-CAP-COM-CAT-019-07
      - INV-DOM-COM-CAT-006-05
    preconditions: Rule and subject fixtures support duplicate and bucket checks
    steps: 'Reuse a name, bucket the same subject twice and assess a fifty-percent holdout'
    expected: 'The name fails, buckets match and approximately half the fixture subjects are withheld'
    negative: true
    data_needs: none
    bound_to:
      - TST-COM-CAT-148
      - TST-COM-CAT-150
    provenance: test
    source: >-
      services-commerce:modules/recommendations/tests/integration/services/persistence/recommendation-rules.integration.spec.js#refuses
      a second rule under the same name, rule_name_taken
    category: rule
    binding_evidence:
      - >-
        services-commerce:modules/recommendations/tests/integration/services/persistence/recommendation-rules.integration.spec.js#refuses
        a second rule under the same name, rule_name_taken
      - >-
        services-commerce:modules/recommendations/tests/unit/holdout.spec.js#answers the same bucket
        for the same subject and rule every time
      - >-
        services-commerce:modules/recommendations/tests/unit/holdout.spec.js#holds out about half of
        a thousand subjects at fifty per cent
    step_evidence:
      - do: 'Reuse a name, bucket the same subject twice and assess a fifty-percent holdout'
        provenance: test
        source: >-
          services-commerce:modules/recommendations/tests/integration/services/persistence/recommendation-rules.integration.spec.js#refuses
          a second rule under the same name, rule_name_taken
    assertions:
      - expect: 'The name fails, buckets match and approximately half the fixture subjects are withheld'
        provenance: test
        source: >-
          services-commerce:modules/recommendations/tests/integration/services/persistence/recommendation-rules.integration.spec.js#refuses
          a second rule under the same name, rule_name_taken
  - id: ATS-COM-CAT-019-07
    title: Recommendation grants separate reading and launching
    level: api
    proves:
      - BR-CAP-COM-CAT-019-11
    preconditions: The caller has read-only rule authority
    steps: Read permitted resources and attempt creation and activation
    expected: Authorized reads succeed and writes or launch requests fail
    negative: true
    data_needs: Read-exclusively persona
    bound_to:
      - TST-COM-CAT-137
    provenance: test
    source: >-
      services-commerce:modules/recommendations/tests/e2e/recommendations-security.e2e.spec.js#lists
      the rules and the placements, and is refused a create and an activation 403 permission_missing
    category: permission
    binding_evidence:
      - >-
        services-commerce:modules/recommendations/tests/e2e/recommendations-security.e2e.spec.js#lists
        the rules and the placements, and is refused a create and an activation 403
        permission_missing
    step_evidence:
      - do: Read permitted resources and attempt creation and activation
        provenance: test
        source: >-
          services-commerce:modules/recommendations/tests/e2e/recommendations-security.e2e.spec.js#lists
          the rules and the placements, and is refused a create and an activation 403
          permission_missing
    assertions:
      - expect: Authorized reads succeed and writes or launch requests fail
        provenance: test
        source: >-
          services-commerce:modules/recommendations/tests/e2e/recommendations-security.e2e.spec.js#lists
          the rules and the placements, and is refused a create and an activation 403
          permission_missing
  - id: ATS-COM-CAT-019-08
    title: Presenting an active rule protects it before acceptance
    category: interaction
    level: api
    proves:
      - BR-CAP-COM-CAT-019-05
      - BR-CAP-COM-CAT-019-06
      - BR-CAP-COM-CAT-020-01
    preconditions: A compatible bound rule can offer a mug.
    steps: >-
      Activate and evaluate, edit its candidate product and then its message, accept the
      presentation and evaluate again.
    expected: >-
      Presentation protects substance, permits messaging changes and completed acceptance suppresses
      the mug.
    negative: false
    data_needs: Run-owned workspace and records; fixed clock where dates are exercised.
    bound_to: []
    provenance: proposed
    source:
      - >-
        services-commerce:modules/recommendations/tests/integration/services/persistence/recommendation-rules.integration.spec.js#refuses
        the twenty-sixth active rule of one placement, too_many_active_rules, naming the placement
      - >-
        services-commerce:modules/recommendations/tests/integration/services/persistence/recommendation-rules.integration.spec.js#refuses
        the substance of a locked rule, rule_locked, naming the columns, while the message stays
        editable
      - >-
        services-commerce:modules/recommendations/tests/e2e/offers.e2e.spec.js#answers one offer:
        the mug, from the listing, priced $12.00 by the quote, live, to add to the checkout,
        expiring with the quote
    exercises:
      - CAP-COM-CAT-019
      - CAP-COM-CAT-020
    workflows: []
    step_evidence:
      - do: >-
          Activate and evaluate, edit its candidate product and then its message, accept the
          presentation and evaluate again.
        provenance: proposed
        source:
          - >-
            services-commerce:modules/recommendations/tests/integration/services/persistence/recommendation-rules.integration.spec.js#refuses
            the twenty-sixth active rule of one placement, too_many_active_rules, naming the
            placement
          - >-
            services-commerce:modules/recommendations/tests/integration/services/persistence/recommendation-rules.integration.spec.js#refuses
            the substance of a locked rule, rule_locked, naming the columns, while the message stays
            editable
          - >-
            services-commerce:modules/recommendations/tests/e2e/offers.e2e.spec.js#answers one
            offer: the mug, from the listing, priced $12.00 by the quote, live, to add to the
            checkout, expiring with the quote
    assertions:
      - expect: >-
          Presentation protects substance, permits messaging changes and completed acceptance
          suppresses the mug.
        provenance: proposed
        source:
          - >-
            services-commerce:modules/recommendations/tests/integration/services/persistence/recommendation-rules.integration.spec.js#refuses
            the twenty-sixth active rule of one placement, too_many_active_rules, naming the
            placement
          - >-
            services-commerce:modules/recommendations/tests/integration/services/persistence/recommendation-rules.integration.spec.js#refuses
            the substance of a locked rule, rule_locked, naming the columns, while the message stays
            editable
          - >-
            services-commerce:modules/recommendations/tests/e2e/offers.e2e.spec.js#answers one
            offer: the mug, from the listing, priced $12.00 by the quote, live, to add to the
            checkout, expiring with the quote
  - id: ATS-COM-CAT-019-09
    title: Provisioning reruns preserve audience and placement edits
    category: interaction
    level: api
    proves:
      - BR-CAP-COM-CAT-010-01
      - BR-CAP-COM-CAT-019-02
    preconditions: A new workspace has built-in audiences and storefront placements.
    steps: >-
      Change a permitted audience field and a placement cap; rerun both seed operations and verify
      setup.
    expected: Required setup exists once and the customer’s saved settings remain.
    negative: false
    data_needs: Run-owned workspace and records; fixed clock where dates are exercised.
    bound_to: []
    provenance: proposed
    source:
      - >-
        services-commerce:modules/pricing/tests/e2e/pricing-audiences.e2e.spec.js#lists standard for
        everyone at rank 0 and member by eligibility at rank 10, built in, member shown to visitors,
        with no binding yet
      - >-
        services-commerce:modules/recommendations/tests/e2e/recommendation-rules.e2e.spec.js#refuses
        a cap above the placement’s, 400 max_offers_exceeds_placement
    exercises:
      - CAP-COM-CAT-010
      - CAP-COM-CAT-019
    workflows:
      - WF-COM-CAT-019
    step_evidence:
      - do: >-
          Change a permitted audience field and a placement cap; rerun both seed operations and
          verify setup.
        provenance: proposed
        source:
          - >-
            services-commerce:modules/pricing/tests/e2e/pricing-audiences.e2e.spec.js#lists standard
            for everyone at rank 0 and member by eligibility at rank 10, built in, member shown to
            visitors, with no binding yet
          - >-
            services-commerce:modules/recommendations/tests/e2e/recommendation-rules.e2e.spec.js#refuses
            a cap above the placement’s, 400 max_offers_exceeds_placement
    assertions:
      - expect: Required setup exists once and the customer’s saved settings remain.
        provenance: proposed
        source:
          - >-
            services-commerce:modules/pricing/tests/e2e/pricing-audiences.e2e.spec.js#lists standard
            for everyone at rank 0 and member by eligibility at rank 10, built in, member shown to
            visitors, with no binding yet
          - >-
            services-commerce:modules/recommendations/tests/e2e/recommendation-rules.e2e.spec.js#refuses
            a cap above the placement’s, 400 max_offers_exceeds_placement
  - id: ATS-COM-CAT-019-10
    title: Recommendation rule lifecycle is exercised across every declared move
    category: transition
    level: api
    proves:
      - BR-CAP-COM-CAT-019-05
      - BR-CAP-COM-CAT-019-06
    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-011-recommendation-rule-lifecycle.md#STATE-COM-CAT-011
      - >-
        services-commerce:modules/recommendations/tests/integration/services/persistence/recommendation-rules.integration.spec.js#refuses
        the twenty-sixth active rule of one placement, too_many_active_rules, naming the placement
      - 'services-commerce:modules/recommendations/services/rules/rule-workflow.ts:RULE_OPERATIONS'
      - >-
        services-commerce:modules/recommendations/tests/e2e/recommendations-security.e2e.spec.js#lists
        the rules and the placements, and is refused a create and an activation 403
        permission_missing
      - 'services-commerce:modules/recommendations/services/persistence/recommendation-rules.ts'
      - 'services-commerce:modules/recommendations/services/persistence/recommendation-rules.ts'
      - 'services-commerce:modules/recommendations/services/persistence/recommendation-rules.ts'
      - 'services-commerce:modules/recommendations/services/persistence/recommendation-rules.ts'
      - >-
        services-commerce:modules/recommendations/tests/integration/services/persistence/recommendation-rules.integration.spec.js#refuses
        the substance of a locked rule, rule_locked, naming the columns, while the message stays
        editable
    state_model: STATE-COM-CAT-011
    transition_cases:
      - from: draft
        to: active
        trigger: Staff request rule activation.
        guard: >-
          Activation requires valid parameters and action, compatible active placement bindings
          within limits, and fewer than twenty-five active rules at each placement.
        provenance: proposed
        source:
          - >-
            services-commerce:modules/recommendations/tests/integration/services/persistence/recommendation-rules.integration.spec.js#refuses
            the twenty-sixth active rule of one placement, too_many_active_rules, naming the
            placement
          - >-
            rhythm-v2-docs:specs/commerce/catalog/design/state-models/STATE-COM-CAT-011-recommendation-rule-lifecycle.md#STATE-COM-CAT-011
      - from: active
        to: paused
        trigger: Staff request a temporary pause.
        guard: The caller must hold rule update authority.
        provenance: proposed
        source:
          - >-
            services-commerce:modules/recommendations/services/rules/rule-workflow.ts:RULE_OPERATIONS
          - >-
            rhythm-v2-docs:specs/commerce/catalog/design/state-models/STATE-COM-CAT-011-recommendation-rule-lifecycle.md#STATE-COM-CAT-011
      - from: paused
        to: active
        trigger: Staff request resumption.
        guard: Activation authority and all placement and rule checks must pass.
        provenance: proposed
        source:
          - >-
            services-commerce:modules/recommendations/tests/e2e/recommendations-security.e2e.spec.js#lists
            the rules and the placements, and is refused a create and an activation 403
            permission_missing
          - >-
            rhythm-v2-docs:specs/commerce/catalog/design/state-models/STATE-COM-CAT-011-recommendation-rule-lifecycle.md#STATE-COM-CAT-011
      - from: active
        to: ended
        trigger: Staff request permanent ending.
        guard: The caller must hold rule update authority.
        provenance: proposed
        source:
          - 'services-commerce:modules/recommendations/services/persistence/recommendation-rules.ts'
          - >-
            rhythm-v2-docs:specs/commerce/catalog/design/state-models/STATE-COM-CAT-011-recommendation-rule-lifecycle.md#STATE-COM-CAT-011
      - from: paused
        to: ended
        trigger: Staff request permanent ending.
        guard: The caller must hold rule update authority.
        provenance: proposed
        source:
          - 'services-commerce:modules/recommendations/services/persistence/recommendation-rules.ts'
          - >-
            rhythm-v2-docs:specs/commerce/catalog/design/state-models/STATE-COM-CAT-011-recommendation-rule-lifecycle.md#STATE-COM-CAT-011
      - from: draft
        to: archived
        trigger: Staff archive a prepared rule.
        guard: The caller must hold rule update authority.
        provenance: proposed
        source:
          - 'services-commerce:modules/recommendations/services/persistence/recommendation-rules.ts'
          - >-
            rhythm-v2-docs:specs/commerce/catalog/design/state-models/STATE-COM-CAT-011-recommendation-rule-lifecycle.md#STATE-COM-CAT-011
      - from: ended
        to: archived
        trigger: Staff archive an ended rule.
        guard: The caller must hold rule update authority.
        provenance: proposed
        source:
          - 'services-commerce:modules/recommendations/services/persistence/recommendation-rules.ts'
          - >-
            rhythm-v2-docs:specs/commerce/catalog/design/state-models/STATE-COM-CAT-011-recommendation-rule-lifecycle.md#STATE-COM-CAT-011
      - from: active
        to: locked
        trigger: Live evaluation commits the first presentation.
        guard: The transaction containing the presentation must commit.
        provenance: proposed
        source:
          - >-
            services-commerce:modules/recommendations/tests/integration/services/persistence/recommendation-rules.integration.spec.js#refuses
            the substance of a locked rule, rule_locked, naming the columns, while the message stays
            editable
          - >-
            rhythm-v2-docs:specs/commerce/catalog/design/state-models/STATE-COM-CAT-011-recommendation-rule-lifecycle.md#STATE-COM-CAT-011
    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-011-recommendation-rule-lifecycle.md#STATE-COM-CAT-011
          - >-
            services-commerce:modules/recommendations/tests/integration/services/persistence/recommendation-rules.integration.spec.js#refuses
            the twenty-sixth active rule of one placement, too_many_active_rules, naming the
            placement
          - >-
            services-commerce:modules/recommendations/services/rules/rule-workflow.ts:RULE_OPERATIONS
          - >-
            services-commerce:modules/recommendations/tests/e2e/recommendations-security.e2e.spec.js#lists
            the rules and the placements, and is refused a create and an activation 403
            permission_missing
          - 'services-commerce:modules/recommendations/services/persistence/recommendation-rules.ts'
          - 'services-commerce:modules/recommendations/services/persistence/recommendation-rules.ts'
          - 'services-commerce:modules/recommendations/services/persistence/recommendation-rules.ts'
          - 'services-commerce:modules/recommendations/services/persistence/recommendation-rules.ts'
          - >-
            services-commerce:modules/recommendations/tests/integration/services/persistence/recommendation-rules.integration.spec.js#refuses
            the substance of a locked rule, rule_locked, naming the columns, while the message stays
            editable
    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-011-recommendation-rule-lifecycle.md#STATE-COM-CAT-011
          - >-
            services-commerce:modules/recommendations/tests/integration/services/persistence/recommendation-rules.integration.spec.js#refuses
            the twenty-sixth active rule of one placement, too_many_active_rules, naming the
            placement
          - >-
            services-commerce:modules/recommendations/services/rules/rule-workflow.ts:RULE_OPERATIONS
          - >-
            services-commerce:modules/recommendations/tests/e2e/recommendations-security.e2e.spec.js#lists
            the rules and the placements, and is refused a create and an activation 403
            permission_missing
          - 'services-commerce:modules/recommendations/services/persistence/recommendation-rules.ts'
          - 'services-commerce:modules/recommendations/services/persistence/recommendation-rules.ts'
          - 'services-commerce:modules/recommendations/services/persistence/recommendation-rules.ts'
          - 'services-commerce:modules/recommendations/services/persistence/recommendation-rules.ts'
          - >-
            services-commerce:modules/recommendations/tests/integration/services/persistence/recommendation-rules.integration.spec.js#refuses
            the substance of a locked rule, rule_locked, naming the columns, while the message stays
            editable
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-019-configure-what-is-recommended-where.md#CAP-COM-CAT-019
  - >-
    rhythm-v2-docs:specs/commerce/catalog/design/workflows/WF-COM-CAT-019-prepare-a-new-workspace-s-built-in-audiences.md#WF-COM-CAT-019
product_intent: proposed
coverage:
  rule: covered
  transition: covered
  validation: covered
  permission: covered
  edge: covered
  failure: 'gap: FND-COM-CAT-073'
  boundary: covered
  concurrency: 'gap: FND-COM-CAT-073'
  invariant: covered
  interaction: covered
coverage_notes:
  failure: >-
    No complete failure scenario is established by this back-fill; the finding records the missing
    proof.
  concurrency: Concurrent execution has no complete scenario; sequential retry is insufficient proof.
permission_coverage:
  - key: commerce.recommendation-rules.read
    coverage: 'gap: FND-COM-CAT-073'
    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-073'
  - key: commerce.recommendation-rules.create
    coverage: 'gap: FND-COM-CAT-073'
    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-073'
  - key: commerce.recommendation-rules.update
    coverage: 'gap: FND-COM-CAT-073'
    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-073'
  - key: commerce.recommendation-rules.activate
    coverage: 'gap: FND-COM-CAT-073'
    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-073'
  - key: commerce.recommendation-rules.delete
    coverage: 'gap: FND-COM-CAT-073'
    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-073'
  - key: commerce.recommendation-rules.bulk
    coverage: 'gap: FND-COM-CAT-073'
    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-073'
  - key: commerce.recommendation-placements.read
    coverage: 'gap: FND-COM-CAT-073'
    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-073'
  - key: commerce.recommendation-journeys.read
    coverage: 'gap: FND-COM-CAT-073'
    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-073'
  - key: commerce.recommendation-journeys.create
    coverage: 'gap: FND-COM-CAT-073'
    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-073'
  - key: commerce.recommendation-journeys.update
    coverage: 'gap: FND-COM-CAT-073'
    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-073'
  - key: commerce.recommendation-journeys.delete
    coverage: 'gap: FND-COM-CAT-073'
    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-073'
  - key: commerce.recommendation-journeys.bulk
    coverage: 'gap: FND-COM-CAT-073'
    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-073'
---

# Configure recommendation rules and placements: Capability Test Specification

## Coverage

| Rule | Proof Scenario or Gap |
|---|---|
| `BR-CAP-COM-CAT-019-01` | `ATS-COM-CAT-019-01` |
| `BR-CAP-COM-CAT-019-02` | `ATS-COM-CAT-019-02`, `ATS-COM-CAT-019-09` |
| `BR-CAP-COM-CAT-019-04` | `ATS-COM-CAT-019-03` |
| `BR-CAP-COM-CAT-019-05` | `ATS-COM-CAT-019-04`, `ATS-COM-CAT-019-08`, `ATS-COM-CAT-019-10` |
| `BR-CAP-COM-CAT-019-06` | `ATS-COM-CAT-019-05`, `ATS-COM-CAT-019-08`, `ATS-COM-CAT-019-10` |
| `BR-CAP-COM-CAT-019-07` | `ATS-COM-CAT-019-06` |
| `BR-CAP-COM-CAT-019-11` | `ATS-COM-CAT-019-07` |

## Interactions With Related Capabilities

Presenting an active rule protects it before acceptance. Provisioning reruns preserve audience and placement edits.

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