From b3d866c2b1933c7f800b6fc57877e8512f8323c8 Mon Sep 17 00:00:00 2001 From: Jing Li Date: Thu, 16 Jul 2026 21:18:32 -0400 Subject: [PATCH 1/4] Add some proposal to make cart compatible with grocery shopping and provide location hints in request context. --- source/schemas/common/types/measure.json | 19 ++++++ source/schemas/shopping/types/adjustment.json | 12 +++- source/schemas/shopping/types/context.json | 4 ++ .../schemas/shopping/types/expectation.json | 17 ++++- .../shopping/types/fulfillment_event.json | 17 ++++- source/schemas/shopping/types/line_item.json | 17 ++++- .../shopping/types/order_line_item.json | 68 ++++++++++++++----- source/schemas/shopping/types/variant.json | 9 +-- 8 files changed, 127 insertions(+), 36 deletions(-) create mode 100644 source/schemas/common/types/measure.json diff --git a/source/schemas/common/types/measure.json b/source/schemas/common/types/measure.json new file mode 100644 index 000000000..27db93336 --- /dev/null +++ b/source/schemas/common/types/measure.json @@ -0,0 +1,19 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://ucp.dev/schemas/common/types/measure.json", + "title": "Measure", + "description": "Represents a quantitative value paired with its physical or standardized unit of measurement.", + "type": "object", + "additionalProperties": true, + "required": ["value", "unit"], + "properties": { + "value": { + "type": "number", + "description": "Precise fractional quantity." + }, + "unit": { + "type": "string", + "description": "Unit of measurement." + } + } +} diff --git a/source/schemas/shopping/types/adjustment.json b/source/schemas/shopping/types/adjustment.json index c4fa91fbd..3f9cbdd50 100644 --- a/source/schemas/shopping/types/adjustment.json +++ b/source/schemas/shopping/types/adjustment.json @@ -44,8 +44,16 @@ "description": "Line item ID reference." }, "quantity": { - "type": "integer", - "description": "Signed quantity affected by this adjustment. Negative values represent reductions (e.g. returns); positive values represent additions (e.g. exchanges)." + "anyOf": [ + { + "type": "integer", + "description": "Signed quantity affected by this adjustment. Negative values represent reductions (e.g. returns); positive values represent additions (e.g. exchanges)." + }, + { + "$ref": "../../common/types/measure.json", + "description": "The precise signed fractional quantity and unit of the item affected by this adjustment. Negative values represent reductions (e.g. returns); positive values represent additions (e.g. exchanges)." + } + ] } } }, diff --git a/source/schemas/shopping/types/context.json b/source/schemas/shopping/types/context.json index 9d7f51207..84c945890 100644 --- a/source/schemas/shopping/types/context.json +++ b/source/schemas/shopping/types/context.json @@ -13,6 +13,10 @@ "type": "object", "additionalProperties": true, "properties": { + "location": { + "type": "string", + "description": "Identifier or name hint for the specific location (e.g., physical store, property, or restaurant) associated with the user. A common example in retail shopping is the default home store selected and saved by the user when purchasing grocery." + }, "intent": { "type": "string", "description": "Background context describing buyer's intent (e.g., 'looking for a gift under $50', 'need something durable for outdoor use'). Informs relevance, recommendations, and personalization." diff --git a/source/schemas/shopping/types/expectation.json b/source/schemas/shopping/types/expectation.json index ccd01c8e9..314d5dd62 100644 --- a/source/schemas/shopping/types/expectation.json +++ b/source/schemas/shopping/types/expectation.json @@ -26,9 +26,20 @@ "description": "Line item ID reference." }, "quantity": { - "type": "integer", - "minimum": 1, - "description": "Quantity of this item in this expectation." + "anyOf": [ + { + "type": "integer", + "minimum": 1, + "description": "Quantity of this item in this expectation." + }, + { + "$ref": "../../common/types/measure.json", + "properties": { + "value": { "exclusiveMinimum": 0 } + }, + "description": "The precise fractional quantity and unit of the item in this expectation." + } + ] } } }, diff --git a/source/schemas/shopping/types/fulfillment_event.json b/source/schemas/shopping/types/fulfillment_event.json index 5d0ba7e7f..fab60625a 100644 --- a/source/schemas/shopping/types/fulfillment_event.json +++ b/source/schemas/shopping/types/fulfillment_event.json @@ -35,9 +35,20 @@ "description": "Line item ID reference." }, "quantity": { - "type": "integer", - "minimum": 1, - "description": "Quantity fulfilled in this event." + "anyOf": [ + { + "type": "integer", + "minimum": 1, + "description": "Quantity fulfilled in this event." + }, + { + "$ref": "../../common/types/measure.json", + "properties": { + "value": { "exclusiveMinimum": 0 } + }, + "description": "The precise fractional quantity and unit of the item in this event." + } + ] } } }, diff --git a/source/schemas/shopping/types/line_item.json b/source/schemas/shopping/types/line_item.json index 0eba9ed05..7d0e269fa 100644 --- a/source/schemas/shopping/types/line_item.json +++ b/source/schemas/shopping/types/line_item.json @@ -22,9 +22,20 @@ "$ref": "item.json" }, "quantity": { - "type": "integer", - "description": "Quantity of the item being purchased.", - "minimum": 1 + "anyOf": [ + { + "type": "integer", + "description": "Quantity of the item being purchased.", + "minimum": 1 + }, + { + "$ref": "../../common/types/measure.json", + "properties": { + "value": { "exclusiveMinimum": 0 } + }, + "description": "The precise fractional quantity and unit of the item being purchased." + } + ] }, "totals": { "type": "array", diff --git a/source/schemas/shopping/types/order_line_item.json b/source/schemas/shopping/types/order_line_item.json index 5f639dcff..c851e1469 100644 --- a/source/schemas/shopping/types/order_line_item.json +++ b/source/schemas/shopping/types/order_line_item.json @@ -20,26 +20,58 @@ "description": "Product data (id, title, price, image_url)." }, "quantity": { - "type": "object", - "required": ["total", "fulfilled"], - "properties": { - "original": { - "type": "integer", - "minimum": 0, - "description": "Quantity from the original checkout." + "anyOf": [ + { + "type": "object", + "required": ["total", "fulfilled"], + "properties": { + "original": { + "type": "integer", + "minimum": 0, + "description": "Quantity from the original checkout." + }, + "total": { + "type": "integer", + "minimum": 0, + "description": "Current total active quantity. May differ from original due to post-order modifications (e.g., returns or cancellations)." + }, + "fulfilled": { + "type": "integer", + "minimum": 0, + "description": "Quantity fulfilled so far." + } + }, + "description": "Quantity tracking for the line item." }, - "total": { - "type": "integer", - "minimum": 0, - "description": "Current total active quantity. May differ from original due to post-order modifications (e.g., returns or cancellations)." - }, - "fulfilled": { - "type": "integer", - "minimum": 0, - "description": "Quantity fulfilled so far." + { + "type": "object", + "required": ["total", "fulfilled"], + "properties": { + "original": { + "$ref": "../../common/types/measure.json", + "properties": { + "value": { "minimum": 0 } + }, + "description": "The fractional quantity and unit of the item in the original checkout." + }, + "total": { + "$ref": "../../common/types/measure.json", + "properties": { + "value": { "minimum": 0 } + }, + "description": "Current total active fractional quantity. May differ from original due to post-order modifications (e.g., returns or cancellations)." + }, + "fulfilled": { + "$ref": "../../common/types/measure.json", + "properties": { + "value": { "minimum": 0 } + }, + "description": "Fractional quantity fulfilled so far." + } + }, + "description": "Precise fractional tracking for the line item." } - }, - "description": "Quantity tracking for the line item." + ] }, "totals": { "type": "array", diff --git a/source/schemas/shopping/types/variant.json b/source/schemas/shopping/types/variant.json index 9355b5f1a..efe00f1c6 100644 --- a/source/schemas/shopping/types/variant.json +++ b/source/schemas/shopping/types/variant.json @@ -84,13 +84,8 @@ "description": "ISO 4217 currency code." }, "measure": { - "type": "object", - "description": "Product quantity in packaging (e.g., 750ml bottle).", - "required": ["value", "unit"], - "properties": { - "value": { "type": "number", "description": "Package quantity." }, - "unit": { "type": "string", "description": "Unit of measurement." } - } + "$ref": "../../common/types/measure.json", + "description": "Product quantity in packaging (e.g., 750ml bottle)." }, "reference": { "type": "object", From a0f08a41e6300af888a124c4d5b791d699d15349 Mon Sep 17 00:00:00 2001 From: Jing Li Date: Thu, 23 Jul 2026 21:42:55 -0400 Subject: [PATCH 2/4] Addressing PR feedback to expand the use cases of product tags in catalog. --- source/schemas/shopping/types/product.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/schemas/shopping/types/product.json b/source/schemas/shopping/types/product.json index 95c4fbdf8..40de390b7 100644 --- a/source/schemas/shopping/types/product.json +++ b/source/schemas/shopping/types/product.json @@ -79,7 +79,7 @@ "items": { "type": "string" }, - "description": "Product tags for categorization and search." + "description": "Product tags for categorization, search, and compliance rules (e.g., restricted goods)." }, "metadata": { "type": "object", From f825c245b15252d25499fc6a9e4e05d54806fbe2 Mon Sep 17 00:00:00 2001 From: Jing Li Date: Fri, 24 Jul 2026 18:45:08 -0400 Subject: [PATCH 3/4] Add schema prose on unit to minimize potential synonym prose. --- source/schemas/common/types/measure.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/schemas/common/types/measure.json b/source/schemas/common/types/measure.json index 27db93336..4d67ce7e5 100644 --- a/source/schemas/common/types/measure.json +++ b/source/schemas/common/types/measure.json @@ -13,7 +13,7 @@ }, "unit": { "type": "string", - "description": "Unit of measurement." + "description": "Unit of measurement. MUST use 'each' to represent countable goods and SHOULD prefer using standard symbol (e.g., kg for kilogram, lb for pound) for other units." } } } From 8d0ea2e483b45fc1d9208110d8d83fc167bb9564 Mon Sep 17 00:00:00 2001 From: Jing Li Date: Mon, 27 Jul 2026 18:51:31 -0400 Subject: [PATCH 4/4] Remove locaiton hint change from the PR scope as it is being split out into a separate PR. --- source/schemas/shopping/types/context.json | 4 ---- 1 file changed, 4 deletions(-) diff --git a/source/schemas/shopping/types/context.json b/source/schemas/shopping/types/context.json index d919f8515..75659ab79 100644 --- a/source/schemas/shopping/types/context.json +++ b/source/schemas/shopping/types/context.json @@ -13,10 +13,6 @@ "type": "object", "additionalProperties": true, "properties": { - "location": { - "type": "string", - "description": "Identifier or name hint for the specific location (e.g., physical store, property, or restaurant) associated with the user. A common example in retail shopping is the default home store selected and saved by the user when purchasing grocery." - }, "intent": { "type": "string", "description": "Background context describing buyer's intent (e.g., 'looking for a gift under $50', 'need something durable for outdoor use'). Informs relevance, recommendations, and personalization."