Expand description
What changed between two reports.
A pipeline that keeps a baseline report asks the same questions of every
new one: did quality move, did a column appear or vanish, did a column’s
null rate change. ReportDelta answers them in one typed value, so the
answer does not depend on which language computed it, and so a policy over
drift can be written against a contract rather than a dictionary.
§The contract
The two reports are a and b, compared in that order. The serialized
shape is the one ProfileReport.compare() returns in Python, and it is
stable: later releases may add keys, never remove or rename one.
- Signs. Every change is
b - a. A positiveabson a score is an improvement, because a score is higher when quality is better. A positivenull_pct_deltais a degradation, because it is more nulls. - Precision. Each side’s number is taken at its serialized precision (2 decimals on a 0-100 scale), and the change is rounded to it too, so a report and its saved document compare alike.
- No invented numbers. A number one side does not carry, an
unassessed dimension, an empty column or an empty report, leaves the
change
None.rel_pctisNoneas well whenais zero, where a relative change is undefined. - Provenance. Each number carries the
Evidencebehind it on both sides, so an exact baseline compared with a sampled or truncated run says so instead of reading a sampling difference as a change in the data. - Definitions.
metric_semantics.comparableisSome(true)only when both reports record every definition this build knows, with the same values. A difference in a measurement whose definition changed between releases is not a difference in the data. - Configuration.
configurationlists each recorded setting that moves a score on unchanged data (the score weights, the semantic hints, the pattern locale) on both sides, withsame:Some(true)when both recorded it and agree,Some(false)when they differ,Nonewhen either did not record it. Configuration is not comparability: a score that moved under a different setting may not reflect a change in the data. Each policy reads only the settings it depends on.
Nothing here decides whether a change is acceptable; that is a policy’s
job. A window-over-window comparison reuses the same vocabulary: a and
b name the two sides without saying which came first.
§Example
use dataprof_runtime::{ProfileReport, ReportDelta};
fn drift(baseline: &ProfileReport, current: &ProfileReport) {
let delta = ReportDelta::between(baseline, current);
if let Some(change) = delta.quality_score.abs {
println!("quality moved {change:+.2} points");
}
for name in &delta.schema.removed {
println!("column {name} is gone");
}
}Structs§
- Column
Change - One column’s change. Serialized as an entry of the
columnsobject, keyed by the column’s name. Each side’s number covers what that side’s scan read; seeReportReference::evidence. - Configuration
Comparison - The recorded settings that move a score on unchanged data, on each side.
- Dimension
Change - One quality dimension’s change. Serialized as an entry of the
dimensionsobject, keyed by the dimension’s name. - Recorded
Hints - The semantic hints a report recorded, by the configuration field that carries each, read from its hint bindings.
- Report
Delta - What changed between two reports. See the module docs for the contract.
- Report
Reference - Which report a side is, and how much of its source it read.
- Report
Side - What a comparison reads from one report.
- Schema
Change - Which columns each side has.
- Score
Change - One score on both sides and how it moved.
- Semantics
Comparison - Each side’s recorded measurement definitions, and whether they agree.
- Setting
Comparison - One recorded setting on each side, and whether the two agree.
- Sides
- The same fact about each side of a comparison.