Event Envelope¶
The event envelope is the single canonical structure that wraps every message moving through the ConnectSoft AI Software Factory — whether it is a factory lifecycle event, a domain event from a platform aggregate, or an integration event crossing a platform boundary. A uniform envelope is what makes the platform traceable, replayable, and observable end to end.
Why one envelope
Every meaningful action in the factory emits an event. Because all events share the same envelope, the Knowledge Platform, Observability & Feedback Platform, and Control Plane can correlate any artifact, agent task, commit, deployment, and runtime signal back to a single traceId — from business intent to running SaaS and back.
Canonical envelope¶
All events are published on Azure Service Bus (via MassTransit, the primary messaging stack) using the following envelope. Fields are stable across versions; the variable part is payload.
{
"eventId": "evt-7b3c1f9a-2e44-4c1a-9b6d-0f2a8c3d5e10",
"eventType": "ArtifactCreated",
"tenantId": "connectsoft",
"projectId": "proj-booking-saas",
"moduleId": "module-reservations-api",
"traceId": "trace-9f1c2b7d",
"correlationId": "corr-3a6e1d40",
"causationId": "evt-previous-event-id",
"occurredAt": "2026-06-11T00:00:00Z",
"payload": {}
}
Field contract¶
| Field | Type | Required | Purpose |
|---|---|---|---|
eventId |
string (prefixed UUID) | Yes | Globally unique id of this event instance. Idempotency anchor for consumers. |
eventType |
string | Yes | Event name in NounVerbPastTense form (e.g. ArtifactCreated, AgentTaskCompleted). See Naming Conventions. |
tenantId |
string | Yes | Owning tenant. Enforces multi-tenant isolation in every consumer and store. |
projectId |
string | Conditional | The factory project the event belongs to. Present for all project-scoped events. |
moduleId |
string | Conditional | The module (microservice, UI, worker, library) the event concerns, when applicable. |
traceId |
string | Yes | End-to-end trace identifier spanning the full prompt-to-runtime lifecycle. |
correlationId |
string | Yes | Correlates all events within one logical workflow/conversation. |
causationId |
string | No | The eventId of the event that directly caused this one. Builds the causation chain. |
occurredAt |
string (ISO-8601 UTC) | Yes | When the event occurred at the producer. |
payload |
object | Yes | Event-specific body. Versioned independently per eventType. |
The identity fields above are a strict superset of the cross-cutting metadata schema; additional dimensions (agentId, skillId, artifactId, workflowId, environment, version) appear inside payload or as Service Bus message application properties when relevant for routing and filtering.
Message metadata (Azure Service Bus)¶
The envelope is carried as the message body; selected fields are mirrored into broker application properties so subscriptions can filter without deserializing the body.
| Application property | Source field | Use |
|---|---|---|
cs-event-type |
eventType |
Subscription rules / topic filters |
cs-tenant-id |
tenantId |
Tenant-scoped subscriptions |
cs-trace-id |
traceId |
Trace stitching and log correlation |
cs-correlation-id |
correlationId |
Saga/workflow correlation in MassTransit |
cs-schema-version |
envelope schema version | Consumer compatibility checks |
Event categories¶
flowchart LR
Commands["Commands<br/>VerbNoun"] -->|handled by| Aggregate["Aggregate Root"]
Aggregate -->|emits| DomainEvents["Domain Events<br/>NounVerbPastTense"]
DomainEvents -->|published to| Topic["Azure Service Bus Topic"]
Topic -->|in-platform| Subscribers["Platform Subscribers"]
Topic -->|cross-platform| Integration["Integration Events"]
Integration --> Knowledge["Knowledge Platform"]
Integration --> Observability["Observability & Feedback"]
- Commands (
VerbNoun, e.g.BuildContextPackage) — imperative requests handled by exactly one aggregate. Not part of the public event stream. - Domain events (
NounVerbPastTense) — facts emitted by an aggregate after a state change, published within the owning platform. - Integration events — domain events promoted to a cross-platform contract. These are the versioned, externally consumed events listed in the Event Catalog.
Versioning¶
eventTypenames never change meaning. Breaking changes create a new type (e.g.ArtifactCreatedV2) or an additivepayloadwith a bumpedcs-schema-version.- Consumers must tolerate unknown
payloadfields (forward compatibility) and unknowneventTypevalues (ignore-and-log). - The Knowledge Replay and Workflow Replay capabilities depend on envelopes being immutable once published.
Consumer rules¶
- Idempotency — consumers deduplicate on
eventId. Workers additionally use an idempotency key derived fromeventId+ handler name. - Tenant guard — every handler asserts
tenantIdagainst the operation scope before touching a store. - Trace propagation —
traceIdandcorrelationIdflow into OpenTelemetry spans and Serilog log context (see Observability Architecture). - Poison handling — unprocessable messages move to a dead-letter subqueue with the full envelope preserved for replay.