Data quality

Late but green, when every job succeeds and the data is still stale

Most data incidents reach a dashboard through jobs that report success. Here is how to measure freshness directly and set expectations a team will trust.

In this post

A data team once told us their quality record was excellent. Every pipeline had tests, every test passed, and the orchestrator showed a wall of green. The same week, the finance dashboard showed Monday’s revenue on Wednesday.

Nothing had failed. A vendor feed had arrived two days late, the transformation job ran on the previous file, and every check agreed that the output was valid. It was valid. It was also old.

The failure that no test catches

Tests describe what correct data looks like: no nulls in this column, ids are unique, totals match. They say nothing about whether the data is the data you expected today. A table can pass every test while holding last week’s rows.

Job status has the same blind spot. A job succeeds when it finishes without an error. It does not know that its input was a day late.

There are three common ways to be late without failing:

  • A source is late. The file, API or event stream arrives after the deadline, and the job runs on what is there.
  • A schedule slips. An upstream task waits for a resource, and everything behind it starts later than usual but still finishes.
  • A job runs on an empty window. The query is correct, the window has no rows yet, and zero rows is a valid result.

Freshness is a property of data, not of jobs

The question to ask is not “did the job run” but “how old is the newest data in this table, and is that acceptable”. That is freshness, and you can measure it directly.

For a table with an event timestamp, the measurement is a query:

select
  max(event_time) as newest_event,
  datediff('minute', max(event_time), current_timestamp) as minutes_behind
from analytics.orders;

For a table without a reliable event time, use the load time that your warehouse already records. Most warehouses keep a last modified time in their metadata views, which is cheaper to read than the table itself.

Once you can measure freshness you can compare it with an expectation. Tidewater stores that expectation next to the table, and shows the answer as one of three states: on time, late, or late and affecting something downstream.

Setting an expectation people will trust

A freshness expectation is a promise, and a promise that is wrong too often is ignored. Three habits keep them credible.

Write the deadline as the consumer would. “The orders table is complete by 06:00 on weekdays” is a statement a finance director can check. “Max lag 240 minutes” is not.

Use history, then round up. Look at the last 30 days of arrival times. Set the deadline just beyond the slowest normal day, not the average. If the table arrives between 04:10 and 05:20, a deadline of 06:00 will rarely fire for no reason.

Separate late from broken. A table that is 20 minutes late is a warning. A table that is four hours late on a close day is an incident. Two thresholds let the system say the difference.

SignalWhat it tells youWhat it misses
Job succeededThe code finished without an errorWhether the input was current
Test passedThe data is shaped as expectedWhether the data is from today
Row count in rangeVolume looks normalWhether the rows are new
Freshness within deadlineThe newest data is recent enoughWhether the values are right

No single signal is enough. Freshness fills the gap that the other three leave, which is why we treat it as the first check on any table that people read.

What to do when a feed is late

When an alert arrives, the first useful fact is what is affected. A late staging table that nothing reads can wait. A late table that feeds the revenue dashboard cannot.

You can ask the Tidewater API for the downstream assets of a table directly:

curl -s "https://api.tidewater.example/v1/lineage/analytics.orders?direction=downstream&depth=3" \
  -H "Authorization: Bearer $TIDEWATER_TOKEN"

The response lists tables, models and dashboards with their owners. The second useful fact is whether the source is late or only your copy of it. That decides whether you wait, ask the vendor, or re-run a job.

A starting checklist

  1. List the ten tables that people outside the data team read most.
  2. For each one, write the deadline as the reader would say it.
  3. Check 30 days of arrival times and move any deadline that would have fired for no reason.
  4. Give each table an owner, and send its alerts to that owner.
  5. Review the alerts that fired after two weeks, and tighten or loosen the deadlines.

Teams that do this usually find, within the first month, one feed that has been quietly late for a long time. That alone tends to pay for the effort.

Keep reading

One short e-mail a month

New posts and changelog highlights.

See your own pipelines in Tidewater

Book a 30 minute walkthrough. We connect a sample of your setup and show you what it would have caught last month.