Data Quality

Data Quality Contracts With a Defined Response

Give each data rule a scope, a null policy and an action, then keep rejected records visible in the accounting.

On this page
  1. Scope the population
  2. Make null handling explicit
  3. Attach an action to each rule
  4. Preserve rejected data responsibly
  5. Keep exceptions narrow and versioned
  6. Test the rule and the response

A quality rule becomes operationally useful when it says what is checked, which data it applies to, and what happens when the check fails. A statement such as amounts should be valid leaves all three questions unresolved. It can produce a dashboard number without giving the pipeline a coherent response.

Start with a dataset contract that includes grain, keys, units, reporting boundary and correction semantics. A rule then checks part of that contract. Without the surrounding meaning, a technically precise query can still enforce the wrong assumption about the producer's data.

Scope the population

State the dataset version and eligible interval. A rule about today's accepted order lines should not accidentally include old rejected staging rows. Conversely, a check that runs only after invalid rows were removed cannot establish the quality of the input batch.

Keep stage-specific counts. Record received rows, accepted rows, rejected rows and explicitly ignored duplicates. Define whether those categories are mutually exclusive and whether their sum should equal the received population. A changed accounting total is itself a finding worth investigating.

For delayed input, state when the interval is considered complete. A daily count observed before the producer finishes delivering its data is a partial observation, not necessarily a quality failure. The rule should carry that readiness assumption with its result.

Make null handling explicit

Unknown is not automatically zero, and missing is not automatically permitted. A required key should reject null. An optional descriptive field might allow null while recording the missing fraction. A field that is conditionally required needs the condition written alongside the check.

This illustrative PostgreSQL table separates requiredness from range validation:

CREATE TABLE accepted_line (
  source_name text NOT NULL,
  line_id text NOT NULL,
  quantity integer NOT NULL CHECK (quantity > 0),
  unit_amount numeric(12, 2) NOT NULL
    CHECK (unit_amount >= 0),
  PRIMARY KEY (source_name, line_id)
);

In PostgreSQL, a CHECK expression that evaluates to null does not reject the row. NOT NULL therefore states a separate requirement. The constraint documentation gives the database semantics; whether zero-priced lines are valid remains a decision for this example's domain contract.

Attach an action to each rule

Some failures should reject a batch before publication. Others can quarantine individual rows while leaving a clearly incomplete accepted result. A warning may be appropriate for an unexpected but permitted distribution change. Do not make every rule fatal merely because it can be expressed as a boolean.

An example rule record can be compact:

rule: required-line-key / revision 2
population: received rows in declared batch
failure: source or line identifier missing
response: quarantine row; report incomplete batch
evidence: batch identity, row position, reason code
release condition: reviewed accounting and completion status

The evidence should be sufficient to locate the input without copying sensitive payloads into a broad-access log. Reason codes are more stable and easier to aggregate than arbitrary parser exception text.

Preserve rejected data responsibly

Quarantine is a controlled state, not a folder where failures disappear. Give it a retention policy, access boundary and replay procedure. Record the input identity and rule version so that a later correction can be distinguished from an unreviewed reprocessing attempt.

If accepted output excludes quarantined records, say so in its completion metadata. A consumer should not have to inspect an unrelated dashboard to discover that five percent of the declared input is missing. The completeness label should travel with the output.

Review repeated failures before weakening the rule. A sudden null population can indicate a producer change, a parser defect or a misunderstood optional field. Each explanation suggests a different repair. Removing the rule without explaining the new contract simply hides the disagreement.

Keep exceptions narrow and versioned

Sometimes a known source interval requires a temporary exception. Give it a reason, owner role, exact scope and expiry condition. An exception covering every source forever changes the contract and should be reviewed as such.

Store the rule revision with the result. A score produced under yesterday's permissive rule is not directly comparable with one produced under a stricter rule today. For trend analysis, either retain that distinction or recompute the relevant population under a common rule set.

Test the rule and the response

Prepare a small fixture with a valid record, a missing key, a prohibited quantity, a duplicate identity and an intentionally permitted null field. Check the classification and accounting, not only whether the validator throws an error.

Then test the consumer boundary. Does incomplete output remain labelled incomplete? Can a corrected quarantined record be replayed without duplicating an already accepted row? Does a rule failure produce a bounded diagnostic rather than an unlimited dump?

The result of a quality check is evidence about a defined population under a defined contract. It does not certify all future input. Useful rules make that boundary visible and connect each failed assumption to a deliberate response.