Skip to content

Commit eb5624c

Browse files
committed
chore(models): regenerate against the pinned 2026-08-25 UCP schema
Regenerates via ./generate_models.sh 2026-08-25 (the same command the model-drift CI job runs) to pick up the postprocessing fix in the prior commit. One file changes: FulfillmentMethod gains an _enforce_conditional_item_retyping validator covering both the shipping and pickup destination retyping rules. Verified: - Full suite: 101 tests, 0 failures, 4 documented skips (both new semantic tests from the RED commit now pass). - Double-regen: ran generate_models.sh 2026-08-25 twice; diff -rq between both outputs (excluding __pycache__) is empty. - Kill-test: reverted postprocess_models.py to its pre-fix state, regenerated, reinstalled -- the same 2 failures + 6 errors from the RED commit reappeared verbatim. Restored the fix and regenerated again to confirm the suite returns to green. - pre-commit run on the changed file: clean. Not committed: README.md, which ruff format also reformats as a pre-existing docstring-code-block spacing drift in main, unrelated to this fix (see the equivalent note on the jwk-conditional-rules branch).
1 parent a94e5e7 commit eb5624c

1 file changed

Lines changed: 53 additions & 1 deletion

File tree

src/ucp_sdk/models/schemas/shopping/types/fulfillment_method.py

Lines changed: 53 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818

1919
from __future__ import annotations
2020

21-
from pydantic import BaseModel, ConfigDict
21+
from pydantic import BaseModel, ConfigDict, model_validator
2222

2323
from . import fulfillment_destination, fulfillment_group
2424

@@ -57,3 +57,55 @@ class FulfillmentMethod(BaseModel):
5757
"""
5858
Fulfillment groups for selecting options. Agent sets selected_option_id on groups to choose shipping method.
5959
"""
60+
61+
@model_validator(mode="after")
62+
def _enforce_conditional_item_retyping(self):
63+
"""JSON Schema if/then: approximate a discriminator's array-item
64+
retyping to a different referenced schema, via that schema's own
65+
required keys and const-pinned fields."""
66+
rules = [
67+
{
68+
"discriminator": "type",
69+
"values": ["shipping"],
70+
"field": "destinations",
71+
"required": ["id", "type"],
72+
"consts": {"type": "shipping_address"},
73+
},
74+
{
75+
"discriminator": "type",
76+
"values": ["pickup"],
77+
"field": "destinations",
78+
"required": ["type"],
79+
"consts": {"type": "business_location"},
80+
},
81+
]
82+
for rule in rules:
83+
actual = getattr(self, rule["discriminator"], None)
84+
if actual not in rule["values"]:
85+
continue
86+
for _item in getattr(self, rule["field"], None) or []:
87+
_provided = (
88+
set(_item.keys())
89+
if isinstance(_item, dict)
90+
else _item.model_fields_set | set(_item.model_extra or {})
91+
)
92+
for _required in rule["required"]:
93+
if _required not in _provided:
94+
raise ValueError(
95+
f"Field {_required!r} is required for "
96+
f"{rule['field']} items when "
97+
f"{rule['discriminator']} is {actual!r}"
98+
)
99+
for _const_field, _const_value in rule["consts"].items():
100+
_actual_value = (
101+
_item.get(_const_field)
102+
if isinstance(_item, dict)
103+
else getattr(_item, _const_field, None)
104+
)
105+
if _actual_value != _const_value:
106+
raise ValueError(
107+
f"Field {_const_field!r} must equal "
108+
f"{_const_value!r} for {rule['field']} items "
109+
f"when {rule['discriminator']} is {actual!r}"
110+
)
111+
return self

0 commit comments

Comments
 (0)