Skip to main content
A semantic layer, dbt/MetricFlow, Cube, or OSI, is a join graph, and every measure is defined relative to an entity key. A per-customer SUM(revenue), a COUNT(DISTINCT customer_id): each is only correct if the declared key uniquely identifies one real-world entity. The semantic layer assumes that. It never resolves it. certify_key_integrity is the advisory artifact GoldenMatch emits over a declared key. It answers two questions a semantic layer can’t:
  1. Structural. Is the key unique at grain, and how much does a duplicated key inflate a measure (fan-out)?
  2. Resolution (opt-in): would entity resolution collapse distinct declared keys onto one real entity (fragmentation / undercount)?
It reports and quantifies trust; it never mutates a number.
Import it explicitly: the semantic subpackage is kept out of import goldenmatch so the top-level import stays lightweight: from goldenmatch.semantic import certify_key_integrity.

The problem, concretely

Take an orders model whose declared entity key is customer_id. Two defects hide in it:
  • customer_id c1 appears twice at grain → a per-customer SUM(revenue) double-counts.
  • c3 and c4 are really the same person (Grace Hopper) under two keys → COUNT(DISTINCT customer_id) over-counts entities.
Neither shows up as an error. The metrics just return the wrong number.

Certifying the key

The structural pass is cheap (a group-by, single-sourced from the shared key-integrity-core Rust kernel so Python / TS / DuckDB / Postgres all agree byte-for-byte). It catches the double-count before any entity resolution runs.

The resolution tier (opt-in)

Pass resolve=True to also run GoldenMatch entity resolution and measure whether distinct declared keys fragment one real entity:
undercount_estimate is a point estimate; the 95% Wilson confidence interval (undercount_ci_low / undercount_ci_high) bounds its sampling uncertainty: few resolved entities means a wide interval. safe_bound_conservative discounts the worst plausible undercount at the CI upper bound, so a fragmentation rate measured from a handful of entities is penalized more than one measured from many.
The interval bounds the SAMPLING uncertainty in the fragmentation rate, not whether ER clustered correctly. It answers “how sure are we of this rate given how few entities we saw,” not “did the resolver make the right call.”

The certificate

The {estimate, safe_bound} shape mirrors RecallCertificate, so a downstream reporter (the goldenanalysis key.integrity analyzer) consumes it uniformly.

Fixing it

The certificate points at the defect; the fix is a normal survivorship step (dedupe the key at grain). Re-certify to a clean bill of health:
The structural double-count is gone. The c3/c4 fragmentation stays a resolution-tier finding for a steward to merge: the certificate keeps the two tiers distinct so you know which kind of defect you’re looking at.

Certifying a whole semantic model

Point certify_semantic_model at a dbt/MetricFlow, Cube, or OSI model (the dialect is auto-detected) plus the frames backing each target: it certifies every declared key and reports which ones a metric silently depends on that would miscount:

Runnable demo

A complete, self-contained walkthrough, planting both defects, certifying, and fixing, ships in the examples:

Writing the verdict back to the catalog

The certificate isn’t only a return value: its trust verdict can be written back into the catalog the semantic layer reads, so “resolve once, the verdict travels with the join.” The Cube, OSI, and MetricFlow crosswalk emitters accept a certificate= and embed a single-sourced key_integrity block:
It rides in meta.goldenmatch (MetricFlow / Cube) or custom_extensions.goldenmatch (OSI). The same block is produced by certificate_verdict(cert) in Python and certificateVerdict(cert) in TypeScript, field-identical, locked by a cross-language fixture, so a downstream tool reads one trust contract regardless of which surface emitted the catalog.

Certifying keys as a build gate (CLI / MCP / REST)

The verdict is exposed on three surfaces, all emitting the same JSON (a shared certification_report_dict) so a CI gate reads n_untrustworthy / all_trustworthy identically wherever it runs. CLI. Point certify-keys at a semantic model + its data; --fail-untrustworthy exits non-zero when any declared key is untrustworthy for metric use:
MCP. The certify_semantic_model tool returns the per-key verdict block ({dialect, n_certified, n_untrustworthy, all_trustworthy, keys:[{target, key, key_integrity}]}), so an agent can certify a model and act on the verdict. REST. POST /semantic/certify with {"model": <path>, "frames": {name: path}, "resolve": bool} returns the same report:
Each key’s key_integrity is the same trust-verdict block the catalog emitters write back: so certifying, gating, and the catalog tag all speak one contract.

Cross-surface

The structural certifier is one Rust kernel (key-integrity-core) behind every surface: Python-native, TS/WASM, DuckDB (goldenmatch_certify_structural via the DuckDB UDF), and Postgres (goldenmatch_certify_structural via pgrx). The dbt goldenmatch_key_integrity test macro is conformance-locked to the same shared golden, so a semantic model certified in SQL returns the identical verdict as one certified in Python.