Inspiration

Every data team has shipped a rename that looked like housekeeping and broke a report someone presents to executives. The reviewer isn't careless — they're reading a diff, and a diff cannot show you that a column feeds a Looker dashboard six hops downstream.

DataHub already knows the answer. It just isn't in the pull request, which is where the decision actually gets made. We wanted to move that knowledge to the moment it matters.

What it does

Open a pull request that renames a column in a dbt model. Blast Radius comments with what actually breaks:

This change breaks 1 dashboard, 2 charts, and 16 tables. Traced orders.order_date through DataHub lineage: 21 downstream entities across 7 platforms, up to 6 hops deep.

It names them — Order Entry Dashboard in Looker, Orders By Month in Tableau, five PowerBI measure tables — and names the humans who own each one, ranked by how much of their surface is affected.

Then it writes the verdict back into DataHub as an institutional-memory link and a HighBlastRadius tag, so the next engineer or agent inherits the finding instead of rediscovering it.

It also generates the migration: a backwards-compatible alias first, then consumers in dependency order, each attributed to its owner.

Severity that actually discriminates

A reviewer who sees a red banner on every pull request stops reading them. Severity is driven by what breaks, not how much:

Level Trigger Example
CRITICAL A dashboard or ML model consumes the column orders.order_date
HIGH A chart renders it orders.order_id
MEDIUM Only derived tables and replication jobs customers.nls_language
LOW Nothing downstream depends on it

How we built it

  1. Parse the PR diff for column-level schema changes — renames, drops, type changes. Handles dbt .sql models and schema.yml, and dedupes a rename that touches both.
  2. Resolve each changed column to its DataHub schemaField URN.
  3. Query searchAcrossLineage downstream across degrees 1, 2, 3+.
  4. Classify casualties, resolve owners via the ownership aspect.
  5. Render a markdown comment and post it with gh pr comment.
  6. Write the verdict back with addLink + createTag/addTag.

Python 3.9+, requests, GitHub CLI. Tested against DataHub v1.7.0 quickstart with the showcase-ecommerce datapack.

Challenges we ran into

The severity model rated everything HIGH. Our first version keyed severity partly on how many platforms a column touched. In a real warehouse every column crosses three or more platforms, so every change came back red. We rebuilt it around what breaks rather than how much. The MEDIUM verdict now states the absence of BI impact explicitly, because a reviewer has to trust the quiet ratings as much as the loud ones.

A typo reported "Safe to merge." An absent column and an unused column look identical in the lineage graph — both return zero downstream entities. That is the one wrong answer this tool must never give, so it now validates against the schema first and lists the real columns.

A bug in the DataHub Python SDK. client.lineage.get_lineage() calls DatasetUrn.from_string() on the parent of every schema field in the returned paths. The Tableau connector legitimately emits chart-parented schema fields, so any column whose lineage reaches a chart raises InvalidUrnError — and one unparseable entry discards the entire result set. That is exactly the set of columns worth analysing. We located the defect, verified raw GraphQL returns all results, and reported it upstream with a reproduction and a suggested fix: datahub-project/datahub#18964

Accomplishments that we're proud of

The tool discriminates. Run it on orders.order_date and it's critical; run it on customers.nls_language in the same warehouse and it's medium, with the reason stated. That distinction is the difference between a bot people act on and a bot people mute.

And the write-back is real, not decorative — the verdict is queryable in DataHub after every run, and it's idempotent, so running on every push doesn't pile up duplicates.

What we learned

Reading metadata is the easy half. The value compounds only when findings go back into the graph, and getting that right meant handling the unglamorous parts — duplicate links, stale verdicts, entities that legitimately have no owner.

We also learned to distrust our own severity ratings until we'd tested the boring case. A tool that's right about the scary column and wrong about the safe one is worse than no tool.

What's next for Blast Radius

  • A GitHub Action so it runs on every PR without local setup
  • Support for dbt's manifest.json for precise model resolution
  • ML lineage: the same analysis for feature tables and model inputs
  • Upstream the SDK fix as a PR, not just an issue

Built With

Share this project:

Updates