Reference

The rules

Two families of checks over one contract and one CSV. Linting reads only the contract; validation reads both. Every finding carries a stable code and one of three severities: error, warning, or info.

Lint rules (contract)

Linting needs only the contract, and it runs before any data is read. A structurally broken contract is not linted at all; it fails as DP-PARSE-000 instead.

Contract checks, DP-101 through DP-109.
Code Severity What it catches
DP-101errorA schema entry has no properties array, or a property object lacks a name.
DP-102errorA property name is duplicated within the same schema.
DP-103errorA property has a missing or unknown logicalType.
DP-104errorA pattern is not a valid regular expression.
DP-105errorA minimum or maximum is not a finite number, or minimum is greater than maximum.
DP-106warningAn enum is present but empty, so it constrains nothing.
DP-107warningA format is present but not supported, so no format check runs.
DP-108warningrequired or unique is set on an object or array property, whose values are not type-checked.
DP-109infoThe contract has no top-level name.

Validation rules (data)

Validation needs the contract and a CSV dataset, and it runs after linting. Every check that applies to a column runs on each non-empty cell, so one cell can produce more than one finding.

Dataset checks, DP-201 through DP-210.
Code Severity What it catches
DP-201errorA required column is absent from the CSV header.
DP-202infoA CSV header column is not declared in the contract.
DP-203errorA value does not parse as the column's logical type.
DP-204errorA value is empty in a required column.
DP-205errorA non-empty value repeats in a unique column.
DP-206errorA numeric value is below minimum.
DP-207errorA numeric value is above maximum.
DP-208errorA value does not match pattern.
DP-209errorA value is not in enum.
DP-210errorA value does not match format.

Uniqueness and bounds. DP-205 compares values as exact, case-sensitive text, so 1 and 1.0 are different values and empty fields are never counted as duplicates. DP-206 and DP-207 fire only when the value parses to a finite number, so a type mismatch on a numeric column does not also produce a bounds finding.

Suppression and the cap (DP-250)

A large dataset can produce a finding on millions of cells. To keep a report usable, datapact caps validation findings at 50 per rule code per run. When a rule would report more, the first 50 are kept, the rest are suppressed, and one notice records how many were dropped. Contract lint findings are not capped.

The suppression notice.
Code Severity What it catches
DP-250infoMore than 50 findings of one rule code were produced; the extras were suppressed. One notice is emitted per truncated code, and neither DP-250 nor DP-PARSE-000 is ever capped.

Parse errors (DP-PARSE-000)

A parse failure is never a clean run.
Code Severity What it catches
DP-PARSE-000errorThe contract is not valid YAML or JSON, the contract is structurally invalid (the top level is not a mapping, schema is missing or not an array, or a property is not an object or lacks a name), or the CSV has no header row.

When either the contract or the CSV fails to parse, the run yields a single DP-PARSE-000 with location -, always exits 2, and is never reported as clean, so a gate cannot pass on input the tool did not understand. JSON is parsed by the same YAML reader, so a JSON contract is valid input.

Logical types

A property's logicalType decides how each cell is interpreted. The alias type is accepted for the same field.

The supported logical types and the values each accepts.
logicalType Accepted values
stringAny non-empty UTF-8 text. A string value never produces a type mismatch.
numberAny text JavaScript Number() parses to a finite value, for example 12, -3.5, 1e3, or 0x10. NaN and Infinity are mismatches.
integerA base-10 integer matching ^-?\d+$; a leading + is not accepted.
booleantrue, false, yes, no, 1, or 0, case-insensitive.
dateA calendar date, exactly YYYY-MM-DD, validated against the real calendar including leap years.
date-timeAny text JavaScript Date.parse() accepts, such as an ISO 8601 date-time. The parser is permissive, not a strict ISO 8601 grammar.
timestampAny text JavaScript Date.parse() accepts, the same as date-time.
objectNot type-checked. Any non-empty text is accepted; the value is not parsed as JSON.
arrayNot type-checked. Any non-empty text is accepted; the value is not parsed as JSON.

A logical type not in this table is DP-103.

Formats

A format is checked in addition to the logical type. When a property's format merely repeats its logical type, the format check is skipped because the type check already covers the value.

The supported formats and the values each accepts.
format Accepted values
dateA calendar date, exactly YYYY-MM-DD.
date-timeA value JavaScript Date.parse() accepts, as the date-time logical type.
emailA value matching ^[^\s@]+@[^\s@]+\.[^\s@]+$: a non-empty local part, an @, and a dotted domain with no whitespace.
uriA value the URL constructor accepts, which requires an absolute URL with a scheme and no whitespace.
uuidA canonical hyphenated UUID, [0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}.
ipv4Four groups of one to three decimal digits, each 0255, separated by .. Leading zeros are accepted.

A format not in this table is DP-107, and no format check runs for that property.

The empty-value rule

A field is empty when it has zero length; both an unquoted empty field and a quoted empty field ("") are empty, while a field of only whitespace is not. The rule differs by column:

  • In a required column, an empty field is DP-204, and no further per-cell check runs for that field.
  • In an optional column, an empty field is skipped by the type, pattern, enum, format, minimum, maximum, and uniqueness checks. An empty cell in an optional column is never an error.

This is what lets a sparse column validate cleanly: absence is not a type error unless the contract marks the column required.

How a run is checked

The pipeline is static and has no warehouse step.

  1. Parse

    The contract is read as YAML or JSON; the CSV is read per RFC 4180. A failure here becomes a single DP-PARSE-000 and exit code 2.

  2. Lint

    The contract alone is checked for duplicate names, unknown types, bad patterns, invalid bounds, empty enums, and unknown formats.

  3. Validate

    Each CSV cell is checked against its property: presence, type, emptiness, uniqueness, bounds, pattern, enum, and format.

  4. Report

    Print text or JSON, write SARIF 2.1.0, and exit 0, 1, 2, or 3 for CI.

Try the lint here

This contract is deliberately broken. Lint it in the browser and watch the contract rules fire.

Nothing linted yet.