Skip to content
Back to skills

Quality Rules

ASecurity

Data Product Builders and Owners. Proposes and adds data quality rules and service levels to an ODCS data contract: schema constraints, library metrics (rowCount, nullValues, missingValues, invalidValues, duplicateValues), SQL rules, freshness and retention, each with a dimension, id, and tags, grounded in the field semantics and, if the user agrees, in a profile of the actual data, then lints and test-runs them. Use when the user wants to add quality checks, data quality expectations, SLAs, ...

  • 4 stars
  • 0 votes
  • 0 copies
  • 5 views
  • Added October 26, 2026
businessgobashsqlexpress

Works with

  • cli

Security analysis

A100/100

Scanned October 26, 2026

npx -y skills add datacontract/datacontract-skills --skill quality-rules --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Quality Rules?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Quality Rules
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/datacontract-quality-rules/badge)](https://www.skillsdirectory.com/skills/datacontract-quality-rules)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: quality-rules
description: "Data Product Builders and Owners. Proposes and adds data quality rules and service levels to an ODCS data contract: schema constraints, library metrics (rowCount, nullValues, missingValues, invalidValues, duplicateValues), SQL rules, freshness and retention, each with a dimension, id, and tags, grounded in the field semantics and, if the user agrees, in a profile of the actual data, then lints and test-runs them. Use when the user wants to add quality checks, data quality expectations, SLAs, freshness checks, or make a contract stricter or more useful for consumers."
---

# Add Quality Rules and Service Levels

**Persona:** data engineer, data product owner
**Trigger:** after a contract is created, before it is marked `active`, or when consumers report a data problem a check should have caught
**Output:** quality rules and service levels in the contract, linted and test-run, with a coverage summary per quality dimension

## Step 0: CLI

Follow the `datacontract-cli` skill, Step 1.

## Step 1: Read the contract

Read the contract and `datacontract lint` it first. List per schema: grain, keys, required fields, closed value sets, amounts and their units, timestamps, relationships, and existing `quality` and `slaProperties`. Ask the owner what consumers rely on most and what has gone wrong before: those are the rules worth having.

## Step 2: Prefer schema constraints

Many expectations are not quality rules but schema attributes, which the CLI checks automatically and every exporter (dbt, SQL, JSON Schema, Pydantic, ...) understands:

| Expectation | Write it as |
|---|---|
| no nulls | `required: true` |
| no duplicates | `unique: true` |
| identifier | `primaryKey: true` (composite: on each member, with `primaryKeyPosition`) |
| reference to another table | `relationships: [{type: foreignKey, to: customers.customer_id}]` |
| closed set of values | `enum: [{value: a}, {value: b}]` |
| length, range, format | `logicalTypeOptions`: `minLength`, `maxLength`, `minimum`, `maximum`, `pattern`, `format` |

Use `quality` rules for what these cannot express.

## Step 3: Propose quality rules

For each schema, consider at least:

| Dimension | Typical rule |
|---|---|
| completeness | `rowCount` above a floor; `missingValues` with `['', 'N/A']` on text fields; `nullValues` with `unit: percent` where a few nulls are acceptable |
| uniqueness | `duplicateValues` over the natural key (schema level, `arguments.properties: [...]`) |
| conformity | `invalidValues` with `validValues` on open-ended but known code lists |
| consistency | `sql`: header total equals sum of line items; end date after start date |
| accuracy | `sql`: share of amounts in a plausible band (`mustBeBetween`) |
| timeliness | service level `freshness` (Step 4) |

Rule shapes:

```yaml
schema:
  - name: orders
    quality:
      - id: orders_not_empty
        type: library
        metric: rowCount
        mustBeGreaterThan: 1000
        dimension: completeness
        tags: [critical, cheap]
        description: A normal day has more than 1,000 orders; fewer means a partial load.
      - id: orders_total_matches_items
        type: sql
        dimension: consistency
        description: The order total equals the sum of its line items.
        query: |
          SELECT COUNT(*) FROM ${table} o
          JOIN (SELECT order_id, SUM(price) AS s FROM line_items GROUP BY order_id) li
            ON li.order_id = o.order_id
          WHERE o.order_total <> li.s
        mustBe: 0
    properties:
      - name: customer_email
        quality:
          - id: customer_email_mostly_present
            type: library
            metric: nullValues
            unit: percent
            mustBeLessThan: 1
            dimension: completeness
```

Rules:

- Every rule gets a `description` that says **why** the threshold is what it is, a `dimension` (one of `accuracy`, `completeness`, `conformity`, `consistency`, `coverage`, `timeliness`, `uniqueness`), and an `id` unique in the contract. Add `tags` (`critical`, `cheap`, `expensive`) so pipelines can run subsets with `--tag`.
- Library metrics: `rowCount` is schema level; `nullValues`, `missingValues`, `invalidValues` are property level; `duplicateValues` is either. Exactly one comparator per rule: `mustBe`, `mustNotBe`, `mustBeGreaterThan`, `mustBeGreaterOrEqualTo`, `mustBeLessThan`, `mustBeLessOrEqualTo`, `mustBeBetween`, `mustNotBeBetween`.
- SQL rules return a single number, are read-only, use the server's dialect, and should use placeholders (`${table}`, `${schema}`, `${column}`) rather than hard-coded names.
- `type: text` documents an expectation nobody can automate. Use it sparingly.
- Thresholds come from the owner or from data, never from thin air. If neither is available, propose a value and mark it as an assumption in the description.

Check the details of a rule type before using an option you have not seen: [quality rules](https://cli.datacontract.com/quality-rules), [library](https://cli.datacontract.com/quality-rules/library), [SQL](https://cli.datacontract.com/quality-rules/sql).

## Step 4: Service levels

Add `slaProperties` at the contract root. `freshness` and `retention` are checked by the CLI when they name the timestamp column in `element`:

```yaml
slaProperties:
  - property: freshness
    value: "24"
    unit: hours
    element: orders.order_timestamp
    description: New orders arrive within 24 hours.
  - property: retention
    value: "2"
    unit: years
    element: orders.order_timestamp
  - property: availability
    value: 99.9%
```

Other properties (`availability`, `latency`, `support`, ...) document promises and are not tested. See [service levels](https://cli.datacontract.com/service-levels).

## Step 5: Ground the thresholds in data (optional)

Only with the user's go-ahead to query the server. Run each candidate rule once and look at the actual value:

```bash
datacontract test contracts/orders.odcs.yaml --server production --checks quality,slaProperties \
  --output "$SCRATCH/quality.json" --output-format json
```

A rule that fails on today's data is either a real problem (tell the owner) or a threshold that is too strict (adjust it with a note). Never silently loosen a threshold until it passes.

## Step 6: Apply and report

Show the additions as a diff, apply on confirmation, `datacontract lint --all-errors`, and test-run with `--dry-run` (no credentials needed) to confirm that every rule can be planned.

Report a coverage table per schema, one row per dimension: rules before, rules after, and which important field has no check yet. Point to `contract-ci` to run the rules on a schedule, for example cheap rules on every load (`--tag cheap`) and expensive ones nightly.

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.