Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 20 additions & 8 deletions preprocess_schemas.py
Original file line number Diff line number Diff line change
Expand Up @@ -532,6 +532,25 @@ def generate_variants(path, schema, ops, global_variant_requirements):
# --- Global Normalization ---


def metadata_union_members(ucp_schema):
"""Return the ``$defs`` names that form the UcpMetadata root union.

The union spans the discovery profiles (platform/business) and every
response schema declared in ``ucp.json``. Deriving the list from
``$defs`` keeps the generated ``UcpMetadata`` complete as the protocol
adds response types — a previous hardcoded list silently omitted
``response_catalog_schema``, dropping catalog responses from every
model's ``ucp`` field.
"""
defs = ucp_schema.get("$defs", {})
return [
name
for name in defs
if name in ("platform_schema", "business_schema")
or (name.startswith("response_") and name.endswith("_schema"))
]


def normalize_metadata_schemas(schemas, target_dir):
"""
Ensures ucp.json has a root union and other files point to it generically.
Expand All @@ -542,14 +561,7 @@ def normalize_metadata_schemas(schemas, target_dir):
if ucp_path in schemas:
ucp = schemas[ucp_path]
ucp["oneOf"] = [
{"$ref": f"#/$defs/{d}"}
for d in [
"platform_schema",
"business_schema",
"response_checkout_schema",
"response_order_schema",
"response_cart_schema",
]
{"$ref": f"#/$defs/{name}"} for name in metadata_union_members(ucp)
]

for p_abs, s in schemas.items():
Expand Down
3 changes: 2 additions & 1 deletion src/ucp_sdk/models/schemas/ucp.py
Original file line number Diff line number Diff line change
Expand Up @@ -338,7 +338,8 @@ class ResponseCatalogSchema(Base):
| BusinessSchema
| ResponseCheckoutSchema
| ResponseOrderSchema
| ResponseCartSchema,
| ResponseCartSchema
| ResponseCatalogSchema,
Field(..., title="UCP Metadata"),
],
)
Expand Down
3 changes: 2 additions & 1 deletion src/ucp_sdk/models/schemas/ucp_create_request.py
Original file line number Diff line number Diff line change
Expand Up @@ -338,7 +338,8 @@ class ResponseCatalogSchema(Base):
| BusinessSchema
| ResponseCheckoutSchema
| ResponseOrderSchema
| ResponseCartSchema,
| ResponseCartSchema
| ResponseCatalogSchema,
Field(..., title="UCP Metadata Create Request"),
],
)
Expand Down
3 changes: 2 additions & 1 deletion src/ucp_sdk/models/schemas/ucp_update_request.py
Original file line number Diff line number Diff line change
Expand Up @@ -338,7 +338,8 @@ class ResponseCatalogSchema(Base):
| BusinessSchema
| ResponseCheckoutSchema
| ResponseOrderSchema
| ResponseCartSchema,
| ResponseCartSchema
| ResponseCatalogSchema,
Field(..., title="UCP Metadata Update Request"),
],
)
Expand Down
78 changes: 77 additions & 1 deletion tests/test_codegen_pipeline.py
Original file line number Diff line number Diff line change
Expand Up @@ -401,7 +401,18 @@ def test_normalize_metadata_schemas_sets_root_union_and_ucp_refs(
(target_dir / "checkout_create_request.json").resolve()
)
schemas = {
ucp_path: {"$defs": {}},
ucp_path: {
"$defs": {
"version": {"type": "string"},
"entity": {"type": "object"},
"platform_schema": {"type": "object"},
"business_schema": {"type": "object"},
"response_checkout_schema": {"type": "object"},
"response_order_schema": {"type": "object"},
"response_cart_schema": {"type": "object"},
"response_catalog_schema": {"type": "object"},
}
},
checkout_path: {
"properties": {
"ucp": {"$ref": "ucp.json#/$defs/response_schema"}
Expand All @@ -424,6 +435,7 @@ def test_normalize_metadata_schemas_sets_root_union_and_ucp_refs(
{"$ref": "#/$defs/response_checkout_schema"},
{"$ref": "#/$defs/response_order_schema"},
{"$ref": "#/$defs/response_cart_schema"},
{"$ref": "#/$defs/response_catalog_schema"},
],
)
self.assertEqual(
Expand Down Expand Up @@ -546,6 +558,70 @@ def test_main_preprocesses_schema_tree_end_to_end(self) -> None:
self.assertEqual(child_variant["required"], ["value"])


class MetadataUnionTest(unittest.TestCase):
"""The UcpMetadata root union is derived from ucp.json $defs."""

def test_includes_profiles_and_all_response_schemas(self) -> None:
"""Profiles and every response_*_schema belong to the union."""
ucp = {
"$defs": {
"version": {"type": "string"},
"version_constraint": {"type": "object"},
"requires": {"type": "object"},
"entity": {"type": "object"},
"base": {"type": "object"},
"success": {"type": "object"},
"error": {"type": "object"},
"platform_schema": {"type": "object"},
"business_schema": {"type": "object"},
"response_checkout_schema": {"type": "object"},
"response_order_schema": {"type": "object"},
"response_cart_schema": {"type": "object"},
"response_catalog_schema": {"type": "object"},
}
}
self.assertEqual(
preprocess_schemas.metadata_union_members(ucp),
[
"platform_schema",
"business_schema",
"response_checkout_schema",
"response_order_schema",
"response_cart_schema",
"response_catalog_schema",
],
)

def test_picks_up_new_response_types_automatically(self) -> None:
"""A response schema added upstream is included without code changes."""
ucp = {
"$defs": {
"platform_schema": {"type": "object"},
"business_schema": {"type": "object"},
"response_invoice_schema": {"type": "object"},
}
}
self.assertEqual(
preprocess_schemas.metadata_union_members(ucp),
["platform_schema", "business_schema", "response_invoice_schema"],
)

def test_excludes_non_schema_defs(self) -> None:
"""Helper and shared defs never leak into the metadata union."""
ucp = {
"$defs": {
"entity": {"type": "object"},
"request_schema": {"type": "object"},
"base": {"type": "object"},
}
}
self.assertEqual(preprocess_schemas.metadata_union_members(ucp), [])

def test_empty_defs_yields_empty_union(self) -> None:
"""No $defs means no union members."""
self.assertEqual(preprocess_schemas.metadata_union_members({}), [])


@unittest.skipUnless(
HAVE_SDK, "requires the installed package (pip install -e .)"
)
Expand Down
Loading