The problem. A data engineer renames a column in a dbt pull request. Every test passes — the rename is internally consistent. Nothing in CI knows that a feature table three hops downstream feeds a production fare model, or that the model reads that column. The PR merges. Two weeks later the fare estimates are quietly wrong. Training-serving skew from an unnoticed upstream change is a named, expensive failure on every ML platform team, and it is invisible to schema checks.
What Interlock does. Interlock is a pull-request gate. When a data change lands in a PR it:
- reads the change out of the diff (dbt manifest + SQL parsing),
- follows DataHub's lineage graph to every production model downstream,
- replays the real model artifact on the data before and after the change and measures how many decisions move,
- blocks the merge when a model's declared contract would break — a hard stop, not a warning,
- stages a validated remediation patch for a human, and writes the verdict back into DataHub as an incident, a tag, and structured properties, so the graph is smarter after every run.
The number no schema check can produce. On real NYC TLC data with a real LightGBM fare model, the actual TLC rename of airport_fee to Airport_fee moves more than 12% of fare decisions. The contract allows 0.5%. The gauge crosses the redline and the merge is blocked. The value is measured on every run, never hard-coded.
Why the context graph matters. Graded against a hidden answer key over 14 changes, Interlock is correct on 13/14 with DataHub's context graph and only 6/14 without it. The cleanest case: a target-leakage column and a harmless new column are the same schema operation. The blind arm treats them identically; the graph knows one reaches the model through a forbidden path and the other reaches nothing. Lineage, not the schema, does the work.
How it works. A deterministic policy engine makes the decision and fails closed — an unreachable graph, ambiguous lineage, a failed replay, or a production model with no contract all block. The language model never decides; it only explains the verdict and drafts remediation, which is then hard-validated by a real dbt compile.
Use of DataHub. Contracts are native DataHub assertions plus a dataContract entity. The gate reads lineage (including column-level), schema, ownership, tags and ML entities through the DataHub MCP Server and the Agent Context Kit, and writes incidents, tags, structured properties and assertion results back. Interlock also ships its own MCP server so other agents can consult the gate, a post-merge watcher on the DataHub Events API, and two new DataHub skills contributed upstream.
Try it in 60 seconds, zero credentials. The console at https://interlock-ml.vercel.app runs off recorded real runs — click a scenario and watch the gate decide. To run it for real: python demo/setup.py brings up DataHub, Postgres, dbt and a trained model, then interlock check gates a change. See JUDGES.md in the repo for the five-minute verification path.
Open-source contribution PRs
- datahub-skills #52 — datahub-impact-gate skill: https://github.com/datahub-project/datahub-skills/pull/52
- datahub-skills #53 — datahub-contract-author skill: https://github.com/datahub-project/datahub-skills/pull/53
- datahub #18632 — mlfeature_table_read example fix: https://github.com/datahub-project/datahub/pull/18632
Built With
- datahub
- dbt
- gemini
- github-actions
- lightgbm
- mcp
- mlflow
- postgresql
- python
- react
- sqlglot
- typescript
- vite
Log in or sign up for Devpost to join the conversation.