Skip to main content

Data Quality Reference

Validation rule types​

The data quality report The data quality report aggregates the score across an entity type.

TypeConstrainsConfiguration
Regular expressionFormatA pattern
RangeBoundsMinimum, maximum
LengthString lengthMinimum, maximum
LookupMembership of a controlled listThe lookup type
UniqueNon-repetition within a scopeThe scope
Cross-fieldA condition on one attribute given anotherA condition and a consequence
CustomA named validatorThe validator name and its parameters

The catalog of custom validators is served by the platform. Query it for the current set.

What the shipped packs actually configure​

Rules as they appear in the seed packs, so the shapes below are the ones the platform accepts:

{ "attribute": "lei", "ruleType": "regex",
"ruleConfig": { "pattern": "^[A-Z0-9]{18}[0-9]{2}$" },
"severity": "error", "errorMessageKey": "errors.LEI_FORMAT" }

{ "attribute": "iban", "ruleType": "regex",
"ruleConfig": { "pattern": "^[A-Z]{2}\\d{2}[A-Z0-9]{11,30}$" },
"severity": "error" }

{ "attribute": "npi", "ruleType": "regex",
"ruleConfig": { "pattern": "^[0-9]{10}$" },
"severity": "error" }

{ "attribute": "chassis", "ruleType": "regex",
"ruleConfig": { "pattern": "^[A-HJ-NPR-Z0-9]{17}$" },
"severity": "error" }

{ "attribute": "date_of_birth", "ruleType": "range",
"ruleConfig": { "min": "1900-01-01", "max": "today" },
"severity": "error" }

{ "attribute": "administrative_gender", "ruleType": "lookup",
"ruleConfig": { "lookupType": "administrative_genders" },
"severity": "error" }

{ "ruleType": "cross_field",
"ruleConfig": {
"if": { "attribute": "address.country", "op": "eq", "value": "US" },
"then": { "attribute": "address.state", "condition": "required" } },
"severity": "warning" }

Three of those carry more than they appear to. The vehicle pattern excludes I, O and Q because a VIN never contains them. max: "today" is a relative bound, not a date you have to maintain. And the cross-field rule is structured rather than a free-text expression, which is what lets the platform reject a malformed rule when you save it instead of failing silently at evaluation time.

Two rules on one attribute​

Rules compose. A US identifier gets a format rule and a rule that rejects known placeholder values:

{ "attribute": "ssn", "ruleType": "regex",
"ruleConfig": { "pattern": "^\\d{3}-?\\d{2}-?\\d{4}$" },
"severity": "error", "errorMessageKey": "errors.SSN_FORMAT" }

{ "attribute": "ssn", "ruleType": "regex",
"ruleConfig": { "pattern": "^(?!(\\d)\\1{8}$)\\d{3}-?\\d{2}-?\\d{4}$" },
"severity": "error", "errorMessageKey": "errors.SSN_PLACEHOLDER" }

The second refuses nine repeated digits — 111-11-1111, 000-00-0000. That matters far more than it looks: a placeholder identifier that passes validation becomes a shared identifier, and a shared identifier is what merges two unrelated people into one record.

Checksum validators exist, but no shipped pack uses one

The platform registers named checksum validators — for the NPI Luhn digit, ABA routing, the LEI ISO 17442 check, and IBAN MOD-97 — and the only one any shipped pack configures is validate_calendar_date, which rejects impossible dates like 30 February.

So out of the box, the identifier rules above verify format, not checksum. A well-formed NPI with a wrong check digit passes. Wiring the checksum validators onto those attributes is a reasonable early hardening step, and it is a configuration change rather than a code one.

The validation rule editor, with the rule list and its test panel.

Validation rule fields​

Every field a validation rule accepts.

FieldAcceptsDefaultChangeableWhat it does
entityTypeIdAn entity type—NoWhich type the rule applies to.
attributeDefIdAn attribute, or empty—NoWhich attribute the rule constrains. Left empty for rules that are not about a single attribute — a cross-field rule spans two, so it binds to neither.
ruleTypeOne of the seven types above—YesWhat kind of constraint this is.
ruleConfigAn object{}YesThe constraint's settings. The shape follows the type — see the examples above.
severityerror, warning, infoerrorYesWhether a violation blocks the write. See the warning below.
errorMessageKeyUp to 255 chars—YesThe message shown when the rule fails, as a translation key so it renders in the reader's language.
sourceTypeFilterUp to 100 chars—YesRestricts the rule to records from one source system. This is what lets a field be mandatory from one system and optional from another.
isActivetrue or falsetrueYesWhether the rule is evaluated. Deactivating is the reversible alternative to deleting.
metadataAn object{}YesYour own annotations, stored and returned uninterpreted.

The type and attribute are fixed once created. To constrain a different attribute, create another rule.

A new rule blocks writes unless you say otherwise

severity defaults to error, and an error-severity violation refuses the record. So a rule added without setting a severity will start rejecting incoming data as soon as it is saved.

That default is the right one — a constraint you meant to enforce should enforce — but if you are introducing a rule against data you have not yet cleaned, save it as warning first. You then get the violation counts without turning away records, and can promote it to error once the backlog is clear.

Scoping a rule to one source system​

sourceTypeFilter is the field most often missed. Without it a rule applies to every record of the type, whichever system it arrived from — which is rarely what you want when one system is authoritative for a field and another does not carry it at all.

With it, the same attribute can be mandatory from the system that owns it and absent from the rest, without either side reporting a false violation.

Severities​

SeverityBlocks the writeRecorded as a violation
ErrorYesYes
WarningNoYes
InfoNoYes

Severity governs whether the write proceeds. No severity changes the score — the score measures completeness, not rule outcomes. Violations are surfaced in their own right.

Cross-field rules​

A cross-field rule expresses "if this, then that" across two attributes — for example, requiring a region when the country is one that has them.

Both halves are structured rather than free-form expressions, which is what allows the configuration to be validated when you save it rather than failing at evaluation time.

Scoring dimensions​

DimensionMeasures
CompletenessFilled attributes as a share of those expected
FreshnessRecency, decaying with age

The overall score is completeness. Freshness is reported alongside it as a separate signal and is not folded into the overall number.

Not a weighted composite

The score is not a weighted blend of several dimensions, and there is no per-tenant weighting to configure. Accuracy, consistency, and uniqueness are not scoring dimensions — validation results are recorded as violations, and duplication is the concern of matching rather than of this score.

Reading the score across records and over time​

A single record's score answers a narrow question. Two further reads answer the ones a steward actually asks:

ReadAnswers
AggregateQuality rolled up across records and broken down by dimension — whether the problem is missing data or stale data
TrendHow the score has moved over time

The trend is what separates a one-off bad load from a source that is quietly degrading. A single score cannot tell those apart, and they call for different responses: reload the batch, or go and talk to whoever owns the source.

Multi-value attribute violations​

SituationSeverity
A value carries no usage type where the attribute expects oneWarning — recorded, not blocking
A value carries a usage type that is not in the bound listError

The asymmetry is deliberate. A missing usage type is incomplete data worth flagging; an unrecognized one is unambiguously wrong, and accepting it would silently discard the caller's intent.

Configuration validity​

A rule whose configuration cannot be evaluated is rejected when saved. A rule that silently never fires is worse than no rule, because it looks like coverage.

Next​