---
id: ATS-COM-CAT-020
scope: CAP-COM-CAT-020
product_area: commerce
module: catalog
revision: 2
status: proposed
source_sha:
  services-commerce: c8b66a98e2490617aec38ba5c8165dd9bd0a8f9b
  react-console: baf6dae382d6f41dce976c7f848667ccc37e076f
scenarios:
  - id: ATS-COM-CAT-020-01
    title: A cart suggestion is accepted without duplicate items
    level: api
    proves:
      - BR-CAP-COM-CAT-020-01
      - BR-CAP-COM-CAT-020-04
      - AS-JNY-COM-CAT-006-02
      - INV-DOM-COM-CAT-006-06
    preconditions: A member’s cart contains the trigger for a related mug
    steps: 'Evaluate, accept twice and reevaluate'
    expected: One twelve-dollar mug offer adds one item and is subsequently suppressed
    negative: false
    data_needs: Catalog and quote fixtures
    bound_to:
      - TST-COM-CAT-135
    provenance: test
    source: >-
      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
    category: interaction
    binding_evidence:
      - >-
        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
      - >-
        services-commerce:modules/recommendations/tests/e2e/offers.e2e.spec.js#adds the mug to the
        checkout with the offer on the item when accepted
      - >-
        services-commerce:modules/recommendations/tests/e2e/offers.e2e.spec.js#answers the first
        acceptance to a second, repeated, adding nothing
      - >-
        services-commerce:modules/recommendations/tests/e2e/offers.e2e.spec.js#offers nothing a
        second time: the mug is in the checkout and was accepted
    step_evidence:
      - do: 'Evaluate, accept twice and reevaluate'
        provenance: test
        source: >-
          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: One twelve-dollar mug offer adds one item and is subsequently suppressed
        provenance: test
        source: >-
          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-020-02
    title: Dismissal suppresses offers and rejects unrelated members
    level: api
    proves:
      - BR-CAP-COM-CAT-020-02
      - BR-CAP-COM-CAT-020-05
    preconditions: Two member subjects have separate offers
    steps: 'Dismiss twice, reevaluate and let the unrelated member accept'
    expected: 'One dismissal remains, reevaluation suppresses the offer and unrelated acceptance fails'
    negative: true
    data_needs: none
    bound_to:
      - TST-COM-CAT-135
    provenance: test
    source: >-
      services-commerce:modules/recommendations/tests/e2e/offers.e2e.spec.js#records the dismissal
      once, the second answering the first
    category: transition
    binding_evidence:
      - >-
        services-commerce:modules/recommendations/tests/e2e/offers.e2e.spec.js#records the dismissal
        once, the second answering the first
      - >-
        services-commerce:modules/recommendations/tests/e2e/offers.e2e.spec.js#offers nothing inside
        the dismissal window
      - >-
        services-commerce:modules/recommendations/tests/e2e/offers.e2e.spec.js#refuses the first
        member accepting what was presented to the other, 403 offer_not_yours
    step_evidence:
      - do: 'Dismiss twice, reevaluate and let the unrelated member accept'
        provenance: test
        source: >-
          services-commerce:modules/recommendations/tests/e2e/offers.e2e.spec.js#records the
          dismissal once, the second answering the first
    assertions:
      - expect: 'One dismissal remains, reevaluation suppresses the offer and unrelated acceptance fails'
        provenance: test
        source: >-
          services-commerce:modules/recommendations/tests/e2e/offers.e2e.spec.js#records the
          dismissal once, the second answering the first
  - id: ATS-COM-CAT-020-03
    title: New acceptance cannot use an expired presentation
    level: api
    proves:
      - BR-CAP-COM-CAT-020-03
    preconditions: The offer expires without a recorded acceptance
    steps: Request its first acceptance
    expected: The refusal identifies the expiry time
    negative: true
    data_needs: Clock control
    bound_to:
      - TST-COM-CAT-135
    provenance: test
    source: >-
      services-commerce:modules/recommendations/tests/e2e/offers.e2e.spec.js#is refused 409
      offer_expired, naming when it expired
    category: boundary
    binding_evidence:
      - >-
        services-commerce:modules/recommendations/tests/e2e/offers.e2e.spec.js#is refused 409
        offer_expired, naming when it expired
    step_evidence:
      - do: Request its first acceptance
        provenance: test
        source: >-
          services-commerce:modules/recommendations/tests/e2e/offers.e2e.spec.js#is refused 409
          offer_expired, naming when it expired
    assertions:
      - expect: The refusal identifies the expiry time
        provenance: test
        source: >-
          services-commerce:modules/recommendations/tests/e2e/offers.e2e.spec.js#is refused 409
          offer_expired, naming when it expired
  - id: ATS-COM-CAT-020-04
    title: Anonymous estimates cannot become accepted offers
    level: api
    proves:
      - BR-CAP-COM-CAT-020-06
      - INV-DOM-COM-CAT-006-07
    preconditions: A visitor uses a public product placement and a private placement
    steps: 'Evaluate publicly, accept the estimate and evaluate privately'
    expected: 'Public pricing is estimated, estimate acceptance fails and private placement access fails'
    negative: true
    data_needs: none
    bound_to:
      - TST-COM-CAT-135
    provenance: test
    source: >-
      services-commerce:modules/recommendations/tests/e2e/offers.e2e.spec.js#sees the mug as an
      estimate at the public price, for a session subject
    category: permission
    binding_evidence:
      - >-
        services-commerce:modules/recommendations/tests/e2e/offers.e2e.spec.js#sees the mug as an
        estimate at the public price, for a session subject
      - >-
        services-commerce:modules/recommendations/tests/e2e/offers.e2e.spec.js#cannot have the
        estimate accepted, even by a signed-in member: 409 sign_in_required
      - >-
        services-commerce:modules/recommendations/tests/e2e/offers.e2e.spec.js#is refused a
        placement that admits no anonymous visitor, 403 placement_not_public
    step_evidence:
      - do: 'Evaluate publicly, accept the estimate and evaluate privately'
        provenance: test
        source: >-
          services-commerce:modules/recommendations/tests/e2e/offers.e2e.spec.js#sees the mug as an
          estimate at the public price, for a session subject
    assertions:
      - expect: 'Public pricing is estimated, estimate acceptance fails and private placement access fails'
        provenance: test
        source: >-
          services-commerce:modules/recommendations/tests/e2e/offers.e2e.spec.js#sees the mug as an
          estimate at the public price, for a session subject
  - id: ATS-COM-CAT-020-05
    title: Offer preview is read-only staff work
    level: api
    proves:
      - BR-CAP-COM-CAT-020-08
    preconditions: Console and portal callers are available
    steps: Request preview as each
    expected: Portal preview fails; staff receive suppression diagnostics without saved presentations
    negative: true
    data_needs: none
    bound_to:
      - TST-COM-CAT-135
    provenance: test
    source: >-
      services-commerce:modules/recommendations/tests/e2e/offers.e2e.spec.js#is refused to a portal
      member, 403 preview_not_allowed, and answers the console the suppressed rules without writing
    category: invariant
    binding_evidence:
      - >-
        services-commerce:modules/recommendations/tests/e2e/offers.e2e.spec.js#is refused to a
        portal member, 403 preview_not_allowed, and answers the console the suppressed rules without
        writing
    step_evidence:
      - do: Request preview as each
        provenance: test
        source: >-
          services-commerce:modules/recommendations/tests/e2e/offers.e2e.spec.js#is refused to a
          portal member, 403 preview_not_allowed, and answers the console the suppressed rules
          without writing
    assertions:
      - expect: Portal preview fails; staff receive suppression diagnostics without saved presentations
        provenance: test
        source: >-
          services-commerce:modules/recommendations/tests/e2e/offers.e2e.spec.js#is refused to a
          portal member, 403 preview_not_allowed, and answers the console the suppressed rules
          without writing
  - id: ATS-COM-CAT-020-06
    title: Offer-response permission remains separate from reading
    level: api
    proves:
      - BR-CAP-COM-CAT-020-10
    preconditions: A reader and anonymous request form are available
    steps: 'Evaluate and accept as the reader, then name a person publicly'
    expected: >-
      Evaluation succeeds, response fails permission checks and public private-context input is
      rejected
    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#may
      evaluate but not accept: 403 permission_missing on the acceptance
    category: permission
    binding_evidence:
      - >-
        services-commerce:modules/recommendations/tests/e2e/recommendations-security.e2e.spec.js#may
        evaluate but not accept: 403 permission_missing on the acceptance
      - >-
        services-commerce:modules/recommendations/tests/e2e/recommendations-security.e2e.spec.js#refuses
        a body naming a person or a cart, 400
    step_evidence:
      - do: 'Evaluate and accept as the reader, then name a person publicly'
        provenance: test
        source: >-
          services-commerce:modules/recommendations/tests/e2e/recommendations-security.e2e.spec.js#may
          evaluate but not accept: 403 permission_missing on the acceptance
    assertions:
      - expect: >-
          Evaluation succeeds, response fails permission checks and public private-context input is
          rejected
        provenance: test
        source: >-
          services-commerce:modules/recommendations/tests/e2e/recommendations-security.e2e.spec.js#may
          evaluate but not accept: 403 permission_missing on the acceptance
  - id: ATS-COM-CAT-020-07
    title: Offer actions expose independent checkout and history outcomes
    category: rule
    level: api
    proves:
      - BR-CAP-COM-CAT-020-11
    preconditions: 'Item, promotion and page actions exist, plus an unsupported application action.'
    steps: >-
      Accept each action; fail history recording after promotion application; read the checkout and
      offer history before retrying.
    expected: >-
      Item acceptance commits with its history; a page target is recorded; the unsupported action
      refuses; a promotion can remain applied when its acceptance history fails.
    negative: true
    data_needs: Run-owned workspace and records; fixed clock where dates are exercised.
    bound_to: []
    provenance: proposed
    source:
      - >-
        services-commerce:modules/recommendations/services/persistence/offer-presentations.ts:insertOfferPresentations
    step_evidence:
      - do: >-
          Accept each action; fail history recording after promotion application; read the checkout
          and offer history before retrying.
        provenance: proposed
        source:
          - >-
            services-commerce:modules/recommendations/services/persistence/offer-presentations.ts:insertOfferPresentations
    assertions:
      - expect: >-
          Item acceptance commits with its history; a page target is recorded; the unsupported
          action refuses; a promotion can remain applied when its acceptance history fails.
        provenance: proposed
        source:
          - >-
            services-commerce:modules/recommendations/services/persistence/offer-presentations.ts:insertOfferPresentations
  - id: ATS-COM-CAT-020-08
    title: Offer presentation and response is exercised across every declared move
    category: transition
    level: api
    proves:
      - BR-CAP-COM-CAT-020-02
      - BR-CAP-COM-CAT-020-03
      - BR-CAP-COM-CAT-020-04
      - BR-CAP-COM-CAT-020-05
      - BR-CAP-COM-CAT-020-11
    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-012-offer-presentation-and-response.md#STATE-COM-CAT-012
      - >-
        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
      - >-
        services-commerce:modules/recommendations/tests/e2e/offers.e2e.spec.js#answers the first
        acceptance to a second, repeated, adding nothing
      - 'services-commerce:modules/recommendations/services/acceptance/accept-offer.ts'
      - >-
        services-commerce:modules/recommendations/tests/e2e/offers.e2e.spec.js#offers nothing inside
        the dismissal window
      - 'services-commerce:modules/recommendations/services/acceptance/accept-offer.ts:acceptOffer'
    state_model: STATE-COM-CAT-012
    transition_cases:
      - from: shown
        to: accepted
        trigger: The subject requests the offered action.
        guard: >-
          Response authority and offer access are required; first acceptance must be unexpired and
          provide an accessible checkout for item or code actions. Application-flow execution is
          unavailable.
        provenance: proposed
        source:
          - >-
            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
          - >-
            rhythm-v2-docs:specs/commerce/catalog/design/state-models/STATE-COM-CAT-012-offer-presentation-and-response.md#STATE-COM-CAT-012
      - from: accepted
        to: accepted
        trigger: The subject repeats a completed acceptance.
        guard: A saved acceptance can repeat without a fresh expiry check.
        provenance: proposed
        source:
          - >-
            services-commerce:modules/recommendations/tests/e2e/offers.e2e.spec.js#answers the first
            acceptance to a second, repeated, adding nothing
          - >-
            rhythm-v2-docs:specs/commerce/catalog/design/state-models/STATE-COM-CAT-012-offer-presentation-and-response.md#STATE-COM-CAT-012
      - from: shown
        to: refused
        trigger: Item processing reports an envelope or participant refusal.
        guard: No additional condition applies.
        provenance: proposed
        source:
          - 'services-commerce:modules/recommendations/services/acceptance/accept-offer.ts'
          - >-
            rhythm-v2-docs:specs/commerce/catalog/design/state-models/STATE-COM-CAT-012-offer-presentation-and-response.md#STATE-COM-CAT-012
      - from: shown
        to: dismissed
        trigger: The subject requests dismissal.
        guard: The caller must have response authority and access to this shown offer.
        provenance: proposed
        source:
          - >-
            services-commerce:modules/recommendations/tests/e2e/offers.e2e.spec.js#offers nothing
            inside the dismissal window
          - >-
            rhythm-v2-docs:specs/commerce/catalog/design/state-models/STATE-COM-CAT-012-offer-presentation-and-response.md#STATE-COM-CAT-012
      - from: shown
        to: expired
        trigger: The quote-based fifteen-minute lifetime ends.
        guard: No additional condition applies.
        provenance: proposed
        source:
          - >-
            services-commerce:modules/recommendations/services/acceptance/accept-offer.ts:acceptOffer
          - >-
            rhythm-v2-docs:specs/commerce/catalog/design/state-models/STATE-COM-CAT-012-offer-presentation-and-response.md#STATE-COM-CAT-012
    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-012-offer-presentation-and-response.md#STATE-COM-CAT-012
          - >-
            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
          - >-
            services-commerce:modules/recommendations/tests/e2e/offers.e2e.spec.js#answers the first
            acceptance to a second, repeated, adding nothing
          - 'services-commerce:modules/recommendations/services/acceptance/accept-offer.ts'
          - >-
            services-commerce:modules/recommendations/tests/e2e/offers.e2e.spec.js#offers nothing
            inside the dismissal window
          - >-
            services-commerce:modules/recommendations/services/acceptance/accept-offer.ts:acceptOffer
    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-012-offer-presentation-and-response.md#STATE-COM-CAT-012
          - >-
            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
          - >-
            services-commerce:modules/recommendations/tests/e2e/offers.e2e.spec.js#answers the first
            acceptance to a second, repeated, adding nothing
          - 'services-commerce:modules/recommendations/services/acceptance/accept-offer.ts'
          - >-
            services-commerce:modules/recommendations/tests/e2e/offers.e2e.spec.js#offers nothing
            inside the dismissal window
          - >-
            services-commerce:modules/recommendations/services/acceptance/accept-offer.ts:acceptOffer
  - id: ATS-COM-CAT-020-09
    title: Preview and live presentation have different protection effects
    category: invariant
    level: api
    proves:
      - INV-DOM-COM-CAT-006-08
      - BR-CAP-COM-CAT-020-11
    preconditions: A new active rule has no presentation and editable substance.
    steps: >-
      Preview and inspect presentation rows and rule protection; evaluate live, inspect both, then
      inject failure before that transaction commits on a separate rule.
    expected: >-
      Preview writes neither presentations nor protection; live evaluation commits both and a failed
      transaction retains neither.
    negative: true
    data_needs: Run-owned workspace and records; fixed clock where dates are exercised.
    bound_to: []
    provenance: proposed
    source:
      - >-
        services-commerce:modules/recommendations/services/persistence/offer-presentations.ts:insertOfferPresentations
      - >-
        rhythm-v2-docs:specs/commerce/catalog/design/objects/DOM-COM-CAT-006-recommendation.md#DOM-COM-CAT-006
    verification_note: >-
      This design references the invariant; executable binding awaits an assertion-by-assertion
      comparison with this complete scenario.
    step_evidence:
      - do: >-
          Preview and inspect presentation rows and rule protection; evaluate live, inspect both,
          then inject failure before that transaction commits on a separate rule.
        provenance: proposed
        source:
          - >-
            services-commerce:modules/recommendations/services/persistence/offer-presentations.ts:insertOfferPresentations
          - >-
            rhythm-v2-docs:specs/commerce/catalog/design/objects/DOM-COM-CAT-006-recommendation.md#DOM-COM-CAT-006
    assertions:
      - expect: >-
          Preview writes neither presentations nor protection; live evaluation commits both and a
          failed transaction retains neither.
        provenance: proposed
        source:
          - >-
            services-commerce:modules/recommendations/services/persistence/offer-presentations.ts:insertOfferPresentations
          - >-
            rhythm-v2-docs:specs/commerce/catalog/design/objects/DOM-COM-CAT-006-recommendation.md#DOM-COM-CAT-006
  - id: ATS-COM-CAT-020-10
    title: Promotion acceptance can outlive its failed history write
    category: interaction
    level: api
    proves:
      - BR-CAP-COM-CAT-020-11
      - BR-CAP-COM-CAT-016-12
    preconditions: A live promotion-action offer is owned by a member with an accessible checkout.
    steps: >-
      Accept the promotion action, fail the separate acceptance-history write, then inspect checkout
      codes and offer interactions before retrying.
    expected: >-
      The applied code can remain without an accepted-offer record; the failed history write does
      not roll back the earlier promotion application.
    negative: true
    data_needs: 'Run-owned workspace, prepared file fixtures and independent fault injection at the handoff.'
    bound_to: []
    provenance: proposed
    source:
      - 'services-commerce:modules/recommendations/services/acceptance/accept-offer.ts:acceptOffer'
      - >-
        rhythm-v2-docs:specs/commerce/catalog/design/workflows/WF-COM-CAT-018-accept-or-dismiss-an-offer.md#WF-COM-CAT-018
    exercises:
      - CAP-COM-CAT-016
      - CAP-COM-CAT-020
    workflows:
      - WF-COM-CAT-018
    step_evidence:
      - do: >-
          Accept the promotion action, fail the separate acceptance-history write, then inspect
          checkout codes and offer interactions before retrying.
        provenance: proposed
        source:
          - >-
            services-commerce:modules/recommendations/services/acceptance/accept-offer.ts:acceptOffer
          - >-
            rhythm-v2-docs:specs/commerce/catalog/design/workflows/WF-COM-CAT-018-accept-or-dismiss-an-offer.md#WF-COM-CAT-018
    assertions:
      - expect: >-
          The applied code can remain without an accepted-offer record; the failed history write
          does not roll back the earlier promotion application.
        provenance: proposed
        source:
          - >-
            services-commerce:modules/recommendations/services/acceptance/accept-offer.ts:acceptOffer
          - >-
            rhythm-v2-docs:specs/commerce/catalog/design/workflows/WF-COM-CAT-018-accept-or-dismiss-an-offer.md#WF-COM-CAT-018
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-020-offer-suggestions-to-a-buyer-and-record-the-answer.md#CAP-COM-CAT-020
  - >-
    rhythm-v2-docs:specs/commerce/catalog/design/workflows/WF-COM-CAT-017-evaluate-offers-for-a-placement.md#WF-COM-CAT-017
  - >-
    rhythm-v2-docs:specs/commerce/catalog/design/workflows/WF-COM-CAT-018-accept-or-dismiss-an-offer.md#WF-COM-CAT-018
product_intent: proposed
coverage:
  rule: covered
  transition: covered
  validation: 'gap: FND-COM-CAT-074'
  permission: covered
  edge: 'gap: FND-COM-CAT-074'
  failure: 'gap: FND-COM-CAT-074'
  boundary: covered
  concurrency: 'gap: FND-COM-CAT-074'
  invariant: covered
  interaction: covered
coverage_notes:
  validation: >-
    No complete validation scenario is established by this back-fill; the finding records the
    missing proof.
  edge: >-
    No complete edge scenario is established by this back-fill; the finding records the missing
    proof.
  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.offers.read
    coverage: 'gap: FND-COM-CAT-074'
    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-074'
  - key: commerce.offers.respond
    coverage: 'gap: FND-COM-CAT-074'
    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-074'
---

# Present offers and process buyer responses: Capability Test Specification

## Coverage

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

## Interactions With Related Capabilities

A cart suggestion is accepted without duplicate items. Promotion acceptance can outlive its failed history write.

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