This complements the GoldenMatch-in-dbt package: that adds GoldenMatch to a dbt pipeline going forward; this converter is for replacing hand-rolled ER a team already has. The emitted config drops straight into a
{{ goldenmatch_dedupe(...) }} model.The key enabler: the manifest, not raw SQL
The converter reads your dbtmanifest.json — the structured metadata dbt compile (or dbt parse / dbt docs generate) produces — not blind .sql files. The manifest carries every model’s compiled SQL, the full ref()/source() DAG, columns, tests, and the warehouse adapter. That structure is what makes distillation tractable, and it needs no warehouse credentials (only the optional verify against a live output table does).
One command
- identifies the models that do entity resolution (DAG + naming + shape signals);
- extracts the recognizable ER idioms into ONE GoldenMatch config;
- prints a coverage scorecard + a
couldn't extractlist for human review.
--verify <output.parquet> --source <rows.parquet> to prove it reproduces your existing clusters (below). Useful flags: --min-confidence tunes how aggressively models are identified as ER; --strict fails on any lossy finding.
Or one line of Python
conv.er_models is the ranked list of identified ER models (each with a confidence + the signals that fired), and conv.signals is every recognized signal — including the couldnt_extract items — so you can audit exactly what carried over.
Two honest value stories
The report tells you which applies, so it never over-claims an F1 win:- Fuzzy / probabilistic ER sprawl → an accuracy + consolidation story: GoldenMatch does the fuzzy matching the SQL did badly, in a tested engine.
- Exact keep-latest dedup sprinkled everywhere (the common case) → a consolidation + maintainability story: 10k lines become a 20-line tested config. The “accuracy” number here is trivially ~1.0 — the win is consolidation, and
conv.coverage.storysays so (exact-dedup, notfuzzy-er).
What it recognizes
Over each identified ER model’s compiled SQL (dialect-aware — DuckDB, Snowflake, BigQuery in the MVP; others fall through to a dialect-agnostic core and are flagged):
Everything else — arbitrary business logic,
CASE ladders, priority hierarchies — is attached to the report as a couldn't extract finding with the model name + SQL excerpt, never silently dropped.
Verify it reproduces your pipeline (the trust step)
Your hand-rolled dbt ER model already produces an output table — a surrogate-key→member mapping or a canonical/golden table. That existing output is label-free ground truth.verify_against_dbt runs the converted config on a sample of the source rows and reports pairwise cluster agreement against it:
output_table is a two-column id, cluster_id frame (name the columns with output_id_column / output_cluster_column if they differ). Verification is best-effort: a missing, empty, or non-overlapping output degrades to a skip notice, never a crash — the config is still written, it’s just a suggestion until you point it at an output table.
Boundaries (stated honestly in the report)
- Extraction is heuristic → partial coverage. The
couldn't extractlist is a first-class output for human review, not a footnote. - Survivorship & conditional business rules are the hardest to extract. The MVP recognizes most-recent (DESC window order-by) and reports it with the exact remediation (GoldenMatch applies
most_recentper field); priority hierarchies andCASEladders are flagged. - Dialect variance — the MVP covers DuckDB / Snowflake / BigQuery; the long tail is flagged.
- Verify needs the output table. With it the proof is strong; without it the config is a reviewed suggestion.