Repository navigation
feat(codegen): add self-contained .well-known/ucp profile scoping for generate-types - #85
Conversation
ba01543 to
4e46cd3
Compare
4e46cd3 to
3ce648d
Compare
095e38d to
eae1f7e
Compare
3ce648d to
7ac4684
Compare
eae1f7e to
5a86208
Compare
61e89d2 to
f5391fa
Compare
5a86208 to
f7cdac2
Compare
f5391fa to
1cfab4d
Compare
2033502 to
f7a1e9d
Compare
1cfab4d to
18f89c0
Compare
f7a1e9d to
013e1cf
Compare
18f89c0 to
280bc37
Compare
013e1cf to
bc1c420
Compare
280bc37 to
20358f7
Compare
20358f7 to
802c9a3
Compare
|
Reviewed this as a downstream consumer: our conformance suite drives The feature works. 1. CI is red on the current head. Run The value on the left arrives through 2. Removing the The behaviour itself is correct, and a profile pair off the real ucp tree pins it. Both profiles declare
One trap for anyone copying the pair: the FQDN must be The discriminating assertion is the narrow row: with fulfillment extending checkout only, the bundle must not contain 3. The two tests that carry the PR claims do not run in CI. 4. URL to local relocation discards the authority. Observed. A capability at Local mode and relocation are deliberate, but one authority is substituted for another with no notice, which matters for the multi origin vendor extension case the PR body names. The prefix before For what it is worth on the consumer side: across 60 |
802c9a3 to
6e678c1
Compare
|
Thanks for the sharp review, @vishkaty — all four items are now fixed in
|
6e678c1 to
ca2b208
Compare
| .schema | ||
| .get("$id") | ||
| .and_then(Value::as_str) | ||
| .is_some_and(|id| id.starts_with("https://ucp.dev/")); |
There was a problem hiding this comment.
One edge case to consider here is if the schema file "maliciously" declare the UCP URL in $id to allow their own vendor type to be considered as the core UCP type and be preserved.
Maybe a stronger assertion here should factor in where the LoadedSchema came from - e.g., it can either be via schema-dir in normal local mode OR in the profile mode, the associated URL's domain defined in schema in the profile.
There was a problem hiding this comment.
Fixed in 5aa23b8. LoadedSchema now tracks owner_namespace: Option<String> propagated from the authority-validated capability name (or target URL host on external $refs), and is_ucp_owned, derive_vendor_prefix, and record_local_schema_root validate against owner_namespace instead of trusting self-declared $id values.
| let Some(prefix) = derive_vendor_prefix(&loaded[idx]) else { | ||
| continue; | ||
| }; | ||
| if stem.starts_with(&prefix) { |
There was a problem hiding this comment.
nit: This introduces a similar same issue as #83 (comment) where this if statement will get triggered if let's say the prefix resolves to Payment and triggering the exception on name collisions done the line.
Can we also remove this special condition to force a rename?
There was a problem hiding this comment.
Fixed in 5aa23b8 — removed the if stem.starts_with(&prefix) { continue; } skip so colliding standalone stems that happen to start with the vendor prefix still get disambiguated.
| local_schema_roots: &[LocalSchemaRoot], | ||
| ) -> Option<String> { | ||
| let target_origin = url_origin(url_str)?; | ||
| let (_, rel_after_schemas) = url_str.split_once("/schemas/")?; |
There was a problem hiding this comment.
This line here purposely drops the version prefix in the UCP URL (e.g., 2026-04-08 will be dropped from https://ucp.dev/2026-04-08/schemas/shopping/types/line_item.json in rel_after_schemas).
When we reconstruct it using the local root below, you would essentially map the schema under the same local file. So in the extension declaration, if let's say a vendor extension declared in the profile references/composes using an older version of the UCP type, they would still get whatever version the local file is on.
Should we include at least the version prefix immediately before the/schemas on top of the origin check before applying relocation (otherwise we should always be forcing a fetch from the URL)?
There was a problem hiding this comment.
Fixed in 5aa23b8. LocalSchemaRoot now records version: Option<String> (from the schema $id or capability entry) and relocate_url_to_local_schemas extracts the version segment before /schemas/ via split_url_marker and requires version compatibility before relocating.
5aa23b8 to
9140b28
Compare
Summary
Implements Task 5 (PR 2) of the two-layer
ucp-schemacode-generation pipeline: self-contained.well-known/ucpprofile scoping (--profile <PATH_OR_URL>) forucp-schema generate-types, stacked on #84.Changes
src/codegen/profile.rs):RestServiceBinding,ParsedProfile,parse_profile_source, andload_and_compute_profile_closureto load.well-known/ucpprofiles from a local file path or HTTP(S) URL, validate namespace authority bindings viacompose::verify_bindings, and extracttransport == "rest"service bindings alongsideucp.capabilities.User-Agentheader (ucp-schema/<version>) onreqwest::blocking::Clientinsrc/loader.rsso Cloudflare-fronted merchant.well-known/ucpendpoints resolve directly over HTTPS.extendsparents are absent from the profile's active capability set (or were themselves pruned), emittingwarning: pruning orphaned extension '<name>' ...tostderrper the UCP Intersection Algorithm."schema"URL or path (supporting multi-origin vendor extensions such asdev.shopify.catalogalongsidedev.ucp.*schemas), crawls relative and absolute child$refs against each parent schema's base location, and seeds ambient protocol roots (common/types/error_response.jsonandprofile.json) relative toucp.jsonso--profilemode produces the exact same$defsclosure as--schema-dirmode.extendsTarget Scoping & Multi-Tier Mixin Composition:extendsarray (declared_extendsonLoadedSchema) and recurses into nestedallOfbranches inmerge_extension_into_schemafor multi-tier operation mixins.--profileand--schema-dir/--capability/--extensionongenerate-typesand removes the unused--schema-remote-baseand--schema-local-baseflags.Stacked PR Series Roadmap
$refrewriting (src/codegen/normalizer.rs)$refalignment (src/codegen/normalizer.rs)generate_types()library API (src/codegen/{mod,reachability,hoist,compose}.rs)generate-typessubcommand (src/bin/ucp-schema.rs,tests/generate_types_test.rs).well-known/ucp--profilescoping (src/codegen/profile.rs)src/codegen/normalizer.rs,src/codegen/reify.rs)<Union>Base) (src/codegen/reify.rs)src/codegen/reify.rs)generate_models.sh,postprocess_models.py,src/ucp_sdk/models/)generate_models.sh,scripts/generate-zod-from-types.mjs,src/spec_generated.ts)ucp-schema generate-openapi,src/openapi/mod.rs)Test Plan
cargo fmt --checkcargo test --all-targetscargo clippy --all-targets -- -D warnings