Repository navigation
Conversation
fac80be to
0e3dee5
Compare
| ], | ||
| ) | ||
| """ | ||
| Key-value map whose keys represent buyer/platform asserted eligibility claims and whose values represent associated membership information. All loyalty keys MUST use reverse-domain naming to ensure provenance and |
There was a problem hiding this comment.
ap2 is generated as a required field on CheckoutCompleteRequest, which breaks validation for any non-AP2 checkout completion request.
In common/payment_ap2_mandate.json, $defs["dev.ucp.shopping.checkout"].properties.ap2 sets "ucp_request": {"create": "omit", "update": "omit", "complete": "required"}. Because ucp-schema generate-types flattens optional capability extensions onto the unified CheckoutCompleteRequest model, top-level extension properties contributed by overlays need to remain optional (ap2: Ap2WithCheckoutMandateCompleteRequest | None = None), while checkout_mandate stays required inside Ap2WithCheckoutMandateCompleteRequest when ap2 is present.
| """ | ||
| Errors, warnings, or informational messages about the search results. | ||
| """ | ||
|
|
||
|
|
||
| Loyalty = TypeAliasType( | ||
| "Loyalty", | ||
| Annotated[ | ||
| dict[ReverseDomainName, LoyaltyMembership], Field(..., title="Loyalty") | ||
| ], | ||
| ) | ||
| """ | ||
| Key-value map whose keys represent buyer/platform asserted eligibility claims and whose values represent associated membership information. All loyalty keys MUST use reverse-domain naming to ensure provenance and |
There was a problem hiding this comment.
buyer and cart_id should be omitted from CheckoutCompleteRequest:
- In
shopping/cart.json,cart_iddefines"ucp_request": {"create": "optional", "update": "omit"}(omitting"complete"). - In
shopping/buyer_consent.json,buyerdefines"ucp_request": {"create": "optional", "update": "optional"}(omitting"complete", while baseshopping/checkout.jsonsets"complete": "omit").
When ucp_request is an operation map, operations not listed in the map should default to "omit" rather than "optional".
| """ | ||
| Locations matching the search criteria. | ||
| """ | ||
| pagination: PaginationResponse | None = None | ||
| messages: list[Message] | None = None | ||
| """ | ||
| Errors, warnings, or informational messages about the search results. | ||
| """ | ||
|
|
||
|
|
||
| Loyalty = TypeAliasType( | ||
| "Loyalty", | ||
| Annotated[ | ||
| dict[ReverseDomainName, LoyaltyMembership], Field(..., title="Loyalty") | ||
| ], | ||
| ) | ||
| """ | ||
| Key-value map whose keys represent buyer/platform asserted eligibility claims and whose values represent associated membership information. All loyalty keys MUST use reverse-domain naming to ensure provenance and |
There was a problem hiding this comment.
Making line_items: list[LineItemCreateRequest] unconditionally required on the unified CheckoutCreateRequest prevents cart-to-checkout conversion using only cart_id (per shopping/cart.json: "Business MUST use cart contents (line_items, context, buyer) and MUST ignore overlapping fields in checkout payload").
Previously, line_items was optional (list[LineItemCreateRequest] | None = None) when cart_id was in scope, and postprocess_models.py injected _enforce_cart_conversion to require at least one of cart_id or line_items.
0e3dee5 to
2c1cec5
Compare
….py and remove workarounds
Summary
Replaces the bespoke 373-line
preprocess_schemas.pyscript and 140-filesrc/ucp_sdk/models/schemas/{shopping,common,transports}/submodule hierarchy with on-the-flyucp-schema generate-typescompilation into a flat Pydantic v2 model module (src/ucp_sdk/models/schemas/__init__.py, re-exported fromucp_sdk.models).Key Changes
generate_models.sh& CI (tests.yml):ucp-schemavia${UCP_SCHEMA_BIN:-}->command -v ucp-schema(verifyinggenerate-typessupport) -> sibling../ucp-schema/target/{release,debug}/ucp-schema->cargo build --release --manifest-path ../ucp-schema/Cargo.toml.ucp-schemaCLI in themodel-driftGitHub Actions job so CI model regeneration is self-contained.$defsbundle viaucp-schema generate-types --schema-dir "$SCHEMA_DIR"($TMP_TYPES_JSON), invokesdatamodel-codegen --input-file-type jsonschema --output src/ucp_sdk/models/schemas/__init__.py --use-title-as-nameso inline objects, array items, and union branches use qualified semantic model names (TotalsItem,ValueConstraintEnum,ValueConstraintConst,ServiceBusinessSchemaRest,LocationServesAddressCountry,UnitPriceMeasure, etc.), and passes$TMP_TYPES_JSONdirectly topostprocess_models.py.templates/pydantic_v2/RootModel.jinja2template override.preprocess_schemas.pyand the 140-filesrc/ucp_sdk/models/schemas/{shopping,common,transports}/directory tree.src/ucp_sdk/models/__init__.pyto re-export all public symbols fromucp_sdk.models.schemas.postprocess_models.pyAdaptations:ucp-schema generate-types$defsbundle ($TMP_TYPES_JSON) directly as its single source of truth viaload_schema_defs(types_json_path)instead of re-walking rawSCHEMA_DIRfiles or maintaining hardcoded definition-name alias maps.datamodel-code-generator'sDict[annotations in__pydantic_extra__, and strips the syntheticUCPSchemaTypes/UcpSchemaTypesroot bundle alias.uniqueItemsconstraints from$defsinto generated classes (Oauth2Provider.required_claims,ValueConstraintEnum.enum,ValueConstraintConst.enum).dependentRequiredvalidators from$defsinto generated classes (Location.timezonewhenhoursorexception_hoursis present,FulfillmentMethodUpdateRequestBaserequiringtypewhendestinationsis present,PostalAddress/FulfillmentAddressstreet address dependencies).Total/TotalsItemconditional numeric bounds and custom-typedisplay_textrequirements, andUnitC62scale-zero constraints onMeasure,UnitPriceMeasure, andUnitPriceReference.not.requiredforbidden-key validators (JwkPublicKeyrejecting private-key JWK fieldsd,p,q,dp,dq,qi,oth,k) and open-unionnot.enumdiscriminator guards on<Union>Basefallback classes (FulfillmentDestinationBase,FulfillmentMethodBase,MediaBase,ProviderBase) so payloads carrying a known discriminator tag with malformed fields raiseValidationErrorrather than falling back to<Union>Base.tests/test_models.pytesting known and unknownFulfillmentDestinationandFulfillmentMethodvariants, fullCheckoutpayload round-tripping with unknown extension variants, missing discriminator rejection, and rejection of malformed known variants.tests/test_codegen_pipeline.pywith tests for semantic model names, omission of response-only request slices (OrderCreateRequest,TotalCreateRequest,TotalsCreateRequest),ShippingMethodUpdateRequest/PickupMethodUpdateRequestrequiredtypediscriminator andFulfillmentMethodUpdateRequestBasetypeless updates +dependentRequired: {"destinations": ["type"]},CapabilityBase.extendsscalar-or-list union (str | list[str]),ValueConstraintEnum/Oauth2ProvideruniqueItems,Locationtimezonedependency,TotalsItem/UnitPriceMeasureconditional bounds, andJwkPublicKeyforbidden private-key fields.Stacked PR Series Roadmap (
ucp-schemaTwo-Layer Codegen Pipeline)to_pascal_case,strip_ucp_keywords,rewrite_refs_to_defs, canonicaltitlenormalization)slice_directional_schemas,align_directional_refs)$defshoisting, overlay composition &generate_types()APIucp-schema generate-typesCLI subcommand & end-to-end integration tests.well-known/ucp--profilemode (src/codegen/profile.rs)src/codegen/reify.rs)anyOf<Union>Baseopen-union lowering (lower_conditional_unions)register_extended_subtypes)python-sdkpreprocess_schemas.pywithucp-schema generate-typesjs-sdkquicktype pre-processors &src/extensions.tswithucp-schema generate-types+json-schema-to-zoducp-schema)ucp-schema generate-openapibindingservice.schema(rest.openapi.json) to Layer 1 typesVerification
./generate_models.sh ../ucpand./generate_models.sh 2026-08-25uv run python -m unittest discover -s tests -v(150 tests passed)uv run ruff check . && uv run ruff format --check .