Skip to content

feat(deployment): add deployment and targetRollout subjects and events - #319

Open
xibz wants to merge 1 commit into
cdevents:mainfrom
xibz:deployment
Open

feat(deployment): add deployment and targetRollout subjects and events#319
xibz wants to merge 1 commit into
cdevents:mainfrom
xibz:deployment

Conversation

@xibz

@xibz xibz commented Jul 21, 2026

Copy link
Copy Markdown
Contributor

Problem

service.deployed/service.upgraded conflate two different kinds of fact into one event. Every other subject pair in the spec separates orchestration (the act of doing something) from entity (the resulting state) — build is the orchestration event, artifact is the entity fact it produces. service.deployed/upgraded are the one place that doesn't hold: a single event tries to say both "a rollout happened" and "this service instance is now running v2," with no way to talk about the rollout on its own. That's also why service has no queued/started predicates — queuing and starting are true of a deployment, not of a service, so producers who need lifecycle visibility into an in-progress rollout have no canonical event to emit and end up inventing their own conventions.

This also means there's no way to represent a single deployment fanning out to multiple simultaneous destinations with one aggregate outcome — e.g. rolling a release out to 3 regions, or to a canary slot plus the main fleet, within the same environment. Today you'd emit N separate service.deployed events and the consumer has to infer, out of band, which ones belong to the same deployment attempt and what the combined success/failure state is.

Finally, environment has no inbound link to what's running in it. environment.created/modified/deleted describe the platform alone; the only way to find out what's deployed into an environment today is to scan service events and filter on content.environment.id, a reference that points from the entity down to the environment — backwards from every other "what happened in this environment" query you'd want to run.

Solution

Introduces deployment (the aggregate act of applying a release to one or more target rollouts, one per environment) and targetRollout (a specific destination within that environment, e.g. a region or canary slot) as the orchestration-side subjects service was missing, each with queued/started/finished lifecycle events. targetRollout.finished carries failureType for per-destination failure detail; deployment.finished is all-or-nothing across all of its target rollouts.

targetRollout also gives environment a first-class inbound link: querying "what was rolled out to this environment" becomes direct instead of an inference over service events.

service.deployed/service.upgraded are unchanged in behavior and retained for backwards compatibility as the entity-side fact, now deprecated in favor of deployment.finished/targetRollout.finished for the orchestration-side fact.

Changes

Submitter Checklist

As the author of this PR, please check off the items in this checklist:

Introduces deployment and targetRollout subjects with queued/started/finished
lifecycle events, giving DORA-style tooling an unambiguous, multi-target-aware
deployment completion fact. service.deployed is retained for backwards
compatibility but deprecated in favor of deployment.finished.

Signed-off-by: xibz <bjp@apple.com>
@xibz
xibz requested a review from a team as a code owner July 21, 2026 17:04
@sol-duara

Copy link
Copy Markdown

Hey @xibz, per your instructions for introducing new concepts, this seems a bit lacking in explanation. It is not clear what problem you are solving that CDEvents already solves, or how this approach addresses it. I would really like to understand what you mean by multi-target-aware deployment. How is that different from other deployments? How did you run into the situation? Where did the existing structure fail you?

Thanks!

@xibz

xibz commented Jul 25, 2026

Copy link
Copy Markdown
Contributor Author

@sol-duara - I updated the PR body which should help

@sol-duara

sol-duara commented Jul 29, 2026

Copy link
Copy Markdown

"service.deployed/service.upgraded conflate two different kinds of fact into one event."

@xibz These seem to be two separate events. What is the 'fact' that you are referring to, and which one of these events is it in?

Are you calling the event that signals a service/application reaching its destination the deployment process proper? I can see the need for a deployment enclosure: deployment.started & deployment.finished. That would allow the deployment manifest to be included, like the information about what is being built in a build event. That would make each service.deployed a landing confirmation event.

Based on what you (or Claude) have written, I can't follow the intent. Currently, I treat service as a per-instance set (one or more) releases of an artifact. But that is what you are calling a targetedRollout. It seems to be a distinction without a difference.

Finally, environment: is your expectation that the event becomes the system source of truth?

@xibz

xibz commented Jul 30, 2026

Copy link
Copy Markdown
Contributor Author

Thanks for pushing on this, these are exactly the right questions.

1. "These are two separate events — which one is 'the fact'?"

Fair, my earlier phrasing was sloppy. It's not that the two events split one fact between them, each one individually conflates two facts. service.deployed alone says both "a rollout action completed" (orchestration) and "this service instance now runs v1.2.3" (entity state), in a single event, with no way to reference or observe the rollout independently of the resulting state. Same for service.upgraded.

2. "I can see the need for a deployment enclosure... make each service.deployed a landing confirmation event."

That's very close to what we're proposing, the disagreement is really just about what fills the "where" slot inside that enclosure, which is point 3.

3. "That's what you're calling a targetRollout. Distinction without a difference."

The cleanest way to state the split:

  • deployment is about what: one release, one artifact/version, one aggregate outcome. It doesn't know or care how many destinations it's going to.
  • targetRollout is about where: one destination that release is being sent to. A deployment fans out into N targetRollouts, one per destination, each with its own outcome and failureType.
  • service is neither of thos, it's the resulting entity. It doesn't answer "what" or "where" in the delivery sense; it answers "what's running here right now, and how did its version change over time." That's why service persists across many deploys (deployed -> upgraded -> upgraded -> rolledback, one identity, many transitions over its life), while targetRollout is minted fresh per deployment attempt, it's the record of this delivery to this place, not the thing that ends up running there.

service happens to already be scoped to one place, which makes it look like it's playing the "where" role targetRollout plays. But it's answering a different question: service says what's currently there; targetRollout says whether a specific delivery attempt to that place succeeded. targetRollout can be queued/started before anything is running at all: service can't express that, since it only exists once there's something to describe.

4. "Is your expectation that the event becomes the system source of truth?"

No. This is saying what happened. Nothing more.

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