Skip to content

refactor!: Refactor common primitive types from shopping/types to common/types - #736

Merged
jingyli merged 9 commits into
Universal-Commerce-Protocol:mainfrom
jingyli:vertical-types
Aug 21, 2026
Merged

refactor!: Refactor common primitive types from shopping/types to common/types#736
jingyli merged 9 commits into
Universal-Commerce-Protocol:mainfrom
jingyli:vertical-types

Conversation

@jingyli

@jingyli jingyli commented Aug 18, 2026

Copy link
Copy Markdown
Contributor

Description

A continuation of #436, addressing Phase 3 + 4 in that PR. Also related to #723 when it comes to schema types clean-ups that go hand-in-hand with specification refactoring.

Design choices made in this PR:

  • Refactor 7 common primitives from source/schemas/shopping/types/ to source/schemas/common/types/:
    • context.json
    • signals.json
    • totals.json
    • total.json
    • policy.json
    • price_filter.json
    • price_range.json
  • Decided to leave attribution.json out-of-scope for now as we haven't fully vetted the design for x-vertical usages.
  • No changes to documentation/specification rendering (taken care of in refactor: organize specification hierarchy by domain verticals (Shopping, Payment, Common)  #723) and payment constructs (separate PR).

Category (Required)

Please select one or more categories that apply to this change.

  • Core Protocol: Changes to the base communication layer, global context, or breaking refactors. (Requires Technical Council approval)
  • Governance/Contributing: Updates to GOVERNANCE.md, CONTRIBUTING.md, or CODEOWNERS. (Requires Governance Council approval)
  • Capability: New schemas (Discovery, Cart, etc.) or extensions. (Requires Maintainer approval)
  • Documentation: Updates to README, or documentations regarding schema or capabilities. (Requires Maintainer approval)
  • Infrastructure: CI/CD, Linters, or build scripts. (Requires DevOps Maintainer approval)
  • Maintenance: Version bumps, lockfile updates, or minor bug fixes. (Requires DevOps Maintainer approval)
  • SDK: Language-specific SDK updates and releases. (Requires DevOps Maintainer approval)
  • Samples / Conformance: Maintaining samples and the conformance suite. (Requires Maintainer approval)
  • UCP Schema: Changes to the ucp-schema tool (resolver, linter, validator). (Requires Maintainer approval)
  • Community Health (.github): Updates to templates, workflows, or org-level configs. (Requires DevOps Maintainer approval)

Related Issues

Phase 2 in #520

Checklist

  • I have followed the Contributing Guide (including Conventional Commits title requirements and ! for breaking changes).
  • I have updated the documentation (if applicable).
  • My changes pass all local linting and formatting checks.
  • I have added tests that prove my fix is effective or that my feature works.
  • New and existing unit tests pass locally with my changes.
  • (For Core/Capability) I have included/updated the relevant JSON schemas.
  • I have regenerated Python Pydantic models by running generate_models.sh under python_sdk.

Screenshots / Logs (if applicable)

Manually validated via local ucp.dev to ensure that none of the reference links in the existing reference.md will break.

Also a screenshot example of how the inline rendering now looks like in capability pages:
inline-rendering

@igrigorik igrigorik left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall, looks good. Two documentation flags before we land this...

Can we preserve inline schema rendering?

Moving these schemas into common/types/ activates the existing shared-type behavior in schema_fields: inline field tables on the Catalog, Cart, Checkout, Fulfillment, and Order pages are replaced with links to the Schema Reference. That's a lot of external refs that were previously directly visible in the document, which I think is a meaningful regression.

This should require only small surgery in main.py. I would make inline rendering the default and make link-only rendering an explicit opt-out:

def schema_fields(entity_name, spec_file_name, inline=True):
    ...

    if (
        not inline
        and spec_file_name != "reference"
        and _resolves_to_shared_type(base_name) is not None
    ):
        return _render_shared_type_link(base_name, spec_file_name)

Call sites that intentionally want only the canonical-reference link can then opt out explicitly:

{{ schema_fields('types/postal_address', 'checkout', inline=False) }}

Nit: stale totals.json reference

The complete Checkout example in docs/documentation/schema-authoring.md still contains:

"totals": {"$ref": "types/totals.json"}

After this move, the correct relative reference from shopping/checkout.json is ../common/types/totals.json.

@jingyli

jingyli commented Aug 20, 2026

Copy link
Copy Markdown
Contributor Author

Thanks @igrigorik!

Can we preserve inline schema rendering?

I'd like to take a step back and make sure we are aligned on the rendering principles here. Based on #536, we aligned that:

  • Inline rendering on capabilities page: any vertical specific types (e.g., shopping/types/buyer.json, shopping/types/line_item.json)
  • Redirect to reference.md: reserved for common/types only

Personally I think the increase in external refs/redirects from this PR is WAI and consistent with the expectation we want to set with developers. The net new effects:

Capability Page Pre-PR #736 (PR #536 Baseline) Post-PR #736 Newly Redirected Types (+Δ)
cart 5 8 +3 (Context, Signals, Total)
checkout 8 11 +3 (Context, Signals, Total)
catalog/index 5 8 +3 (Context, Signals, Price Range)
catalog/search 2 3 +1 (Price Filter)
fulfillment 1 2 +1 (Total)
order 1 2 +1 (Total)
embedded-checkout 1 1 0 (no refactored types referenced)
Total 23 35 +12 newly redirected instances

I'm also fine to always inline schema rendering by default on capabilities documentation, but I want to make sure it then means we are doing it consistently to all common/types (and not have an split between the two styles selectively), which means technically it will remove all the effects of the redirect predicates and force them to render inline on capability pages.

Nit: stale totals.json reference

Good catch! I realized that there was one more stale reference to (link.json) so fixed both in 2de5f4a.

@jingyli
jingyli requested a review from igrigorik August 20, 2026 01:08
@igrigorik

Copy link
Copy Markdown
Contributor

which means technically it will remove all the effects of the redirect predicates and force them to render inline on capability pages.

@jingyli my vote is for inline render. The main reason to avoid it is due to risk of them getting out of sync in different places, but since these are auto-resolved + inlined refs and we rebuild the whole tree, that risk is a no-op. By inlining we get the benefit of much easier and friendlier reading and comprehension -- no need to jump across tabs, etc.

…. By default, we will always force an inline rendering and only redirect if the caller explicitly opted out.
@jingyli

jingyli commented Aug 20, 2026

Copy link
Copy Markdown
Contributor Author

@igrigorik Sounds good, PTAL at 623b2c8 - this updates both schema_fields and extension_schema_fields consistently to by default force inline rendering on all common/types schemas (also attached a sample example screenshot of checkout.md in the PR description).

Correct the checkout schema example to model links as an array of the
singular shared link type.

Align the shared-type resolver documentation with the default-inline
rendering policy used by capability pages.

@igrigorik igrigorik left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jingyli pushed a small fix: de7f17e — ptal.

LGTM.

Comment thread main.py
# itself always renders full tables via auto_generate_schema_reference.
# base_name is passed (suffix stripped) so the link anchor targets
# the canonical heading.
if (

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: Note that _resolves_to_shared_type(base_name) strips suffixes but assumes base_name does not already end with .json. If a caller passes a .json path or pointer with #, _resolves_to_shared_type can construct .json.json. Normalizing clean = str(ref_path).split('#', 1)[0] and name = Path(clean).stem in _resolves_to_shared_type avoids this edge case.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree with the suggestion to strengthen our parsing logic in _resolves_to_shared_type, though just calling out the gap more explicitly here with our current logic:

We may unintentionally introduce false negatives: i.e. schema_fields('context.json', ..., render_inline=False) will cause _resolves_to_shared_type to attempt resolve whether /common/types/context.json.json exists - which will result in None being returned from the function and the redirect rendering will not happen.

Another downside here is that it also expects the author to read through main.py to understand what ref_path we truly expect (which may or may not be a huge problem - if I play the devil's advocate here, we are forcing consistency since all other forms will result in broken documentation rendering and and the author will need to correct/fix the incorrect `ref_path).

Comment thread main.py Outdated
Comment thread main.py Outdated
@amithanda

Copy link
Copy Markdown
Contributor

Overall, this refactor is in great shape and is a solid step forward for the multi-vertical roadmap (#520). The switch to render_inline=True by default in main.py is a great documentation UX win.

Before we land this breaking refactor, here are a few non-blocking suggestions to address before merging:

1. SDK Model Regeneration

  • In the PR checklist, - [ ] I have regenerated Python Pydantic models by running generate_models.sh under python_sdk is currently unchecked.
  • Because moving these 7 schemas to common/types/ changes class namespaces and import paths (e.g., ucp.models.shopping.types.context $\rightarrow$ ucp.models.common.types.context), please ensure SDK models are regenerated and verified prior to release (and this box is checked).

2. Schema Authoring Guide Update (render_inline)

  • The new render_inline parameter in schema_fields and extension_schema_fields is great. Could we add a brief example in docs/documentation/schema-authoring.md demonstrating how capability authors can pass render_inline=False (e.g., {{ schema_fields('types/context', 'checkout', render_inline=False) }}) when they explicitly want to emit a reference link instead of an inlined table?

@jingyli

jingyli commented Aug 21, 2026

Copy link
Copy Markdown
Contributor Author

Thanks @amithanda!

1. SDK Model Regeneration

Ack on this - I think a known gap is that our current generation script cannot be executed on draft PRs (even if there is a way to hack around it, it's not very well documented) and we will need to think about how to streamline that so that checkbox in the PR template makes sense for developers (@gsmith85 FYI).

FWIW, when I tried regenerating the Python SDK based on the current main branch, there are already some warnings popping up to which we should sift through as part of the upcoming release.

2. Schema Authoring Guide Update (render_inline)

I gave this some thoughts when updating the script (e.g., documenting down our principles like always force inline type rendering on specification pages). But I think right now Schema Authoring is very targeted to conventions for authoring UCP JSON schemas and this kind of content/examples don't really fit well.

I think as a follow-up, maybe we should create a sibling page called Specification Authoring that would capture this, along with how our specification markdown files should be structured (as a consequence of #723), etc. Let me track this as a TODO to follow-up!

@jingyli
jingyli merged commit 64842b7 into Universal-Commerce-Protocol:main Aug 21, 2026
19 checks passed
@jingyli
jingyli deleted the vertical-types branch August 21, 2026 00:33
@dkoch74 dkoch74 added the area:payments Issues and pull requests related to the Payments vertical label Aug 28, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:payments Issues and pull requests related to the Payments vertical TC review Ready for TC review

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants