Go home
Menu

The rule card I keep beside coded data-quality checks

When a coded data-quality check blocks planning, I keep a rule card beside it so the failed condition, allowed exception, owner, blocked action, and review cadence stay visible.

7 min read by Berhan Turkkaynagi

A coded business-rule check can block a planning action and still leave the domain rule hard to see.

That is the uncomfortable gap. The check is doing its job, but the planner sees a failed validation result instead of the operating rule behind it: which condition failed, which action is blocked, and who can approve an exception.

When a coded check can stop buy, expedite, reallocate, release, or publish decisions, I keep a readable rule card beside it. The SQL catches the failed condition. The card keeps the domain rule, blocked action, allowed exception, first responder, approver, and review cadence visible.

Problem

Automated business-rule checks can move faster than the explanation around them.

A check fails in CI, dbt, a publish job, or a validation notebook. The planning slice is blocked. The red result says something is wrong, but it does not tell a planner whether the issue is a stale UOM mapping, a missing exception approval, or a real shortage-risk block.

That gap creates two bad habits. Technical owners point planners back to a model name, and planners look for a workaround because the operational decision is not visible: what failed, what cannot proceed, who responds first, and who can approve the exception.

This is narrower than the supply-chain checks I add before planners trust a feed. That post names the categories that make a planning slice safe. This post takes one of those categories after it has moved into code and asks whether the domain rule is still visible enough to operate.

It is also narrower than the dbt tests I write first for business-critical models. Test ordering matters, but this post starts after the check exists. The problem is keeping the business rule readable beside it.

Default approach

For every coded business-rule check that can block a planning action, I keep one rule card next to the check, pull request, validation output, or release note.

The split is deliberate. Code should catch the failed condition. The rule card should explain the operating rule.

The card has to answer six questions.

  • Name the domain rule in business language before naming the test.
  • State the failed condition the coded check catches.
  • Tie the rule to one or more blocked actions, such as buy, expedite, reallocate, release, or publish.
  • Separate ordinary failures from approved exceptions.
  • Name one first responder and one exception approver.
  • Add a review cadence so temporary exceptions do not become hidden policy.

The blocked-action line is what makes the card operational. It tells the planner what cannot proceed while the rule is failing. The exception approver prevents an ad hoc bypass from becoming the path of least resistance. The review cadence catches a different risk: a temporary exception that quietly becomes the real policy.

The coded check should stay narrow enough to fail on a clear condition. The rule card should stay readable enough that a planner can understand the consequence without opening the model.

Example

For one inventory UOM conversion rule, I would start with this slice.

Scenario
Feed: item_location_week_supply_plan
Slice: FG-104 @ WEST-03
Failure: supplier sends quantity in CASE, ERP receipts post in EA, and the active case-pack mapping is missing for the planning effective date
Planning risk: phantom on-hand quantity suppresses a needed buy, expedite, or reallocation
Blocked action: buy, expedite, and reallocate stay blocked until the rule passes or an approved exception exists

The coded check can stay small because it has one job: return rows where the CASE-to-EA mapping is missing for the planning date.

select
  p.item_id,
  p.supplier_id,
  p.location_id,
  p.plan_date,
  p.source_uom,
  p.canonical_uom,
  p.source_quantity
from item_location_week_supply_plan p
left join item_supplier_case_pack_map m
  on m.item_id = p.item_id
 and m.supplier_id = p.supplier_id
 and m.location_id = p.location_id
 and p.plan_date >= m.effective_start_date
 and p.plan_date < coalesce(m.effective_end_date, date '9999-12-31')
where p.source_uom = 'CASE'
  and p.canonical_uom = 'EA'
  and m.case_pack_mapping_id is null;

That query tells me which rows violate the condition. It does not tell the planner what action is blocked or who can approve the exception.

The rule card carries that part.

Domain rule card
Rule name: inventory_uom_conversion_integrity
Business rule: CASE -> EA conversion must use the active case-pack mapping for the item, supplier, location, and effective date.
Why it matters: stale conversion can inflate on-hand quantity and hide a true shortage.
Failed condition: source UOM is CASE, canonical UOM is EA, and no active case-pack mapping exists for the effective date.
Coded check: tests/inventory_uom_conversion_integrity.sql
Blocked action: buy, expedite, reallocate
Allowed exception: approved item-master transition window with owner note and expiry date
Exception approver: master-data / UOM owner
First responder: planning analytics owner
Review cadence: weekly exception-pattern review until recurring failures are zero
Evidence location: PR, test result, rule card, incident note, or release note

Now the failed check is not just a red result.

The planner can see that the issue is UOM conversion, not source freshness or missing demand. The blocked-action line says planning should not buy, expedite, or reallocate from that slice until the conversion rule passes or an approved exception exists. The exception line says that a transition window is valid only when the owner note and expiry date exist. The review cadence prevents the same exception from staying open until it quietly becomes the real rule.

That ownership split is the point. Planning analytics responds first because the failed check sits in the planning data path. The master-data or UOM owner approves exceptions because that team owns the case-pack truth. Those are different jobs, and the card makes the difference visible before a planner has to ask in chat.

The card does not need to become a governance catalog. It earns its place only when the coded check can block a real action. For a low-risk warning, the SQL result and a short model comment may be enough. For a check that stops buy, expedite, reallocate, release, publish, or financial reporting, the rule needs a readable operating artifact.

Tradeoffs

  • Breaks when: code becomes the only documentation for the rule → Mitigation: store the rule card beside the check name, PR, validation result, or release note so the business rule and coded condition move together.
  • Breaks when: every failed row gets treated as equally severe → Mitigation: tie the rule to the action it blocks and keep warning-only checks separate from release-blocking checks.
  • Breaks when: exceptions bypass the rule forever → Mitigation: require approver, reason, expiry date, and a recurring exception-pattern review.
  • Breaks when: the rule card drifts from the SQL → Mitigation: update the card and the coded check in the same PR or release note whenever the rule changes.
  • Breaks when: approval happens only in chat → Mitigation: record the exception approval in the same evidence location as the failed check or release decision.
  • Breaks when: the card becomes a broad inventory of every quality check → Mitigation: reserve the full version for checks that block planning, reporting, release, or financial decisions.

Close

Next step: Pick one coded business-rule check that already blocks a planning action and write the rule card beside it: failed condition, blocked action, allowed exception, first responder, approver, and review cadence.

The test earns trust when a planner can trace the failed condition to the blocked action without reading the model.