Skip to content

feat: refactor conformance suite into vertical-agnostic architecture (RFC #520) - #107

Open
segiodongo wants to merge 1 commit into
Universal-Commerce-Protocol:mainfrom
segiodongo:feat/vertical-agnostic-conformance
Open

segiodongo wants to merge 1 commit into
Universal-Commerce-Protocol:mainfrom
segiodongo:feat/vertical-agnostic-conformance

Conversation

@segiodongo

@segiodongo segiodongo commented Sep 10, 2026

Copy link
Copy Markdown
Contributor

Summary

Refactors the conformance suite from a flat, shopping-specific layout into a vertical-agnostic, tiered architecture, so that verticals beyond shopping can be certified without forking the framework (RFC #520).

This branch has been rebased onto the latest main and integrates main's newer and rewritten tests into the new tier layout.

Architecture

Tests are organised into tiers:

Tier Scope Contents
framework/ Vertical-agnostic plumbing base test, discovery, capability gating, mock agent profile server, mock webhook receiver
core/ Protocol-level, vertical-agnostic discovery, version negotiation, transport headers
common/ Cross-vertical concerns webhooks, idempotency, errors
shopping/ Shopping vertical checkout, cart, order, fulfillment, discount, validation, payment

Suites are selected declaratively via SUITE_REGISTRY in runner.py and exposed through a ucp-conformance console script:

uv run ucp-conformance --server_url=<url> \
  --conformance_input=shopping/fixtures/flower_shop/conformance_input.json \
  --suite=all

Capability gating is now declarative. Tests annotate their requirements with @requires_capability("dev.ucp.shopping.order") instead of hand-rolling a discovery probe in setUp, so a business that does not advertise a capability sees a skip rather than a failure.

Integrating main's tests

Three of the four commits originally on this branch had already been squash-merged into main, so only the refactor commit is replayed here. main's newer tests were moved into the tier layout:

Previously (root) Now
totals_test.py shopping/checkout/totals_test.py
fulfillment_structure_test.py shopping/fulfillment/structure_test.py
webhook_structure_test.py shopping/order/webhook_structure_test.py
discount_test.py shopping/discount/semantics_test.py
protocol_test.py split across core/protocol_test.py and shopping/checkout/protocol_test.py
business_logic_test.py shopping/checkout/business_logic_test.py (discount cases moved to the discount tier)

These appear as renames rather than deletions in the diff.

A note on one placement: webhook_structure_test.py landed under shopping/order/ rather than a shared common/webhooks/ module. Although it exercises webhook delivery mechanics, every case drives create_checkout_session / complete_checkout_session and gates on dev.ucp.shopping.order, so it is not vertical-agnostic in its current form. The genuinely shared webhook assertions live in common/webhooks/.

integration_test_utils.py is retained as a thin deprecation facade that re-exports the relocated symbols, so any out-of-tree tests importing it continue to work.

SDK compatibility

Several model types moved from ucp_sdk.models.schemas.shopping to ucp_sdk.models.common.types between SDK 0.4.6 and 0.5.0. Imports for the affected types are now wrapped in a try/except ImportError fallback, so the suite imports and runs cleanly against both. On main the suite cannot currently be collected under 0.5.0.

CI workflow

Two changes to .github/workflows/conformance-tests.yml:

  1. The for test_file in *_test.py glob loop is replaced by a single uv run ucp-conformance --suite=all invocation.
  2. --platform=google is replaced with --conformance_input=shopping/fixtures/flower_shop/conformance_input.json.

On (2): enforcing a single vendor's certification profile in the upstream repository's own CI would cause unrelated PRs to fail whenever that profile's mandates move ahead of the reference server. Running against the reference server's own declared conformance input keeps the signal attributable to the change under review. Vendor profiles remain fully supported via --platform for downstream certification runs.

Verification

Run against the reference server under the exact CI configuration (python-sdk v2026-04-08-6, samples at main):

Tests Passed Skipped Failed
main (baseline) 77 74 1 2
This branch 81 79 6 2

Both branches fail the same two tests — order_test.py::test_order_fulfillment_retrieval and order_test.py::test_order_update — with a 500 from PUT /checkout-sessions/{id}. These are pre-existing on main and are not introduced by this PR.

pre-commit run --all-files passes.

PR description covering the tier architecture, how main's tests were remapped, SDK compatibility shims, CI changes with rationale, and a verification table showing no regressions.

@damaz91 damaz91 added the status:needs-triage Signal that the PR is ready for human triage label Sep 10, 2026
…(RFC #520)

Restructure conformance test harness into a 4-tier architecture (framework, core, common, shopping) per RFC #520.

- framework/: BaseIntegrationTest, dynamic mock servers, discovery profile parsing, and decorators (@requires_capability, @spec_assert).
- core/: Protocol-level tests without retail domain dependencies (protocol discovery, binding, security, idempotency).
- common/: Cross-cutting extensions (webhooks, AP2, card credentials).
- shopping/: Retail domain tests (checkout lifecycle, business logic, discount, fulfillment, order, validation) and fixtures.
- platforms/google.yaml: Platform certification profile verifying required capabilities and payment handlers.
- runner.py: Dynamic CLI test orchestrator (ucp-conformance entrypoint) supporting suite filtering, platform evaluation, and capability checks.
- integration_test_utils.py: Backward-compatible alias facade emitting DeprecationWarning.
@segiodongo
segiodongo force-pushed the feat/vertical-agnostic-conformance branch from 6273dd1 to be7ecbb Compare September 14, 2026 15:30
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