Skip to content

update(link): Relax link schemas to support domain-level identifiers#292

Open
xibz wants to merge 1 commit intocdevents:mainfrom
xibz:links
Open

update(link): Relax link schemas to support domain-level identifiers#292
xibz wants to merge 1 commit intocdevents:mainfrom
xibz:links

Conversation

@xibz
Copy link
Contributor

@xibz xibz commented Feb 11, 2026

This change updates all link schemas (START, END, RELATION, and embedded variants) to allow references to either a CDEvent contextId, a domainId, or both.

Previously, links could only reference event context IDs. This limited cross-system connectivity and encouraged embedding execution identifiers in customData purely for graph reconstruction.

By allowing domainId alongside contextId:

  • Links can represent relationships between domain executions (e.g., pipelinerun) as well as individual events.
  • Connectivity metadata no longer needs to be embedded in event payloads.
  • Chain-first modeling constraints are relaxed, enabling relation-first graph modeling.
  • The change remains backward compatible.

At least one of contextId or domainId is now required for link endpoints. AdditionalProperties are restricted to prevent schema drift.

This preserves existing semantics while improving flexibility and reducing customData pollution.

This change updates all link schemas (START, END, RELATION, and embedded variants)
to allow references to either a CDEvent contextId, a domainId, or both.

Previously, links could only reference event context IDs. This limited
cross-system connectivity and encouraged embedding execution identifiers
in customData purely for graph reconstruction.

By allowing domainId alongside contextId:
- Links can represent relationships between domain executions
  (e.g., pipelinerun) as well as individual events.
- Connectivity metadata no longer needs to be embedded in event payloads.
- Chain-first modeling constraints are relaxed, enabling relation-first
  graph modeling.
- The change remains backward compatible.

At least one of contextId or domainId is now required for link endpoints.
AdditionalProperties are restricted to prevent schema drift.

This preserves existing semantics while improving flexibility and reducing
customData pollution.

Signed-off-by: xibz <bjp@apple.com>
@xibz xibz requested a review from a team as a code owner February 11, 2026 18:42
@afrittoli
Copy link
Member

Thanks @xibz - could you clarify the definition of domainId?

@xibz
Copy link
Contributor Author

xibz commented Feb 17, 2026

@afrittoli

The Core Problem

contextId requires the publisher to know the parent event's context ID.

But if the parent isn't a CDEvent, there is no context ID to know.

Today: GitHub doesn't emit CDEvents. So we use domainId to link to GitHub PRs explicitly.
Tomorrow: If/when GitHub emits CDEvents, we can migrate those links to contextId.
In the meantime: We have explicit causality without polluting customData.
This is a temporary bridge, not a permanent design.

Solution

Introduce a domain specific identifier which can be used to relate information

URNs will be used for domain IDs, where it follows the format of
urn:<provider>:<namespace>:<instance>:<type>:<resource id>

Examples:

  • GitHub PR: urn:github:xibz:repo:pr:42
  • Jira ticket: urn:jira:xibz:project:ticket:12345
  • Datadog alert: urn:datadog:prod:monitor:alert:98765

Example 1 (GH to CI)

Build event wants to link to GitHub PR

Publisher asks: "What is the GitHub PR's contextId?"
Answer: GitHub doesn't emit CDEvents. There is no contextId.
Result: Can't use contextId. Forced into customData.

How domainId solves this

{
  "context": { "id": "build-event-789" },
  "links": [
    {
      "linkType": "RELATION",
      "linkKind": "triggeredBy",
      "target": {
        "domainId": "urn:github:xibz:repo:pr:42"
      }
    }
  ]
}

Example 2 (Jira to CI)

Imagine CircleCI wants to relate a Jira ticket

Build event links to CircleCI task:
{
  "links": [
    {
      "target": {
        "contextId": "circleci-task-event-456"  // ✓ Works, circle ci emits CDEvents
      }
    }
  ]
}

CircleCI task wants to link to Jira ticket:
{
  "links": [
    {
      "target": {
        "contextId": "???"  // ✗ Jira doesn't emit CDEvents. No contextId exists.
      }
    }
  ]
}

Result: CircleCI task can't link to Jira. Forced into customData.

Example 3: Datadog Alert Triggers Rollback Pipeline

Imagine you have a Datadog alert that monitors system health during releases.
If it detects an issue, it automatically triggers a rollback pipeline.

The rollback pipeline needs to link back to the alert that triggered it:

{
  "links": [
    {
      "linkType": "RELATION",
      "linkKind": "triggeredBy",
      "target": {
        "domainId": "urn:datadog:prod:monitor:alert:98765"
      }
    }
  ]
}

Example 4 Linking to Events Without Knowing Their Context ID

Imagine a consumer (like a dashboard or audit system) receives an event and wants to query for all related events, but doesn't know their context IDs upfront.

A deployment fails. You want to find:

  • What build triggered it?
  • What git commit caused the build?
  • What PR introduced that commit?

Without domainId, you're stuck:

Deployment Failed event:
{
  "context": { "id": "deploy-event-999" },
  "customData": {
    "buildId": "build-789",
    "commitHash": "abc123def456",
    "prNumber": 42
  }
}

Problem: You have to parse customData and hope the IDs are there. No standardized way to query back.

With domainId, you can link forward AND backward:

Deployment Failed event:
{
  "context": { "id": "deploy-event-999" },
  "links": [
    {
      "linkType": "RELATION",
      "linkKind": "causedBy",
      "target": {
        "domainId": "urn:circleci:xibz:build:789"
      }
    },
    {
      "linkType": "RELATION",
      "linkKind": "causedBy",
      "target": {
        "domainId": "urn:github:xibz:repo:commit:abc123def456"
      }
    },
    {
      "linkType": "RELATION",
      "linkKind": "causedBy",
      "target": {
        "domainId": "urn:github:xibz:repo:pr:42"
      }
    }
  ]
}

with this:

  • Consumer doesn't need to know CircleCI's context ID for build-789
  • Consumer doesn't need to know GitHub's context ID for the commit
  • Consumer can query by domainId URN directly
  • Causality is explicit and discoverable without parsing customData

This shows that domainId isn't just for "non-CDEvent systems", but it's also useful for querying across systems when you don't have context IDs.

Why it works

Each system uses what it knows. Systems knows its own context IDs (contextId). Systems also knows how to identify triggering systems (domainId URN). No system needs to know another system's internal IDs or context IDs.

FAQS

Why link something outside CDEvents?

Because causality exists outside CDEvents.

  • GitHub PRs cause builds.
  • Jira tickets cause tasks.
  • Datadog alerts cause rollbacks.

If you don't link them, you lose that causality. If you can't link them with contextId (because they're not CDEvents), you're forced to hide it in customData.

domainId lets you link anything, anywhere. That's why it matters.

If you don't solve cross-domain linking, who does?

Your engineers will. They'll put it in customData. Because causality is real whether CDEvents acknowledges it or not.

Doesn't this mean CDEvents becomes a catch-all for every system?

No. domainId is a stopgap until systems emit CDEvents natively.
As more systems adopt CDEvents, those domainId links naturally
migrate to contextId links. This is a temporary bridge, not a
permanent design decision.

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.

2 participants