Skip to content

fix: compose extensions when any parent is active#39

Open
igrigorik wants to merge 2 commits into
mainfrom
fix/multi-parent-composition
Open

fix: compose extensions when any parent is active#39
igrigorik wants to merge 2 commits into
mainfrom
fix/multi-parent-composition

Conversation

@igrigorik

Copy link
Copy Markdown
Contributor

The UCP intersection algorithm states:

Remove any capability where extends is set but none of its parent capabilities are in the intersection...
For multi-parent extensions (extends: ["a", "b"]): at least one parent must be present.

The composer required every parent in extends[] to be present in the active response graph. For example, Discount can extend either Cart or Checkout:

{
  "dev.ucp.shopping.discount": [{
    "extends": [
      "dev.ucp.shopping.cart",
      "dev.ucp.shopping.checkout"
    ]
  }]
}

A response containing Checkout + Discount capability, but not Cart, previously failed with:

extension 'dev.ucp.shopping.discount' references unknown parent 'dev.ucp.shopping.cart'

Updated logic allows above / aligns with normative requirement in the UCP spec.


Checklist

  • Infrastructure: CI/CD, Linters, or build scripts. (Requires DevOps Maintainer approval)
  • I have followed the Contributing Guide
  • 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.

The UCP intersection algorithm states:

“Remove any capability where `extends` is set but none of its parent
capabilities are in the intersection.”

“For multi-parent extensions (`extends: ["a", "b"]`): at least one parent
must be present.”

— docs/specification/overview.md, “Intersection Algorithm”

The composer instead required every declared parent to be active. Discount
extending `[Cart, Checkout]` therefore failed to compose into a Checkout
response when Cart was absent.

Remove the all-parents-present check and retain root-reachability validation.
Extensions with no path to the active root remain rejected. Add Cart and
Checkout regressions for root-specific `$defs` selection, parent ordering,
orphan rejection, and cycle termination.
@igrigorik igrigorik self-assigned this Jul 9, 2026
@igrigorik igrigorik requested a review from wry-ry July 9, 2026 23:18
@damaz91 damaz91 added the status:needs-triage Signal that the PR is ready for human triage label Jul 9, 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