---
id: DOM-COM-CAT-006
title: Recommendation
realises: CON-COM-CAT-006
product_area: commerce
module: catalog
revision: 1
status: draft
design_intent: open
implementation_evidence: partially-observed
source_sha:
  services-commerce: c8b66a98e2490617aec38ba5c8165dd9bd0a8f9b
owned_by: SVC-COM-CAT-recommendations
readable_by: []
lifecycle: STATE-COM-CAT-011
custom_fields: none
identity: >-
  A readable rule key is supplied or derived at creation, and its name is unique within the workspace.
  Application-qualified keys identify placements and flow declarations. Each presentation receives an offer
  key carried by its interactions and any accepted checkout item or order line.
attributes:
  - name: rule kind and parameters
    kind: enum
    required: true
    computed: false
    notes: >-
      Kind-specific inputs configure related products, add-ons, upgrades or deferred membership savings;
      add-ons need candidate products.
  - name: 'trigger scope, stores and window'
    kind: collection
    required: false
    computed: false
    notes: 'Optional product triggers, stores and dates narrow evaluation; no selected stores means all stores.'
  - name: audience
    kind: reference
    required: false
    computed: false
    notes: The saved audience binding has no evaluator in the current recommendation path.
  - name: message
    kind: text
    required: false
    computed: false
    notes: >-
      Message templates can use candidate, price, difference and currency values; each kind also has a default
      message.
  - name: 'frequency, suppression and exclusions'
    kind: collection
    required: false
    computed: false
    notes: >-
      Suppression can limit repetition within a checkout or after dismissal or acceptance, and exclude
      specified or already-chosen products. Dismissal defaults to thirty days.
  - name: holdout
    kind: number
    required: false
    computed: false
    notes: 'A stable calculation withholds offers from the configured proportion of subjects, up to fifty percent.'
  - name: action
    kind: enum
    required: false
    computed: false
    notes: >-
      The default action adds an item or replaces one for an upgrade. Page opening and promotion application
      are supported overrides; flow execution is unavailable.
  - name: 'priority, status and lock'
    kind: enum
    required: true
    computed: false
    notes: >-
      Priority orders rules from lower to higher values. Lifecycle status is separate from the
      protected-fields lock stamped at first presentation.
  - name: placement bindings
    kind: collection
    required: false
    computed: false
    notes: Each rule-to-placement link limits output to one through ten offers within the placement’s own ceiling.
  - name: placements and application flows
    kind: collection
    required: true
    computed: false
    notes: >-
      Commerce declares catalog, product, cart, review and confirmation placements with supported contexts,
      actions, kinds, public access and limits; applications can register flow kinds.
  - name: presentations
    kind: collection
    required: false
    computed: false
    notes: >-
      Presentations retain subject, placement, candidate, priced result, action and evidence for both shown
      and withheld offers. Quote-based expiry is fifteen minutes.
  - name: interactions
    kind: collection
    required: false
    computed: false
    notes: >-
      Interaction records capture viewing, expansion, dismissal, acceptance outcomes, refusals, flow activity
      and item removal; acceptance and dismissal history each have one entry per offer.
  - name: performance
    kind: computed
    required: false
    computed: true
    notes: >-
      Performance derives shown, accepted and converted counts and attributed value from presentations,
      interactions and order lines by day and placement.
relationships:
  - to: DOM-COM-CAT-003
    cardinality: one listing to up to eight related candidates
    ownership: Listing links supply related-product candidates; other rule kinds retain their own candidate references.
    cross_service: false
  - to: DOM-COM-CAT-004
    cardinality: one quote per evaluation
    ownership: The subject’s quote supplies candidate amounts without fixing the price ultimately charged.
    cross_service: false
  - to: DOM-COM-CAT-005
    cardinality: many rules to one code
    ownership: A promotion action passes its code through the checkout promotion path.
    cross_service: false
  - to: DOM-COM-CAT-002
    cardinality: many rules to many stores
    ownership: Store references narrow rule scope; the seeded storefront placements are declared by Commerce.
    cross_service: false
invariants:
  - id: INV-DOM-COM-CAT-006-01
    statement: Rules accept only parameters supported by their kind; add-on rules require candidate products.
    enforced_at:
      - service
    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: INV-DOM-COM-CAT-006-02
    statement: >-
      Bindings require a compatible placement and action, with an offer limit from one through ten that does
      not exceed the placement limit.
    enforced_at:
      - service
      - database
    provenance: test
    source: >-
      services-commerce:modules/recommendations/tests/e2e/recommendation-rules.e2e.spec.js#refuses a cap above
      the placement’s, 400 max_offers_exceeds_placement
  - id: INV-DOM-COM-CAT-006-03
    statement: Activation rejects a placement already holding twenty-five active rules.
    enforced_at:
      - service
    provenance: test
    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
  - id: INV-DOM-COM-CAT-006-04
    statement: 'A first presentation fixes the protected rule fields, while message editing remains available.'
    enforced_at:
      - service
    provenance: test
    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
  - id: INV-DOM-COM-CAT-006-05
    statement: A subject and rule produce the same holdout assignment on repeated calculation.
    enforced_at:
      - service
    provenance: test
    source: >-
      services-commerce:modules/recommendations/tests/unit/holdout.spec.js#answers the same bucket for the
      same subject and rule every time
  - id: INV-DOM-COM-CAT-006-06
    statement: >-
      After an acceptance has completed, a later request returns its recorded outcome; concurrent first-action
      execution remains unproved.
    enforced_at:
      - service
    provenance: test
    source: >-
      services-commerce:modules/recommendations/tests/e2e/offers.e2e.spec.js#answers the first acceptance to a
      second, repeated, adding nothing
  - id: INV-DOM-COM-CAT-006-07
    statement: Offers recorded for anonymous sessions cannot be accepted.
    enforced_at:
      - service
    provenance: test
    source: >-
      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
  - id: INV-DOM-COM-CAT-006-08
    statement: Live evaluation commits presentations and first-presentation locks together; preview commits neither.
    enforced_at:
      - service
    provenance: observed
    source: >-
      services-commerce:modules/recommendations/services/persistence/offer-presentations.ts:insertOfferPresentations
physical:
  - recommendation_rules
  - recommendation_rule_placements
  - recommendation_placements
  - recommendation_journeys
  - offer_presentations
  - offer_interactions
evidence:
  - >-
    services-commerce at c8b66a98: modules/recommendations/db/*.table.ts, db/vocabulary.ts;
    services/persistence/*.ts; services/evaluation/evaluate-offers.ts, holdout.ts, messages.ts;
    services/acceptance/accept-offer.ts; services/placements/store-placements.ts;
    services/rules/rule-rules.ts, rule-workflow.ts.
  - 'services-commerce at c8b66a98: docs/milestones/README.md (COMM-M7, proposed).'
---

# Recommendation

## What It Models

A recommendation rule determines a suggestion at an application placement. Evaluation produces offers for a particular subject, including deliberate holdouts. Supported suggestions include related products, add-ons and upgrades, with acceptance or dismissal recorded separately from presentation.

## Identity and Attributes

Rules use readable keys and distinct names. Qualified keys identify placements and registered application flows. Offer identifiers connect accepted items to checkout and order lines. Displayed amounts expire with the quote and are recalculated by ordinary checkout processing.

## Relationships

Related candidates come from listings, prices come from quotes and promotion actions use codes. Store restrictions narrow a rule’s scope. Commerce seeds five storefront placements.

## Invariants

Validation constrains kinds, actions and placement limits. Presentation fixes protected rule fields, and holdout calculation is stable. Completed responses repeat safely in sequential requests, but the history index alone does not prove once-only concurrent checkout actions. Anonymous estimates cannot be accepted.

## How It Is Stored and Shared

Recommendations owns rules, placement bindings, flow declarations, presentations and interactions. Acceptance calls checkout workflows to add or replace items. Promotion application and acceptance history use separate commits. No custom-field capability or external change event is declared.

## Open Design Questions

Product scope is still open and no staff administration screen exists. Membership-savings evaluation, application-flow execution and presentation retention remain deferred. Concurrent first acceptance needs proof or serialization.
