Data Quality
Source freshness
Measured against the build anchor ("today" = 2026-04-01), not wall-clock — so committed static seeds don't go perpetually stale in CI. The pattern (max load time vs an SLA) is identical to production.
No Results
Deliberate-defect ledger
The synthetic source data has realistic defects baked in on purpose — they give the staging models real cleaning work and give the dbt tests something to catch. Each defect maps to the model that resolves it and the test that guards it.
| Defect | Resolved by | Guarded by |
|---|---|---|
| Duplicate opportunities | stg_sf__opportunities dedupe | unique_combination_of_columns |
| Duplicate HubSpot contacts | stg_hs__contacts dedupe by email | combo test on email |
| Null / inactive owners | int_opportunities__enriched flags | documented |
| Inconsistent / null segment labels | stg_sf__accounts crosswalk + fallback | accepted_values (3 segments) |
| Timezone mismatch (UTC vs rep-local) | int_activities__first_touch + to_utc() | speed-to-lead / SLA |
| Late / missing stage history | int_opportunities__stage_spells | recency anomaly + coverage |
| Null / $0 / non-USD amounts | fct_opportunities excludes / flags | assert_canonical_pipeline_excludes_renewals |
| Test / internal records | staging filters | assert_no_test_records_in_marts |
| MQL threshold drift (40 vs 50) | int_leads__lifecycle_events uses 50 | assert_mql_threshold_is_canonical |
| Broken hs↔sf crosswalk (~8%) | int_leads__unified LEFT join + flag | the "Data team" reconciliation variant |
Every push runs dbt build (seed → run → test); a single failed test fails CI and
blocks the dashboard from refreshing — the same contract Arcline's KPI Dictionary spells out.
