Numeric quality assertions¶
Contract data_quality.rules can compare an observed batch metric with a
numeric threshold. These assertions run when a pipeline step enables
contract.quality; they do not control record quarantine or scheduling.
| Assertion | Passes when |
|---|---|
mustBe |
observed equals the operand |
mustNotBe |
observed differs from the operand |
mustBeGreaterThan |
observed is strictly greater |
mustBeGreaterOrEqualTo |
observed is greater or equal |
mustBeLessThan |
observed is strictly less |
mustBeLessOrEqualTo |
observed is less or equal |
mustBeBetween |
observed is within [lower, upper], including endpoints |
Snake case spellings are also supported, for example must_not_be and
must_be_between. Operands must be finite numbers or numeric strings.
Booleans, nonnumeric strings, NaN, and infinity are invalid. A range needs
exactly two finite endpoints in ascending order. Equal endpoints and
negative thresholds are valid.
This rule fails for an empty batch and passes for a batch containing one or
more records. For per-column validators and expression rules, the observed
metric is the number of failures, so mustNotBe: 0 asks for at least one
failure. Use mustBe: 0 to require zero failures.
An omitted or null operand is unset. Without an explicit assertion, the
metric evaluator retains its observed-equals-zero default; expression and
per-column rules require zero failures. Custom quality callables retain
ownership of their boolean or CustomRuleResult.passed verdict. Numeric
declarations on a custom rule are validated, but do not override its verdict.
Every distinct non-null numeric assertion on a native metric rule must pass (logical AND). The metric is measured once, and the rule retains one outcome and one severity regardless of how many assertions it declares:
data_quality:
rules:
- name: bounded_volume
rule: row_count
mustBeGreaterThan: 0
mustBeLessThan: 1000
severity: error
This rule passes for 1–999 records and fails for an empty batch or 1,000 or more records. Failure guidance includes every failed requirement in a fixed order: equality, strict lower bound, inclusive lower bound, strict upper bound, inclusive upper bound, range, then inequality. YAML key order does not change the verdict or failure order. Contradictory requirements remain valid declarations but can never pass together; fix the intended bounds rather than expecting one assertion to override another.
Equivalent camelCase and snake case declarations of the same assertion collapse to one; null is unset. Conflicting non-null aliases are rejected. Remove the duplicate and keep the intended operand. All operands are validated before any comparison, including operands on later assertions.
This is a semantic compatibility change from first-match evaluation. Older executors could pass the example with 1,500 records by checking only the lower bound. Review mixed-assertion rules before upgrading: retain every intended requirement, remove accidentally authored assertions, or split independent checks into separate named rules when they need separate severities/outcomes. Single assertions, unset defaults, and custom callable verdict ownership remain compatible. See the migration guide.
Malformed declarations fail contract loading with a rule/field path and repair guidance, without including the rejected operand. Direct evaluator dictionaries raise a configuration error when their rule is reached; outcomes from earlier rules remain available to an execution observer.
ODCS export uses native library metrics when the authored assertion fits
the selected ODCS schema. Otherwise it uses the existing engine: pycharter
custom representation, preserving operators and the authored rule type.
This includes equal range endpoints, numeric strings where ODCS requires a
number, snake case assertions, multiple assertions, and absent assertions.
A foreign engine needs an implementation for this custom representation;
an exported document alone does not establish that engine's executability.