Software & TechnicalFree
Data Quality Incident Postmortem and RCA
Fixing the pipeline erases the evidence. River captures what the table held, then works out which reports and which decisions used it.
River reads the pipeline logs, the test results and the model definitions, then writes the incident report: the root cause, the window each consumer was exposed to, and the corrections owed. The impact sheet has two halves. One holds the reports, extracts and models that read the data, from lineage and from query history. The other holds the decisions already taken on it, which no lineage graph has ever contained: a quota set, an invoice sent, a campaign fired.
Every template for this asks for a timeline and a five whys. Both are right and neither is urgent. The urgent thing is that the answer to what did they actually see expires: a Snowflake account keeps one day of history by default, BigQuery keeps seven, and a vacuumed Delta table keeps seven. A data incident is usually found later than that. So the first output here is a capture, not a diagnosis. Fixing the pipeline is what destroys the record.
Built for the analytics engineer whose Monday started with a screenshot from finance. Reach for it in the first hour, before anyone reruns the model. The pipeline documentation pack is where the checks that should have caught this are written down, and the service postmortem covers the outage version of the same job. An analysis write-up is what stops the corrected number going out with the same unstated population as the wrong one.
The record of what they saw expires
Snowflake documents that the standard retention period is one day, twenty-four hours, and is automatically enabled for all accounts, and on Standard Edition the only other setting is zero. So a bad load on Tuesday, noticed on Thursday, is already unrecoverable as a question: you can fix the number and you cannot say what the number was. The report has to be written from what you preserve in the first hour, or from nothing.
The other engines buy you a week. BigQuery's time travel window covers the past seven days by default and can be set no lower than two. Delta Lake gives thirty days of history until you vacuum, and its deleted-file retention defaults to seven days, which is the number that governs once a maintenance job runs. Seven days is enough for an incident somebody noticed. It is not enough for a quarter-end reconciliation that surfaces in April.
Exposure is a property of each consumer, not of the incident. A dashboard refreshing at six every morning showed the wrong figure on a different set of days from a scheduled export that ran on Tuesday, and both differ from a model that trained once on the whole window. So the impact sheet carries a window per consumer, computed from its own refresh cadence, with the correction status beside it. One list of affected reports and one date range is the version that produces a follow-up email a week later.
How it works
Capture first
River records what the affected tables hold right now, before a rerun overwrites the evidence.
Send the logs
Pipeline runs, test results and model definitions, plus how you found out and when.
Trace the readers
Lineage plus query history, so scheduled exports and spreadsheet connections are in the list.
Write and correct
The report, the exposure window per consumer, and the corrections owed with owners against them.
What you get
- A capture of what the tables held, taken before anything is rerun or fixed
- The root cause separated from the trigger, with the check that should have caught it
- An exposure window computed per consumer, from that consumer's own refresh cadence
- Every report, extract and model that read the data, from lineage and query history
- The decisions already taken on the wrong number, which lineage cannot see
- Correction status per consumer, so a retraction is a list rather than a guess
Common questions
We already fixed it. Is it too late?
No, and one section gets harder. The root cause, the timeline and the reader list all survive a fix. What does not always survive is the exact figure each consumer saw, because the history window on most warehouses is measured in days. Where it has gone, the report reconstructs the range from run logs and says which figures are bounded rather than known.
Our lineage graph already tells us what is downstream.
It tells you what queries the table. It does not tell you that the head of revenue built next quarter's territory split on Thursday's export, or that 4,100 emails went out priced off the wrong column. Those are the corrections that cost something, and they come from asking who acted rather than from the graph. It will not name the tables nobody reads, which the warehouse cost review counts.
How does it decide when the data was wrong?
From the run record rather than the fix time. The first run that produced the bad output, which is not the first alert and not the first complaint, and the run that first produced a correct one. Where the logs cannot narrow it beyond a day, the window is written as a bound and the query that would tighten it is named.
The tests passed. How is that possible?
Usually because the test measured something the failure did not touch, or because it was configured to warn rather than fail. Both are findings and both belong beside the root cause. The pipeline documentation pack carries the register showing which checks enforce anything, which is the fix for the next one.
Who is the report for?
Two audiences and one document. The data team gets the run record, the model, the mechanism and the check that failed to fire. Finance, sales or whoever read the number gets the window they were exposed to, the corrected figure, and whether anything they did on it needs undoing. The second half is the one that gets read.
We are not on a cloud warehouse.
Then the capture step matters more, because a Postgres or MySQL table holds no history at all once it is updated. The report opens with what was preserved and what was not, so a reader knows which figures are recorded and which are inferred from run logs. That distinction is what makes the document usable in a dispute six weeks later.
Does it produce the action items too?
One list, each item tied to the specific link in the chain it breaks: the check that would have caught it, the contract the upstream change violated, the alert nobody owns. Items with no owner or no date do not go in. The service-side version of the same discipline sits in the incident postmortem.
Data Quality Incident Postmortem and RCA
Fill in the form and your workspace opens with the work already underway.