Skip to content

fix(rest/python): seed valid totals when creating a checkout - #152

Merged
damaz91 merged 1 commit into
Universal-Commerce-Protocol:mainfrom
vishkaty:fix/checkout-totals-construction-order
Jul 30, 2026
Merged

fix(rest/python): seed valid totals when creating a checkout#152
damaz91 merged 1 commit into
Universal-Commerce-Protocol:mainfrom
vishkaty:fix/checkout-totals-construction-order

Conversation

@vishkaty

@vishkaty vishkaty commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

Problem

With the totals contains cardinality now enforced on the response models (exactly one subtotal and one total), every POST /checkout-sessions returns 500.

create_checkout constructs the checkout with an empty totals list and fills it in during _recalculate_totals (the server is the authority for pricing). Construction runs the totals validator on that empty list and raises before recalculation:

pydantic_core.ValidationError: 1 validation error for UnifiedCheckout
totals
  Value error, Array must contain at least 1 entry matching type=='subtotal' (schema minContains=1)

The final wire document is fully valid (exactly one subtotal and one total) - this is purely about when the check fires.

Fix

Seed a valid placeholder ([{subtotal, 0}, {total, 0}]) at construction so the in-progress model satisfies the constraint; _recalculate_totals overwrites it with the server-authoritative amounts immediately after. Construction stays fully validated (no model_construct, so extension fields like discounts are still coerced normally), and the emitted wire document is unchanged. Single-site change in create_checkout (the update path mutates an already-valid checkout via assignment, which is not validated).

Placeholder entries are passed as dicts so pydantic coerces them to the field's own Total type, avoiding a generated-class identity mismatch.

Verification

Booted the reference flower-shop server and ran, with the totals validators active:

Before After
Conformance suite 2 pass / 67 fail 69 pass / 0 fail

Also green without the validators (released SDK, as this repo's CI resolves it), confirming it is safe to land independently:

  • Server integration tests (rest/python/server pytest): 16 passed
  • Happy-path client (simple_happy_path_client.py): completed

ruff format --check and ruff check clean.

Relates to Universal-Commerce-Protocol/python-sdk#57 (keeps that enforcement strict while keeping the reference server green).

The SDK now enforces the totals contains cardinality (exactly one subtotal
and one total) on the response models. create_checkout constructed the
checkout with an empty totals list and filled it in during recalculation,
so construction validated the empty list and rejected it, returning 500 on
every create.

Seed a valid placeholder (one subtotal + one total) at construction so the
in-progress model satisfies the constraint; _recalculate_totals overwrites
it with the server-authoritative amounts immediately after. Construction
stays fully validated, and the emitted wire document is unchanged.

Verified against the pinned SDK build with the totals validators active:
full conformance suite 69 passing / 0 failures (was 67 failures). Also
green without the validators: server integration tests (16) and the
happy-path client, so it is safe to land independently.

Relates to Universal-Commerce-Protocol/python-sdk#57
@vishkaty
vishkaty force-pushed the fix/checkout-totals-construction-order branch from 049f527 to 31660aa Compare July 29, 2026 15:43
@vishkaty vishkaty changed the title fix(rest/python): build checkout as transient before totals are computed fix(rest/python): seed valid totals when creating a checkout Jul 29, 2026
@damaz91 damaz91 added status:under-review and removed status:needs-triage Signal that the PR is ready for human triage labels Jul 30, 2026
@damaz91
damaz91 merged commit 0c27fa3 into Universal-Commerce-Protocol:main Jul 30, 2026
16 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants