portage-ucp 0.14.0 → 0.15.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a245e863596f643972f10c9be20792055d6bf1d2925b90373571966896ee429a
4
- data.tar.gz: ad0008e190d5c865e613b616653a7d5dbd5f6b19166f8f71723e57ae70ef7ce0
3
+ metadata.gz: 3030cd7b510d8e0e829878dd48ab11fd18f70e0d0e5cac5107852ead26a0077c
4
+ data.tar.gz: 7e6abed9cd7ea40da3ee5f8681ec69f80a6f8c852e8956901f4fce1b383816da
5
5
  SHA512:
6
- metadata.gz: d9a93b39705265b1095da290e5615ddbfcf3d3ea529d9b5863308ad99819c70b11ed77bc9805444a003b78c61bb418d4faa756617148d74b964b88beb90b5330
7
- data.tar.gz: c2c95f6b3217ea2c2dc6b86318eaa845677b45c753b707ad2eb17f2ae7599f92fe457f7f82a34d46cfea26f1b5bfa8bc17ff4ee46459c94967c6de5ed6286611
6
+ metadata.gz: 4c4dddb8b6aaeaa674d270400287420f3bcbbfc028c8d38b9482fe53fe2cb47b493711cd7fffe50051b892b49f720f4332ba0e3af89fe595df9d46cdf80c5306
7
+ data.tar.gz: 5b1c1ee5a21fae8d7c8821c43820bcdcca15f54001e9d6e25af3b4916965da69a1bedb144faadb06ec222c11a59d3cd7e60c753579a4d8931924f51e62f06b78
data/CHANGELOG.md CHANGED
@@ -6,6 +6,10 @@ pre-1.0, so APIs may still shift between minor versions.
6
6
 
7
7
  ## [Unreleased]
8
8
 
9
+ ## [0.15.0] - 2026-10-13
10
+
11
+ - **Added: optional `policies:` on `Cart`, `Checkout`, `Order`, `Product`, `CatalogSearchResult` and `ProductDetail`** (UCP 2026-08-25 `policies[]`). An array of `policy.json` hashes (`type` and `description` required; `applies_to` and `url` optional), default `[]`, omitted from the wire payload when empty. `portage-ucp-shopify` 0.7.0 supplies it (design-log §60).
12
+
9
13
  ## [0.14.0] - 2026-10-09
10
14
 
11
15
  Moves the gem to UCP 2026-08-25 (design-log §56-58). Minor-level for a pre-1.0 gem, with breaking config changes below.
@@ -105,7 +105,7 @@ module Portage
105
105
 
106
106
  # --- Reorder (app.portage-ucp.reorder — Portage extension, not part of
107
107
  # the UCP spec: dev.ucp.dev has no reorder/cart-hydration capability as
108
- # of the 2026-04-08 spec) ---
108
+ # of the 2026-08-25 spec) ---
109
109
  # Hydrates a cart from a previous order's line items so a caller doesn't
110
110
  # have to re-walk get_order + create_cart itself. Re-checks each item's
111
111
  # current price/availability rather than replaying the order's snapshot
@@ -7,7 +7,7 @@ module Portage
7
7
  module Security
8
8
  # Verifies that an inbound agent request carries a valid RFC 9421 HTTP
9
9
  # Message Signature, per UCP's own signature spec
10
- # (ucp.dev/2026-04-08/specification/signatures/, pinned 2026-09-15 —
10
+ # (ucp.dev/2026-08-25/specification/signatures/, pinned 2026-09-15 —
11
11
  # this is the piece §22 of the design log flagged as unresearched
12
12
  # before writing code, now checked against the live spec rather than
13
13
  # guessed). This is a distinct concern from three other signing
@@ -115,9 +115,10 @@ module Portage
115
115
  # (Shopify/Wix metafields etc.) — see Portage::Ucp::Shopify.configure's
116
116
  # metadata_field.
117
117
  Product = Data.define(:id, :title, :description, :price_range, :variants, :handle, :url, :categories,
118
- :list_price_range, :media, :options, :tags, :metadata, :rating) do
118
+ :list_price_range, :media, :options, :tags, :metadata, :rating, :policies) do
119
119
  def initialize(id:, title:, description:, price_range:, variants:, handle: nil, url: nil, categories: [],
120
- list_price_range: nil, media: [], options: [], tags: [], metadata: nil, rating: nil)
120
+ list_price_range: nil, media: [], options: [], tags: [], metadata: nil, rating: nil,
121
+ policies: [])
121
122
  super
122
123
  end
123
124
 
@@ -135,6 +136,7 @@ module Portage
135
136
  h["media"] = media.map(&:to_wire_h) unless media.empty?
136
137
  h["options"] = options.map(&:to_wire_h) unless options.empty?
137
138
  h["tags"] = tags unless tags.empty?
139
+ h["policies"] = policies unless policies.empty?
138
140
  h
139
141
  end
140
142
  end
@@ -144,12 +146,13 @@ module Portage
144
146
  # isn't schema-conformant (search_response requires `ucp` + `products` at
145
147
  # the top level, not a bare array). `messages` entries are left as plain
146
148
  # wire-shaped hashes, same rationale as Variant#barcodes above.
147
- CatalogSearchResult = Data.define(:products, :messages) do
148
- def initialize(products:, messages: []) = super
149
+ CatalogSearchResult = Data.define(:products, :messages, :policies) do
150
+ def initialize(products:, messages: [], policies: []) = super
149
151
 
150
152
  def to_wire_h
151
153
  h = { "products" => products.map(&:to_wire_h) }
152
154
  h["messages"] = messages unless messages.empty?
155
+ h["policies"] = policies unless policies.empty?
153
156
  h
154
157
  end
155
158
  end
@@ -161,8 +164,14 @@ module Portage
161
164
  # extension (interactive variant narrowing) — Adapter#get_product's
162
165
  # signature has no `selected:`/`preferences:` params to source it from
163
166
  # yet; unresearched, same status as design-log §16's other backlog items.
164
- ProductDetail = Data.define(:product) do
165
- def to_wire_h = { "product" => product.to_wire_h }
167
+ ProductDetail = Data.define(:product, :policies) do
168
+ def initialize(product:, policies: []) = super
169
+
170
+ def to_wire_h
171
+ h = { "product" => product.to_wire_h }
172
+ h["policies"] = policies unless policies.empty?
173
+ h
174
+ end
166
175
  end
167
176
 
168
177
  # One cost-breakdown entry (schemas/shopping/types/total.json). `amount` is a
@@ -198,6 +207,10 @@ module Portage
198
207
  end
199
208
  end
200
209
 
210
+ # `policies` (cart/checkout/order/catalog responses and products) is the
211
+ # 2026-08-25 policy.json array (return/warranty terms), optional and omitted
212
+ # when empty. Entries stay wire-shaped hashes (`type` and `description` are
213
+ # required, `applies_to`/`url` optional), same posture as `messages`.
201
214
  # schemas/shopping/types/link.json
202
215
  Link = Data.define(:type, :url, :title) do
203
216
  def initialize(type:, url:, title: nil) = super
@@ -380,13 +393,14 @@ module Portage
380
393
  # `discounts` is the dev.ucp.shopping.discount extension (optional on both
381
394
  # cart.json and its own schema) — omitted from the wire payload when empty,
382
395
  # same as Order#adjustments.
383
- Cart = Data.define(:id, :line_items, :currency, :totals, :discounts) do
384
- def initialize(id:, line_items:, currency:, totals:, discounts: Discounts.new) = super
396
+ Cart = Data.define(:id, :line_items, :currency, :totals, :discounts, :policies) do
397
+ def initialize(id:, line_items:, currency:, totals:, discounts: Discounts.new, policies: []) = super
385
398
 
386
399
  def to_wire_h
387
400
  h = { "id" => id, "line_items" => line_items.map(&:to_wire_h), "currency" => currency,
388
401
  "totals" => totals.map(&:to_wire_h) }
389
402
  h["discounts"] = discounts.to_wire_h unless discounts.empty?
403
+ h["policies"] = policies unless policies.empty?
390
404
  h
391
405
  end
392
406
  end
@@ -415,9 +429,9 @@ module Portage
415
429
  # omitted from the wire payload when empty), same posture as
416
430
  # Order#adjustments.
417
431
  Checkout = Data.define(:id, :status, :line_items, :currency, :totals, :links, :order, :discounts,
418
- :fulfillment) do
432
+ :fulfillment, :policies) do
419
433
  def initialize(id:, status:, line_items:, currency:, totals:, links:, order: nil, discounts: Discounts.new,
420
- fulfillment: CheckoutFulfillment.new)
434
+ fulfillment: CheckoutFulfillment.new, policies: [])
421
435
  super
422
436
  end
423
437
 
@@ -427,6 +441,7 @@ module Portage
427
441
  h["order"] = order.to_wire_h if order
428
442
  h["discounts"] = discounts.to_wire_h unless discounts.empty?
429
443
  h["fulfillment"] = fulfillment.to_wire_h unless fulfillment.empty?
444
+ h["policies"] = policies unless policies.empty?
430
445
  h
431
446
  end
432
447
  end
@@ -508,9 +523,9 @@ module Portage
508
523
  # line_items/fulfillment/currency/totals. `adjustments` is optional —
509
524
  # omitted from the wire payload when empty.
510
525
  Order = Data.define(:id, :checkout_id, :permalink_url, :line_items, :fulfillment, :currency, :totals,
511
- :adjustments) do
526
+ :adjustments, :policies) do
512
527
  def initialize(id:, checkout_id:, permalink_url:, line_items:, fulfillment:, currency:, totals:,
513
- adjustments: [])
528
+ adjustments: [], policies: [])
514
529
  super
515
530
  end
516
531
 
@@ -519,6 +534,7 @@ module Portage
519
534
  "line_items" => line_items.map(&:to_wire_h), "fulfillment" => fulfillment.to_wire_h,
520
535
  "currency" => currency, "totals" => totals.map(&:to_wire_h) }
521
536
  h["adjustments"] = adjustments.map(&:to_wire_h) unless adjustments.empty?
537
+ h["policies"] = policies unless policies.empty?
522
538
  h
523
539
  end
524
540
  end
@@ -1,5 +1,5 @@
1
1
  module Portage
2
2
  module Ucp
3
- VERSION = "0.14.0".freeze
3
+ VERSION = "0.15.0".freeze
4
4
  end
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: portage-ucp
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.14.0
4
+ version: 0.15.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tom Whitbread
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2026-10-09 00:00:00.000000000 Z
11
+ date: 2026-10-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: base64
@@ -24,6 +24,20 @@ dependencies:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
26
  version: '0.2'
27
+ - !ruby/object:Gem::Dependency
28
+ name: bigdecimal
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '3.1'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '3.1'
27
41
  - !ruby/object:Gem::Dependency
28
42
  name: json_schemer
29
43
  requirement: !ruby/object:Gem::Requirement
@@ -38,6 +52,20 @@ dependencies:
38
52
  - - "~>"
39
53
  - !ruby/object:Gem::Version
40
54
  version: '2.5'
55
+ - !ruby/object:Gem::Dependency
56
+ name: logger
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '1.5'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '1.5'
41
69
  - !ruby/object:Gem::Dependency
42
70
  name: mcp
43
71
  requirement: !ruby/object:Gem::Requirement