CDEvents Namespacing Proposal (WSDL-Inspired)
CDEvents Namespacing Proposal (WSDL-Inspired)
Purpose
Propose a standardized, extensible namespacing convention for CDEvents to support:
- Organizational and vendor-defined events
- Experimental schemas
- Clear schema versioning
- Collision-free graph traversal in a SDLC workflow orchestrator or similar system
- Smooth consumption via DSLs and typed libraries
- Explicit schema validation via
schemaUri
Background
As CDEvents adoption grows, contributors and implementers face the need to:
- Extend existing events for domain- or org-specific use cases
- Define new events without a central coordination delay
- Maintain semantic interoperability across toolchains
- Validate events consistently in code and DSLs
This proposal draws from WSDL’s targetNamespace model and extends it with structured event typing, schema binding, and semantic versioning.
Event Type Format
We define a structured event type format as follows:
<namespace>.<subject>.<predicate>.<version>
| Component | Description |
|---|---|
namespace |
Owning org or domain (e.g., dev.cdevents, org.jpmc, com.harness) |
subject |
The entity or process the event describes (e.g., pipelineRun, branch, testCaseRun) |
predicate |
The state change or intent (e.g., started, finished, initialCommit) |
version |
The semantic version of the event schema (e.g., v0.1.0, v1.0.0) |
Each fully qualified event type (e.g. dev.cdevents.pipelineRun.started.v0.4.1) should be paired with a schemaUri field in the event’s context, pointing to a schema that validates the full structure of the event.
Examples
| Use Case | Event Type |
|---|---|
| Official CDEvents | dev.cdevents.pipelineRun.started.v0.4.1 |
| Experimental SIG | dev.cdeventsx.cdf-branch.initialCommit.v0.1.0 |
| Vendor-specific | com.harness.artifact.approvalGranted.v1.2.0 |
| Org-internal | org.jpmc.secops.scanner.failed.v0.3.1 |
Semantic Versioning Rules
Semantic Versioning governs the schema of the event, not the CDEvents spec as a whole. It enables the independent evolution of event types.
| Version Change | Definition | Examples | Compatibility Requirement |
|---|---|---|---|
MAJOR |
Breaking change to the event’s schema or field types | Removing required fields, changing types | ❌ Incompatible with consumers expecting previous version |
MINOR |
Additive changes (e.g., new optional fields) | Adding optional customData keys |
✅ Backward compatible |
PATCH |
Metadata clarifications or documentation fixes | Updating field descriptions | ✅ Safe upgrade |
Each namespaced event type must include a schemaUri that matches its declared version and structure. This schema:
- MUST be a superset of the base event’s schema
- MUST validate any namespaced
customDataextensions
Base Event Contract Model
All CDEvents (standard, vendor, org-defined, or experimental) must declare a baseEvent in the context section. This creates a clear inheritance tree and enforces semantic interoperability.
Base Event Requirements
- Inheriting events must:
- Preserve all required fields from the base schema
- Not alter types or semantics
- Add fields only
- A
schemaUrimust be provided for each versioned event
Understanding the Roles
schemaUri: This field points to the JSON Schema that defines the event's structure. It enables consumers to validate the event and generate code bindings.
baseEvent: This field indicates the event type from which the current event inherits. It serves as a semantic reference, allowing consumers to understand the event's lineage and apply appropriate processing logic.
Example Metadata Snippet
"context": {
"type": "com.somecompany.change.created.v0.1.0",
"baseEvent": "dev.cdevents.change.created.v0.4.1",
"schemaURI": "https://somecompany.com/cdevents/V1/ci/change/created",
"version": "0.1.0"
}
Empty Base Event
A new root-level "empty" base event is introduced for net-new event types that do not extend an existing CDEvent. These must align structurally with the CDEvents envelope.
JSON Envelope
{
"context": {
"type": "dev.cdevents.base.empty.v0.1.0",
"version": "0.4.1",
"id": "<uuid>",
"source": "<source-uri>",
"timestamp": "<timestamp>"
},
"subject": {},
"customData": {}
}
Namespaced Plugin Routing via customData
CDEvents may include customData keys using the reserved ns: prefix to denote plugin-specific logic:
"customData": {
"ns:jenkins": {
"jobName": "build-api",
"buildNumber": 5432
},
"ns:homedepot": {
"complianceZone": "blue"
}
}
- Conduit (SDLC Workflow Orchestrator) uses these keys to route payloads to registered plugins.
- Plugins are version-controlled and resolved by name+version from segment definitions.
- Each plugin SHOULD publish a schema under a known URI and conform to that shape.
Plugin Declaration in Segment YAML
segment: build
plugins:
- name: jenkins
version: 1.3.2
- name: homedepot
version: 2025.04
At runtime, Conduit looks up plugin versions from its internal registry and applies them to interpret and validate any ns: extensions in customData.
Developer Consumption Model
Schemas linked via schemaUri support:
- Runtime validation
- SDK generation
- DSL autocomplete
- Policy enforcement
- Trust and contract stability
Acknowledgements
Inspired by:
- WSDL
targetNamespace - Kubernetes Group-Version-Resource (GVR)
- XSD schema compatibility principles
- Practical implementations in the Conduit project
- Collaborative design by Dadisi Sanyika and Benjamin Powell
I find this proposal interesting. There is something in this direction already through the schemaUri field, but this takes the idea a major step further. I don't have any strong opinions against this proposal. On the contrary it sounds interesting to get a well-defined structure also for experimental & vendor-specific events. The continued existence of the schemaUri field should be considered as part of this proposal as well. It might still serve a purpose, to easily identify the schema used.
Due to my lack of knowledge on the Conduit system/project, could you elaborate a bit more on that? Example?
Thank you, @e-backmark-ericsson! Great call out. I have updated the issue utilizing schemaURI.
Note that the schemaUri is currently optional, and if omitted it is assumed that a producer/consumer of CDEvents knows where to find the official schemas. Most users of CDEvents will probably use the existing SDKs that have built-in support for the schemas, as they are generated from them. And this proposed change might be somewhat hidden from the users of these SDKs, since it could be handled as part of the SDK itself and doesn't need to be exposed to the user unless they want to customize the events.
In your proposal you now propose the schemaUri to become mandatory, which might be fine even though I believe it could still be implicit if no customization is made to the event type, to not pollute the events with redundant information. If making it mandatory the docs must be updated and also all example events and the schemas themselves, to change the schemaUri field to mandatory.
Thanks @darckorner for this thorough proposal.
In general, I'm in favour of a more clearly defined namespacing. I like the idea of namespacing custom data, as it enables better use of plugins and possibly collecting custom data from various tools in one event.
I also like the idea of the baseEvent, which allows customising existing events while still enforcing the original event schema.
I have a few questions related to the various sections.
Event Type Format
-
dev.cdeventsx: Anyone can use this today for custom events, with the namespace included in thesubjectin the form<org>-<subject>to avoid conflicts. What do you envision thedev.cdeventsxrole to be if we introduce the proposed root<namespace>? Will open-source projects use their domain for custom events ordev.cdeventsx? -
vendor-specific vs. org internal: it's not clear to me if these are just examples of if there is a structural difference between these two
Semantic Versioning Rules
Today, we have two versions:
- the spec version, which is sent in the CDEvents context through a dedicated field
- the event version, which is part of the event type
dev.cdevents.<subject>.<predicate>.<version>
Both versions use semantic versioning rules today. I don't understand what the change proposed here is. Note that @xibz and @davidB are planning a versioning rework, so changes here should be synced.
Empty Base Event
I don't fully understand the need for the empty base event. Custom events have a base schema today, which defines common structures for all custom events.
I like the proposed possibility of specifying a baseEvent, but I don't see the need to make it mandatory, which leads to the need for an empty base event. If no baseEvent is specified, only the existing base schema applies. If a baseEvent is specified, the schema of the base event must also be considered when validating. In any case, this looks to me like an implementation detail, and definitely not a show-stopper.
Thanks for the details
- I don't understand, does the schema define the content of customData or subject (or both)?
- In "Namespaced Plugin Routing", does it mean that the event's producer knows the consumers/routers?
DISCLAIMER
I'm in favor of:
- A non-proliferation of custom/org events, as the goal is to create a common language and NOT to replace (IHMO) the existing language/events provided by tools (with complete control of the content by producer, often with more information and existing ecosystem).
- Extension (by producer,...) should be possible,
- Easier & faster update of the specs (and implementation)
Data binding and automatic SDK generation are pains to implement from multiple schemas (the case with one schema per predicate), and it could be worse if developers have to support runtime schema changes.
If the schema is "just" for the customData part, and as
- Stacking schema is not a standard way (=> not supported by SDK generator, json validators,...)
- Triggering a json validator using
schemaUrialready requires custom code
Why not define the namespaces in a dedicated field (like customDataContentType), eg.
{
...
"customData": {
"ns1": {
...
}
},
"customDataNamespace": {
"ns1": "https://somecompany.com/cdevents/V1/ci/change/created",
}
Alternatively, customData could become an array + use a tag field to identify the structure. The array avoids naming collision on the key; it could be harder to manage (override, duplicate, ...), depending on the use cases.
{
...
"customData": [
{
"schemaUri": "https://somecompany.com/cdevents/V1/ci/change/created",
...
}
],