@@ -594,6 +594,228 @@ Relation links are used to add some context to certain events
594594 }
595595}
596596```
597+ ## Cross-Domain Linking with ` domainId `
598+
599+ ### The Problem
600+
601+ ` contextId ` requires the publisher to know the parent event's context ID.
602+ If the parent is not a CDEvent, there is no context ID to reference.
603+
604+ For example, GitHub does not emit CDEvents today. A build event triggered by a
605+ GitHub PR cannot use ` contextId ` to link back to that PR — there is no CDEvent
606+ context ID to know. Without ` domainId ` , the only option is to bury that
607+ causality in ` customData ` , where it is unstructured and non-queryable.
608+
609+ ` domainId ` provides a first-class way to express causality and relationships
610+ across system boundaries, regardless of whether the referenced system emits
611+ CDEvents.
612+
613+ This is a transitional mechanism: as more systems adopt CDEvents, ` domainId `
614+ links naturally migrate to ` contextId ` links. It is a bridge, not a
615+ permanent replacement.
616+
617+ ### Event-to-Event vs Event-to-Resource Linking
618+
619+ ` contextId ` and ` domainId ` represent two fundamentally different linking models.
620+
621+ ` contextId ` is ** event-to-event** : it points to a single, specific CDEvent by
622+ its unique context ID. One event references exactly one other event.
623+
624+ ` domainId ` is ** many-to-many** : a ` domainId ` URN acts as a container. Many
625+ CDEvents can reference the same external resource, and a single CDEvent can
626+ reference many external resources. There is no requirement that any CDEvent
627+ know about the others referencing the same ` domainId ` .
628+
629+ ``` plaintext
630+ contextId — event-to-event (1:1)
631+
632+ +--------------------+ contextId +--------------------+
633+ | CDEvent |<----- "abc-123" ------| CDEvent |
634+ | id: "abc-123" | | build.started |
635+ | change.merged | | links: [{ |
636+ +--------------------+ | target: { |
637+ | contextId: |
638+ | "abc-123" |
639+ | } |
640+ | }] |
641+ +--------------------+
642+
643+
644+ domainId — many-to-many (N events, M resources)
645+
646+ Many events referencing one resource (domainId as container/grouping key):
647+
648+ cdevents:github:xibz:repo:pr:42
649+ (external resource — container)
650+ ^
651+ |
652+ +--------------------+--------------------+
653+ | | |
654+ +----------+-------+ +---------+---------+ +------+-----------+
655+ | CDEvent | | CDEvent | | CDEvent |
656+ | build.started | | testrun.started | | service.deployed |
657+ | domainId: | | domainId: | | domainId: |
658+ | cdevents:github: | | cdevents:github: | | cdevents:github: |
659+ | :repo:pr:42 | | :repo:pr:42 | | :repo:pr:42 |
660+ +------------------+ +-------------------+ +------------------+
661+
662+
663+ One event referencing many resources (fan-out):
664+
665+ +----------------------------------+
666+ | CDEvent |
667+ | service.deployed |
668+ | links: [ +-----> cdevents:github:xibz:repo:pr:42
669+ | { domainId: |
670+ | cdevents:github:...:pr:42 }, +-----> cdevents:jira:xibz:project:issue:12
671+ | { domainId: |
672+ | cdevents:jira:...:issue:12 },+-----> cdevents:circleci:xibz:pipeline:execution:789
673+ | { domainId: |
674+ | cdevents:circleci:...:789 } |
675+ | ] |
676+ +----------------------------------+
677+ ```
678+
679+ A consumer querying by ` cdevents:github:xibz:repo:pr:42 ` gets back every CDEvent
680+ that referenced that resource — build, test, deploy — without any single event
681+ needing to know about the others. A single event can simultaneously express
682+ causality across multiple external systems by listing multiple ` domainId ` links,
683+ covering fan-out scenarios where one action triggers work across several systems.
684+
685+ ### CDEvents Domain IDs
686+
687+ ` domainId ` values are URNs following this format:
688+
689+ ```
690+ cdevents:<service>:<namespace>:<instance>:<type>:<resource id>
691+ ```
692+
693+ | Segment | Description |
694+ | ---------------| ----------------------------------------------------------------------------------------------------------------|
695+ | ` service ` | A governed identifier for the system or tool. Must match a known entry in the CDEvents service registry or a shared identifier agreed upon by producers and consumers (e.g. ` github ` , ` jira ` , ` datadog ` ). Free-form values are not permitted. |
696+ | ` namespace ` | The org, account, or tenant within the service |
697+ | ` instance ` | The specific instance or environment within the namespace |
698+ | ` type ` | A governed resource type. Must be one of the values defined in [ Common Resource Types] ( #common-resource-types ) |
699+ | ` resource id ` | The publicly exposed identifier that end users see for this resource (e.g. a PR number, commit SHA, or ticket number). Must not be an internal or opaque system-generated ID. |
700+
701+ Examples:
702+
703+ - GitHub PR: ` cdevents:github:xibz:repo:pr:42 `
704+ - Jira ticket: ` cdevents:jira:xibz:project:issue:12345 `
705+ - Datadog alert: ` cdevents:datadog:prod:monitor:alert:98765 `
706+
707+ ### Common Resource Types
708+
709+ The ` type ` segment is a governed field. Producers MUST use one of the following
710+ values. This ensures interoperability — consumers can match and query by ` type `
711+ without handling variations like ` pull_request ` , ` PR ` , or ` pullrequest ` .
712+
713+ | Type | Description | ` resource id ` example |
714+ | ---------------| ------------------------------------------------------------------------------------| -------------------------------|
715+ | ` pr ` | A pull or merge request | ` 42 ` (PR number) |
716+ | ` commit ` | A source code commit | ` abc123def456 ` (commit SHA) |
717+ | ` issue ` | An issue or ticket in a tracking system | ` 1234 ` (issue number) |
718+ | ` branch ` | A source code branch | ` main ` , ` feature/my-branch ` |
719+ | ` tag ` | A source code tag or release | ` v1.2.3 ` |
720+ | ` definition ` | A named, reusable pipeline or workflow template | ` my-pipeline ` |
721+ | ` execution ` | A single run of a build, pipeline, workflow, or deployment | ` 789 ` (run number) |
722+ | ` artifact ` | A build artifact (binary, container image, package, etc.) | ` myapp:1.0.0 ` |
723+ | ` environment ` | A target deployment environment | ` production ` , ` staging ` |
724+ | ` alert ` | A monitoring or observability alert | ` 98765 ` (alert ID) |
725+
726+ If a resource does not fit any of the above types, it SHOULD be proposed for
727+ addition to this list before using a custom value.
728+
729+ ### Usage in Relation Links
730+
731+ ` domainId ` can be used in place of ` contextId ` in the ` source ` and ` target `
732+ fields of a ` RELATION ` link. Both embedded and standalone relation links support
733+ this.
734+
735+ ** Example: Build triggered by a GitHub PR**
736+
737+ ``` json
738+ {
739+ "context" : {
740+ "id" : " build-event-789" ,
741+ "chainId" : " d0be0005-cca7-4175-8fe3-f64d2f27bc01"
742+ },
743+ "links" : [
744+ {
745+ "linkType" : " RELATION" ,
746+ "linkKind" : " triggeredBy" ,
747+ "target" : {
748+ "domainId" : " cdevents:github:xibz:repo:pr:42"
749+ }
750+ }
751+ ]
752+ }
753+ ```
754+
755+ ** Example: Rollback pipeline triggered by a Datadog alert**
756+
757+ ``` json
758+ {
759+ "links" : [
760+ {
761+ "linkType" : " RELATION" ,
762+ "linkKind" : " triggeredBy" ,
763+ "target" : {
764+ "domainId" : " cdevents:datadog:prod:monitor:alert:98765"
765+ }
766+ }
767+ ]
768+ }
769+ ```
770+
771+ ** Example: Deployment failure with full cross-domain causality**
772+
773+ A deployment failure can link back to its causes across multiple systems,
774+ without requiring any system to know another system's internal context IDs:
775+
776+ ``` json
777+ {
778+ "context" : { "id" : " deploy-event-999" },
779+ "links" : [
780+ {
781+ "linkType" : " RELATION" ,
782+ "linkKind" : " causedBy" ,
783+ "target" : {
784+ "domainId" : " cdevents:circleci:xibz:pipeline:execution:789"
785+ }
786+ },
787+ {
788+ "linkType" : " RELATION" ,
789+ "linkKind" : " causedBy" ,
790+ "target" : {
791+ "domainId" : " cdevents:github:xibz:repo:commit:abc123def456"
792+ }
793+ },
794+ {
795+ "linkType" : " RELATION" ,
796+ "linkKind" : " causedBy" ,
797+ "target" : {
798+ "domainId" : " cdevents:github:xibz:repo:pr:42"
799+ }
800+ }
801+ ]
802+ }
803+ ```
804+
805+ Consumers can query directly by ` domainId ` URN without parsing ` customData ` or
806+ needing to know the context IDs of external systems.
807+
808+ ### When to Use ` contextId ` vs ` domainId `
809+
810+ | Scenario | Use |
811+ | ----------| -----|
812+ | Linking to another CDEvent whose context ID is known | ` contextId ` |
813+ | Linking to a system that does not emit CDEvents | ` domainId ` |
814+ | Linking to a CDEvent but context ID is not available | ` domainId ` as a fallback |
815+
816+ Each system uses what it knows: ` contextId ` for events within the CDEvents
817+ ecosystem, and ` domainId ` URNs for anything outside it.
818+
597819### Scalability
598820
599821Scalability is one of the bigger goals in this proposal and we wanted to ensure
0 commit comments