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 ⚠Scoped by design: the report always notes that only -1 / +2 was checked. If your change is in a widely shared staging model, manually verify anything beyond +2 before merging.
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:
Column renamed, removed, or type/logic changed
race_id → race_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
🟢 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
For HIGH severity changes the scoped scan still applies — there is no automatic full-DAG walk. The scoped scan notice and reviewer sign-off requirement handle the residual risk for models beyond +2.
Enforcement rules
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 wins → total_race_wins in stg_f1__constructor_standings.sql.
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:
DinoAI detects the trigger and runs the scoped scan
Before writing any file, DinoAI:
Checks
-1for input schema compatibilityWalks
+1column-aware — flagsint_f1__race_results_standingsbecause it selectswinsWalks
+2column-aware — skipsfct_f1__constructor_race_resultbecause it does not selectwinsdirectly
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.
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.
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:
Run
dbt runanddbt teston all affected models and surface any failures before the PR is openedCreate the PR with the correct
[type]:title based on the change madePopulate the PR description with the impact report — including the scan scope, affected assets table, action items, and the scoped scan notice — under
## Data Contract CheckRequest a reviewer if one is configured in your repo settings
For HIGH severity changes, DinoAI will add a ⚠️ Breaking Contract Changes section to the PR description automatically and pause for your confirmation before opening the PR.
Last updated
Was this helpful?