ContextCI

Shift-left data governance · Apache 2.0

Every schema change ships with a blast radius.

A developer drops a column. Every application test passes — it is valid SQL, and nothing in that repository mentions data. Twelve hours later a dbt model returns NULLs, a dashboard shows the wrong revenue, and a model trains on empty values. Nothing errored.

The lineage that would have caught it already exists in DataHub. It is just on the wrong side of the merge button. ContextCI moves it.

ALTER TABLE SampleHiveDataset DROP COLUMN field_foo; verdict: block · exit 1
SampleHiveDataset field_foo
reads the dropped column downstream, column-level unconfirmed 13 assets · 2 datasets · 2 Airflow jobs · 7 ML features · 1 S3 backup · 1 view

The run

Four phases, on every pull request

The Action triggers on pull_request. No developer has to open DataHub, know dbt, or wait for a data-team review.

PHASE 01

Read the diff

Parses the patch — not whole files — for raw SQL DDL, Alembic op.* migrations, dbt schema.yml removals and dbt select lists. Deleting an old migration is not a schema change; commented-out DDL is ignored.

PHASE 02

Ask the catalog

Resolves each table to a dataset URN, then pulls column-level lineage, ownership, glossary terms, the dataset profile, and the SQL people actually run against it.

PHASE 03

Judge and repair

An LLM weighs the evidence and writes the backward-compatible migration. Deterministic rules set a floor it cannot go below, and a compliance gate can override both.

PHASE 04

Act, both ways

One sticky PR comment, an optional fix commit, and tags written back into DataHub. Exit 1 on a block verdict stops the merge.

Two-way integration

DataHub as an operating system, not a catalog

Reading metadata is table stakes. The graph is richer after a ContextCI run than it was before.

CapabilityHow ContextCI uses it
Column-level lineagesearchAcrossLineage finds downstream assets; each one's fineGrainedLineages is checked for the changed column's schemaField URN — so “reads this table” and “reads this column” are never conflated.
OwnershipThe owners of the assets that actually break are named on the pull request, so the conversation starts with the right people.
Glossary & tagsPII, GDPR, PHI and Tier-1 markers drive a compliance gate that can force a block regardless of blast radius.
Dataset profileRow count, size and the column's null fraction size the migration — a backfill across four million rows is not the same as one on a staging stub.
Query historytopSqlQueries and per-column fieldCounts ground the generated SQL in joins and filters people really use.
Tag mutationsWrites Schema-Change-Pending and PR-Under-Review on the dataset, Blast-Risk-{level} downstream, and a tag on the column itself via editableSchemaMetadata.
Institutional memoryA pending-change note keyed by the PR URL, so an analyst browsing the catalog learns why the dataset is flagged.

Non-negotiable

Two invariants that make it a gate

Both came from real failures found by re-running against live infrastructure, not from design meetings.

Absent lineage is never approval

A table missing from the catalog, or a downstream asset whose column-level lineage cannot be confirmed, produces a warning — never a pass. The comment labels every asset confirmed or table-level only, so nobody mistakes silence for safety.

The model never rules a change safer than the rules do

Hosted inference is not reproducible: the same input returned high / block twice and medium / warn on the third run, and temperature=0 does not fix it. The deterministic analysis is a floor. The model writes the narrative and the migration; the rules own the decision.

Verified, not claimed

It has run against real infrastructure

A DataHub v1.7.0 instance with authentication enabled, and a live pull request on this repository.

13DOWNSTREAM ASSETS FOUND
17/17GRAPH MUTATIONS APPLIED
74TESTS, NO NETWORK
401→200ANONYMOUS VS TOKEN
$ make demo
phase 1: 1 schema change detected
phase 2: SampleHiveDataset → 13 downstream
phase 3: verdict from groq · risk=critical action=block
phase 4b: 17/17 DataHub mutations applied
phase 4a: comment → github.com/LSUDOKO/ContextCI/pull/1

ContextCI verdict: block (risk: critical)
Blocking merge: this change breaks downstream assets.

Try it

Nothing to install

In GitHub Codespaces

  1. Open the repo → Code ▸ Codespaces ▸ New with options
  2. Choose the 4-core machine — DataHub needs about 6 GB resident and refuses to start below 13 GB free disk
  3. Run make demo

It boots DataHub, ingests sample metadata with real column-level lineage, runs the gate against a breaking DROP COLUMN, and prints the forwarded DataHub UI URL. Roughly 10–15 minutes cold, almost all of it pulling images.

In your own repository

  1. Copy .github/workflows/contextci-gate.yml
  2. Add secrets: DATAHUB_MCP_URL, DATAHUB_GMS_TOKEN, and either GROQ_API_KEY or ANTHROPIC_API_KEY
  3. Open a pull request that changes a schema

With no LLM key the deterministic analyzer runs instead, and the gate still works. If DataHub is unreachable the run degrades to diff-only with a banner rather than failing your build — only a real block verdict exits non-zero.