feat: extend warning to support disclosure contract#267
Conversation
|
A question on the approach (apologies in case I missed the discussion): An evolutionary side effect of adding a new message type can be fostering a pattern that we will start evolving the type as needed for future requirements as well. IMHO the types defined today To that effect an alternate approach would be to evolve message structure to have some of these explicit signals (content, content_type, image_url etc.) and maybe a mandate signal from the business to display it that the agent has to honor? This alternate model can have some cons though such as making the interpretation more nested however I was curious if that is still a better choice than adding new types some of which might not be at the same level of abstraction? |
Extends message_warning with disclosure: true flag, image_url, and url fields. When disclosure is set, platforms MUST display the warning in proximity to the path-referenced component and MUST NOT hide or dismiss it. This preserves the existing three-type message model (error/warning/info) while giving disclosures a prescribed rendering contract. Platforms that don't recognize the flag still render the underlying warning — graceful degradation by design.
7770730 to
f3a115a
Compare
|
@sinhanurag fair, pushed an update so we can look at them side by side.. Flag approach forfeits schema-level distinction. With a separate type: "disclosure", code generators produce a distinct type, validators can enforce disclosure-specific fields, and platforms switch(message.type) with an explicit case. On the other hand, flag approach gains graceful degradation. A platform that doesn't recognize disclosure: true still renders the warning — the buyer sees the content, just without the proximity and persistence guarantees. It also preserves the established error/warning/info model without proliferating new types. On balance, I'm 👍 on warning + disclosure flag. |
|
I like the warnings+disclosure flag based approach better as well. |
|
Looks like we're converging on extending warning. @amithanda @sinhanurag updated PR title & description to match. |
Maxime flagged that platform requirements say omitted path means "applies
to the whole response" while business requirements say MUST use path —
a contradiction.
Three options:
1. Require path via JSON Schema if/then when disclosure: true. Valid
2020-12 but adds conditional complexity that many validators handle
poorly in practice.
2. Require path in prose, use root JSONPath ($) for response-wide
disclosures. Elegant but introduces a convention nobody uses in
the spec today — practically a novelty implementers need to learn.
3. Keep path optional, downgrade business requirement to SHOULD, define
fallback behavior explicitly. When path is omitted, disclosure applies
to the response as a whole.
Going with (3): no schema gymnastics, no novel conventions, and the
platform requirement already defines the fallback behavior, which
addresses the concern about divergent client rendering.
1. Disclosure vs acknowledgment: add section clarifying that disclosure
is a presentation mechanism. When buyer acknowledgment is also needed,
business MAY combine with escalation mechanisms from the checkout
status lifecycle.
2. Escalation fallback: platforms that cannot honor the disclosure
rendering contract MUST escalate to merchant UI via continue_url
rather than silently downgrading to a regular warning.
Removed "item-anchored" qualifier from disclosure descriptions in checkout.md and catalog/index.md — the rendering contract in Platform Requirements already specifies proximity to the path-referenced component.
Pivots from `disclosure: true` (boolean) to `presentation: "disclosure"`
(string) on warning messages, based on converging feedback from three
independent reviewers (Chris Sauve, ACSchil, Alex/Maxime's team) who
each independently suggested a more extensible field.
Design options:
1. Boolean `disclosure: true` — simple, fully validatable, but three
reviewers flagged boolean proliferation risk. No migration path
without adding a new field and deprecating the old one.
2. `subtype: "disclosure"` (ACSchil) — extensible, but names the
content category ("what") rather than the rendering behavior.
Content category is already served by `code`.
3. `presentation: "notice" | "disclosure"` (inspired by Chris Sauve's
`presentation_policy` suggestion) — names the rendering behavior
dimension ("how"), not the content category. Two concrete points
on the axis: `notice` describes existing warning behavior, `disclosure`
describes the new contract.
Going with (3) because it correctly separates the two axes:
- `code` = what the warning is about (allergens, prop65, etc.)
- `presentation` = how the platform must render it (notice, disclosure)
This also provides a natural home for future rendering contracts.
For example, an `acknowledgment` value could fill the gap between
display-only (disclosure) and full escalation (requires_buyer_review) —
where the platform can natively collect buyer confirmation without
handing off to merchant UI. That value isn't needed today, but the
axis is ready for it without migration.
Schema: `presentation` is open string defaulting to `"notice"`.
|
@ACSchil @lemonmade having sat on it for some more, how about: e4be6c4 - h/t to Chris for suggestion. I think it works and fits the contract we're after well. |
Resolves #222
Extends
message_warningwith apresentationfield and two new optional fields (image_url,url). Whenpresentation: "disclosure", the warning carries a notice — safety warnings, allergen declarations, compliance content, etc. — that platforms MUST display in proximity to the referenced component and MUST NOT hide, collapse, or auto-dismiss.The
presentationfield defines the rendering contract axis for warnings. Two values are defined today:"notice"(default) — current warning behavior: MUST display, MAY dismiss"disclosure"— MUST display in proximity topath, MUST NOT dismiss, MUST escalate viacontinue_urlif cannot honorWhy extend warning rather than a new message type or
line_item.disclosures[]This is an alternative to both
line_item.disclosures[](#222) and a separatetype: "disclosure":messages[]already works across all surfaces (checkout, cart, catalog_lookup, catalog_search)$.products[0]applies to all variantspresentationfield still render the underlying warningWhy
presentation(string) rather thandisclosure(boolean)code= what the warning is about (allergens, prop65, etc.)presentation= how the platform must render it (notice, disclosure)Provides a natural home for future rendering contracts. For example, an
acknowledgevalue could fill the gap between display-only (disclosure) and full escalation (requires_buyer_review) — where the platform natively collects buyer confirmation without handing off to merchant UI. That value isn't needed today, but the axis is ready for it without migration.Examples
Catalog — allergen disclosure targeting a product (all variants inherit):
{ "ucp": { "version": "2026-01-11", "status": "success" }, "products": [ { "id": "prod_nut_butter", "title": "Artisan Nut Butter Collection", "variants": [ { "id": "var_almond", "title": "Almond Butter", "price": { "amount": 1299, "currency": "USD" }, "availability": { "available": true } }, { "id": "var_cashew", "title": "Cashew Butter", "price": { "amount": 1499, "currency": "USD" }, "availability": { "available": true } } ] } ], "messages": [ { "type": "warning", "code": "allergens", "path": "$.products[0]", "content": "**Contains: tree nuts.** Produced in a facility that also processes peanuts, milk, and soy.", "content_type": "markdown", "presentation": "disclosure", "image_url": "https://merchant.com/allergen-tree-nuts.svg", "url": "https://merchant.com/allergen-info" } ] }The path targets
$.products[0]— both Almond Butter and Cashew Butter variants inherit the disclosure without duplication. This is the key advantage overline_item.disclosures[], which would require repeating the disclosure on every variant.Checkout — disclosure co-existing with a recoverable error:
{ "ucp": { "version": "2026-01-11", "status": "success" }, "id": "chk_abc123", "status": "incomplete", "currency": "USD", "line_items": [ { "id": "li_1", "item": { "id": "item_456", "title": "Artisan Nut Butter Collection", "image_url": "https://merchant.com/nut-butter.jpg" }, "quantity": 1, "totals": [{ "type": "subtotal", "amount": 1299 }] } ], "totals": [{ "type": "total", "amount": 1299 }], "messages": [ { "type": "error", "code": "field_required", "path": "$.buyer.email", "content": "Buyer email is required", "severity": "recoverable" }, { "type": "warning", "code": "allergens", "path": "$.line_items[0]", "content": "**Contains: tree nuts.** Produced in a facility that also processes peanuts, milk, and soy.", "content_type": "markdown", "presentation": "disclosure", "image_url": "https://merchant.com/allergen-tree-nuts.svg", "url": "https://merchant.com/allergen-info" } ], "links": [] }Key design decisions
presentationon warning, not a new type — preserves error/warning/info model; graceful degradation over schema puritycodecarries the "what",presentationcarries the "how"contextand other inputs) and product attributes to determine applicable disclosures; platforms do not affect or resolve disclosure applicabilityimage_urlandurlon warning only — other message types (error, info) don't need these fieldspathis SHOULD, not MUST — kept optional in schema; when omitted, disclosure applies to response as a wholecontinue_urlrather than silently downgradingChecklist