River
Y CombinatorBacked by Y Combinator
FREE TEMPLATE

SQL Style Guide Template

Three documents and three sheets that turn a model's test status into a fix priority once you know what it actually feeds.

Free download  ·  No account needed

Test Coverage by Model

One row per model, two facts checked separately

Filled in after the standards scan, not instead of it. A model earns its priority from what it actually feeds, never from a test count alone.

Any Test at All

The project-wide question a coverage percentage already answers: does at least one test exist anywhere on this model, on any column.

Primary Key Verified

Checked separately, because a test on a convenient column is not the same claim: does the model's actual grain carry a real unique and not_null check.

Feeds an Exposure

Board-level, executive-facing, internal-only, or none. This is the column a coverage percentage has no way to see.

Priority

Critical, High, Medium or Covered, derived from the two checks above rather than assigned by hand.

dbt's own style guide already settles most of this. Name every CTE after the ref or source it wraps, keep every join explicit, use an explicit `as` on every alias, and a linter enforces all of it once a team writes the rules down once. SQL and Model Standards and the Review Checklist in this pack are that write-down. Getting a warehouse to agree on formatting was never the hard part, and a linter catches most of it on every pull request without a person reading a single line.

Testing is closer to solved than it looks, too. dbt's own project-evaluator package reports test_coverage_pct, the percentage of models carrying at least one test, and separately flags every model missing a real check on its primary key. At Kettlewell Logistics, a fictional freight company, that gap is real: 70.8 percent of 96 models read as tested, and only 45.8 percent have their actual primary key verified.

dbt's own exposures feature already lets a model declare a downstream dashboard, typed and rated by maturity. Nothing joins that declaration to the missing-test list. Test Coverage by Model is that join: of Kettlewell's 52 models with an unverified key, 15 feed a board or executive dashboard directly. Built for the engineer reviewing someone else's pull request and the lead deciding what to fix before Monday's board deck runs, before the query's own cost is even a question.

70.8% test coverage, 45.8% of it on a verified primary key, and 15 models carrying the gap between them

The Test Coverage by Model sheet, and the coverage percentage it replaces with a priority list.

Test Coverage by Model

Kettlewell Logistics, a fictional freight company. 96 models in the project; 8 shown here.

ModelLayerAny testPK verifiedFeedsPriority
fct_revenue_by_lanemartYes, 22NoMonthly Board DeckCritical
fct_on_time_performancemartNoNoMonthly Board DeckCritical
fct_fuel_surcharge_recoverymartNoNoMonthly Board DeckCritical
fct_carrier_scorecardmartNoNoRegional Ops ReviewHigh
fct_customer_health_scoremartYes, 1NoRegional Ops ReviewHigh
int_shipment_costsintermediateNoNononeMedium
dim_customermartYesYesBoard Deck, Ops ReviewCovered
stg_shipmentsstagingYesYesnoneCovered

fct_on_time_performance and fct_fuel_surcharge_recovery carry zero tests of any kind and feed the board deck directly. fct_revenue_by_lane is the sharper case: it carries 22 tests and reads as tested in any project-wide percentage, while none of them touch lane_id plus week_start, its actual grain.

dim_customer feeds both the board deck and the executive review and is not on this list as a problem. Its primary key is verified. Feeding an important dashboard is not itself a defect. An unverified key is.

8 of 96 models shown. The other 4 Critical and High rows are in the full sheet.

Coverage vs. Reality

The same 96 models at Kettlewell Logistics, read two ways.

Question askedAnswer
Models with at least one test (test_coverage_pct)68 / 96, 70.8%
Models with their actual primary key verified44 / 96, 45.8%
Gap between the headline and the reality25.0 points
Priority tierModelsShareWhat it means
Critical66.3%Unverified key, feeds the board deck directly
High99.4%Unverified key, feeds an executive-facing review
Medium3738.5%Unverified key, internal only or no declared exposure
Covered4445.8%Primary key verified, regardless of what it feeds

70.8 percent reads as a healthy warehouse. Checking the same 96 models for a verified primary key instead of any test at all drops that to 45.8 percent, a 25-point gap hiding inside a number every project-wide metric already reports as fine.

15 of the 96 models, 15.6 percent of the warehouse, are Critical or High. That is the fix list this sheet exists to produce: not the 52 models with an unverified key, all of them, but the 15 whose defect already has a reader.

Zero of the 15 were found by asking whether the model is tested. All 15 were found by asking what it feeds.

What's in the pack

01

SQL and Model Standards

Naming by layer, explicit columns and joins, no hardcoded literals, written down once so a review stops relitigating the same fix.

02

Review Checklist

What blocks a merge versus what gets a follow-up, including whether every downstream reader was re-verified after a grain change.

03

Testing Guidance

The layer-by-layer minimum test, and the rule for turning a primary key gap into Critical, High, Medium or Covered.

04

Standards Compliance Scan

One row per model against the standards document: naming, explicit columns, explicit joins, hardcoded literals, and a description check.

05

Common Issue Register

Every recurring style failure ranked by how many models it touches, with one real example and the exact fix, a different gap than a missing column definition.

06

Test Coverage by Model

Every model's real primary key test status, joined to whether it feeds a board, an executive dashboard, or nothing at all.

How to use it

  1. 1

    Open in River, or take it blank

    Claim the pack in River and hand it the repository, or take the blank documents and sheets and fill them in yourself.

  2. 2

    Send the repository

    A dbt project, a sample of model files and schema definitions, or whatever your transformation tool exports. Partial is fine and gets said.

  3. 3

    Name what it feeds

    Which models feed a dashboard, a scheduled report, or a recurring review, and which of those a board member or executive actually reads.

  4. 4

    Get the fix list

    The Test Coverage by Model sheet, ordered by what breaks something somebody looks at, not by how many models are untested.

Frequently asked questions

Is this template free?

Yes, no account or card needed to download it. Edit with AI is the optional half, where River reads your repository and builds the scan and the coverage sheet itself. Every other pack sits in the template library.

What format are the downloaded files?

Three documents as Word files and three sheets as CSVs, zipped together. The sheets ship with Kettlewell Logistics' illustrative rows in place, so the priority split is visible before you replace them with your own models.

dbt already reports a test coverage percentage. Why do we need this?

That percentage counts any model with at least one test, on any column. It says nothing about whether the test landed on the model's actual primary key, and nothing about whether the model feeds anything a person answers to. This pack checks both, separately, and only then assigns a priority.

We haven't declared exposures in dbt. Can we still build the coverage sheet?

Yes. An exposure declaration is one way to know what a model feeds, not the only way. Naming what shows up in a board deck or a recurring review by asking the people who run those meetings gets to the same answer directly.

Does this replace a SQL linter?

No, it's the standards document a linter enforces. Most of SQL and Model Standards, naming, explicit columns, explicit joins, formatting, is mechanical enough to lint automatically once it's written down; the primary key and exposure questions still need a person.

Can a well-tested model still come out as a priority?

No, and the sheet says so directly: a verified primary key marks a model Covered regardless of what it feeds. The reverse is the actual finding, a model with several tests, none of them on its real grain, feeding something important.

Our model repository can't leave our network. Can we still use this?

Yes. A private AI workspace runs the scan and builds the coverage sheet inside your own tenancy, so model code and schema names never cross a boundary your data governance hasn't approved. The scan, the register and the sheet behave exactly as described here.

Find out which untested models are one bad number away from a board meeting

Start from the blank documents and sheets, or send River your repository and let it join what's untested to what it actually feeds.

Edit with AI