Data Quality Report — Sample
A worked example of a daily pipeline quality report — the five checks with thresholds and results, what a failure did to the output, and the definition disputes that no check can catch.
Markdown. No sign-up, no email.
This is an illustrative example. The pipelines, thresholds and results are invented to show the shape of a report someone will actually act on. Copy the structure; your thresholds must come from your own data.
A quality report has one job: say whether today's numbers can be relied on, and if not, exactly which ones. Everything below is arranged so that a person who reads only the first table knows the answer.
Data quality — 2026-08-04#
| Pipelines | 9 |
| Runs | 14 (9 daily, 5 hourly) |
| Overall | 1 pipeline failed closed · 1 degraded · 7 clean |
| Reported to | Data platform team and the finance definition owner |
1. Can today's numbers be relied on?#
| Domain | Status | If not, what is affected |
|---|---|---|
| Orders | ✅ Clean | — |
| Revenue | ⚠️ Yesterday's data | Revenue dashboards show 2026-08-03. Not wrong; one day behind. |
| Customers | ✅ Clean | — |
| Inventory | ⚠️ Degraded | Loaded, but 4.1% of rows missing a category |
| Web analytics | ✅ Clean | — |
Nothing published today is wrong. One domain is stale and one is incomplete, and both are labelled as such on the dashboards.
2. The five checks#
| Pipeline | Freshness | Volume | Uniqueness | Nulls | Reconciliation |
|---|---|---|---|---|---|
| orders_daily | ✅ 02:14 | ✅ 48,201 | ✅ | ✅ | ✅ ±0.00% |
| revenue_daily | ❌ not run | — | — | — | — |
| customers_daily | ✅ 02:31 | ✅ 1,204 new | ✅ | ✅ | ✅ ±0.00% |
| inventory_daily | ✅ 03:02 | ✅ 88,410 | ✅ | ⚠️ category 4.1% | ✅ ±0.02% |
| web_events_hourly | ✅ 09:05 | ⚠️ low, in range | ✅ | ✅ | n/a |
| finance_extract | ✅ 04:00 | ✅ | ✅ | ✅ | ⚠️ ±0.31% |
Thresholds, for reference: volume within ±25% of the 28-day median for the same weekday; nulls above 1% in a normally-populated field; reconciliation beyond ±0.1% against the system of record.
3. revenue_daily — failed closed, as designed#
| Time | 02:45 |
| Trigger | Source extract contained 312 rows against a 28-day median of 44,900 |
| Check that caught it | Volume |
| Action taken | Wrote nothing. Previous day's output left in place. Exited non-zero. |
| Alert | Paged the on-call data engineer at 02:46 |
| Cause | Upstream export ran against a replica mid-resync |
| Fix | Upstream scheduling changed. Re-run scheduled for 06:00 tomorrow. |
This is the report's most important entry, and it records a success. The pipeline was handed obviously wrong input and refused to publish it. Yesterday's revenue figure remained on the dashboard with its date visible.
Consider the alternative. Had it written what it received, every revenue dashboard would have shown a near-zero day. Someone would have escalated it as a commercial emergency, and the first hour of the working day would have gone into explaining a number rather than fixing a pipeline. Stale data announces itself. Wrong data gets acted on.
4. inventory_daily — degraded but published#
4.1% of rows arrived with a null category, against a 0.2% baseline. Above the threshold, so it is reported; not structurally broken, so it published with a marker.
Traced to a supplier feed that added a product line under a category code not in our mapping. The rows are correct in every other field. Category-level inventory reporting is incomplete for that supplier until the mapping is extended; total inventory is unaffected.
Publishing here was a judgement, and the judgement is recorded: the affected slice is identifiable, everything else is intact, and the dashboard shows the gap rather than hiding it. Had the nulls been spread unpredictably across suppliers, the same 4.1% would have been a stop.
5. finance_extract — reconciliation drift#
Totals differ from the source ledger by 0.31%, against a ±0.1% threshold. Third consecutive day, and the gap is widening: 0.08%, 0.19%, 0.31%.
The direction is consistent, which rules out random loss. Current hypothesis is a timezone boundary — transactions after 23:00 local landing in the following day's extract. Under investigation; the pipeline continues to publish with the variance shown, because a known and quantified 0.31% is more useful than no figure at all.
6. What no check can catch#
Two open items are definition disputes, not data problems, and no automated check will ever find them.
"Active customer" has two definitions in use. Marketing counts a purchase in 90 days; finance counts any account not closed. Both dashboards are correct against their own definition and they differ by roughly 40,000 people. The pipeline is not wrong. This is the most common cause of "our dashboards disagree", and it is resolved by naming an owner for the definition, not by editing a query.
Refund timing is unspecified. Refunds are currently applied to the original order date. Whether they should reduce that day's revenue or the day the refund was issued has never been written down. Both are defensible; only one can be true at a time.
Both are with the finance definition owner.
7. Actions#
| Action | Owner | By |
|---|---|---|
| Re-run revenue_daily after the upstream fix | Data platform | Tomorrow 06:00 |
| Extend the supplier category mapping | Data platform | This week |
| Confirm or reject the timezone hypothesis on finance_extract | Data platform | 48 hours |
| Rule on the "active customer" definition | Finance definition owner | This week |
| Write down the refund timing rule | Finance definition owner | This week |
Notes on using this format#
Lead with whether the numbers can be relied on. Most readers need only that. The checks underneath are for the people who have to act.
Report a fail-closed event as a success. If a stopped pipeline is written up as a failure, the next engineer under pressure will make it publish through the error, and the report will have caused exactly the incident it exists to prevent.
Keep definition disputes in the report even though no check produces them. They cause more disagreement about numbers than every data defect above combined, and they are invisible in any report generated purely from the pipeline.