Bad rows shouldn't reach the warehouse
When a row fails a quality check, you have two honest choices: stop the world, or set it aside. faucet-stream does both — as a per-check decision — and never silently drops data.
Two bad options, and the one nobody should pick
A row violates a rule — a null where you require a value, a negative amount, a broken enum. There are three things a pipeline can do: abort the run, quarantine the row, or silently drop it. The third is the one that ruins your data quietly, and it's the one faucet-stream never does.
Quality checks decide, per rule, before the write
Quality is a stage in the movement path — it runs on each page before the sink sees it. Every check declares what happens on failure:
quality:
checks:
- { field: amount, rule: { gte: 0 }, on_failure: abort }
- { field: email, rule: not_null, on_failure: quarantine } - abort — stop the run. Use it for violations that mean the whole batch is suspect.
- quarantine — route the offending row to a dead-letter queue, and let the good rows through. The bad row is captured, not discarded.
Quarantine needs somewhere to go
A quarantine action requires a DLQ sink to be configured — otherwise
the run is rejected at startup, not quietly turned into a drop. "Set the row aside"
only means something if there's a side to set it on.
And because governance runs in a fixed order with masking first, a quarantined row carries the masked payload, not the raw one — a bad row never leaks a secret into the DLQ. (More on that ordering in the governance paper.)
Takeaway
Invalid data stays out of the target, valid data keeps flowing, and nothing vanishes without a trace. Abort when the batch is untrustworthy; quarantine when it's a few bad rows — and never pick the silent third option, because faucet won't offer it.
More on the blog, or read the documentation.