Skip to content

fix: accept the spec's in-band posture for payment failure (drop 402/prose pin) - #77

Open
vishkaty wants to merge 1 commit into
Universal-Commerce-Protocol:mainfrom
vishkaty:fix/payment-failure-postures
Open

fix: accept the spec's in-band posture for payment failure (drop 402/prose pin)#77
vishkaty wants to merge 1 commit into
Universal-Commerce-Protocol:mainfrom
vishkaty:fix/payment-failure-postures

Conversation

@vishkaty

@vishkaty vishkaty commented Aug 8, 2026

Copy link
Copy Markdown
Contributor

Observed

test_payment_failure (validation_test.py) asserts the payment-failure response is HTTP 402 with the substring "Payment Failed". Both are stricter than the 2026-04-08 spec:

  • 402 is not in the spec. It appears nowhere in the 04-08 docs or schemas. payment_failed is a standard error message code (checkout.md error-code table; types/error_code.json), and checkout-rest.md ("Error Responses") states business outcomes "Return HTTP 200 with UCP envelope and messages array." So a spec-conformant server returning 200 + a messages[] entry with code: payment_failed fails this check.
  • The prose is the sample's mock string (samples/rest/python/server/services/checkout_service.py: "Payment Failed: Insufficient Funds (Mock)"), not a spec-mandated message. Any conformant server with different wording fails.

Fix

Use the file's own dual-posture helper assert_business_error(response, accepted_codes={"payment_failed"}, error_4xx_substring="payment") — already used by test_out_of_stock and test_structured_error_messages in the same file. This accepts either the in-band 200 + messages[code=payment_failed] posture or a payment-related 4xx, without pinning 402 or asserting sample prose.

Verification

The relaxed check still catches a genuinely non-conformant server: a server that silently completes the checkout (200, status: completed), returns a wrong/missing error code, a broken envelope, or a non-answer all still fail. The reference server's existing 402 posture still passes (no regression), and validation_test.py passes on both the Python and Node references.

Observed: test_payment_failure required HTTP 402 plus the English
prose Payment Failed in the response body. The status code 402 appears
nowhere in the 2026-04-08 specification, and the prose is the
hardcoded mock string of the Flower Shop sample server (Payment
Failed: Insufficient Funds (Mock)), not a spec requirement.

Expected: payment_failed is a standard error message code (checkout.md
error code table; error_code.json), and checkout-rest.md Error
Responses prescribes that business outcomes return HTTP 200 with the
UCP envelope and a typed messages[] entry. A conformant server that
answers completion with HTTP 200 and a payment_failed error message
failed this test with: Expected status 402, got 200.

The fix routes the assertion through assert_business_error, the same
dual posture helper already used by test_out_of_stock and
test_structured_error_messages in this file: a 4xx rejection must
describe the payment problem in its body, and a 2xx answer must carry
a full typed error message with code payment_failed on a checkout that
has not completed and carries no order. The relaxation stays sound: a
server that neither rejects with a 4xx nor reports payment_failed in
band, or that silently completes the checkout, still fails. Verified
against both the Python and the Node reference servers (both suites
green) and against stub servers implementing the in band posture and
two genuinely broken behaviors.
@damaz91 damaz91 added the status:needs-triage Signal that the PR is ready for human triage label Aug 8, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

status:needs-triage Signal that the PR is ready for human triage

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants