Skip to content
Menu

Data quality

Explore · Data quality

Agree on what a good table looks like, then score it.

A data contract states the expected state of one table: how fresh, how large, which columns must be unique, present or valid. Beacon checks it on a schedule, turns the rule results into one weighted score, keeps the history and the trend, and alerts when the score drops below the agreed threshold.

  • 8rule types
  • 0–100%weighted score
  • 3database engines
DATA QUALITY · SHOP DBPostgreSQL
87.7%
Customerspublic.customersDegrading
96.4%
Orders freshness and volumepublic.ordersImproving
73.5%
Invoice linespublic.invoice_linesStable
85.9%average score
3tables
2healthy
1degrading

The tick on each ring marks the 80% failure threshold.

01Anatomy

A table, a set of weighted rules, one score.

A contract targets one table on one database data source and runs on a cron schedule. Each rule has a type, an optional column, a JSON configuration, a severity and a weight. Together they produce one score per evaluation.

TARGET1 table
Data source
Shop DB (PostgreSQL)
Table
public.customers
Schedule
0 */6 * * *
Failure threshold
80%
Alert on failure
on · #data-team
Owner
Ana Horvat
RULES8 enabled
FreshnessCritical ×4
VolumeMedium ×2
UniquenessCritical ×4
Null rateHigh ×3w 1.5
RangeLow ×1
PatternMedium ×2
ReferentialHigh ×3
Custom SQLMedium ×2
SCOREstored
87.7%
Degrading from 91.2%

Every evaluation is stored. The table keeps a latest score and a trend.

Severity multiplies influenceLow ×1Medium ×2High ×3Critical ×4Weight: 0.1 to 10, default 1.0
02Rule types

Eight checks, from freshness to your own SQL.

Rules stay on the contract's data source: Beacon takes the schema and table from the contract, checks every table and column a rule names against the data source's stored metadata, and quotes them as identifiers, so a rule cannot reach another schema, database or catalog.

Freshness

The newest value in a timestamp column is no older than a maximum age.

{"column": "updated_at", "maxAgeMinutes": 60}

Volume

The row count is within an expected range: minRows, maxRows, or both.

{"minRows": 100}

Null rate

The percentage of NULLs in a column stays at or below a threshold.

{"column": "email", "maxNullPercent": 5}Small overruns cost little.

Uniqueness

A column contains no duplicate values.

{"column": "id"}

Referential

Every non-null value exists in a reference table: no orphans.

{"column": "user_id", "referenceTable": "users", "referenceColumn": "id"}

Range

Numeric values stay between min and max; either bound is optional.

{"column": "age", "min": "0", "max": "150"}Scores by the share of rows in range.

Pattern

All values match a pattern: a regular expression on PostgreSQL and MySQL, LIKE on SQL Server.

{"column": "email", "pattern": "^[^@]+@[^@]+$"}

Custom SQL

Any check you can express as one read-only SELECT. Created only by an Admin.

{"sql": "SELECT … AS passed FROM …"}Returns its own score.

Most rules score 100 on pass and 0 on fail. Null rate scores max(0, 100 − (actual − max)), Range scores the share of rows within range, and Custom SQL returns its own score.

03Worked example

Scoring the customers table.

Eight rules on public.customers, each with a severity and a weight. Toggle rules off to see how the weighted average moves: a disabled rule is skipped and does not affect the score.

LATEST RESULTS · public.customersevaluation of 12:00
OnRuleResultScoreSeverityWeightEffectiveScore × effective
Fresh updatesFreshnessPassnewest row 12 minutes old100Critical ×414400
Expected sizeVolumePass48,000 rows100Medium ×212200
Unique idsUniquenessPassno duplicates100Critical ×414400
Email presentNull rateFail5.5% null: 100 − (5.5 − 2)96.5High ×31.54.5434.25
Plausible ageRangeFail480 of 48,000 out of range: (1 − 0.01) × 10099Low ×11199
Email formatPatternFail214 values do not match0Medium ×2120
Known countryReferentialPassno orphans100High ×313300
Active have signup dateCustom SQLFail30 active customers without one70Medium ×212140
Σ(score × effective) / Σ(effective)= 1,973.25 / 22.5= 87.70%
Degradingprevious score 91.20%; more than 1 point lower is Degrading

At or above the 80% threshold: no alert.

Effective weight is the rule's weight times its severity multiplier. The overall score is rounded to two decimals. Alerts are sent only by scheduled evaluations, never by Evaluate now.

04Evaluation

What happens on every run.

Each enabled contract is a recurring job on the host's scheduler, and Evaluate now runs one on demand. A scheduled evaluation runs as the contract's owner.

  1. Schedule firesThe cron expression, or Evaluate now on the contract page.
  2. Check the ownerThe owner must still run saved SQL in a project that links the data source.
  3. Run each ruleEngine-specific SQL per enabled rule, read-only, 60 seconds each.
  4. ScorePass or fail, a rule score, expected and actual values, a message.
  5. StoreThe evaluation with every rule result; the table score and trend.
  6. AlertBelow the threshold, a scheduled run notifies the recipients.

One failing rule stays contained

A rule with a bad configuration, a missing column or a timeout is recorded as failed with score 0, and the other rules still run.

Skipped when the owner lost access

No rule runs and no score, history or alert is written. The contract shows Owner not authorized, and an Admin or UserAdmin can assign a new owner with Change owner.

PostgreSQL, SQL Server and MySQL

Contracts evaluate on these three database engines. Pattern rules follow each engine's own matching: regular expressions, or LIKE on SQL Server.

05Custom SQL rules

Any check you can write as one SELECT.

A Custom SQL rule runs your query and reads the first row of the result. Only an Admin creates, changes or deletes a contract that contains one, and when the approval workflow is enabled, a second person approves its SQL before it is evaluated.

Custom SQL rule · Active have signup date
SELECT
CASE WHEN COUNT(*) = 0 THEN 1 ELSE 0 END AS passed,
GREATEST(0, 100 - COUNT(*)) AS score,
COUNT(*) AS actual_value,
'Active customers without a signup date' AS message
FROM public.customers
WHERE status = 'active'
AND signed_up_at IS NULL;
ColumnRequiredMeaning
passedYes1 pass, 0 fail
scoreNo0 to 100; defaults to 100 on pass, 0 on fail
actual_valueNoShown as the observed value
messageNoShown as the result message

Read-only and bounded

One read-only SELECT in the data source's dialect, checked when the contract is saved and on every evaluation. Beacon caps the result at one row itself, so the query sets no outer LIMIT, TOP or FETCH, and it names only the data source's own database.

Masked observations

actual_value and message reach the history and alerts. A PII column read into them is masked first, under the strictest PII setting of the projects that link the data source.

WHEN THE APPROVAL WORKFLOW IS ENABLED
Awaiting approvalA new or changed Custom SQL rule is left out of evaluations; the other rules keep running.
PartialAn evaluation that left rules out does not replace the table's score, so a held rule never improves it silently.
ApprovedAn Approver other than the requester approves exactly that SQL on that data source.
06Where scores surface

Scores where people and assistants look.

ALERT · SCHEDULED EVALUATIONBelow threshold
[Data Quality] Invoice lines
Overall score
73.50% (threshold 80%)
Table
public.invoice_lines
Rules
5 passed, 2 failed
Failed ruleScoreExpectedActual
Line totals in range880 to 100,00012% out of range
Fresh lines0≤ 60 min7 h old

Delivered to the contract's recipients on any channel: email, Teams, Slack, Jira or a webhook.

Data Quality page

Overview cards per data source: average score, tables, Healthy tables (80 or more), Degrading tables and contracts, then the contracts list with each latest score.

Contract page

Rules, Evaluations (history with scores, pass and fail counts) and Latest results per rule, with Evaluate now in the header.

AI assistants over MCP

Table scores appear in get_documentation, so an assistant sees a table's quality next to its schema, and get_context shows each data source's overall score.

Control Tower

When contracts are not evaluated because their owner may no longer run them, the Control Tower shows how many and links to Data Quality.