Skip to content

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.

data_quality:
  rules:
    - name: nonempty_batch
      rule: row_count
      mustNotBe: 0
      severity: error

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.

See pipeline quality and reports and ODCS integration.