Skip to content

Commit 4c5a469

Browse files
committed
feat: add policies[] to order, decouple refund
- Add `policies[]` to `order` as a read-only snapshot of the policies that applied at checkout (`ucp_request: omit`), mirroring how `order.attribution` snapshots checkout data. Completes the catalog -> cart -> checkout -> order lifecycle; returns are post-purchase, so the order is the durable home for their terms. - Remove the refund `allOf` overlay from `policy.json` and delete the now-empty `policy_refund.json`. Core stays a pure generic container; the refund type attaches its body via extension composition (#257). - Type `policy.type` via `$ref` to `reverse_domain_name.json`, so the reverse-DNS format is enforced rather than described only in prose. - State in Precedence that a Platform MUST NOT merge same-type policy bodies: a consumer cannot infer combine-vs-replace semantics, so it resolves a single governing policy by structure alone. Composition is authored into the most-specific policy, not resolved at read time. - Collapse the disclosure-pairing passage to one paragraph plus two numbered rules (editorial).
1 parent eac2724 commit 4c5a469

5 files changed

Lines changed: 25 additions & 35 deletions

File tree

docs/specification/order.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,11 @@ Businesses MAY surface a snapshot of the originating checkout's
9494
`order.attribution`. See [Attribution](overview.md#attribution) for the
9595
underlying contract.
9696

97+
### Policies
98+
99+
Businesses MAY surface a snapshot of the policies that applied at checkout on
100+
the order. See [Policies](overview.md#policies) for the underlying contract.
101+
97102
### Adjustments
98103

99104
**Adjustments** are post-order events that exist independently of

docs/specification/overview.md

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2280,7 +2280,7 @@ presenting the policy from its `description` (see
22802280

22812281
`applies_to` is an array of RFC 9535 JSONPath expressions, evaluated relative to
22822282
the **embedding response root** — the same convention `messages[].path` uses.
2283-
The root differs by surface: `$.line_items[N]` on cart and checkout,
2283+
The root differs by surface: `$.line_items[N]` on cart, checkout, and order,
22842284
`$.products[N]` on catalog search and lookup, `$.product` on get_product. A
22852285
policy targets nodes in one of three forms:
22862286

@@ -2306,9 +2306,12 @@ Policies of **different** `type` are independent: each applies on its own, so a
23062306
single node can carry a warranty policy and a price-match policy at once.
23072307

23082308
Policies of the **same** `type` can contest a node. When they do, exactly one
2309-
governs and **replaces** the rest at that node — same-type policies do not
2310-
compose, so their bodies are never merged. Resolving which one governs is a
2311-
**longest-prefix match** against the response in hand.
2309+
governs and **replaces** the rest — a Platform **MUST NOT** merge their bodies.
2310+
Merging would mean inferring whether policies combine or replace, which a
2311+
Platform cannot read from the data; resolution selects one governing policy by
2312+
structure alone. When terms genuinely stack, the Business folds them into the
2313+
most-specific policy — composition is authored, not resolved. Resolving which
2314+
one governs is a **longest-prefix match** against the response in hand.
23122315

23132316
Every node has a canonical identity: its **Normalized Path** ([RFC 9535
23142317
§2.7](https://www.rfc-editor.org/rfc/rfc9535#section-2.7)), the sequence of
@@ -2371,14 +2374,12 @@ final-sale terms to regulatory notices.
23712374

23722375
A disclosure pairs with the policy that **governs** its `path` node — the one
23732376
[Precedence](#precedence) selects when several policies of the same `type` cover
2374-
that node. Precedence yields at most one such policy, so the pairing is
2375-
unambiguous.
2376-
2377-
Two authoring rules apply:
2377+
that node. Precedence yields at most one, so the pairing is unambiguous. Two
2378+
rules apply:
23782379

23792380
1. A disclosure's content **MUST** agree with the policy it pairs with — the
23802381
notice and the policy are two statements about the same node.
2381-
2. A disclosure **SHOULD** resolve to a governing policy. When its `code` names
2382+
2. A disclosure **SHOULD** resolve to a governing policy: when its `code` names
23822383
a `type` no policy covers at that node, the notice still displays, but
23832384
nothing structured stands behind it.
23842385

source/schemas/shopping/order.json

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,14 @@
9696
"$ref": "types/totals.json",
9797
"description": "Different totals for the order."
9898
},
99+
"policies": {
100+
"type": "array",
101+
"items": {
102+
"$ref": "types/policy.json"
103+
},
104+
"description": "Snapshot of the policies that applied to the items at checkout, captured on the order as a durable record. `applies_to` targets are relative to the response root.",
105+
"ucp_request": "omit"
106+
},
99107
"messages": {
100108
"type": "array",
101109
"items": {

source/schemas/shopping/types/policy.json

Lines changed: 2 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
"additionalProperties": true,
1212
"properties": {
1313
"type": {
14-
"type": "string",
14+
"$ref": "../../common/types/reverse_domain_name.json",
1515
"description": "Policy type discriminator. Open reverse-DNS vocabulary. Well-known values: `dev.ucp.shopping.policy.refund` (return/refund terms), `dev.ucp.shopping.policy.warranty` (warranty terms). Businesses MAY define custom types in their own domain (e.g., `com.example.policy.price_match`). Platforms MUST tolerate unknown values."
1616
},
1717
"description": {
@@ -30,22 +30,5 @@
3030
"format": "uri",
3131
"description": "Optional link to the full policy document."
3232
}
33-
},
34-
"allOf": [
35-
{
36-
"if": {
37-
"required": [
38-
"type"
39-
],
40-
"properties": {
41-
"type": {
42-
"const": "dev.ucp.shopping.policy.refund"
43-
}
44-
}
45-
},
46-
"then": {
47-
"$ref": "policy_refund.json"
48-
}
49-
}
50-
]
33+
}
5134
}

source/schemas/shopping/types/policy_refund.json

Lines changed: 0 additions & 7 deletions
This file was deleted.

0 commit comments

Comments
 (0)