From ab8c81be1757e5a9a9a2ea52739d329889371092 Mon Sep 17 00:00:00 2001 From: Patricio Date: Mon, 27 Jul 2026 11:13:14 +0200 Subject: [PATCH 1/3] [DPS-2329] Document event spec validation for Micro and good/bad routing Co-Authored-By: Claude Fable 5 --- .../images/data-quality-rules-modal.png | Bin 0 -> 32478 bytes .../event-specification-validation/index.md | 20 ++++++++++++++---- docs/testing/snowplow-micro/console/index.md | 8 +++++++ 3 files changed, 24 insertions(+), 4 deletions(-) create mode 100644 docs/event-studio/tracking-plans/event-specification-validation/images/data-quality-rules-modal.png diff --git a/docs/event-studio/tracking-plans/event-specification-validation/images/data-quality-rules-modal.png b/docs/event-studio/tracking-plans/event-specification-validation/images/data-quality-rules-modal.png new file mode 100644 index 0000000000000000000000000000000000000000..bcf7824308a82ecf3e5ae43783de7b3a931a199d GIT binary patch literal 32478 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 literal 0 HcmV?d00001 diff --git a/docs/event-studio/tracking-plans/event-specification-validation/index.md b/docs/event-studio/tracking-plans/event-specification-validation/index.md index 02117054c..558e9eaea 100644 --- a/docs/event-studio/tracking-plans/event-specification-validation/index.md +++ b/docs/event-studio/tracking-plans/event-specification-validation/index.md @@ -13,10 +13,10 @@ Event specification validation checks whether incoming events conform to the rul The pipeline runs validation on events that arrive with an `event_specification` entity already attached, typically from a tracker using [Snowtype](/docs/event-studio/implement-tracking/index.md) version 0.17.0 or later (see [Validate against a new specification version](#validate-against-a-new-specification-version) for the upgrade steps). For events that arrive without one, the pipeline runs [event specification inference](/docs/event-studio/tracking-plans/event-specification-inference/index.md) instead. Each event takes one path or the other; the two paths are mutually exclusive per event. Inference never produces a validation entity, even when an event would have failed validation. -When an event fails validation, the pipeline attaches an [entity](/docs/fundamentals/entities/index.md) to it describing the failure. The pipeline still enriches and delivers events that fail validation alongside successful ones; only the validation entity reflects the failure. You don't need to change your tracking implementation, as validation runs against newly published specifications immediately. +When an event fails validation, the pipeline attaches an [entity](/docs/fundamentals/entities/index.md) to it describing the failure. By default, the pipeline still enriches and delivers events that fail validation alongside successful ones; only the validation entity reflects the failure. You don't need to change your tracking implementation, as validation runs against newly published specifications immediately. -:::note[Validation failures don't drop events] -The pipeline still delivers events that fail validation as enriched events. The pipeline records the failure in the validation entity, but does not route the event to [failed events](/docs/fundamentals/failed-events/index.md). +:::note[Validation failures don't drop events by default] +The pipeline still delivers events that fail validation as enriched events. The pipeline records the failure in the validation entity, but does not route the event to [failed events](/docs/fundamentals/failed-events/index.md), unless the tracking plan is configured to [send invalid events to failed events](#send-invalid-events-to-failed-events). ::: In your warehouse, three cases are possible: @@ -24,6 +24,8 @@ In your warehouse, three cases are possible: - **Passed validation, or matched by inference**: the event has an `event_specification` entity but no `event_specification_validation` entity. Either the event was Snowtype-tracked and passed validation, or the pipeline matched it to a specification by inference. - **Not associated with a specification**: the event has neither entity. No specification was attached at tracking time, and the pipeline did not match the event to a published specification. +These cases assume the default behavior. If the tracking plan [sends invalid events to failed events](#send-invalid-events-to-failed-events), events that fail validation don't reach your warehouse events table. + ## Validation entity The pipeline attaches an `event_specification_validation` entity to events that fail validation. @@ -94,10 +96,20 @@ A Snowtype-tracked event declares a specific `(id, version)` pair in its `event_ :::info[Enable validation for an existing tracking implementation] 1. Update the Snowtype dependency in your package manager or CI configuration to 0.17.0 or later 2. Regenerate the tracker code with `snowtype generate`, either manually or as part of your build pipeline -3. [Publish](/docs/event-studio/tracking-plans/event-specifications/index.md) the relevant event specifications; validation doesn't run against drafts +3. [Publish](/docs/event-studio/tracking-plans/event-specifications/index.md) the relevant event specifications; validation in pipelines doesn't run against drafts. To validate against a draft before publishing, use a [development environment](/docs/testing/snowplow-micro/console/index.md#validate-event-specifications) 4. Deploy the regenerated tracker code ::: When you publish a new version of a specification, events from existing tracker code continue to declare the previous version, validating against its instructions. The new version applies once you regenerate your tracker code with [Snowtype](/docs/event-studio/implement-tracking/index.md) and deploy the updated tracker code, after which new events declare and validate against the new version. Different versions of a specification can coexist. Each event validates against the version it declares, whether the variation comes from a rolling update, from different applications using different versions, or from different deployment stages. + +## Send invalid events to failed events + +By default, events that fail validation are still delivered as enriched events, with the validation entity attached. Each tracking plan has a setting to send them to [failed events](/docs/fundamentals/failed-events/index.md) instead, keeping events that don't conform to their specifications out of your warehouse events table. + +!["Data quality rules" dialog with a dropdown offering two options, "Send to valid events and mark as violation" (selected) and "Send to failed events as validation error", and a note that the setting applies to all the event specifications of the tracking plan](images/data-quality-rules-modal.png) + +The setting applies to all event specifications in the tracking plan and all their versions. Changing it takes effect automatically, with no new specification version to publish and no tracking code to redeploy. + +Routed events appear as enrichment failures and keep both the `event_specification` and the `event_specification_validation` entities, so you can inspect why each event failed. diff --git a/docs/testing/snowplow-micro/console/index.md b/docs/testing/snowplow-micro/console/index.md index 6fdf31117..b7ef97e54 100644 --- a/docs/testing/snowplow-micro/console/index.md +++ b/docs/testing/snowplow-micro/console/index.md @@ -48,3 +48,11 @@ Do not send production data to development environments. Anyone with the _View e ::: To enable or disable enrichments and edit their configurations, select the **Enrichments** tab. The process is the same as for regular pipelines. We highly recommend testing enrichments in a development environment before deploying them to production. + +## Validate event specifications + +Development environments validate incoming events against every published version of your [event specifications](/docs/event-studio/tracking-plans/event-specifications/index.md), following the same rules as [event specification validation](/docs/event-studio/tracking-plans/event-specification-validation/index.md) in a pipeline. Unlike pipelines, they also validate against the latest draft of each specification: you don't need to publish the tracking plan or its event specifications to test your tracking against them. + +Edit the specification in Console, send a test event, and inspect the result in the [Micro dashboard](/docs/testing/snowplow-micro/ui/index.md): events that fail validation carry an `event_specification_validation` entity describing each error. The environment picks up specification changes automatically within a few minutes. + +Events that arrive without an `event_specification` entity are matched by [inference](/docs/event-studio/tracking-plans/event-specification-inference/index.md) instead, against both published specifications and the latest drafts. From 35671704adc0430b4784148a5f8c6a94f3b74150 Mon Sep 17 00:00:00 2001 From: Patricio Date: Tue, 28 Jul 2026 10:17:29 +0200 Subject: [PATCH 2/3] [DPS-2329] Point inference testing at development environments Co-Authored-By: Claude Fable 5 --- .../tracking-plans/event-specification-inference/index.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/event-studio/tracking-plans/event-specification-inference/index.md b/docs/event-studio/tracking-plans/event-specification-inference/index.md index 88d425597..cb3baeff0 100644 --- a/docs/event-studio/tracking-plans/event-specification-inference/index.md +++ b/docs/event-studio/tracking-plans/event-specification-inference/index.md @@ -40,7 +40,7 @@ Once a specification is published, the pipeline evaluates every eligible incomin 2. **Entity set**: the event must carry all [entities](/docs/fundamentals/entities/index.md) listed in the specification according to the cardinality rules. Extra entities with different schemas on the event are ignored. 3. **Property instructions**: any property-level instructions defined on those data structures in the specification — for example, `category = "product"` — must be satisfied. -The pipeline does not match on `appId`, environment, or any other source attribute. A single incoming event can match more than one specification if multiple published specifications share overlapping definitions. +The pipeline does not match on `appId`, source applications, environment, or any other source attribute. A single incoming event can match more than one specification if multiple published specifications share overlapping definitions. When a match occurs, the pipeline: @@ -60,6 +60,8 @@ The same `page_view` event carrying a `product` entity where `category = "clothi Inference is the path the pipeline takes for events that do not arrive with an `event_specification` entity already attached. For events that do, the pipeline runs [event specification validation](/docs/event-studio/tracking-plans/event-specification-validation/index.md) against that specification instead, which produces explicit per-event findings when an event fails to conform to its rules. +To try inference without affecting production, send test events to a [development environment](/docs/testing/snowplow-micro/console/index.md#validate-event-specifications). It matches events against your published specifications and against the latest draft of each one, so you can check that an event matches before publishing. + :::tip[No tracking changes needed] You do not need to change your tracking implementation to benefit from inference. Events already flowing through your pipeline will be matched against newly published specifications automatically. ::: From cbb2488fe81d8a7ffe9e1503355df904ef88d9ab Mon Sep 17 00:00:00 2001 From: Patricio Date: Tue, 28 Jul 2026 10:28:22 +0200 Subject: [PATCH 3/3] [DPS-2329] Address style review Co-Authored-By: Claude Fable 5 --- .../tracking-plans/event-specification-inference/index.md | 2 +- .../tracking-plans/event-specification-validation/index.md | 6 +++--- docs/testing/snowplow-micro/console/index.md | 6 +++--- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/docs/event-studio/tracking-plans/event-specification-inference/index.md b/docs/event-studio/tracking-plans/event-specification-inference/index.md index cb3baeff0..b46ae99c5 100644 --- a/docs/event-studio/tracking-plans/event-specification-inference/index.md +++ b/docs/event-studio/tracking-plans/event-specification-inference/index.md @@ -60,7 +60,7 @@ The same `page_view` event carrying a `product` entity where `category = "clothi Inference is the path the pipeline takes for events that do not arrive with an `event_specification` entity already attached. For events that do, the pipeline runs [event specification validation](/docs/event-studio/tracking-plans/event-specification-validation/index.md) against that specification instead, which produces explicit per-event findings when an event fails to conform to its rules. -To try inference without affecting production, send test events to a [development environment](/docs/testing/snowplow-micro/console/index.md#validate-event-specifications). It matches events against your published specifications and against the latest draft of each one, so you can check that an event matches before publishing. +To try inference without affecting production, send test events to a [development environment](/docs/testing/snowplow-micro/console/index.md#validate-event-specifications). It matches events against your published specifications and against the current draft of each one, so you can check that an event matches before publishing. :::tip[No tracking changes needed] You do not need to change your tracking implementation to benefit from inference. Events already flowing through your pipeline will be matched against newly published specifications automatically. diff --git a/docs/event-studio/tracking-plans/event-specification-validation/index.md b/docs/event-studio/tracking-plans/event-specification-validation/index.md index 558e9eaea..98f6be562 100644 --- a/docs/event-studio/tracking-plans/event-specification-validation/index.md +++ b/docs/event-studio/tracking-plans/event-specification-validation/index.md @@ -106,10 +106,10 @@ Different versions of a specification can coexist. Each event validates against ## Send invalid events to failed events -By default, events that fail validation are still delivered as enriched events, with the validation entity attached. Each tracking plan has a setting to send them to [failed events](/docs/fundamentals/failed-events/index.md) instead, keeping events that don't conform to their specifications out of your warehouse events table. +By default, the pipeline still delivers events that fail validation as enriched events, with the validation entity attached. Each tracking plan has a **Data quality rules** setting that controls this: select **Send to failed events as validation error** to route events that fail validation to [failed events](/docs/fundamentals/failed-events/index.md) instead, keeping events that don't conform to their specifications out of your warehouse events table. The default is **Send to valid events and mark as violation**. -!["Data quality rules" dialog with a dropdown offering two options, "Send to valid events and mark as violation" (selected) and "Send to failed events as validation error", and a note that the setting applies to all the event specifications of the tracking plan](images/data-quality-rules-modal.png) +!["Data quality rules" dialog showing the two routing options for a tracking plan](images/data-quality-rules-modal.png) The setting applies to all event specifications in the tracking plan and all their versions. Changing it takes effect automatically, with no new specification version to publish and no tracking code to redeploy. -Routed events appear as enrichment failures and keep both the `event_specification` and the `event_specification_validation` entities, so you can inspect why each event failed. +Events sent to failed events appear as enrichment failures and keep both the `event_specification` and the `event_specification_validation` entities, so you can inspect why each event failed. diff --git a/docs/testing/snowplow-micro/console/index.md b/docs/testing/snowplow-micro/console/index.md index b7ef97e54..8c3f4fd3c 100644 --- a/docs/testing/snowplow-micro/console/index.md +++ b/docs/testing/snowplow-micro/console/index.md @@ -51,8 +51,8 @@ To enable or disable enrichments and edit their configurations, select the **Enr ## Validate event specifications -Development environments validate incoming events against every published version of your [event specifications](/docs/event-studio/tracking-plans/event-specifications/index.md), following the same rules as [event specification validation](/docs/event-studio/tracking-plans/event-specification-validation/index.md) in a pipeline. Unlike pipelines, they also validate against the latest draft of each specification: you don't need to publish the tracking plan or its event specifications to test your tracking against them. +Development environments validate incoming events against every published version of your [event specifications](/docs/event-studio/tracking-plans/event-specifications/index.md), following the same rules as [event specification validation](/docs/event-studio/tracking-plans/event-specification-validation/index.md) in a pipeline. Unlike pipelines, they also validate against the current draft of each specification, so you don't need to publish the tracking plan or its event specifications to test your tracking against them. -Edit the specification in Console, send a test event, and inspect the result in the [Micro dashboard](/docs/testing/snowplow-micro/ui/index.md): events that fail validation carry an `event_specification_validation` entity describing each error. The environment picks up specification changes automatically within a few minutes. +Edit the specification in Console, send a test event, and inspect the result in the [Micro dashboard](/docs/testing/snowplow-micro/ui/index.md). Events that fail validation carry an `event_specification_validation` entity describing each error, and the environment picks up specification changes automatically within a few minutes. -Events that arrive without an `event_specification` entity are matched by [inference](/docs/event-studio/tracking-plans/event-specification-inference/index.md) instead, against both published specifications and the latest drafts. +The environment infers a specification for events that arrive without an `event_specification` entity, matching them against both published specifications and drafts. See [event specification inference](/docs/event-studio/tracking-plans/event-specification-inference/index.md) for the matching rules.