Command-line tool for data engineers

Rename a column
without breaking
everything downstream.

Renaming a column in your warehouse takes one line of SQL. Finding every dbt model, contract and dashboard that depended on it takes days, and you usually miss one. RippleProof finds them from your data catalog, writes the repairs, proves they build, and opens pull requests for you to review.

Apache 2.0 · Python 3.11 · the demo needs no install, no account and no network

what depends on this column
POSTGRES · SOURCE analytics.orders user_id customer_id column-level lineage, read from DataHub dbt_operations_primary customer_identity_primary.sql PATCHED dbt_finance_project customer_revenue.sql PATCHED dbt_growth_project customer_segments.sql PATCHED dbt_project orders_daily.sql PATCHED looker · dashboard Revenue Dashboard REFUSED
The problem

A column is never just a column.

It feeds dbt models in other repositories, declared data contracts, and dashboards owned by other teams. The rename is one line. Finding what it breaks is the job.

Renaming it by hand

  • Grep across repositories and hope you caught everything
  • No way to prove a dashboard actually used the column
  • Find-and-replace corrupts string literals and comments
  • You discover what broke in production on Monday

Renaming it with RippleProof

  • Reads real column lineage from your DataHub catalog
  • Writes the dbt and contract changes, across every repository
  • Builds every affected project before you see it
  • Refuses, and tells you why, when it cannot prove something
It does not parse your whole dialect

RippleProof is a conservative lexical transformer behind a structural ownership preflight. Before it rewrites a single identifier it refuses any model whose column ownership it cannot prove: joins, CTEs, set operations, subqueries, lateral relations, and anything that is not a plain SELECT. Strings, comments, dollar-quoted bodies and Jinja are preserved, never rewritten. It repairs the narrow case it can prove and hands you the rest.

It re-reads the graph before it acts

Metadata goes stale between planning and delivery, and a cache will happily serve an edge that no longer exists. Before any change, RippleProof re-reads DataHub and independently bypasses the lineage cache, then compares. In a controlled test the cached interface returned a removed edge while the uncached read did not, and the campaign refused rather than execute yesterday's plan. That refusal is the reason the cache-bypass option was sent upstream.

How it works

One command. Two places it stops for you.

RippleProof does the mechanical work end to end, and hands control back at exactly the two points where a human is genuinely needed.

1

You describe the change

Run ripple-proof plan with the dataset and the rename you want. Plain language is fine.

2

It asks your catalog what depends on that column

It reads schema, column-level lineage, wider reachability and ownership from DataHub, so the impact list comes from your real metadata rather than a guess.

3

It stops if anything is ambiguousyou decide

If two dbt models both claim one catalog asset, it refuses to pick. You choose, from candidates it actually found.

4

It writes the repairs and proves they build

Generated dbt SQL and contract updates, then every affected project is built in an isolated sandbox. The migration is applied and rolled back in a throwaway database. Your source database is never touched.

5

You review pull requests in your own repositoriesyou merge

It opens review-only pull requests with passing checks and auto-merge disabled, then records the decision back into DataHub. Merging is always yours.

What it refuses to do

Five ways a confident agent gets this wrong.

Each of these is a case where automation finishes cleanly, reports success, and leaves something silently broken. RippleProof stops instead, and says which one it hit.

The trap A confident agent RippleProof
Two dbt models claim one catalog assetNothing in the metadata says which one is real picks one and patches it refuses, and asks you to choose
A dashboard is reachable but its column use is unprovenReachability is not usage patches it anyway sends it to manual review
The destination column already existsThe rename would land on real data silently repoints your models refuses before touching anything
A dbt build exits 0 having run nothingAn empty selector still returns success calls it green fails, and names the models it expected
The lineage graph changed while it was planningThe cache still served a removed edge acts on yesterday's plan re-reads past the cache, and refuses
Adversarial regression corpus

Those five, plus nine more, run as a deterministic corpus on every change. It is a regression suite over cases we authored, not an industry benchmark, and eight of the fourteen exist purely to check that RippleProof still says no.

14/14cases behave as declared
8must refuse, and do
0false repairs
Get started

Five seconds, or your own warehouse.

The demo on the left needs no install, no account, no credentials, no Docker and no network call. It re-verifies a real captured run on your machine.

Try it with no setup~5s
$ git clone https://github.com/itxcrusher/ripple-proof.git
$ cd ripple-proof
$ PYTHONPATH=src python -S -m lineage_agent.cli demo

CAMPAIGN AUDIT: PASSED   11 of 11 checks

Eleven independent checks re-derived from the recorded evidence, with no third-party packages.

Run it against your own warehousepython 3.11
$ pip install ripple-proof
$ ripple-proof doctor          # checks Docker, DataHub, MCP
$ ripple-proof plan \
    --asset-urn "urn:li:dataset:(urn:li:dataPlatform:postgres,analytics.orders,PROD)" \
    --instruction "rename user_id to customer_id" \
    --target-repo ../your-dbt-project

Full options, including validation and pull-request delivery, are in the README.

See it run on a real project

We ran RippleProof against a five-repository dbt setup and kept everything it produced. This is a worked example, not your data: you can read every step it took, every file it wrote, and every case where it stopped.

5downstream assets found
8files written, 4 repositories
3times it refused
4pull requests opened