---
id: ATS-COM-CAT-016
scope: CAP-COM-CAT-016
product_area: commerce
module: catalog
revision: 2
status: proposed
source_sha:
  services-commerce: c8b66a98e2490617aec38ba5c8165dd9bd0a8f9b
  react-console: baf6dae382d6f41dce976c7f848667ccc37e076f
scenarios:
  - id: ATS-COM-CAT-016-01
    title: Alternative pricing matches the decision’s examples
    level: unit
    proves:
      - BR-CAP-COM-CAT-016-01
      - BR-CAP-COM-CAT-016-02
      - AS-JNY-COM-CAT-005-01
    preconditions: 'Standard, Member and Student prices are one hundred, eighty and sixty dollars'
    steps: Assess combining and noncombining twenty-five-percent benefits
    expected: >-
      Results are sixty, seventy-five and sixty dollars, with the ineffective code unused and
      explained
    negative: false
    data_needs: none
    bound_to:
      - TST-COM-CAT-122
    provenance: test
    source: >-
      services-commerce:modules/promotions/tests/unit/pricing/alternatives.spec.js#1. combine = yes,
      member: $80.00 less 25 % is $60.00 (tax 8 % is $4.80)
    category: rule
    binding_evidence:
      - >-
        services-commerce:modules/promotions/tests/unit/pricing/alternatives.spec.js#1. combine =
        yes, member: $80.00 less 25 % is $60.00 (tax 8 % is $4.80)
      - >-
        services-commerce:modules/promotions/tests/unit/pricing/alternatives.spec.js#2. combine =
        no, member: audience pricing $80.00 against $100.00 less 25 % = $75.00; the promotional
        price wins
      - >-
        services-commerce:modules/promotions/tests/unit/pricing/alternatives.spec.js#3. combine =
        no, student at $60.00: audience pricing wins, EARLY25 consumes no use, and the buyer is told
        why
      - >-
        services-commerce:modules/promotions/tests/unit/pricing/alternatives.spec.js#is the same
        answer for the same input
    step_evidence:
      - do: Assess combining and noncombining twenty-five-percent benefits
        provenance: test
        source: >-
          services-commerce:modules/promotions/tests/unit/pricing/alternatives.spec.js#1. combine =
          yes, member: $80.00 less 25 % is $60.00 (tax 8 % is $4.80)
    assertions:
      - expect: >-
          Results are sixty, seventy-five and sixty dollars, with the ineffective code unused and
          explained
        provenance: test
        source: >-
          services-commerce:modules/promotions/tests/unit/pricing/alternatives.spec.js#1. combine =
          yes, member: $80.00 less 25 % is $60.00 (tax 8 % is $4.80)
  - id: ATS-COM-CAT-016-02
    title: Bounded combination search handles extra promotions
    level: unit
    proves:
      - BR-CAP-COM-CAT-016-03
    preconditions: Five promotions cannot combine with audience prices
    steps: Evaluate the candidate set
    expected: >-
      At most sixteen base alternatives are explored; later entries are retained only when they
      improve the total
    negative: false
    data_needs: none
    bound_to:
      - TST-COM-CAT-122
    provenance: test
    source: >-
      services-commerce:modules/promotions/tests/unit/pricing/alternatives.spec.js#takes one of two
      when the other loses on its own line: A a better price on the guide, B a worse one on the mug
    category: boundary
    binding_evidence:
      - >-
        services-commerce:modules/promotions/tests/unit/pricing/alternatives.spec.js#takes one of
        two when the other loses on its own line: A a better price on the guide, B a worse one on
        the mug
      - >-
        services-commerce:modules/promotions/tests/unit/pricing/alternatives.spec.js#tries the fifth
        and later one at a time in entry order
      - >-
        services-commerce:modules/promotions/tests/unit/pricing/alternatives.spec.js#leaves the
        fifth unused when it does not lower the total
      - >-
        services-commerce:modules/promotions/tests/unit/pricing/alternatives.spec.js#asks for at
        most sixteen distinct alternatives when four promotions stay off audience prices
    step_evidence:
      - do: Evaluate the candidate set
        provenance: test
        source: >-
          services-commerce:modules/promotions/tests/unit/pricing/alternatives.spec.js#takes one of
          two when the other loses on its own line: A a better price on the guide, B a worse one on
          the mug
    assertions:
      - expect: >-
          At most sixteen base alternatives are explored; later entries are retained only when they
          improve the total
        provenance: test
        source: >-
          services-commerce:modules/promotions/tests/unit/pricing/alternatives.spec.js#takes one of
          two when the other loses on its own line: A a better price on the guide, B a worse one on
          the mug
  - id: ATS-COM-CAT-016-03
    title: Sequential line benefits precede order benefits
    level: unit
    proves:
      - BR-CAP-COM-CAT-016-04
    preconditions: A hundred-dollar line supports ten-percent and twenty-dollar order benefits
    steps: Evaluate their application
    expected: The result is seventy dollars and subsequent benefits use the prior result
    negative: false
    data_needs: none
    bound_to:
      - TST-COM-CAT-122
      - TST-COM-CAT-131
    provenance: test
    source: >-
      services-commerce:modules/promotions/tests/unit/pricing/alternatives.spec.js#Q2: line-level
      before order-level: 10 % and $20 off the order on $100.00 is $70.00, not $72.00
    category: rule
    binding_evidence:
      - >-
        services-commerce:modules/promotions/tests/unit/pricing/alternatives.spec.js#Q2: line-level
        before order-level: 10 % and $20 off the order on $100.00 is $70.00, not $72.00
      - >-
        services-commerce:modules/promotions/tests/unit/pricing/stacking.spec.js#puts automatic
        promotions first by priority, then the codes in the order entered
      - >-
        services-commerce:modules/promotions/tests/unit/pricing/stacking.spec.js#J16: an automatic
        10% stackable then a 15% stackable code on 20000 give 2000 then 2700, net 15300
    step_evidence:
      - do: Evaluate their application
        provenance: test
        source: >-
          services-commerce:modules/promotions/tests/unit/pricing/alternatives.spec.js#Q2:
          line-level before order-level: 10 % and $20 off the order on $100.00 is $70.00, not $72.00
    assertions:
      - expect: The result is seventy dollars and subsequent benefits use the prior result
        provenance: test
        source: >-
          services-commerce:modules/promotions/tests/unit/pricing/alternatives.spec.js#Q2:
          line-level before order-level: 10 % and $20 off the order on $100.00 is $70.00, not $72.00
  - id: ATS-COM-CAT-016-04
    title: Exclusive codes compete against automatic benefits
    level: unit
    proves:
      - BR-CAP-COM-CAT-016-05
    preconditions: Automatic Fall pricing and two exclusive VIP benefits exist
    steps: Assess the weaker VIP alone and both VIP codes in either order
    expected: >-
      The weak code loses to automatic pricing; the better exclusive wins consistently and conflicts
      identify the holder
    negative: false
    data_needs: none
    bound_to:
      - TST-COM-CAT-122
      - TST-COM-CAT-131
    provenance: test
    source: >-
      services-commerce:modules/promotions/tests/unit/pricing/alternatives.spec.js#5. exclusive code
      against the automatic outcome: VIP5 (5 %) would give $76.00, Fall 10 % gives $72.00; VIP5 is
      dropped and consumes no use
    category: interaction
    binding_evidence:
      - >-
        services-commerce:modules/promotions/tests/unit/pricing/alternatives.spec.js#5. exclusive
        code against the automatic outcome: VIP5 (5 %) would give $76.00, Fall 10 % gives $72.00;
        VIP5 is dropped and consumes no use
      - >-
        services-commerce:modules/promotions/tests/unit/pricing/alternatives.spec.js#Q5: every
        combination of the exclusive codes: the better of two exclusive codes wins whatever the
        order entered
      - >-
        services-commerce:modules/promotions/tests/unit/pricing/alternatives.spec.js#Q5: the
        exclusive code that loses to another is refused, naming the one that holds the line
      - >-
        services-commerce:modules/promotions/tests/unit/pricing/stacking.spec.js#refuses any
        promotion on a line an exclusive one holds
    step_evidence:
      - do: Assess the weaker VIP alone and both VIP codes in either order
        provenance: test
        source: >-
          services-commerce:modules/promotions/tests/unit/pricing/alternatives.spec.js#5. exclusive
          code against the automatic outcome: VIP5 (5 %) would give $76.00, Fall 10 % gives $72.00;
          VIP5 is dropped and consumes no use
    assertions:
      - expect: >-
          The weak code loses to automatic pricing; the better exclusive wins consistently and
          conflicts identify the holder
        provenance: test
        source: >-
          services-commerce:modules/promotions/tests/unit/pricing/alternatives.spec.js#5. exclusive
          code against the automatic outcome: VIP5 (5 %) would give $76.00, Fall 10 % gives $72.00;
          VIP5 is dropped and consumes no use
  - id: ATS-COM-CAT-016-05
    title: Comparison bases and ties preserve audience pricing
    level: unit
    proves:
      - BR-CAP-COM-CAT-016-06
    preconditions: Alternatives tie and another cart has a minimum threshold
    steps: Assess the alternatives and qualifying subtotal
    expected: >-
      The tie retains audience pricing without usage, and minimum qualification uses
      post-line-discount amounts
    negative: false
    data_needs: none
    bound_to:
      - TST-COM-CAT-122
    provenance: test
    source: >-
      services-commerce:modules/promotions/tests/unit/pricing/alternatives.spec.js#Q4: a tie goes to
      audience pricing, and the tied code is not used up
    category: edge
    binding_evidence:
      - >-
        services-commerce:modules/promotions/tests/unit/pricing/alternatives.spec.js#Q4: a tie goes
        to audience pricing, and the tied code is not used up
      - >-
        services-commerce:modules/promotions/tests/unit/pricing/alternatives.spec.js#Q7: the
        comparison is the order total before tax and shipping
      - >-
        services-commerce:modules/promotions/tests/unit/pricing/alternatives.spec.js#Q3: the minimum
        order is measured on the qualifying lines after the line-level promotions
    step_evidence:
      - do: Assess the alternatives and qualifying subtotal
        provenance: test
        source: >-
          services-commerce:modules/promotions/tests/unit/pricing/alternatives.spec.js#Q4: a tie
          goes to audience pricing, and the tied code is not used up
    assertions:
      - expect: >-
          The tie retains audience pricing without usage, and minimum qualification uses
          post-line-discount amounts
        provenance: test
        source: >-
          services-commerce:modules/promotions/tests/unit/pricing/alternatives.spec.js#Q4: a tie
          goes to audience pricing, and the tied code is not used up
  - id: ATS-COM-CAT-016-06
    title: Discount arithmetic preserves rounded allocations
    level: unit
    proves:
      - BR-CAP-COM-CAT-016-08
      - BR-CAP-COM-CAT-016-09
    preconditions: Amounts support percentage and proportional examples
    steps: Calculate fifteen percent of 3333 and allocate fixed discounts across unequal and equal lines
    expected: 'Results are 500, allocations 1714/857/429 and 834/833/833'
    negative: false
    data_needs: none
    bound_to:
      - TST-COM-CAT-124
      - TST-COM-CAT-121
    provenance: test
    source: >-
      services-commerce:modules/promotions/tests/unit/pricing/benefits.spec.js#takes 15% off 3333 as
      500 (499.95 rounded half up)
    category: invariant
    binding_evidence:
      - >-
        services-commerce:modules/promotions/tests/unit/pricing/benefits.spec.js#takes 15% off 3333
        as 500 (499.95 rounded half up)
      - >-
        services-commerce:modules/promotions/tests/unit/pricing/allocation.spec.js#shares 3000 over
        10000, 5000 and 2500 as 1714, 857, 429: the largest fraction gets the unit
      - >-
        services-commerce:modules/promotions/tests/unit/pricing/allocation.spec.js#shares 2500 over
        three 10000 lines as 834, 833, 833: the tie goes to the first line
      - >-
        services-commerce:modules/promotions/tests/unit/pricing/allocation.spec.js#sums to the
        amount exactly, every part its floor or one more and never above its basis, ties to the
        earlier line
    step_evidence:
      - do: >-
          Calculate fifteen percent of 3333 and allocate fixed discounts across unequal and equal
          lines
        provenance: test
        source: >-
          services-commerce:modules/promotions/tests/unit/pricing/benefits.spec.js#takes 15% off
          3333 as 500 (499.95 rounded half up)
    assertions:
      - expect: 'Results are 500, allocations 1714/857/429 and 834/833/833'
        provenance: test
        source: >-
          services-commerce:modules/promotions/tests/unit/pricing/benefits.spec.js#takes 15% off
          3333 as 500 (499.95 rounded half up)
  - id: ATS-COM-CAT-016-07
    title: Item exclusions and shipping caps remain distinct
    level: unit
    proves:
      - BR-CAP-COM-CAT-016-10
    preconditions: The cart includes pass-through and promotion-excluded lines
    steps: Apply an item percentage and a shipping benefit
    expected: Only qualifying item lines receive the percentage and shipping reduction stops at zero
    negative: false
    data_needs: none
    bound_to:
      - TST-COM-CAT-123
      - TST-COM-CAT-130
      - TST-COM-CAT-127
    provenance: test
    source: >-
      services-commerce:modules/promotions/tests/unit/pricing/apply-promotions.spec.js#never touches
      a tax, shipping or fee line, nor a product excluded from promotions
    category: rule
    binding_evidence:
      - >-
        services-commerce:modules/promotions/tests/unit/pricing/apply-promotions.spec.js#never
        touches a tax, shipping or fee line, nor a product excluded from promotions
      - >-
        services-commerce:modules/promotions/tests/unit/pricing/shipping-offers.spec.js#caps
        amount_off_shipping at the charge and never takes it below zero
      - >-
        services-commerce:modules/promotions/tests/unit/pricing/parts.spec.js#leaves a line excluded
        from promotions out of every part, whatever the provider says
    step_evidence:
      - do: Apply an item percentage and a shipping benefit
        provenance: test
        source: >-
          services-commerce:modules/promotions/tests/unit/pricing/apply-promotions.spec.js#never
          touches a tax, shipping or fee line, nor a product excluded from promotions
    assertions:
      - expect: Only qualifying item lines receive the percentage and shipping reduction stops at zero
        provenance: test
        source: >-
          services-commerce:modules/promotions/tests/unit/pricing/apply-promotions.spec.js#never
          touches a tax, shipping or fee line, nor a product excluded from promotions
  - id: ATS-COM-CAT-016-08
    title: Refusal order returns private-information-safe messages
    level: unit
    proves:
      - BR-CAP-COM-CAT-016-11
      - BR-CAP-COM-CAT-016-13
    preconditions: Codes independently fail qualification checks
    steps: 'Validate each code, including uncertain and anonymous eligibility'
    expected: >-
      The first applicable reason wins, private values remain hidden, uncertainty refuses and
      restricted visitors are asked to sign in
    negative: true
    data_needs: none
    bound_to:
      - TST-COM-CAT-132
    provenance: test
    source: >-
      services-commerce:modules/promotions/tests/unit/pricing/validation.spec.js#answers the first
      refusal in the order of 10.3: an inactive code before an exhausted one
    category: validation
    binding_evidence:
      - >-
        services-commerce:modules/promotions/tests/unit/pricing/validation.spec.js#answers the first
        refusal in the order of 10.3: an inactive code before an exhausted one
      - >-
        services-commerce:modules/promotions/tests/unit/pricing/validation.spec.js#keeps the limit,
        the owner and the rule out of every customer message
      - >-
        services-commerce:modules/promotions/tests/unit/pricing/validation.spec.js#fails closed on
        an indeterminate verdict, for must_match and for must_not_match alike
      - >-
        services-commerce:modules/promotions/tests/unit/pricing/validation.spec.js#asks an anonymous
        purchaser to sign in for an eligibility rule (J15), before refusing it as ineligible
    step_evidence:
      - do: 'Validate each code, including uncertain and anonymous eligibility'
        provenance: test
        source: >-
          services-commerce:modules/promotions/tests/unit/pricing/validation.spec.js#answers the
          first refusal in the order of 10.3: an inactive code before an exhausted one
    assertions:
      - expect: >-
          The first applicable reason wins, private values remain hidden, uncertainty refuses and
          restricted visitors are asked to sign in
        provenance: test
        source: >-
          services-commerce:modules/promotions/tests/unit/pricing/validation.spec.js#answers the
          first refusal in the order of 10.3: an inactive code before an exhausted one
  - id: ATS-COM-CAT-016-09
    title: Ineffective codes produce no applied benefit
    level: unit
    proves:
      - BR-CAP-COM-CAT-016-12
      - AS-JNY-COM-CAT-005-02
    preconditions: 'Codes have zero benefit, wrong business unit or no qualifying item'
    steps: Assess each against the cart
    expected: No discount or use is applied and the reason remains reported
    negative: false
    data_needs: none
    bound_to:
      - TST-COM-CAT-123
      - TST-COM-CAT-122
    provenance: test
    source: >-
      services-commerce:modules/promotions/tests/unit/pricing/apply-promotions.spec.js#refuses a
      promotion whose benefit is zero on every qualifying line (an amount off a line already free)
    category: edge
    binding_evidence:
      - >-
        services-commerce:modules/promotions/tests/unit/pricing/apply-promotions.spec.js#refuses a
        promotion whose benefit is zero on every qualifying line (an amount off a line already free)
      - >-
        services-commerce:modules/promotions/tests/unit/pricing/apply-promotions.spec.js#J14:
        refuses a promotion of another business unit with the staff reason business unit
      - >-
        services-commerce:modules/promotions/tests/unit/pricing/alternatives.spec.js#records as
        applied only the promotions that gave a discount; a code that gave nothing is rejected and
        not applied
    step_evidence:
      - do: Assess each against the cart
        provenance: test
        source: >-
          services-commerce:modules/promotions/tests/unit/pricing/apply-promotions.spec.js#refuses a
          promotion whose benefit is zero on every qualifying line (an amount off a line already
          free)
    assertions:
      - expect: No discount or use is applied and the reason remains reported
        provenance: test
        source: >-
          services-commerce:modules/promotions/tests/unit/pricing/apply-promotions.spec.js#refuses a
          promotion whose benefit is zero on every qualifying line (an amount off a line already
          free)
  - id: ATS-COM-CAT-016-10
    title: Alternative explanations identify why a code loses or wins
    level: unit
    proves:
      - BR-CAP-COM-CAT-016-14
    preconditions: Codes compete with audience and automatic prices
    steps: Render the comparison messages
    expected: Messages explain the outcome using both totals where applicable
    negative: false
    data_needs: none
    bound_to:
      - TST-COM-CAT-129
    provenance: test
    source: >-
      services-commerce:modules/promotions/tests/unit/pricing/reason-codes.spec.js#says in the
      customer’s words that the audience price was better, with both totals
    category: rule
    binding_evidence:
      - >-
        services-commerce:modules/promotions/tests/unit/pricing/reason-codes.spec.js#says in the
        customer’s words that the audience price was better, with both totals
      - >-
        services-commerce:modules/promotions/tests/unit/pricing/reason-codes.spec.js#says, the
        reverse, that the promotional price was lower than the audience price
      - >-
        services-commerce:modules/promotions/tests/unit/pricing/reason-codes.spec.js#says that the
        automatic promotions were better
    step_evidence:
      - do: Render the comparison messages
        provenance: test
        source: >-
          services-commerce:modules/promotions/tests/unit/pricing/reason-codes.spec.js#says in the
          customer’s words that the audience price was better, with both totals
    assertions:
      - expect: Messages explain the outcome using both totals where applicable
        provenance: test
        source: >-
          services-commerce:modules/promotions/tests/unit/pricing/reason-codes.spec.js#says in the
          customer’s words that the audience price was better, with both totals
  - id: ATS-COM-CAT-016-11
    title: Selling-area timeout distinguishes preview from placement
    level: unit
    proves:
      - BR-CAP-COM-CAT-016-15
    preconditions: A part provider cannot answer within its timeout
    steps: Preview the cart and attempt placement
    expected: Preview omits the unavailable parts; placement returns the retry refusal
    negative: true
    data_needs: Fake slow provider
    bound_to:
      - TST-COM-CAT-127
      - TST-COM-CAT-117
    provenance: test
    source: >-
      services-commerce:modules/promotions/tests/unit/pricing/parts.spec.js#refuses a code
      promotion_check_unavailable when a part is listed unavailable, and discounts nothing
    category: failure
    binding_evidence:
      - >-
        services-commerce:modules/promotions/tests/unit/pricing/parts.spec.js#refuses a code
        promotion_check_unavailable when a part is listed unavailable, and discounts nothing
      - >-
        services-commerce:modules/promotions/tests/unit/pricing/parts.spec.js#simply does not apply
        an automatic promotion with an unavailable part, and reports nothing
      - >-
        services-commerce:modules/promotions/tests/unit/areas/area-registry.spec.js#cuts a slow
        provider at the timeout and makes its parts unavailable
    step_evidence:
      - do: Preview the cart and attempt placement
        provenance: test
        source: >-
          services-commerce:modules/promotions/tests/unit/pricing/parts.spec.js#refuses a code
          promotion_check_unavailable when a part is listed unavailable, and discounts nothing
    assertions:
      - expect: Preview omits the unavailable parts; placement returns the retry refusal
        provenance: test
        source: >-
          services-commerce:modules/promotions/tests/unit/pricing/parts.spec.js#refuses a code
          promotion_check_unavailable when a part is listed unavailable, and discounts nothing
  - id: ATS-COM-CAT-016-12
    title: Concurrent usage respects finite capacity
    level: api
    proves:
      - BR-CAP-COM-CAT-016-16
      - INV-DOM-COM-CAT-005-10
    preconditions: A code permits one hundred uses
    steps: Run two hundred competing placements
    expected: 'One hundred succeed, one hundred fail and usage totals remain one hundred'
    negative: true
    data_needs: Concurrency harness
    bound_to:
      - TST-COM-CAT-115
    provenance: test
    source: >-
      services-commerce:modules/promotions/tests/integration/services/persistence/redemption-concurrency.integration.spec.js#applies
      exactly 100 and answers the other 100 code_exhausted
    category: concurrency
    binding_evidence:
      - >-
        services-commerce:modules/promotions/tests/integration/services/persistence/redemption-concurrency.integration.spec.js#applies
        exactly 100 and answers the other 100 code_exhausted
      - >-
        services-commerce:modules/promotions/tests/integration/services/persistence/redemption-concurrency.integration.spec.js#counts
        100 uses on the code
    step_evidence:
      - do: Run two hundred competing placements
        provenance: test
        source: >-
          services-commerce:modules/promotions/tests/integration/services/persistence/redemption-concurrency.integration.spec.js#applies
          exactly 100 and answers the other 100 code_exhausted
    assertions:
      - expect: 'One hundred succeed, one hundred fail and usage totals remain one hundred'
        provenance: test
        source: >-
          services-commerce:modules/promotions/tests/integration/services/persistence/redemption-concurrency.integration.spec.js#applies
          exactly 100 and answers the other 100 code_exhausted
  - id: ATS-COM-CAT-016-13
    title: Only an applied benefit consumes redemption capacity
    category: interaction
    level: api
    proves:
      - BR-CAP-COM-CAT-016-12
      - BR-CAP-COM-CAT-016-16
      - BR-CAP-COM-CAT-017-01
      - BR-CAP-COM-CAT-017-02
    preconditions: One code loses to a cheaper audience and another wins.
    steps: Place each result and read redemption rows and usage counters.
    expected: Only the winning applied promotion has a redemption and increased counters.
    negative: false
    data_needs: Run-owned workspace and records; fixed clock where dates are exercised.
    bound_to: []
    provenance: proposed
    source:
      - >-
        services-commerce:modules/promotions/tests/unit/pricing/apply-promotions.spec.js#refuses a
        promotion whose benefit is zero on every qualifying line (an amount off a line already free)
      - >-
        services-commerce:modules/promotions/tests/integration/services/persistence/redemption-concurrency.integration.spec.js#applies
        exactly 100 and answers the other 100 code_exhausted
      - >-
        services-commerce:modules/promotions/tests/integration/services/persistence/promotion-redemptions.integration.spec.js#locks
        the promotion at its first redemption
      - >-
        services-commerce:modules/promotions/tests/integration/db/redemptions.table.integration.spec.js#refuses
        at COMMIT a redemption whose discount is not its allocations’ sum, naming the redemption
    exercises:
      - CAP-COM-CAT-016
      - CAP-COM-CAT-017
    workflows:
      - WF-COM-CAT-014
    step_evidence:
      - do: Place each result and read redemption rows and usage counters.
        provenance: proposed
        source:
          - >-
            services-commerce:modules/promotions/tests/unit/pricing/apply-promotions.spec.js#refuses
            a promotion whose benefit is zero on every qualifying line (an amount off a line already
            free)
          - >-
            services-commerce:modules/promotions/tests/integration/services/persistence/redemption-concurrency.integration.spec.js#applies
            exactly 100 and answers the other 100 code_exhausted
          - >-
            services-commerce:modules/promotions/tests/integration/services/persistence/promotion-redemptions.integration.spec.js#locks
            the promotion at its first redemption
          - >-
            services-commerce:modules/promotions/tests/integration/db/redemptions.table.integration.spec.js#refuses
            at COMMIT a redemption whose discount is not its allocations’ sum, naming the redemption
    assertions:
      - expect: Only the winning applied promotion has a redemption and increased counters.
        provenance: proposed
        source:
          - >-
            services-commerce:modules/promotions/tests/unit/pricing/apply-promotions.spec.js#refuses
            a promotion whose benefit is zero on every qualifying line (an amount off a line already
            free)
          - >-
            services-commerce:modules/promotions/tests/integration/services/persistence/redemption-concurrency.integration.spec.js#applies
            exactly 100 and answers the other 100 code_exhausted
          - >-
            services-commerce:modules/promotions/tests/integration/services/persistence/promotion-redemptions.integration.spec.js#locks
            the promotion at its first redemption
          - >-
            services-commerce:modules/promotions/tests/integration/db/redemptions.table.integration.spec.js#refuses
            at COMMIT a redemption whose discount is not its allocations’ sum, naming the redemption
  - id: ATS-COM-CAT-016-14
    title: Sample preview agrees with checkout without recording a use
    category: interaction
    level: api
    proves:
      - BR-CAP-COM-CAT-016-02
      - BR-CAP-COM-CAT-016-15
      - BR-CAP-COM-CAT-018-01
      - BR-CAP-COM-CAT-018-03
    preconditions: A combining code and a noncombining code match sample and checkout carts.
    steps: 'Compare line amounts and explanations, then compare counters and saved rows.'
    expected: The exercised price results agree and sample preview adds no checkout or redemption.
    negative: false
    data_needs: Run-owned workspace and records; fixed clock where dates are exercised.
    bound_to: []
    provenance: proposed
    source:
      - >-
        services-commerce:modules/promotions/tests/unit/pricing/alternatives.spec.js#2. combine =
        no, member: audience pricing $80.00 against $100.00 less 25 % = $75.00; the promotional
        price wins
      - >-
        services-commerce:modules/promotions/tests/unit/pricing/parts.spec.js#refuses a code
        promotion_check_unavailable when a part is listed unavailable, and discounts nothing
      - >-
        services-commerce:modules/promotions/tests/e2e/promotion-previews.e2e.spec.js#is, line for
        line and total for total, what the real checkout preview answers
      - >-
        services-commerce:modules/promotions/tests/e2e/promotion-previews.e2e.spec.js#opens no
        checkout and writes no item, event, evaluation, redemption, reservation or order
    exercises:
      - CAP-COM-CAT-016
      - CAP-COM-CAT-018
    workflows: []
    step_evidence:
      - do: 'Compare line amounts and explanations, then compare counters and saved rows.'
        provenance: proposed
        source:
          - >-
            services-commerce:modules/promotions/tests/unit/pricing/alternatives.spec.js#2. combine
            = no, member: audience pricing $80.00 against $100.00 less 25 % = $75.00; the
            promotional price wins
          - >-
            services-commerce:modules/promotions/tests/unit/pricing/parts.spec.js#refuses a code
            promotion_check_unavailable when a part is listed unavailable, and discounts nothing
          - >-
            services-commerce:modules/promotions/tests/e2e/promotion-previews.e2e.spec.js#is, line
            for line and total for total, what the real checkout preview answers
          - >-
            services-commerce:modules/promotions/tests/e2e/promotion-previews.e2e.spec.js#opens no
            checkout and writes no item, event, evaluation, redemption, reservation or order
    assertions:
      - expect: The exercised price results agree and sample preview adds no checkout or redemption.
        provenance: proposed
        source:
          - >-
            services-commerce:modules/promotions/tests/unit/pricing/alternatives.spec.js#2. combine
            = no, member: audience pricing $80.00 against $100.00 less 25 % = $75.00; the
            promotional price wins
          - >-
            services-commerce:modules/promotions/tests/unit/pricing/parts.spec.js#refuses a code
            promotion_check_unavailable when a part is listed unavailable, and discounts nothing
          - >-
            services-commerce:modules/promotions/tests/e2e/promotion-previews.e2e.spec.js#is, line
            for line and total for total, what the real checkout preview answers
          - >-
            services-commerce:modules/promotions/tests/e2e/promotion-previews.e2e.spec.js#opens no
            checkout and writes no item, event, evaluation, redemption, reservation or order
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-016-apply-the-lowest-valid-discount-at-checkout.md#CAP-COM-CAT-016
  - >-
    rhythm-v2-docs:specs/commerce/catalog/design/workflows/WF-COM-CAT-014-apply-promotions-at-checkout-and-record-their.md#WF-COM-CAT-014
product_intent: proposed
coverage:
  rule: covered
  transition: 'gap: FND-COM-CAT-070'
  validation: covered
  permission: 'gap: FND-COM-CAT-070'
  edge: covered
  failure: covered
  boundary: covered
  concurrency: covered
  invariant: covered
  interaction: covered
coverage_notes:
  transition: >-
    No complete transition scenario is established by this back-fill; the finding records the
    missing proof.
  permission: >-
    No complete permission scenario is established by this back-fill; the finding records the
    missing proof.
  concurrency: >-
    The bound race exercises persistence transactions; API placement and distributed execution are
    not established.
permission_coverage:
  - key: commerce.checkouts.update
    coverage: 'gap: FND-COM-CAT-070'
    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-070'
  - key: commerce.orders.create
    coverage: 'gap: FND-COM-CAT-070'
    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-070'
---

# Choose the best permitted promotional result: Capability Test Specification

## Coverage

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

## Interactions With Related Capabilities

Exclusive codes compete against automatic benefits. Only an applied benefit consumes redemption capacity. Sample preview agrees with checkout without recording a use.

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