Skip to content

feat: Support location context hint in platform-initiated requests - #642

Merged
jingyli merged 11 commits into
Universal-Commerce-Protocol:mainfrom
jingyli:location-context
Aug 13, 2026
Merged

feat: Support location context hint in platform-initiated requests#642
jingyli merged 11 commits into
Universal-Commerce-Protocol:mainfrom
jingyli:location-context

Conversation

@jingyli

@jingyli jingyli commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

Description

Addressing a gap that would extend existing UCP shopping service schema/capabilities to support hyper-local goods (i.e. grocery) use cases:

  • Store/Branch Context: Enable platform to provide location hints on top of user addresses, especially if the user has a known "favourite store".

Key Design Decision

Standardized location Field in context.json

  • Problem: Cart pricing & availability for these purchase journeys are often tied to specific physical stores, which requires passing a store identifier as hint to businesses (if the location is retrieved through upper-funnel journeys like catalog search).
  • Solution: Add an optional location string property directly to context.json. This also allows the hint to be overwritten by more authoritative data constructs like filters.fulfills_to in catalog_search and fulfillment extension's pickup location ID.

Category (Required)

Please select one or more categories that apply to this change.

  • Core Protocol: Changes to the base communication layer, global context, or breaking refactors. (Requires Technical Council approval)
  • Governance/Contributing: Updates to GOVERNANCE.md, CONTRIBUTING.md, or CODEOWNERS. (Requires Governance Council approval)
  • Capability: New schemas (Discovery, Cart, etc.) or extensions. (Requires Maintainer approval)
  • Documentation: Updates to README, or documentations regarding schema or capabilities. (Requires Maintainer approval)
  • Infrastructure: CI/CD, Linters, or build scripts. (Requires DevOps Maintainer approval)
  • Maintenance: Version bumps, lockfile updates, or minor bug fixes. (Requires DevOps Maintainer approval)
  • SDK: Language-specific SDK updates and releases. (Requires DevOps Maintainer approval)
  • Samples / Conformance: Maintaining samples and the conformance suite. (Requires Maintainer approval)
  • UCP Schema: Changes to the ucp-schema tool (resolver, linter, validator). (Requires Maintainer approval)
  • Community Health (.github): Updates to templates, workflows, or org-level configs. (Requires DevOps Maintainer approval)

Checklist

  • I have followed the Contributing Guide (including Conventional Commits title requirements and ! for breaking changes).
  • I have updated the documentation (if applicable).
  • My changes pass all local linting and formatting checks.
  • I have added tests that prove my fix is effective or that my feature works.
  • New and existing unit tests pass locally with my changes.
  • (For Core/Capability) I have included/updated the relevant JSON schemas.
  • I have regenerated Python Pydantic models by running generate_models.sh under python_sdk.

Screenshots / Logs (if applicable)

@jingyli jingyli added this to the Working Draft milestone Jul 27, 2026
@jingyli jingyli added the TC review Ready for TC review label Jul 27, 2026
Comment thread source/schemas/shopping/types/context.json Outdated
@jingyli
jingyli requested a review from jamesandersen July 28, 2026 20:13
Comment thread source/schemas/shopping/types/context.json
   Establish Location as a stable, opaque, Business-scoped commerce concept and
   align context.location with that identity.

   Keep the field as a provisional string hint whose effects are defined by the
   active operation, capability, or extension, without coupling it to Location
   discovery.

@igrigorik igrigorik left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jingyli @gsmith85 @jamesandersen pushed a small update (0b5035e) to hopefully bring this one home. Taking Greg's suggestion on Glossary, ptal.

@jingyli

jingyli commented Aug 12, 2026

Copy link
Copy Markdown
Contributor Author

Thanks @igrigorik for 0b5035e - update LG though one nit I'd like to update on top of is to remove the explicit ucp_request: optional annotation on this new field so it remains consistent with other provisional hints where the optionality is determined by the enclosing capability.

@gsmith85 gsmith85 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

"properties": {
"location": {
"type": "string",
"description": "Stable, opaque identifier for a Location in the Business's namespace. This provisional, non-binding hint is distinct from the Buyer's locality. The operation specification or an active capability or extension defines its effects."

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The operation specification or an active capability or extension defines its effects.

Minor nit: Replace the first "or" with a comma

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No I think 'or' is correct. It's saying operation (e.g. create_cart) or extension (e.g. org.foo.fancy-fulfillment that extends dev.ucp.cart) define the semantics of this field.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jingyli - can we add the examples back in the schema file to make it clearer?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@gsmith85 To @igrigorik's callout above, I think the first or should still be preserved. However, the second one (an active capability or extension) can be simplified to just a / so the sentence runs a bit more smoothly. Made the corresponding update, PTAL!

@amithanda Added back the common example for retail shopping, PTAL!

@igrigorik

Copy link
Copy Markdown
Contributor

@jingyli @gsmith85 lgtm on updated shape. @amithanda final pass?

@amithanda amithanda left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added a minor suggestion, PTAL.

Comment thread source/schemas/shopping/types/context.json Outdated
@jingyli
jingyli merged commit 72914f4 into Universal-Commerce-Protocol:main Aug 13, 2026
18 checks passed
@jingyli
jingyli deleted the location-context branch August 13, 2026 02:56
igrigorik added a commit that referenced this pull request Aug 13, 2026
Base Context (#642) carries an optional `context.location`, a stable opaque
identifier for a Business Location, and defers its effects to the operation
specification or an active capability/extension. Nothing had taken up that
deferral, so a Platform sending a store ID had no advertised behavior to rely
on, and Catalog's existing `filters.fulfills_to` looked like a competing way to
say the same thing.

Fulfillment now defines those effects. When the Fulfillment extension is
active, `context.location` names the provisional Business Location that a
Business evaluates fulfillment availability against and generates initial
fulfillment choices for; it never selects a destination. Precedence is scoped to
what each field governs: `filters.fulfills_to` supersedes the Context locality
fields and `context.location` for fulfillment destination and availability
resolution only, and once a Platform sets `selected_destination_id` that
selection governs its own method.

Base Cart Context already carries `location`, and cart-to-checkout conversion
initializes Checkout from the Cart's context, so a Catalog -> Cart -> Checkout
journey preserves the identifier and an explicit Checkout selection then
governs it.

The schema delta is description-only, correcting four field descriptions that
were inaccurate or circular: the root named only Checkout as a parent though
Fulfillment also extends Catalog; `methods[].location` defined itself as "a
location id" rather than as the Location the glossary now names; method
`options` claimed the high-resolution set is negotiated in Cart; and
`fulfills_to` claimed it supersedes `context` wholesale, which would imply
overriding unrelated fields such as `context.currency`.
igrigorik added a commit that referenced this pull request Aug 17, 2026
* add negotiated fulfillment location context

   Store-scoped Catalog results had no advertised way to preserve the
   Business location through Cart and into Checkout. Defining the field on
   base Context would make every Shopping implementation accept an opaque
   Business-scoped identifier without advertising the behavior that produces
   or consumes it.

   Have Fulfillment contribute `context.location` to Catalog requests, Cart,
   and Checkout through explicit parent composition. Cart receives only the
   location context, and implementations supporting both Catalog and Cart
   should extend both to preserve continuity. For example, `loc_123` can
   scope Catalog availability, continue through Cart, and become explicit
   only when selected as a Checkout destination.

   Introduce a shared Location Identifier and reuse it for Fulfillment
   context, Catalog method locations, destination filters, and retail
   locations. This preserves one identity across surfaces while each
   containing field defines its role. Keep `selected_destination_id` generic
   because it may also reference non-location destinations.

* feat: define Fulfillment behavior for location context

Base Context (#642) carries an optional `context.location`, a stable opaque
identifier for a Business Location, and defers its effects to the operation
specification or an active capability/extension. Nothing had taken up that
deferral, so a Platform sending a store ID had no advertised behavior to rely
on, and Catalog's existing `filters.fulfills_to` looked like a competing way to
say the same thing.

Fulfillment now defines those effects. When the Fulfillment extension is
active, `context.location` names the provisional Business Location that a
Business evaluates fulfillment availability against and generates initial
fulfillment choices for; it never selects a destination. Precedence is scoped to
what each field governs: `filters.fulfills_to` supersedes the Context locality
fields and `context.location` for fulfillment destination and availability
resolution only, and once a Platform sets `selected_destination_id` that
selection governs its own method.

Base Cart Context already carries `location`, and cart-to-checkout conversion
initializes Checkout from the Cart's context, so a Catalog -> Cart -> Checkout
journey preserves the identifier and an explicit Checkout selection then
governs it.

The schema delta is description-only, correcting four field descriptions that
were inaccurate or circular: the root named only Checkout as a parent though
Fulfillment also extends Catalog; `methods[].location` defined itself as "a
location id" rather than as the Location the glossary now names; method
`options` claimed the high-resolution set is negotiated in Cart; and
`fulfills_to` claimed it supersedes `context` wholesale, which would imply
overriding unrelated fields such as `context.currency`.

* clarify fulfills_to wording

`fulfills_to` now describes where "items" are fulfilled rather than "the
order": no order exists during Catalog search, and "items" also reads
correctly at Checkout. The gift example says why a destination diverges from
`context`.

Supersession is stated generically: `fulfills_to` supersedes `context` only
for fulfillment destination and availability resolution. The scope clause
carries the bound, so enumerating the locality fields and `context.location`
was redundant and would rot as Context grows. Prose keeps the boundary
explicit with "Other `context` fields are unaffected."

The destination shape is no longer restated here or in prose. It belongs to
`fulfillment_destination_filter.json` and `locality.json`, which this field
composes, and `allOf` descriptions coexist rather than override, so the
contract was published twice. The bullet links to the rendered filter section
instead.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement TC review Ready for TC review

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants