Skip to content

feat(catalog): add purpose and reference_ids to catalog search - #902

Open
amithanda wants to merge 2 commits into
mainfrom
feat/catalog-search-purpose
Open

amithanda wants to merge 2 commits into
mainfrom
feat/catalog-search-purpose

Conversation

@amithanda

@amithanda amithanda commented Oct 5, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Extends dev.ucp.shopping.catalog.search (search_request) with two optional fields, purpose and reference_ids, to support relational and intent-specific catalog discovery (recommendation and swap) alongside standard free-text and filter-based search.

Motivation

Platforms and agents need to retrieve complementary recommendations and functional substitutes (e.g., swapping an out-of-stock cart item) where query may be omitted and one or more anchor product or variant IDs are supplied. Previously, catalog.search lacked a structured way to pass anchor item identifiers or distinguish whether the Business should return complementary items (recommendation) versus functional substitutes (swap).

Schema Shapes and Examples

1. search_request Schema Addition (catalog_search.json)

{
  "search_request": {
    "type": "object",
    "properties": {
      "query": { "type": "string" },
      "purpose": {
        "type": "string",
        "examples": ["search", "recommendation", "swap"]
      },
      "reference_ids": {
        "type": "array",
        "items": { "type": "string", "minLength": 1 },
        "minItems": 1,
        "uniqueItems": true
      },
      "context": { "$ref": "../common/types/context.json" },
      "signals": { "$ref": "../common/types/signals.json" },
      "attribution": { "$ref": "types/attribution.json" },
      "filters": { "$ref": "types/search_filters.json" },
      "pagination": { "$ref": "../common/types/pagination.json#/$defs/request" }
    },
    "dependentRequired": {
      "reference_ids": ["purpose"]
    }
  }
}

2. Retrieval Modes at a Glance

purpose reference_ids Other Required Inputs Self-Exclusion Rule
search (or omitted) MUST NOT be present At least one of query, filters, or extension input N/A
recommendation Optional (product IDs, variant IDs, or mix) Anchored to reference_ids and/or context; optional query / filters MUST exclude referenced products/variants (and parent product of any referenced variant)
swap MUST be present (SHOULD pass 1 ID per request) Optional query (e.g., guided swap) and filters MUST exclude referenced product/variant; SHOULD exclude parent product of a referenced variant unless returning a distinct substitute variant

3. Example Payloads

Use Case A: Product Swap (Substituting an Unavailable Variant)
Passing a variant ID (prod_abc123_size10) lets the Business match variant-level attributes (Size 10, price, quantity_unit), optionally guided by query and constrained by filters:

{
  "purpose": "swap",
  "reference_ids": ["prod_abc123_size10"],
  "query": "waterproof",
  "context": {
    "location": "loc_downtown",
    "currency": "USD"
  },
  "filters": {
    "price": { "max": 15000 }
  },
  "pagination": { "limit": 5 }
}

Use Case B: Product Recommendation
Accepts product IDs, variant IDs, or a mix of both (or omits reference_ids for contextual/session recommendations):

{
  "purpose": "recommendation",
  "reference_ids": ["prod_abc123", "var_xyz789"],
  "context": {
    "address_country": "US",
    "currency": "USD"
  },
  "pagination": { "limit": 10 }
}

Changes

  • Schema (source/schemas/shopping/catalog_search.json):
    • Added purpose (string, open vocabulary with well-known values search, recommendation, swap) and reference_ids (non-empty array of unique, non-empty strings) to search_request.
    • Added "dependentRequired": { "reference_ids": ["purpose"] } and a schema description on search_request.
  • Specification (docs/specification/shopping/catalog/search.md):
    • Updated ## Search Inputs and added ### Purpose and Reference Identifiers defining 5 normative rules: Pairing, Supported Identifiers, Self-Exclusion, Combination with Query and Filters, and Unsupported Purpose.
    • Added schema-validated request examples for Product Swap and Product Recommendation.

Design Decisions & Alternatives Considered

  • First-class fields on search_request vs. context or filters:
    • context (common/types/context.json) is reserved for provisional, ignorable buyer signals shared across all UCP capabilities, and context.intent is already a free-text buyer background string. A Business must not silently ignore purpose or reference_ids and return a generic catalog browse.
    • filters (shopping/types/search_filters.json) is shared with catalog.lookup and applies conjunctive (AND) predicates to narrow candidate items, whereas purpose and reference_ids define the retrieval relation and ranking objective.
  • Extending search_request vs. separate recommend / swap operations:
    • Recommendations and swaps share the exact same request/response grammar (query for guided swaps, filters, context, pagination, products[]) and dev.ucp.shopping.fulfillment extension composition as catalog.search. Modeling them via purpose and reference_ids avoids duplicating endpoints, MCP tools, and fulfillment composition schemas across the specification.
  • Asymmetric pairing (dependentRequired):
    • Supplying reference_ids requires purpose (dependentRequired, and purpose MUST NOT be search) so the Business never has to guess whether anchor IDs represent a complement or a substitute. Conversely, purpose: "recommendation" is permitted without reference_ids to support contextual recommendations anchored to context, while purpose: "swap" requires reference_ids, and purpose: "search" (or omitted) requires query, filters, or an extension input.
  • Identifier resolution & variant-aware self-exclusion:
    • Aligned reference_ids resolution with catalog.lookup (MUST support product ID and variant ID; MAY support secondary IDs like SKU or handle) so Platforms can pass a specific variant ID when swapping an unavailable cart item (allowing the Business to match variant-level options, price, and quantity_unit).
    • Referenced items are excluded from results; when a variant ID is supplied, the Business MUST exclude its parent product for recommendation, and SHOULD exclude its parent product for swap unless returning a distinct substitute variant of that product.

Validation

  • ucp-schema lint source/ (144 files checked, all passed)
  • uv run python scripts/validate_examples.py --schema-base source/schemas/ (378 passed, 0 failed)
  • pre-commit run --files source/schemas/shopping/catalog_search.json docs/specification/shopping/catalog/search.md (all hooks passed)
  • DOCS_MODE=spec uv run mkdocs build --strict && DOCS_MODE=spec uv run python scripts/check_links.py site (strict build and link validation passed)

Extend dev.ucp.shopping.catalog.search (search_request) to support relational and intent-specific catalog discovery alongside free-text and filter-based search:

- Add purpose (open string vocabulary with well-known values search, recommendation, and swap) to search_request in source/schemas/shopping/catalog_search.json.
- Add reference_ids (non-empty array of unique, non-empty product or variant identifiers) to search_request with dependentRequired on purpose.
- Document normative processing rules in docs/specification/shopping/catalog/search.md covering pairing constraints, supported identifiers (aligned with catalog.lookup), product and variant self-exclusion semantics, combination with query and filters, and handling of unsupported purpose values.
- Add schema-validated request examples for product swap and product recommendation.
@damaz91 damaz91 added the status:needs-triage Signal that the PR is ready for human triage label Oct 5, 2026
Comment thread docs/specification/shopping/catalog/search.md
Address review feedback on #902:
- Qualify standalone purpose in ## Search Inputs as a non-search purpose (such as contextual recommendation) so {"purpose": "search"} alone is not treated as a valid standalone input.
- Explicitly state in Rule 1 (Pairing) and purpose.description that when purpose is search (or omitted), the request MUST include at least one of query, filters, or an extension-defined input.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

status:needs-triage Signal that the PR is ready for human triage

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants