Data Contract Checks with DinoAI & .dinorules

Use DinoAI and .dinorules to automatically enforce schema integrity whenever dbt™ code is generated or updated — before any file is touched.

What this does: DinoAI runs a scoped column-level lineage scan on every structural change. The scan completes before DinoAI writes a single line of code, surfacing every breaking change as a structured impact report.

dbt™ model contracts catch type mismatches at compile time, but they can't detect a downstream model referencing a renamed column. DinoAI + .dinorules fills that gap automatically.

How the scoped scan works

Instead of walking the full DAG, DinoAI uses a column-level blast radius: one level upstream to confirm the input schema is still compatible, and two levels downstream to catch the models most likely to break — but only if they actually select the changed column.

[ Source / seed ]  →  [ Changed model ]  →  [ +1 child ]  →  [ +2 child ]  →  [ Further downstream ]
     -1 upstream           trigger             scanned          scanned            NOT scanned ⚠

Column-aware only: at each level DinoAI checks whether the downstream model's SELECT actually references the changed column. Models that ref() the changed model but don't use the column are skipped — no false positives.


What triggers a check

A data contract check is automatically triggered whenever any of the following occur:

Trigger
Example

Column renamed, removed, or type/logic changed

race_idrace_key in stg_f1__races.sql

Source schema modified

Editing any *_sources.yml file

Staging or intermediate output columns altered

Adding or removing a column from stg_f1__account.sql

Mart grain, primary key, or key metric columns changed

Changing the grain of fct_f1__constructor_race_result.sql

dbt™ test added, removed, or modified on a key field

Removing not_null from constructor_id in a .yml file

Model deleted or renamed

Renaming f1__account_master.sql

The check is never skipped. It always runs before any file is generated or modified.


What gets scanned

For every triggering change, the following are checked within the -1 / +2 window:

-1 upstream Confirm the direct parent model or source still exposes the expected column with a compatible type.

+1 downstream (column-aware) Find all direct children that ref() the changed model and check whether their SELECT uses the changed column. Skip those that don't.

+2 downstream (column-aware) Repeat the same column-aware check one level further. Only flag models where the column actually propagates.

YAML documentation files Verify that column entries in _<model_name>.yml still match the model's actual output at the changed layer.

Tests Confirm no tests on the changed column are orphaned within the scanned range.

If the changed model references a seed within the -1 / +2 window, seed schema compatibility is also checked.


Add the rule to .dinorules

In your project root, open or create .dinorules and add the following block:

Commit .dinorules to version control alongside your dbt™ project. Every team member using DinoAI will automatically pick up the same contract enforcement rules.


Reading the impact report

After every scan DinoAI produces a structured impact report. The format is always the same:

If no downstream assets are affected, the report will explicitly state: "No downstream contract violations detected."


Severity levels

Severity
When it applies
Required action

🟢 LOW

New column added — no downstream consumers affected within scan window

Document in PR description

🟡 MEDIUM

Non-key column renamed or removed — one or more +1 / +2 models select the changed column

Update affected consumers; prefer aliasing; include impact report in PR description

🔴 HIGH

PK or mart grain changed

Explicit reviewer sign-off + ⚠️ Breaking Contract Changes section in PR + manual check beyond +2


Enforcement rules

Rule
Detail

Never skip

The scan runs on every triggering event before any file is touched

Column-aware only

At +1 and +2, only flag models whose SELECT actually uses the changed column; skip models that merely ref() the changed model

Prefer aliasing

Keep the old column name as an alias while introducing the new one to preserve backward compatibility

Always note scan scope

The report must state that only -1 / +2 was checked and prompt manual verification further downstream

HIGH severity sign-off

PK / grain changes require explicit reviewer sign-off; scoped scan still applies

End-to-end workflow

The following example walks through renaming winstotal_race_wins in stg_f1__constructor_standings.sql.

1

Make the change using an alias

Keep the old column name as a backward-compat alias so +1 / +2 consumers keep working while the rename rolls out:

2

DinoAI detects the trigger and runs the scoped scan

Before writing any file, DinoAI:

  1. Checks -1 for input schema compatibility

  2. Walks +1 column-aware — flags int_f1__race_results_standings because it selects wins

  3. Walks +2 column-aware — skips fct_f1__constructor_race_result because it does not select wins directly

3

Review the impact report and scope notice

Check every flagged asset. Note the scoped scan warning at the bottom of the report. If the changed column is used in widely shared models, manually check anything beyond +2 before proceeding.

4

DinoAI generates or updates the files

With the scan complete, DinoAI writes the SQL and YAML changes. HIGH severity items pause generation and prompt for explicit confirmation before continuing.

5

Ask DinoAI to run dbt™ tests and raise the PR

Once the files are generated, ask DinoAI to run the tests and create the PR in one go:

Paste the impact report into the PR description under ## Data Contract Check. Request at least one reviewer before merging.

DinoAI will:

  1. Run dbt run and dbt test on all affected models and surface any failures before the PR is opened

  2. Create the PR with the correct [type]: title based on the change made

  3. Populate the PR description with the impact report — including the scan scope, affected assets table, action items, and the scoped scan notice — under ## Data Contract Check

  4. Request a reviewer if one is configured in your repo settings

Last updated

Was this helpful?