feat(shopping): Add additional fields proposal (from Shopify)#481
feat(shopping): Add additional fields proposal (from Shopify)#481SaifBenChahed wants to merge 7 commits into
Conversation
0f3f644 to
7ddded6
Compare
7ddded6 to
d89904f
Compare
jamesandersen
left a comment
There was a problem hiding this comment.
@SaifBenChahed thanks for submitting this! I think this will unlock agentic commerce for a non-trivial cohort of merchants requiring some incidental extra inputs.
| "ucp_request": "omit" | ||
| }, | ||
| "value": { | ||
| "type": [ |
There was a problem hiding this comment.
Just a thought, for booleans, might consider making the base value accept a union, then use the same if/then pattern the PR already uses for input to pin boolean-typed fields to a real boolean:
// additional_field.value base type:
"value": { "type": ["string", "boolean", "null"], ... }
// additional_field.allOf — add:
{
"if": {
"properties": { "input": { "properties": { "type": { "const": "boolean" } }, "required": ["type"] } },
"required": ["input"]
},
"then": { "properties": { "value": { "type": ["boolean", "null"] } } }
}
Request becomes { "key": "gift_wrap", "value": true }, cleared as { "key": "gift_wrap", "value": null }.
Otherwise I'd just add some language indicated the expected string formats for boolean values
There was a problem hiding this comment.
Thanks, that makes sense. The conditional schema approach would work well for responses, since each field includes input.type.
For submissions, though, we only send key + value, without the field definition. The business still needs to resolve the key back to its field definition to validate type-specific rules, whether that rule is boolean format, choice membership, date bounds, or text constraints.
My slight preference is to keep value as string | null here for a uniform submission shape, so I added normative language that non-null boolean values MUST be the exact strings "true" or "false".
There was a problem hiding this comment.
While there's a preference for machine resolvable schema, this seems reasonable; we'll see if there's any second opinion here ;-)
|
|
||
| ### Checkout Extension | ||
|
|
||
| {{ extension_fields('additional_fields', 'additional-fields') }} |
There was a problem hiding this comment.
it should be {{ extension_fields('additional_fields', 'checkout') }}
jingyli
left a comment
There was a problem hiding this comment.
Thanks for the proposal! Some fundamental questions I had:
- [Discussed and aligned on most, would love to see if it would be good to consider adding a section in
overview.mdto clarify best practices on the use cases and scenarios further] Now in UCP, we will have multiple mechanisms to allow data to be collected on top of the main request & response wiring: 1) embedded transport viacontinue_url, 2) escalation redirect handoff viacontinue_url, 3) new actions construct being introduced in #582. How should implementators think about when to use what - let's take an example of needing to collect a user's age for verification, I can naively see it fall into all 4 buckets - what would be best practices and guidelines we set around them? Or is this something we don't want to get into at all and leave it to the implementors to define? - With this extension's vast flexibility to support various use cases, what are the principles we will now hold to decide what use cases to promote into UCP as first-class citizens vs. just re-leveraging this extension? An example can be scheduled delivery: this extension will be able to support the collection of its values, but I do see a path to also model this directly into the fulfillment extension.
- I see the scope of this extension, so far, is only decorating
checkout&order(which is 100% fine to start with a narrow scope). But I'm curious what are our thoughts on this extension decorating other capabilities likecartor even going beyond shopping service? - Are there other data (on top of the supported type) we want to negotiate up front between platforms & businesses when using this extension? An example: a platform may have UI wiring for
type = choice, but it can only display up to 5 options. Then should that restriction be negotiated up-front? - Any guidelines we should set for businesses & platforms on rendering contracts? What about privacy & security considerations since now platforms will need to dynamically understand/interpret data needs from businesses and collect/disclose them from the user?
| Each field definition includes an `input` object with a required `type` string. | ||
| Platforms SHOULD respect the declared type. Platforms that do not recognize a | ||
| type SHOULD NOT render it as a different supported type, coerce it to text, or | ||
| collect a value unless a negotiated extension defines that type. |
There was a problem hiding this comment.
Trying to unpack this sentence here along with the Standard Input Types below and the schema design. Is it correct to interpret this as:
- UCP defines 4 well-known input types (essentially authored and endorsed by UCP governing body) = the standard input types
- Platforms & businesses can negotiate on other primitive supported input types (for example, "number" for numeric input) out-of-band. When the same input value is advertised and negotiated, then it can be leveraged as-is.
My confusion is around what we mean by "a negotiated extension defines that type"? Are we talking about the fact that we can have something like com.example.number as a type value? Can we bring some clarity in the sentence here by giving some examples? Also some naive questions on top:
- How are we thinking of mapping type value (i.e.
number) to the actual input schema (i.e.com.example.number) for these custom extensions? - How would we advertise these custom type extensions in the UCP profile?
Would we have:
"dev.ucp.shopping.additional_fields": [
{
...
"config": {
"supported_types": ["text", "boolean", "com.example.number"]
}
}
],
"com.example.number": [
{
....
extends: "dev.ucp.shopping.additional_fields"
}
]
If yes to the example above, then I believe this may be the first time where an extension is now extending another extension explicitly in UCP (not saying this is not okey, but just want to explicitly call it out this is the first time UCP is broadly advocating for this kind of pattern).
There was a problem hiding this comment.
Read through Extensibility section below and it aligned with my understanding/assumption in the comment, though some additional clarity in language & examples would still be nice here 😃.
However, the 2 naive questions bullet still hold:1) Are we expecting the reverse-DNS to be part of supported_types? 2) This is the first instance of extension decorating an extension.
|
|
||
| ### Standard Input Types | ||
|
|
||
| This version defines the following standard types: |
There was a problem hiding this comment.
Curious how did we land on the standard types here? Did we evaluate other primitives like numeric and/or list inputs to be a well-known value?
| "dev.ucp.shopping.additional_fields": [ | ||
| { | ||
| "version": "{{ ucp_version }}", | ||
| "extends": "dev.ucp.shopping.order", |
There was a problem hiding this comment.
Trying to envision the scenario where dev.ucp.shopping.additional_fields is supported only in order but not checkout in UCP. In checkout, let's say platform opted to redirect/hand off user to business for collection of these values. If the extension is supported in order, does that mean platform would still get back those values through this structured additional_fields extension for read-only?
Or is there a strong dependency that values returned here MUST be collected via the extension when decorating UCP checkout?
Summary
Adds an Additional Fields proposal using a single extension with optional config-based type narrowing.
Businesses sometimes need to collect checkout data that is specific to their workflow, such as PO numbers, gift options, delivery notes, requested dates, or buyer acknowledgements. Today there is no standard way for a business to describe those fields to a platform, for the platform to collect values, or for captured values to appear on orders.
This proposal standardizes that exchange:
additional_fieldsdefinitions and submitted valuestext,boolean,date, andchoicemessages[]It also adds optional
config.supported_typeson the capability. Platforms and businesses may usesupported_typesto narrow the active type set; when both declare it, the active set is their intersection.Notes
The payload schema remains the full standard type superset. Config is treated as an optional negotiation constraint, not the primary extension model.