Skip to content

docs: add proposal for basemessage and messagegroups that allows for …#467

Merged
duglin merged 5 commits into
xregistry:mainfrom
thirschel-microsoft:thirschel/uri-proposal
May 22, 2026
Merged

docs: add proposal for basemessage and messagegroups that allows for …#467
duglin merged 5 commits into
xregistry:mainfrom
thirschel-microsoft:thirschel/uri-proposal

Conversation

@thirschel-microsoft

@thirschel-microsoft thirschel-microsoft commented May 20, 2026

Copy link
Copy Markdown
Contributor

Proposal: Change basemessage and messagegroups from XID to URI-Reference

Summary

Change two attributes from Type: XID (same-registry only) to
Type: URI-reference (relative XIDs and absolute URIs):

  1. basemessage on Message definitions, enabling cross-registry message
    inheritance.
  2. messagegroups on Endpoint definitions, enabling endpoints to reference
    MessageGroups in external registries.

Both changes remain fully backward compatible.

Motivation

basemessage enables message inheritance with deep-merge semantics: a derived
message references a base and shadows specific properties. messagegroups on
endpoints references the MessageGroups whose messages the endpoint handles.

Both attributes are currently typed as XID, restricting references to the same
registry. In multi-registry environments, message contracts defined in one
registry are consumed by endpoints in another. The XID restriction forces
either duplicating definitions across registries or using ad-hoc workarounds.

Why These Changes Are Safe

Backward Compatible

Every existing basemessage value is a relative XID (e.g.,
/messagegroups/group1/messages/msg1). Every existing messagegroups entry
is a relative XID (e.g., /messagegroups/mygroup). Under the new type:

  • Relative references beginning with / are validated as XIDs with the
    target constraint, which is identical behavior to today.
  • Only absolute URIs are new, and they are additive.

No existing data or behavior changes.

Consistent with Existing Patterns

The message spec already uses this exact pattern for schema references:

Attribute Type Same-Registry Cross-Registry
dataschemaxid xid
dataschemauri uri ✓ (as relative) ✓ (as absolute)
basemessage (current) xid
basemessage (proposed) uri-reference ✓ (as relative) ✓ (as absolute)
messagegroups items (current) xid
messagegroups items (proposed) uri-reference ✓ (as relative) ✓ (as absolute)

The dataschemauri / dataschemaxid pair is the existing precedent: URI type
for cross-registry references, XID for same-registry validation.

Dangling References Already Permitted

The spec states: "If the referenced message can not be found then an error
MUST NOT be generated, dangling references are permitted."

An absolute URI to an unreachable external registry is equivalent to
a dangling XID reference. The existing error handling covers this.

Resolution Is Client-Side

The spec says: "The processing that a client SHOULD take to materialize
the message..."
Materialization is a client responsibility. The server stores
the reference; the client resolves it. Whether the target is a local XID or an
external URI is a client concern.

The Model Already Uses URI

The model.json already defines basemessageurl as type: "uri". This
proposal aligns the spec prose with the model.

Core Spec Infrastructure Exists

The core model spec (core/model.md:243-247) defines the behavior:

"A URI/URL-reference entity attribute MAY include target as part of its
definition. If so, then any runtime value that is a relative URI/URL
(begins with /) MUST be an xid and MUST adhere to the target entity
type specified, if specified. Absolute URIs/URLs are not constrained by
the presence of a target value.
"

Relative references are validated as XIDs; absolute URIs pass through
unconstrained. This mechanism is already in place.

Server Behavior

basemessage

Scenario Server Action
Relative XID: /messagegroups/g1/messages/m1 Validate as XID with target /messagegroups/messages[/versions]. Store. May resolve locally for inline expansion.
Absolute URI: https://other.registry/messagegroups/g1/messages/m1 Store as-is. No validation, no resolution, no fetching.
Malformed relative: /notavalidpath Error: malformed_xid (same as today)
Dangling XID: /messagegroups/deleted/messages/gone Store. No error. (same as today)
Unreachable absolute URI Store. No error. (dangling reference)

messagegroups

Scenario Server Action
Relative XID: /messagegroups/mygroup Validate as XID with target /messagegroups/messages. Store. Resolve locally for inline expansion.
Absolute URI: https://other.registry/messagegroups/external Store as-is. No validation, no resolution, no fetching.
Malformed relative: /notavalidpath Error: malformed_xid (same as today)
Dangling XID: /messagegroups/deleted Store. No error.
Unreachable absolute URI Store. No error.

Client Behavior

Client receives message with basemessage:
  ├── Value starts with "/"?
  │   └── YES: Resolve as XID within same registry
  │            GET {registry-base}{basemessage}/$details
  │            Perform deep-merge
  │
  └── NO (absolute URI):
      └── Resolve as absolute URI (client has credentials)
          GET {basemessage}/$details
          Perform deep-merge
          (If unreachable, treat as dangling; use message as-is)

Example: Cross-Registry Message Inheritance

Registry A (https://catalog-a.example.com) defines base CloudEvents messages.
Registry B (https://catalog-b.example.com) defines endpoint-specific variants.

Base message in Registry A

{
  "messageid": "com.xyz.orders.created",
  "envelope": "CloudEvents/1.0",
  "envelopemetadata": {
    "type": {
      "value": "com.xyz.orders.created",
      "required": true
    }
  },
  "dataschemaformat": "Avro/1.12.0",
  "dataschemauri": "/schemagroups/com.xyz.orders/schemas/com.xyz.orders.created"
}

Derived message in Registry B (endpoint-specific override)

{
  "messageid": "com.xyz.orders.created.eventhubs",
  "basemessage": "https://catalog-a.example.com/messagegroups/com.xyz.orders/messages/com.xyz.orders.created",
  "envelope": "CloudEvents/1.0",
  "protocoloptions": {
    "messagemappings": {
      "headers": {
        "ce-source": { "value": "/xyz/order-service" }
      }
    }
  }
}

The client fetches the base from Registry A, performs the deep-merge, and
produces a materialized message with the original schema reference plus the
endpoint-specific header mapping.

Registry B's server never contacts Registry A. It stores the absolute URI.
The client resolves it using its own credentials.

@duglin

duglin commented May 20, 2026

Copy link
Copy Markdown
Contributor

@thirschel-microsoft thanks. We're not quite as formal as this :-) Putting the text you wrote into an issue or PR comment is all that's needed - no need for a formal "proposal" doc that's checked into the repo. The actually PR code-changes should just include the spec-level changes you want made.

@thirschel-microsoft

Copy link
Copy Markdown
Contributor Author

@thirschel-microsoft thanks. We're not quite as formal as this :-) Putting the text you wrote into an issue or PR comment is all that's needed - no need for a formal "proposal" doc that's checked into the repo. The actually PR code-changes should just include the spec-level changes you want made.

No problem, i've updated the PR

Comment thread message/model.json Outdated
@@ -33,8 +33,9 @@
"attributes": {
"basemessageurl": {

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.

s/url/uri/g

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.

Updated

@duglin

duglin commented May 20, 2026

Copy link
Copy Markdown
Contributor

@thirschel-microsoft can you sign your commits? (git commit -s)

…absolute urls

Signed-off-by: Tyler Hirschel <thirschel@microsoft.com>
Signed-off-by: Tyler Hirschel <thirschel@microsoft.com>
@thirschel-microsoft

Copy link
Copy Markdown
Contributor Author

Signed the commits

@deissnerk

Copy link
Copy Markdown
Contributor

This looks good to me. It makes use of the URI concept with target in exactly the way we intended it, and it doesn't block us from introducing a special URI scheme for absolute xids in the future.

Comment thread endpoint/spec.md Outdated
Comment thread message/spec.md Outdated

When the value is a relative reference (begins with `/`), it MUST be a
valid XID referencing a Resource, or Version, of type `message` within the
same registry. When the value is an absolute URI, it SHOULD resolve to a

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.

why not MUST?

@thirschel-microsoft thirschel-microsoft May 21, 2026

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 left it as SHOULD in the relative case because the server can verify that the message does exist and can offer validation. That same validation isn't available to the server if it is an external link.

If we feel the language here is better as MUST I will change it

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.

We'll discuss it on tomorrow's call,but I'm leaning towards making it a MUST. Even though specs often try to avoid hard requirements for things that can't be tested, I'm uncomfortable with someone using the wiggle-room to put something else at the URI other than a msgDef as an extension.

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.

Yeah that point makes sense. Updated. Just let me know if you want it changed back based on the discussion

Comment thread message/spec.md Outdated
as defined by this specification.
- If the value is a relative reference, it MUST be a valid `xid` of a
Resource, or Version, of type `message` as defined by this specification.
- If the value is an absolute URI, it SHOULD point to a message definition

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.

same question here, why not MUST since when it's an XID it's a MUST?

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.

Updated

@duglin

duglin commented May 21, 2026

Copy link
Copy Markdown
Contributor

LGTM just a few minor questions

Signed-off-by: Tyler Hirschel <thirschel@microsoft.com>
Signed-off-by: Tyler Hirschel <thirschel@microsoft.com>
Comment thread message/spec.md Outdated

When the value is a relative reference (begins with `/`), it MUST be a
valid XID referencing a Resource, or Version, of type `message` within the
same registry. When the value is an absolute URI, it MUST resolve to a

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.

Per our call today, we're ok with MUST but let's change "resolve to" to "point to" so we don't imply that ALL clients need to be able to resolve it. There may be other spots where we need to make this change too

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.

Updated

Signed-off-by: Tyler Hirschel <thirschel@microsoft.com>
@duglin

duglin commented May 22, 2026

Copy link
Copy Markdown
Contributor

Approved on the 5/21 call - with minor tweaks

@duglin
duglin merged commit 2d4635c into xregistry:main May 22, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants