DSL Naming
Conventions

How we name YAML definitions, compiled SQL models, contracts,
and everything in between

March 2026

Why Naming Matters

  • Predictability — Given a YAML filename, you can guess the compiled SQL model name without looking it up
  • Globbingdbt build --select probe_findings__* does what you’d expect
  • DAG readability — In dbt’s DAG, you can see at a glance what layer and family a model belongs to
  • Union coherence — The union view’s name hints at what its children are called
  • Mechanical renaming — One convention means one search-and-replace when things change
The most important property of a naming convention is consistency. The second most important is that it fails loudly when violated.

The Three Artefact Families

Probes, hypotheses, diagnoses — and how each one is named.

Identity Prefixes

Family Prefix YAML Example ID Field
Probe probe_ probe_revenue_leakage.yaml probe_id: probe_revenue_leakage
Assessment assessment_ assessment_material_health.yaml probe_id: assessment_material_health
Hypothesis hyp_ hyp_revenue_leakage_unbilled.yaml hypothesis_id: hyp_revenue_leakage_unbilled
Diagnosis diag_ diag_billing_workflow_gap.yaml diagnosis_id: diag_billing_workflow_gap
Rule: the ID field must match the filename (without .yaml). Enforced by hypothesischeck.py and diagnosischeck.py at compile time. Probes follow the same convention by practice.

Assessments Are a Subtype of Probe

  • Assessments use probe_id as their identifier field — not assessment_id
  • Compiled output follows the probe_findings__ pattern, just like regular probes
  • The assessment_ prefix on the probe_id value is what distinguishes them
Compiled model names probe_findings__probe_revenue_leakage # regular probe probe_findings__probe_duplicate_billing # regular probe probe_findings__assessment_material_health # assessment probe_findings__assessment_billing_quality # assessment
From the dbt DAG’s perspective, assessments are probes. The prefix is the only signal — and it’s enough for --select probe_findings__assessment_*.

The Double-Underscore Convention

How compiled SQL model names are built from YAML identifiers.

The __ Pattern

Anatomy of a compiled model name probe_findings__probe_revenue_leakage ^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^ output type artefact identity (= probe_id from YAML)
  • Left of __ — what kind of table it is: probe_findings, conforming to the findings contract
  • Right of __ — the literal ID from the YAML definition, including its prefix
  • Formulaf"probe_findings__{probe['probe_id']}" in probecompile.py
The double underscore is a namespace separator. Single underscores appear within names (revenue_leakage). Double underscores separate the output type from the instance identity. No ambiguity.

Probes: One File Per Artefact

probe_*.yaml
18 files
probecompile.py
probe_findings__*.sql
18 files (1:1)
dbt/numetrix/models/probes/ probe_findings__probe_revenue_leakage.sql probe_findings__probe_duplicate_billing.sql probe_findings__probe_orphan_billing.sql probe_findings__probe_stale_article.sql probe_findings__assessment_material_health.sql probe_findings__assessment_billing_quality.sql ... (18 models total)
Each probe compiles to its own dbt model. The union view platform_probe_findings aggregates them via UNION ALL BY NAME. Naming invariant: the union view’s prefix matches its children.

Hypotheses & Diagnoses: Monolithic Files

Hypotheses
hyp_revenue_leakage.yaml
hyp_stale_catalogue.yaml
hyp_duplicate_billing.yaml
↓ hypothesiscompile.py
hypothesis_verdicts.sql (one file)
hypothesis_registry.sql (one file)
Diagnoses
diag_billing_workflow_gap.yaml
diag_catalogue_maintenance_lag.yaml
diag_duplicate_interface_error.yaml
↓ diagnosiscompile.py
diagnosis_verdicts.sql (one file)
diagnosis_registry.sql (one file)
Unlike probes, hypotheses and diagnoses compile N YAML files into one monolithic SQL file. All hypothesis CTEs are UNION ALL’d inside a single hypothesis_verdicts.sql. No __ separator because there are no per-artefact files.

Why the Asymmetry?

Probes → One File Each
Probes are independent. Each queries Gold entities directly. No inter-probe dependencies (except assessments). Adding a probe = adding a file. dbt build --select probe_findings__probe_X rebuilds just one.
Verdicts → Monolithic
Hypotheses reference multiple probe findings tables. Diagnoses reference hypothesis_verdicts + probe findings. A single model with all CTEs lets dbt resolve the full dependency graph in one pass.
The trade-off: monolithic files are harder to selectively rebuild, but they avoid a combinatorial explosion of dbt ref() cross-dependencies. The naming convention adapts to the compilation strategy, not the other way around.

Layer Prefixes & Contracts

Medallion layer naming and the contract versioning scheme.

Layer Prefixes

A material row flows through the pipeline bronze_materials → silver_materials → gold_materials → platform_gold_materials
Prefix Layer Materialization Example
bronze_ Bronze TABLE bronze_cases, bronze_billing_events
silver_ Silver TABLE silver_cases, silver_billing_events
gold_ Gold VIEW gold_cases, gold_taxonomy_closure
platform_gold_ Platform VIEW platform_gold_cases
platform_ Platform (DSL) VIEW platform_probe_findings, platform_hypothesis_verdicts
The entity name (cases, billing_events, materials) is invariant across all layers. Change the prefix, keep the noun.

Contract Naming

File Version Key YAML Reference Who Uses It
gold_contract.v1.json gold.v1 contract: "gold.v1" Most probes
silver_contract.v1.json silver.v1 contract: "silver.v1" Silver audit probes
findings_contract.v1.json findings.v1 contract: "findings.v1" Assessments
diagnosis_contract.v1.json diagnosis.v1 contract: "diagnosis.v1" Diagnosis compiler
Pattern: {layer}_contract.v{N}.json. The version key inside the JSON uses the short form (gold.v1). YAML definitions reference this short key. Bumping to v2 = new file, old probes still compile against v1.

Entity Names in Contracts

Contract Entity (PascalCase)
BillingEvent
CaseMaterialUsage
Case
Material
Procedure
dbt Model (snake_case)
gold_billing_events
gold_case_material_usage
gold_cases
gold_materials
gold_procedures
Probes reference BillingEvent (PascalCase, domain language). The contract maps it to gold_billing_events (snake_case, dbt convention). resolve_ref() bridges the gap. If a dbt model renames, update one JSON field — all probes recompile correctly.

The Full Naming Pipeline

From YAML file to platform union view — following one name through the system.

Probe: End-to-End

Following a probe through the naming system 1. YAML definition probes/probe_revenue_leakage.yaml probe_id: probe_revenue_leakage # must match filename contract: "gold.v1" # references gold_contract.v1.json 2. Compiled dbt model models/probes/probe_findings__probe_revenue_leakage.sql # one file per probe 3. Per-tenant table (via generate_schema_name) hospital_alpha.probe_findings__probe_revenue_leakage 4. Platform union view platform.platform_probe_findings # UNION ALL BY NAME across tenants 5. Registry entry platform.platform_probe_registry # tri-lingual display text

Hypothesis: End-to-End

Following a hypothesis through the naming system 1. YAML definition hypotheses/hyp_revenue_leakage_unbilled.yaml hypothesis_id: hyp_revenue_leakage_unbilled # must match filename (enforced) 2. Compiled dbt model (monolithic — no __ separator) models/probes/hypothesis_verdicts.sql # all hypotheses in one file # Inside: CTEs named hyp_revenue_leakage_unbilled__evidence, # hyp_revenue_leakage_unbilled__scored, # hyp_revenue_leakage_unbilled__verdict 3. Per-tenant table hospital_alpha.hypothesis_verdicts # one row per hypothesis 4. Platform union view platform.platform_hypothesis_verdicts # UNION ALL across tenants

Diagnosis: End-to-End

Following a diagnosis through the naming system 1. YAML definition diagnoses/diag_billing_workflow_gap.yaml diagnosis_id: diag_billing_workflow_gap # must match filename (enforced) hypothesis_id: hyp_revenue_leakage_unbilled # must reference existing hypothesis 2. Compiled dbt model (monolithic — no __ separator) models/probes/diagnosis_verdicts.sql # all diagnoses in one file 3. Per-tenant table hospital_alpha.diagnosis_verdicts # rows only for confirmed hypotheses 4. Platform union view platform.platform_diagnosis_verdicts # UNION ALL across tenants
Note the cross-family reference: diagnosis_id: diag_billing_workflow_gap points to hypothesis_id: hyp_revenue_leakage_unbilled. Prefixes (diag_, hyp_) make the reference direction unambiguous.

Design Decisions

The trade-offs we considered and why we chose this way.

Why {family}__{instance}?

We considered three alternatives for verdict model names:

Option Example Trade-off
Main noun prefix verdict__hyp_X Both families share verdict__*. Union view name diverges from children.
Family prefix hypothesis_verdicts__hyp_X Consistent with probes. Union view matches children. Verbose but predictable.
Bare ID hyp_X Cleanest, but loses the “this is a verdict” signal in the DAG.
We chose family prefix because the union view’s name (hypothesis_verdicts) naturally matches its children (hypothesis_verdicts__hyp_*). --select hypothesis_verdicts__* does what you’d expect. Same pattern as probes.

Registry Naming

Per-Tenant (in models/probes/)
probe_registry.sql
hypothesis_registry.sql
diagnosis_registry.sql
Platform (in models/platform/)
platform_probe_registry.sql
platform_hypothesis_registry.sql
platform_diagnosis_registry.sql
Registries contain tri-lingual display text (DE/EN/FR). Content is tenant-independent — identical across all tenants. Platform views read from the first tenant only, unlike findings/verdicts which union across all.

The Complete Naming Map

Family YAML Dir Prefix Compiled SQL Strategy Platform View
Probe probes/ probe_ probe_findings__probe_* 1 file each platform_probe_findings
Assessment probes/ assessment_ probe_findings__assessment_* 1 file each (same union)
Hypothesis hypotheses/ hyp_ hypothesis_verdicts monolithic platform_hypothesis_verdicts
Diagnosis diagnoses/ diag_ diagnosis_verdicts monolithic platform_diagnosis_verdicts
One convention, one search-and-replace. Given any YAML file, you can derive every downstream name mechanically. That’s the whole point.
nuMetrix