> ## Documentation Index
> Fetch the complete documentation index at: https://docs.synq.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Check categories

> Classify every check into governance and technical categories so analytics, coverage, and reporting stay consistent across your data stack

Checks arrive from many tools, each with its own naming. A dbt `not_null`
test, a dbt `not_null_proportion` test, an `elementary` test, a SQLMesh audit,
and a hand-written SQL assertion can all be checking the same thing — that a
column has no missing values — yet none of them share a name. Left as-is,
there's no way to ask *"how well is completeness covered across my stack?"*
without knowing every tool's vocabulary.

Check categorisation solves this. Coalesce Quality categorises every check
(dbt tests, SQLMesh audits, custom assertions, …) as it is ingested, mapping
each one onto a **consistent taxonomy** regardless of which tool produced it.
That shared vocabulary is what powers the analytics dashboards, coverage
reports, and filtering across the product — so a check only shows up in the
right place if it is categorised correctly.

Categorisation happens along **two independent dimensions**:

| Dimension      | Answers                                     | Example values                                           | Primarily used by                                                       |
| -------------- | ------------------------------------------- | -------------------------------------------------------- | ----------------------------------------------------------------------- |
| **Governance** | *What is the purpose of this check?*        | Completeness, Accuracy, Validity, Timeliness, Uniqueness | Data governance teams tracking coverage against governance requirements |
| **Technical**  | *What kind of check is this, mechanically?* | nullness, uniqueness, referential integrity, freshness   | Analysts and developers navigating and organising checks                |

The governance dimension maps onto the
[data quality dimensions](/analytics/analytics-overview) you see in Analytics.
The technical dimension groups checks by their validation logic — for example
every `not_null` variant across dbt, SQLMesh and custom SQL collapses into a
single `nullness` group.

A check carries **one category per dimension**. The two are resolved
independently, so a single check can be `Completeness` for governance and
`nullness` for technical at the same time.

## Where categories come from

For each dimension, a check's effective category is resolved from three
sources, in descending priority:

1. **Admin override** — a per-check category set by a workspace admin from the
   **Checks** tab (see [Per-check overrides](#per-check-overrides)). Overrides
   always win.
2. **Producer-explicit category** — set directly by the producer, or carried on
   the source asset as a `synq.check_category` / `synq.governance_category`
   annotation.
3. **Computed category** — derived by the categorisation engine from the
   **categorisation rules** described below. A matching **workspace** rule wins
   over a matching **global** rule.

If none of these produces a value the check is **Uncategorised** for that
dimension. When a higher tier supplies the value, the UI still shows which rule
*would* have matched — so you can see what an override or explicit value is
masking.

## Categorisation rules

A categorisation rule says *"checks matching this predicate get this
category"*. Rules are managed under **Health → Check categorisation**, which has
a section per dimension (**Governance**, **Technical**) plus a **Checks**
section for inspecting how individual checks were categorised.

Each rule has:

* a **category** — the value assigned to checks it matches (free-form, e.g.
  `completeness` or `nullness`);
* a **priority** — when several rules match the same check, the
  highest-priority rule wins;
* a **predicate** — either a [structured predicate](#structured-predicate) or a
  [CEL expression](#cel-expressions), never both.

<Info>
  Rules created in the app are **workspace rules** — they apply only to your
  workspace and win over the **global**, Coalesce Quality-provided rules on a
  priority tie. Global rules are maintained by Coalesce Quality administrators.
</Info>

### Structured predicate

The structured predicate matches on the facts a check already carries. A check
matches when **every non-empty group** below contains the check's value — an
empty group matches anything.

| Group                     | Matches against                        | Example                                 |
| ------------------------- | -------------------------------------- | --------------------------------------- |
| **Platforms**             | The platform the check comes from      | `dbt`, `SQLMesh`                        |
| **Asset types**           | The check's asset type                 | `dbt test`, `SQLMesh audit`             |
| **Packages**              | The package providing the check        | `dbt-utils`, `elementary`               |
| **Kinds**                 | The check's validation-logic kind      | `not_null`, `unique`, `accepted_values` |
| **Names**                 | Glob patterns against the check's name | `freshness_*`                           |
| **Annotation predicates** | Key/value annotations on the check     | `dbt.tag` equals `pii`                  |

For example, a rule with **Platforms** = `dbt` and **Kinds** = `not_null`,
`not_null_proportion` matches every dbt not-null-style test and nothing else.

**Names** use `*` as a wildcard for any sequence of characters (every other
character is literal); multiple patterns are OR-ed.

**Annotation predicates** match a check's annotations by key, with one of four
modes per key:

| Mode              | Matches when the annotation…     |
| ----------------- | -------------------------------- |
| **exists**        | …is present, regardless of value |
| **equals**        | …equals a given value            |
| **is one of**     | …equals any value in a list      |
| **matches regex** | …matches a regular expression    |

The platform and asset-type dropdowns are populated from checks actually present
in your workspace and narrow as you pick, so you only ever see real values.

### CEL expressions

When the structured predicate isn't expressive enough — string prefixes,
regular expressions, combining conditions with `||` — switch the predicate to a
**CEL expression**. The rule matches a check when the expression evaluates to
`true`.

[CEL](https://github.com/google/cel-spec) (Common Expression Language) is a
small, safe expression language. The following variables are available:

| Variable             | Type                  | Description                                                           |
| -------------------- | --------------------- | --------------------------------------------------------------------- |
| `platform`           | `string`              | Platform name, e.g. `PLATFORM_DBT`                                    |
| `asset_type`         | `string`              | Asset type name, e.g. `ASSET_TYPE_DBT_TEST`                           |
| `package`            | `string`              | Package providing the check, may be empty                             |
| `kind`               | `string`              | Validation-logic kind, e.g. `not_null`                                |
| `name`               | `string`              | Short name of the check                                               |
| `description`        | `string`              | Human-readable description, may be empty                              |
| `is_platform_native` | `bool`                | `true` for checks built into the platform (vs. custom or third-party) |
| `annotations`        | `map<string, string>` | Key/value annotations on the check                                    |

`PLATFORM_*` and `ASSET_TYPE_*` enum names are exposed as string constants, so
you can compare against them directly.

```python theme={null}
# every dbt not-null-style test
platform == PLATFORM_DBT && kind.startsWith("not_null")

# checks the source asset tagged as PII
annotations["dbt.tag"] == "pii"

# anything matching a naming convention, on any platform
name.matches("(?i)^freshness_.*")

# custom assertions that are not platform-native
asset_type == ASSET_TYPE_CUSTOM_TEST && !is_platform_native
```

<Tip>
  Prefer the structured predicate when it can express your rule — it's easier to
  read at a glance and cheaper to evaluate. Reach for CEL only for the cases it
  can't cover.
</Tip>

## Live impact preview

While you edit a rule, the dialog runs a **live impact preview** against the
checks in your workspace, showing how many checks the rule would match before
you save. A rule with no predicate (an empty structured predicate and no CEL
expression) is flagged as a **catch-all** — it would match every check at its
priority — and the preview is skipped until you add at least one condition.

## Per-check overrides

The **Checks** section lists every check with its resolved Technical and
Governance categories and the source that produced each one. Workspace admins
can pin a category on an individual check with **Set explicit category**, which
sets a Technical and/or Governance value that takes precedence over both the
producer-explicit value and any rule match. Clearing both dimensions removes the
override, and the check falls back to its underlying category.

You can also create a rule straight from a check — the rule dialog opens
prefilled with that check's platform, asset type, package, and kind so it
matches checks shaped like it.

## Recategorisation

Whenever you add, edit, or delete a rule, Coalesce Quality enqueues a
**recategorisation sweep** that re-evaluates existing checks against the
updated rule set. The Check categorisation page shows the sweep's progress;
new checks are categorised as they are ingested.
