DE//AGENT
Explore
Tutorial Lesson 5 of 10 · The Data Quality Series community intermediate

Split a batch into quarantine and publish

Build the pipeline-dq-quarantine starter the way the Quarantine then Publish pattern prescribes: a quality contract splits each batch into a published set and a quarantine with reasons. You finish with a test that proves no row is ever lost and an alert on the quarantine rate.

At a glance

When External/partner data or any table with an SLA; High-value downstream metrics that one bad batch could poison
Where Data Quality
Why A row never disappears — it is either published or quarantined with a reason, so one bad batch cannot poison the table.

Learning objectives

  • Express a quality contract as executable checks
  • Design a quarantine table with a reason
  • Alert on the quarantine rate, not just on failure

What you need

  • The pipeline-dq-quarantine starter (contract/orders.yml, src/validate.py, src/publish.py)
  • DuckDB or PySpark to compile the contract rules to SQL
  • A batch with ~5% deliberately invalid rows (nulls, dupes, out-of-range)
  • [object Object]

Steps

  1. Split every batch into publish and quarantine on a quality contract. (from pattern-quarantine-publish )
  2. Validate the contract offline against fixtures with `make test`, then run `make run`. (from project-pipeline-dq-quarantine )
  3. Load the contract and compile rules to SQL (DuckDB) or Spark expressions. (from project-pipeline-dq-quarantine )
  4. Split into pass/fail with a stable `failure_reason`. (from project-pipeline-dq-quarantine )
  5. Publish the pass set; write the fail set to quarantine with provenance. (from project-pipeline-dq-quarantine )
  6. Alert when the quarantine rate > 1% for 2 consecutive runs. (from project-pipeline-dq-quarantine )

Check yourself

  • Every row is either published or quarantined — never lost; the quarantine contains exactly the seeded bad rows, and a clean batch produces an empty quarantine.
  • A quarantine rate above 1% for 2 consecutive runs fires the alert with the failure_reason breakdown attached.

Worked example

Split every batch — pass publishes, fail quarantines with a reason — from pattern-quarantine-publish

Split every batch into publish and quarantine on a quality contract.
  pass ─▶ published table (SLA-bearing)
  fail ─▶ quarantine table (retained, alertable, reprocessable)
A row never disappears: it is either published or quarantined with a reason.
Alert on quarantine *rate*, not just on a hard failure — a rising rate is the
early signal of an upstream problem.

Starter layout — contract, validate, publish — from project-pipeline-dq-quarantine

pipeline-dq-quarantine/
  contract/orders.yml       # rules: not_null, unique, range, enum
  src/validate.py
  src/publish.py
  tests/test_quarantine.py

Validate the contract offline, then run the batch — from project-pipeline-dq-quarantine

make test  # validates against the fixtures offline
make run

Sourced from

Security scan

Last sweep 2026-10-24: 0 finding(s), 0 marked as examples.

Common gotchas

  • A quarantine nobody reviews is just a slower data loss.
  • Contract too strict → quarantine rate explodes; tier rules and loosen with evidence.
  • Alert on quarantine rate, not just on a hard failure — a rising rate is the early signal of an upstream problem.

Production considerations

  • Alert when quarantine rate > 1% for 2 consecutive runs.
  • Ship a reprocess command that re-runs the quarantined rows after a fix.

Diagram

batch
   |
   |- [contract check] --> pass --> published/ (SLA-bearing)
   |
   |- [contract check] --> fail --> quarantine/ (+reason, +source_file)
   |
   |- quarantine rate > 1% x2 runs --> alert --> review + reprocess

Registry stats

Verification community · Oct 21, 2026
Completeness 81
Trust multiplier ×1.25
Composite 34.15 · adequate
Freshness 3 days since last source check
Difficulty intermediate
Version 0.1.0
License CC-BY-4.0
Security flags none