Metacenta

Sample review

What a review looks like

Two complete reviews, as a client reads them. Every score says what it rests on, and every limit is stated. The second project is public, so you can check its findings against its code.

The short version

A review reads the artefacts you send, runs every rule it has evidence for, and gives you a short list of what to fix first. Below are two finished reports. The first has 811 findings cut to five things to do. The second is a small, well-tested project, and its review finds little.

How to read them

The engine checks every rule it has evidence for and raises every finding. A reviewer then cuts the list to what is worth doing first, and that cut is what you read. The summary of each report counts what was raised as well as what was kept. Each finding names its rule, and the rule pages say why it matters and how to fix it.

What these two cannot show

A paid review reads more than a dbt project. It can also read your BI tool, your scheduler and your warehouse history, each only if you send it. These samples read a manifest, plus a repository for the second, so most areas say not assessed. That is how a report marks what it was not given.

Frequently asked questions

Are these real reviews?

Yes. The engine produced both, from the same code a client's review runs on, and a reviewer cut each one. Only the projects differ from a paid review: one is a project we built, and one is public.

Is this the whole report?

It is the report a client reads. A delivered review adds a table of every finding, which runs to hundreds of rows, so it is left out here. It also comes as a PDF, with the full list as a spreadsheet.

A 200-model project, built to look like production

We built this dbt project, bigshop, to test the review at the size of a real estate. It is not a client's, and its model names show it. It has the problems real projects have at this size: most models untested, copied logic, and main tables with no declared grain. The review raised every finding below, and a reviewer cut them to five things to do first.

Summary

Of the 113 checks in the suite, 31 ran on the artefacts supplied and raised 811 findings. The 289 findings selected for this report are 47 high, 242 medium.

The weakest areas are testing (10) and maintainability (63). Two more areas score below 70 on part of their checks: modelling correctness 0 (1 of 5 checks) and documentation 5 (2 of 3 checks). Those are narrower claims than a full pass, and the basis column says what is missing. One area came back clean on every check: lineage integrity.

The first three things to do:

  1. Give every model at least one test — 180 findings, medium effort.
  2. Stop partial reloads from duplicating rows — 7 findings, low effort.
  3. Collapse duplicated model logic to a single definition — 22 findings, medium effort.

Who this review is for

No engagement profile was supplied, so the findings below are ranked by the engine's default ordering and measured against a full pass on every check. That is a bar most teams neither reach nor should aim for. Tell us the size of the business, what the data touches and what good enough looks like for you. We can then rank and score the same evidence against that instead.

Platform health

Dimension Score Basis
Documentation 5 based on 2 of 3 checks — 20 of 200 models have a description; 0 of 6 data sources have a description. 1 check needs an artefact that was not collected.
Testing 10 20 of 200 models have at least one test; 20 of 200 models are tested and checked for duplicate rows
Source monitoring 100 based on 1 of 3 checks — 6 of 6 data sources say how late their data may arrive. 2 checks need an artefact that was not collected.
AI lifecycle n/a not assessed — the artefact these checks read was not supplied
Orchestration & reliability n/a not assessed — the artefact these checks read was not supplied
BI semantic layer n/a not measurable — 2 checks had nothing of that kind in this project; 6 checks need an artefact that was not collected
Execution health n/a not assessed — the artefact these checks read was not supplied
Lineage integrity 100 200 of 200 models read their inputs through the project, not by fixed table names; 200 of 200 models are free of circular dependencies
Modelling correctness 0 based on 1 of 5 checks — 0 of 7 models that update in place declare a key. 1 check had nothing of that kind in this project; 3 checks need an artefact that was not collected.
Consumption & cost n/a not assessed — the artefact these checks read was not supplied
Maintainability 63 51 of 200 models list their columns explicitly; 200 of 200 models are short enough to read
Ownership & accountability n/a not measurable — 2 checks had nothing of that kind in this project; whether models name an owner and whether data sources name an owner could not be assessed from the artefacts supplied
Repository hygiene n/a not assessed — the artefact these checks read was not supplied

A score is the average of its checks' pass rates. Each check's rate is the share of the entities it examined that passed. So a check covering only tested models counts as much as one covering every model. It is not a weighted sum of findings, which would measure project size. n/a means the artefacts supplied could not answer, which differs from a zero. The basis column says which, and how many checks a score rests on.

What this exposes you to

Each of these is a consequence the platform currently carries, not a style preference. They are ordered by the cost of leaving them alone.

HIGH · Give every model at least one test

  • This is a presentation-layer model, the layer reports normally read, so a silent data error here can reach one before anyone notices. No consumer is declared, so the report cannot say which.
  • Threatens: Silently wrong numbers
  • Reaches, at its widest: 14 models built from the affected entity
  • Affects 180 entities: fct_mart_1, fct_mart_2, fct_mart_4, fct_mart_5, fct_mart_7, +175 more

HIGH · Stop partial reloads from duplicating rows

  • Any re-run that re-reads an already-loaded window appends duplicate rows instead of replacing them. Totals drift upward and a full refresh is the only repair.
  • Threatens: Silently wrong numbers
  • Affects 7 entities: fct_mart_0, fct_mart_9, fct_mart_18, fct_mart_27, fct_mart_36, +2 more

MEDIUM · Collapse duplicated model logic to a single definition

  • The same definition exists in more than one place, so a fix applied to one copy leaves the others wrong — this is how two dashboards come to disagree.
  • Threatens: Hard to change safely · Silently wrong numbers
  • Reaches, at its widest: 6 models built from the affected entity
  • Affects 22 entities: fct_mart_8, fct_mart_14, fct_mart_32, fct_mart_49, fct_mart_59, +17 more

MEDIUM · Describe every column of each main table

  • Column names and descriptions are all an AI agent or a new analyst reads. Where a description is missing, they guess what the column means, and the guess reaches a dashboard.
  • Threatens: Silently wrong numbers · Visible outside the team
  • Affects 40 entities: fct_mart_1, fct_mart_2, fct_mart_4, fct_mart_5, fct_mart_7, +35 more

MEDIUM · Declare what one row of each main table is

  • A count or a join assumes one row per key. If the table holds one row per key per day, an agent's totals are multiplied and nothing fails.
  • Threatens: Silently wrong numbers
  • Affects 40 entities: fct_mart_1, fct_mart_2, fct_mart_4, fct_mart_5, fct_mart_7, +35 more

What an AI agent would get wrong

An AI agent answering questions from a data estate gets three kinds of question wrong. This is where this estate stands on each, worst first, sized by the findings in this review. It is not a score.

  1. What does this field mean? 40 findings across 40 items, the worst rated medium. An agent reads names and descriptions. Where a field has no description it guesses, and where a table has several undescribed dates it may filter on the wrong one.
  2. What does one row stand for? 40 findings across 40 items, the worst rated medium. Without a declared key, an agent cannot tell a table of customers from a table of customers per day, so its counts and totals can double.
  3. Which number is right? Not assessed: the artefacts supplied could not show it. Asked for a figure such as revenue, an agent picks one definition. Where two definitions disagree, it answers confidently with either one.

Not assessed: whether the estate keeps a set of checked questions with known answers, used to test an agent before release. Tools that hold such a set keep it in their own service, not in project files, so the files supplied cannot show whether one exists.

Roadmap to recovery

Work grouped by when it should happen. Each stage assumes the ones above it are done, and the projected scores are what the scorecard reaches once that stage closes.

Fix immediately

227 findings across 3 workstreams:

  • Give every model at least one test — 180 findings, medium effort
  • Stop partial reloads from duplicating rows — 7 findings, low effort
  • Declare what one row of each main table is — 40 findings, low effort

Takes it to: Modelling correctness 0 → 100 · Testing 10 → 100

Next 30 days

62 findings across 2 workstreams:

  • Collapse duplicated model logic to a single definition — 22 findings, medium effort
  • Describe every column of each main table — 40 findings, medium effort

Not every stage moves a score: the scorecard measures the checks it can count, and some of this work is worth doing for the consequence rather than the number.

What to do first

This review ran 31 checks and produced 811 findings. A reviewer read them and selected the 5 below, accounting for 289 of them; the remainder are held and available on request.

The scores, the coverage table and the scope statement in this report describe everything that was examined, not only what is listed here.

1. Give every model at least one test

  • Impact: very high · Effort: medium · Confidence: high · When: Fix immediately
  • 180 findings (40 high, 140 medium): fct_mart_1, fct_mart_2, fct_mart_4, fct_mart_5, fct_mart_7 (+175 more)
  • Why: This is a presentation-layer model, the layer reports normally read, so a silent data error here can reach one before anyone notices. No consumer is declared, so the report cannot say which.

Example, for fct_mart_1 — values in angle brackets are yours to fill in:

# the schema.yml beside the model
models:
  - name: fct_mart_1
    columns:
      - name: <key column>  # the column one row is unique on; confirm before applying
        data_tests: [unique, not_null]

2. Stop partial reloads from duplicating rows

  • Impact: high · Effort: low · Confidence: high · When: Fix immediately
  • 7 findings: fct_mart_0, fct_mart_9, fct_mart_18, fct_mart_27, fct_mart_36 (+2 more)
  • Why: Any re-run that re-reads an already-loaded window appends duplicate rows instead of replacing them. Totals drift upward and a full refresh is the only repair.

Example, for fct_mart_0 — values in angle brackets are yours to fill in:

-- top of models/marts/fct_mart_0.sql
{{ config(materialized='incremental', unique_key='<key column>') }}  -- confirm the key before applying
-- then rebuild once: dbt build -s fct_mart_0 --full-refresh

3. Collapse duplicated model logic to a single definition

  • Impact: high · Effort: medium · Confidence: high · When: Next 30 days
  • 22 findings: fct_mart_8, fct_mart_14, fct_mart_32, fct_mart_49, fct_mart_59 (+17 more)
  • Why: The same definition exists in more than one place, so a fix applied to one copy leaves the others wrong — this is how two dashboards come to disagree.

4. Describe every column of each main table

  • Impact: high · Effort: medium · Confidence: high · When: Next 30 days
  • 40 findings: fct_mart_1, fct_mart_2, fct_mart_4, fct_mart_5, fct_mart_7 (+35 more)
  • Why: Column names and descriptions are all an AI agent or a new analyst reads. Where a description is missing, they guess what the column means, and the guess reaches a dashboard.

5. Declare what one row of each main table is

  • Impact: high · Effort: low · Confidence: high · When: Fix immediately
  • 40 findings: fct_mart_1, fct_mart_2, fct_mart_4, fct_mart_5, fct_mart_7 (+35 more)
  • Why: A count or a join assumes one row per key. If the table holds one row per key per day, an agent's totals are multiplied and nothing fails.

Where one edit closes several findings

40 models carry 120 findings between them that one YAML entry per model closes — whichever of a description, columns, a key test and an owner it is missing.

  • fct_mart_1 — 3 findings
  • fct_mart_2 — 3 findings
  • fct_mart_4 — 3 findings
  • fct_mart_5 — 3 findings
  • fct_mart_7 — 3 findings
  • fct_mart_8 — 3 findings
  • fct_mart_10 — 3 findings
  • fct_mart_11 — 3 findings
  • fct_mart_13 — 3 findings
  • fct_mart_14 — 3 findings
  • fct_mart_16 — 3 findings
  • fct_mart_17 — 3 findings
  • …and 28 more models

Whose area this is

Nothing in this review can be routed to a named owner. The project declares no dbt groups: and no ownership-shaped meta key, so the manifest carries nobody to send a finding to. That is a limit of what a manifest records, not a statement that the work is unowned. It does mean whoever picks up this review must assign every item by hand first.

Test coverage by layer

The project is laid out in layers, so the same test findings regroup by the one a model sits in. This covers all 200 models in this project.

Layer Models No test at all Tested No grain assertion No not_null
Staging 60 60 of 60 (100%) 0 — —
Intermediate 80 80 of 80 (100%) 0 — —
Marts 60 40 of 60 (67%) 20 none none

Each figure is counted against the column to its left: no test at all out of Models, the two assertion columns out of Tested. There is no single coverage figure for a layer, because a model with no tests cannot also be a model whose tests miss its grain. These are counts, not scores — nothing here is comparable with Platform health above.

The gap sits equally across staging (60 of 60) and intermediate (80 of 80) — no one layer is thinner than the others.

What this review could not see

This pass read one artefact: the dbt manifest. The following are unassessed, not passing — each needs evidence that pass did not have.

Unassessed Needs
Whether two dashboards define a metric differently a comparison of metric definitions ACROSS layers — dbt metrics against the BI tool's own measures. Each layer is read on its own; the two are not yet compared
Whether a credential-shaped file actually contains a live secret a human opening it — the engine reads filenames, never contents
Dependency vulnerabilities and license compatibility a dependency manifest scan (not yet built)
Leaf models are consumed by something (check model-possibly-unused could not run) the project declares no exposures, metrics or semantic models, so there is no way to tell a used leaf model from an abandoned one
Models declare an owner (check model-unowned could not run) this project declares no dbt groups: and no ownership-shaped meta key, so there is no convention to measure its models against — ownership held outside dbt (CODEOWNERS, a rota, a wiki) is not visible in a manifest
Sources declare an owner (check source-unowned could not run) this project declares no dbt groups: and no ownership-shaped meta key, so there is no convention to measure its sources against — ownership held outside dbt (CODEOWNERS, a rota, a wiki) is not visible in a manifest
Query cost, full scans and partition use a warehouse query history (--query-history <path>) — collected by a read-only query the client runs themselves, with no credential granted
Table sizes, row counts and storage cost catalog.json, or a warehouse connection
Repository hygiene: CI, tests, documentation, credential-shaped filenames a repository inventory (--repo owner/name)
Whether the declared tests actually pass, and what a failure is blocking target/run_results.json from a recent dbt build (--run-results <path>) — the same directory as the manifest
Whether the monitored sources are actually arriving on time target/sources.json from dbt source freshness (--source-freshness <path>)
Whether the warehouse actually matches what the project declares target/catalog.json from dbt docs generate (--catalog <path>) — the same directory again
How this project is scheduled — retries, alerting, ownership, and what a redeploy replays the DAG or job definition files themselves (--dag <path>, one per file). They are read for schedule, owner, retry and alert declarations only, and nothing in them is retained
Which scheduled jobs have actually been failing, and for how long the orchestrator's own run history — Airflow's metadata database or REST API, or the equivalent. Not reachable from a repository at any depth: a DAG file states intent, not what happened. Reaching it needs a credential to the scheduler, which this review does not ask for
How the BI layer reads this project — whether dashboards sit on the models dbt builds, and whether their joins count correctly the LookML project, if there is one (--lookml <dir>). Only .lkml files are read; a measure's or dimension's SQL is reduced to a fingerprint and discarded, and every other SQL body is not read at all
Which dashboards people open, and which nobody has opened in months a BI usage export the client produces (--bi-usage <csv>): view counts per dashboard, named by the tool's own id. An export naming people is refused
Which models change most often, and whether those are the tested ones the change history — one git log command, run from the dbt project directory in a full clone, printing commit hashes, dates and file paths only (no names, no messages). No access is needed, and we send the exact command to run
How often CI fails, and whether changes are reviewed before they merge the repository host's own records — Actions run history and pull-request reviews. A change history has neither, and both need token permissions (Actions: read, Pull requests: read) this review does not ask for

Evidence

dbt project

Source dbt manifest.json
Project bigshop
dbt version 1.10.23
Manifest schema https://schemas.getdbt.com/dbt/manifest/v12.json
Warehouse adapter duckdb
Manifest generated 2026-09-20T17:20:53.005637Z
Project size 200 models · 6 sources · 40 tests · 0 exposures · 0 metrics
Test attribution attached_node (authoritative)
Dependency map manifest child_map
Scope bigshop — no installed package contributed entities

Exactly what was read

Artefact Supplied as SHA-256 Size
dbt manifest bigproj-manifest.json 849fad1cbb88b7e0… 1000.0 KB

Produced by Metacenta check suite v1.30 (113 checks). The digests are of the files as supplied, and shasum -a 256 <file> reproduces them. So every finding traces to the exact artefact it came from, and a later disagreement about what was reviewed is a matter of record rather than recollection.

Findings fingerprint: 4f466ba5284e1a60…, covering 811 findings and the outcome of each of 43 checks, taken before the shortlist was cut. Re-running the same check suite on these files gives the same fingerprint. If you have portal access, its Verify page does that in your own browser.

Ownership and routing

Convention in use none declared in dbt
Findings routed to a named owner 0 of 811

This project declares no dbt groups: and no ownership-shaped meta key, so no finding in this review can be addressed to a named owner from the manifest alone. A manifest cannot show ownership held elsewhere, such as in a CODEOWNERS file, a rota or a wiki. So this is a limit of what was read, not a statement about the team.

Every finding below is traceable to a field in the artefacts above. This review connected to no warehouse and no dashboard tool, and everything was read from files. Nothing here is inferred from a test run, a source-freshness reading or the warehouse's own account of what it holds. No finding is inferred from the contents of any file in the repository. See What this review could not see.

What was examined

Artefact
dbt entities (models, sources, tests, exposures, metrics) 246
Findings raised 811

This is the whole of what was read. Everything in this report is derived from it, and nothing outside it was assumed.

Check coverage

Every check, including the ones that found nothing. A check that could not run is listed as such — so an absent finding is never mistaken for a passing grade.

Check Dimension Outcome Examined Findings Corresponds to Note
incremental-without-unique-key Modelling correctness ran 7 7 —
dependency-cycle Lineage integrity ran 200 0 —
hardcoded-table-reference Lineage integrity ran 200 0 fct_hard_coded_references
model-untested Testing ran 200 180 fct_test_coverage (related)
model-grain-not-asserted Testing ran 20 0 fct_missing_primary_key_tests (narrower)
source-no-freshness Source monitoring ran 6 0 fct_sources_without_freshness
duplicate-model-logic Maintainability ran 200 22 —
public-model-without-contract Modelling correctness not applicable 0 0 fct_public_models_without_contracts no model is declared access: public
model-possibly-unused Lineage integrity could not run 0 0 — the project declares no exposures, metrics or semantic models, so there is no way to tell a used leaf model from an abandoned one
model-undocumented Documentation ran 200 180 fct_undocumented_models; fct_undocumented_public_models (broader)
model-columns-undocumented Documentation ran 20 0 —
model-no-column-schema Documentation ran 200 180 —
source-undocumented Documentation ran 6 6 fct_undocumented_source_tables
source-parent-undocumented Documentation ran 1 1 fct_undocumented_sources
duplicate-source Modelling correctness ran 6 0 fct_duplicate_sources
source-freshness-no-timestamp Source monitoring ran 6 0 —
model-no-not-null-test Testing ran 20 0 fct_missing_primary_key_tests (narrower)
select-star Maintainability ran 200 149 —
high-cte-count Maintainability ran 200 0 —
layer-naming-mismatch Maintainability ran 200 0 fct_model_naming_conventions (related)
test-not-beside-model Maintainability ran 40 0 fct_test_directories (narrower)
deep-lineage Lineage integrity ran 200 0 fct_chained_views_dependencies (related)
fan-out-hotspot Lineage integrity ran 200 0 fct_model_fanout (related)
staging-depends-on-staging Modelling correctness ran 60 0 fct_staging_dependent_on_staging
staging-depends-on-downstream Modelling correctness ran 60 0 fct_staging_dependent_on_marts_or_intermediate
downstream-depends-on-source Modelling correctness ran 140 0 fct_marts_or_intermediate_dependent_on_source
direct-join-to-source Modelling correctness ran 200 0 fct_direct_join_to_source
root-model Lineage integrity ran 200 0 fct_root_models
source-fanout Modelling correctness ran 6 6 fct_source_fanout (broader)
multiple-sources-joined Modelling correctness ran 200 0 fct_multiple_sources_joined
rejoining-upstream-concept Modelling correctness ran 200 0 fct_rejoining_of_upstream_concepts
exposure-parent-not-materialized Modelling correctness not applicable 0 0 fct_exposure_parents_materializations the project declares no exposures
exposure-on-private-model Modelling correctness not applicable 0 0 fct_exposures_dependent_on_private_models the project declares no exposures
model-unowned Ownership & accountability could not run 0 0 — this project declares no dbt groups: and no ownership-shaped meta key, so there is no convention to measure its models against — ownership held outside dbt (CODEOWNERS, a rota, a wiki) is not visible in a manifest
source-unowned Ownership & accountability could not run 0 0 — this project declares no dbt groups: and no ownership-shaped meta key, so there is no convention to measure its sources against — ownership held outside dbt (CODEOWNERS, a rota, a wiki) is not visible in a manifest
group-owner-unreachable Ownership & accountability not applicable 0 0 — the project declares no groups
exposure-owner-unreachable Ownership & accountability not applicable 0 0 — the project declares no exposures
semantic-column-not-built BI semantic layer not applicable 0 0 — the project declares no semantic models — whether it should have is a choice, not a finding
semantic-primary-entity-unasserted BI semantic layer not applicable 0 0 — the project declares no semantic models — whether it should have is a choice, not a finding
metric-undocumented Documentation not applicable 0 0 — the project declares no metrics — whether it should is a choice, not a finding
model-date-ambiguous Documentation not applicable 0 0 — no core model declares two or more date columns (core models are the marts)
core-model-columns-undocumented Documentation ran 60 40 —
core-model-grain-undeclared Modelling correctness ran 60 40 fct_missing_primary_key_tests (narrower)

Where these checks come from

  • dbt_project_evaluator (dbt Labs) — 21 of its 29 rules were answered by checks in this review. A further 4 have checks that could not run on the artefacts supplied — see the coverage table for which, and why. https://dbt-labs.github.io/dbt-project-evaluator/

The 4 rules not checked, and why

Listed rather than left out. Each is a position you can disagree with, not a gap being glossed over.

Rule Not checked because Reasoning
fct_too_many_joins it needs evidence this review does not collect dbt applies its join threshold to COMPILED SQL. This review holds each model's raw code with its Jinja unrendered, so a join count taken from it would be wrong wherever a macro expands to a join — and picking our own threshold to compare it against would be an invented bar wearing somebody else's citation.
fct_documentation_coverage it is a project-wide measure, not an assignable defect A project-wide documentation percentage has no entity to attach to and nobody to assign. The underlying defect is reported per model by model-undocumented and model-columns-undocumented, which name which models and can be worked through.
fct_source_directories checking it would impose a layout you did not choose The rule requires each source to be defined in a staging subdirectory named after it. That is dbt Labs' preferred layout, not a correctness property, and a project keeping one sources.yml per staging folder is not wrong. Unlike layer naming and test placement — both of which this review measures before enforcing — a project with a handful of sources gives too weak a signal to tell a deliberate layout from an inconsistent one.
fct_model_directories checking it would impose a layout you did not choose Same ground as fct_source_directories: it requires staging models to sit in folders named after their source. layer-naming-mismatch covers the part of this that can be self-calibrated — whether a project applies its OWN naming convention consistently — without asserting which convention it should have chosen.

22 checks here correspond to a rule published by somebody else. Each is named in the table above, so you can look it up and disagree with the criterion rather than with us. The other 9 have no published counterpart. They cover how the last run went, whether the warehouse matches what the project declares, whether the build is reproducible, and who is accountable for each asset.

Correspondence, not conformance. Citing a rule does not make its publisher a party to this review, and nothing here is a certification against any standard.

dbt Labs' jaffle_shop_duckdb

The public demo project from dbt Labs, reviewed from its repository and a manifest built with real dbt. It is small and well tested, so the review finds little. That is the point of showing it: a review should not invent problems to look busy.

Summary

Of the 113 checks in the suite, 29 ran on the artefacts supplied and raised 7 findings. The 7 findings selected for this report are 1 medium, 6 low.

One area scores below 70 on part of its checks: documentation 40 (1 of 3 checks). That is a narrower claim than a full pass, and the basis column says what is missing. Three areas came back clean on every check: testing, lineage integrity, maintainability.

The first three things to do:

  1. Show what schedules this project — 1 finding, medium effort.
  2. Document the models — 3 findings, medium effort.
  3. Document the declared columns — 3 findings, high effort.

Who this review is for

No engagement profile was supplied, so the findings below are ranked by the engine's default ordering and measured against a full pass on every check. That is a bar most teams neither reach nor should aim for. Tell us the size of the business, what the data touches and what good enough looks like for you. We can then rank and score the same evidence against that instead.

Platform health

Dimension Score Basis
Documentation 40 based on 1 of 3 checks — 2 of 5 models have a description. 1 check had nothing of that kind in this project; 1 check needs an artefact that was not collected.
Testing 100 5 of 5 models have at least one test; 5 of 5 tested models are checked for duplicate rows
Source monitoring n/a not measurable — 1 check had nothing of that kind in this project; 2 checks need an artefact that was not collected
AI lifecycle n/a not measurable — 1 check had nothing of that kind in this project
Orchestration & reliability n/a not assessed — the artefact these checks read was not supplied
BI semantic layer n/a not measurable — 2 checks had nothing of that kind in this project; 6 checks need an artefact that was not collected
Execution health n/a not assessed — the artefact these checks read was not supplied
Lineage integrity 100 5 of 5 models read their inputs through the project, not by fixed table names; 5 of 5 models are free of circular dependencies
Modelling correctness n/a not measurable — 2 checks had nothing of that kind in this project; 3 checks need an artefact that was not collected
Consumption & cost n/a not assessed — the artefact these checks read was not supplied
Maintainability 100 5 of 5 models list their columns explicitly; 5 of 5 models are short enough to read
Ownership & accountability n/a not measurable — 3 checks had nothing of that kind in this project; whether models name an owner could not be assessed from the artefacts supplied
Repository hygiene 100 based on 6 of 7 checks — free of committed credential files: yes; automated checks on every change: yes; tests in the repository: yes; README: yes; required dbt version declared: yes; code owners declared: yes. 1 check had nothing of that kind in this project.

A score is the average of its checks' pass rates. Each check's rate is the share of the entities it examined that passed. So a check covering only tested models counts as much as one covering every model. It is not a weighted sum of findings, which would measure project size. n/a means the artefacts supplied could not answer, which differs from a zero. The basis column says which, and how many checks a score rests on.

What this exposes you to

Each of these is a consequence the platform currently carries, not a style preference. They are ordered by the cost of leaving them alone.

LOW · Document the models

  • Consumers cannot tell what the model means without reading its SQL, so definitions get re-derived (and diverge) downstream.
  • Threatens: Hard to change safely
  • Reaches, at its widest: 2 models built from the affected entity
  • Affects 3 entities: stg_customers, stg_orders, stg_payments

LOW · Document the declared columns

  • Analysts guess at column meaning, which is how two dashboards end up defining the same metric differently.
  • Threatens: Hard to change safely
  • Reaches, at its widest: 2 models built from the affected entity
  • Affects 3 entities: stg_customers, stg_orders, stg_payments

MEDIUM · Show what schedules this project

  • If the schedule lives somewhere this repository cannot see, nobody can review how the platform runs in production. It is not versioned with the models it builds, and a new joiner cannot find it by reading the project. That is a handover problem long before it is an outage.
  • Affects 1 entity: this project

Roadmap to recovery

Work grouped by when it should happen. Each stage assumes the ones above it are done, and the projected scores are what the scorecard reaches once that stage closes.

Next 90 days

1 finding across 1 workstream:

  • Show what schedules this project — 1 finding, medium effort

Later

6 findings across 2 workstreams:

  • Document the models — 3 findings, medium effort
  • Document the declared columns — 3 findings, high effort

Takes it to: Documentation 40 → 100

Not every stage moves a score: the scorecard measures the checks it can count, and some of this work is worth doing for the consequence rather than the number.

What to do first

This review ran 29 checks and produced 7 findings. A reviewer read them and selected the 3 below, accounting for all of them; the remainder are held and available on request.

The scores, the coverage table and the scope statement in this report describe everything that was examined, not only what is listed here.

1. Show what schedules this project

  • Impact: medium · Effort: medium · Confidence: medium · When: Next 90 days
  • 1 finding: this project
  • Why: If the schedule lives somewhere this repository cannot see, nobody can review how the platform runs in production. It is not versioned with the models it builds, and a new joiner cannot find it by reading the project. That is a handover problem long before it is an outage.

2. Document the models

  • Impact: low · Effort: medium · Confidence: high · When: Later
  • 3 findings: stg_customers, stg_orders, stg_payments
  • Why: Consumers cannot tell what the model means without reading its SQL, so definitions get re-derived (and diverge) downstream.

Example, for stg_customers — values in angle brackets are yours to fill in:

# models/staging/schema.yml
models:
  - name: stg_customers
    description: <what one row is, and who reads this>

3. Document the declared columns

  • Impact: low · Effort: high · Confidence: high · When: Later
  • 3 findings: stg_customers, stg_orders, stg_payments
  • Why: Analysts guess at column meaning, which is how two dashboards end up defining the same metric differently.

Whose area this is

Nothing in this review can be routed to a named owner. The project declares no dbt groups: and no ownership-shaped meta key, so the manifest carries nobody to send a finding to. That is a limit of what a manifest records, not a statement that the work is unowned. It does mean whoever picks up this review must assign every item by hand first.

Test coverage by layer

The project is laid out in layers, so the same test findings regroup by the one a model sits in. This covers 3 of the project's 5 models.

Layer Models No test at all Tested No grain assertion No not_null
Staging 3 none 3 none none

Each figure is counted against the column to its left: no test at all out of Models, the two assertion columns out of Tested. There is no single coverage figure for a layer, because a model with no tests cannot also be a model whose tests miss its grain. These are counts, not scores — nothing here is comparable with Platform health above.

2 further models sit outside these directories and are not in this table. They are still checked individually, and appear in the findings and the worklist like any other model.

What this review could not see

This pass read three artefacts: the dbt manifest, the repository's metadata — file paths and repo-level facts, not file contents and one named configuration file (dbt_project.yml). The following are unassessed, not passing — each needs evidence that pass did not have.

Unassessed Needs
Whether two dashboards define a metric differently a comparison of metric definitions ACROSS layers — dbt metrics against the BI tool's own measures. Each layer is read on its own; the two are not yet compared
Whether a credential-shaped file actually contains a live secret a human opening it — the engine reads filenames, never contents
Dependency vulnerabilities and license compatibility a dependency manifest scan (not yet built)
Leaf models are consumed by something (check model-possibly-unused could not run) the project declares no exposures, metrics or semantic models, so there is no way to tell a used leaf model from an abandoned one
Each warehouse relation is declared as a source once (check duplicate-source could not run) the manifest declares no sources
Models declare an owner (check model-unowned could not run) this project declares no dbt groups: and no ownership-shaped meta key, so there is no convention to measure its models against — ownership held outside dbt (CODEOWNERS, a rota, a wiki) is not visible in a manifest
Query cost, full scans and partition use a warehouse query history (--query-history <path>) — collected by a read-only query the client runs themselves, with no credential granted
Table sizes, row counts and storage cost catalog.json, or a warehouse connection
Whether the declared tests actually pass, and what a failure is blocking target/run_results.json from a recent dbt build (--run-results <path>) — the same directory as the manifest
Whether the monitored sources are actually arriving on time target/sources.json from dbt source freshness (--source-freshness <path>)
Whether the warehouse actually matches what the project declares target/catalog.json from dbt docs generate (--catalog <path>) — the same directory again
How this project is scheduled — retries, alerting, ownership, and what a redeploy replays the DAG or job definition files themselves (--dag <path>, one per file). They are read for schedule, owner, retry and alert declarations only, and nothing in them is retained
Which scheduled jobs have actually been failing, and for how long the orchestrator's own run history — Airflow's metadata database or REST API, or the equivalent. Not reachable from a repository at any depth: a DAG file states intent, not what happened. Reaching it needs a credential to the scheduler, which this review does not ask for
How the BI layer reads this project — whether dashboards sit on the models dbt builds, and whether their joins count correctly the LookML project, if there is one (--lookml <dir>). Only .lkml files are read; a measure's or dimension's SQL is reduced to a fingerprint and discarded, and every other SQL body is not read at all
Which dashboards people open, and which nobody has opened in months a BI usage export the client produces (--bi-usage <csv>): view counts per dashboard, named by the tool's own id. An export naming people is refused
Which models change most often, and whether those are the tested ones the change history — one git log command, run from the dbt project directory in a full clone, printing commit hashes, dates and file paths only (no names, no messages). No access is needed, and we send the exact command to run
How often CI fails, and whether changes are reviewed before they merge the repository host's own records — Actions run history and pull-request reviews. A change history has neither, and both need token permissions (Actions: read, Pull requests: read) this review does not ask for

Evidence

Repository

Source repository metadata and named configuration files (no clone)
Repository dbt-labs/jaffle_shop_duckdb
Ref duckdb @ 20cc90437081
Visibility public
Files listed 36 files
Contributors 27
Last push 2026-10-09T19:36:54Z
Languages Shell 94% · Dockerfile 6%
Access token scopes not reported (unauthenticated, or a fine-grained token)
Collected 2026-10-14T08:34:40.440Z

dbt project

Source dbt manifest.json
Project jaffle_shop
dbt version 1.12.5
Manifest schema https://schemas.getdbt.com/dbt/manifest/v12.json
Warehouse adapter duckdb
Manifest generated 2026-10-14T08:26:50.487218Z
Project size 5 models · 0 sources · 20 tests · 0 exposures · 0 metrics
Test attribution attached_node (authoritative)
Dependency map manifest child_map
Scope jaffle_shop — no installed package contributed entities

Not covered by this check suite: 3 seed nodes. The manifest describes them, and nothing here examined it — so it is neither passing nor failing below. Snapshots in particular are usually where a project keeps its history, and this review says nothing about it either way.

Named configuration files opened

File
dbt_project.yml read
dbt_project.yml not present in this repository

These are the only files whose contents were opened. No other file was fetched, nothing was cloned, and profiles.yml is deliberately never read — it is the one dbt config file that holds warehouse credentials.

Exactly what was read

Artefact Supplied as SHA-256 Size
dbt manifest manifest.json bfa3e93cdea9412a… 669.3 KB

Produced by Metacenta check suite v1.30 (113 checks). The digests are of the files as supplied, and shasum -a 256 <file> reproduces them. So every finding traces to the exact artefact it came from, and a later disagreement about what was reviewed is a matter of record rather than recollection.

Findings fingerprint: 98c5a9919ee7fb4d…, covering 7 findings and the outcome of each of 59 checks, taken before the shortlist was cut. Re-running the same check suite on these files gives the same fingerprint. If you have portal access, its Verify page does that in your own browser.

Ownership and routing

Convention in use none declared in dbt
Findings routed to a named owner 0 of 7

This project declares no dbt groups: and no ownership-shaped meta key, so no finding in this review can be addressed to a named owner from the manifest alone. A manifest cannot show ownership held elsewhere, such as in a CODEOWNERS file, a rota or a wiki. So this is a limit of what was read, not a statement about the team.

Every finding below is traceable to a field in the artefacts above. This review connected to no warehouse and no dashboard tool, and everything was read from files. Nothing here is inferred from a test run, a source-freshness reading or the warehouse's own account of what it holds. No finding is inferred from the contents of any file beyond the named configuration files listed above. See What this review could not see.

What was examined

Artefact
Repository size (host-reported) 661 KB
Tracked files 36
Tracked bytes 711.7 KB
dbt entities (models, sources, tests, exposures, metrics) 25
Findings raised 7

This is the whole of what was read. Everything in this report is derived from it, and nothing outside it was assumed.

Check coverage

Every check, including the ones that found nothing. A check that could not run is listed as such — so an absent finding is never mistaken for a passing grade.

Check Dimension Outcome Examined Findings Corresponds to Note
incremental-without-unique-key Modelling correctness not applicable 0 0 — the project has no incremental models
dependency-cycle Lineage integrity ran 5 0 —
hardcoded-table-reference Lineage integrity ran 5 0 fct_hard_coded_references
model-untested Testing ran 5 0 fct_test_coverage (related)
model-grain-not-asserted Testing ran 5 0 fct_missing_primary_key_tests (narrower)
source-no-freshness Source monitoring not applicable 0 0 fct_sources_without_freshness the manifest declares no sources
duplicate-model-logic Maintainability ran 5 0 —
public-model-without-contract Modelling correctness not applicable 0 0 fct_public_models_without_contracts no model is declared access: public
model-possibly-unused Lineage integrity could not run 0 0 — the project declares no exposures, metrics or semantic models, so there is no way to tell a used leaf model from an abandoned one
model-undocumented Documentation ran 5 3 fct_undocumented_models; fct_undocumented_public_models (broader)
model-columns-undocumented Documentation ran 5 3 —
model-no-column-schema Documentation ran 5 0 —
source-undocumented Documentation not applicable 0 0 fct_undocumented_source_tables the manifest declares no sources
source-parent-undocumented Documentation not applicable 0 0 fct_undocumented_sources the manifest declares no sources
duplicate-source Modelling correctness could not run 0 0 fct_duplicate_sources the manifest declares no sources
source-freshness-no-timestamp Source monitoring not applicable 0 0 — no source has a freshness threshold to evaluate
model-no-not-null-test Testing ran 5 0 fct_missing_primary_key_tests (narrower)
select-star Maintainability ran 5 0 —
high-cte-count Maintainability ran 5 0 —
layer-naming-mismatch Maintainability ran 3 0 fct_model_naming_conventions (related)
test-not-beside-model Maintainability ran 20 0 fct_test_directories (narrower)
deep-lineage Lineage integrity ran 5 0 fct_chained_views_dependencies (related)
fan-out-hotspot Lineage integrity ran 5 0 fct_model_fanout (related)
staging-depends-on-staging Modelling correctness ran 3 0 fct_staging_dependent_on_staging
staging-depends-on-downstream Modelling correctness ran 3 0 fct_staging_dependent_on_marts_or_intermediate
downstream-depends-on-source Modelling correctness not applicable 0 0 fct_marts_or_intermediate_dependent_on_source the project declares no intermediate or marts models
direct-join-to-source Modelling correctness not applicable 0 0 fct_direct_join_to_source the manifest declares no sources
root-model Lineage integrity ran 5 0 fct_root_models
source-fanout Modelling correctness not applicable 0 0 fct_source_fanout (broader) the manifest declares no sources
multiple-sources-joined Modelling correctness not applicable 0 0 fct_multiple_sources_joined the manifest declares no sources
rejoining-upstream-concept Modelling correctness ran 5 0 fct_rejoining_of_upstream_concepts
exposure-parent-not-materialized Modelling correctness not applicable 0 0 fct_exposure_parents_materializations the project declares no exposures
exposure-on-private-model Modelling correctness not applicable 0 0 fct_exposures_dependent_on_private_models the project declares no exposures
model-unowned Ownership & accountability could not run 0 0 — this project declares no dbt groups: and no ownership-shaped meta key, so there is no convention to measure its models against — ownership held outside dbt (CODEOWNERS, a rota, a wiki) is not visible in a manifest
source-unowned Ownership & accountability not applicable 0 0 — the project declares no sources
group-owner-unreachable Ownership & accountability not applicable 0 0 — the project declares no groups
exposure-owner-unreachable Ownership & accountability not applicable 0 0 — the project declares no exposures
semantic-column-not-built BI semantic layer not applicable 0 0 — the project declares no semantic models — whether it should have is a choice, not a finding
semantic-primary-entity-unasserted BI semantic layer not applicable 0 0 — the project declares no semantic models — whether it should have is a choice, not a finding
metric-undocumented Documentation not applicable 0 0 — the project declares no metrics — whether it should is a choice, not a finding
repo-committed-credential-file Repository hygiene ran 1 0 —
repo-no-ci Repository hygiene ran 1 0 CI-Tests (related)
repo-archived Repository hygiene ran 1 0 Maintained (related)
repo-no-tests Repository hygiene ran 1 0 —
repo-no-readme Repository hygiene ran 1 0 —
repo-no-codeowners Repository hygiene ran 1 0 —
repo-unlicensed Repository hygiene ran 1 0 License (narrower)
repo-stale Repository hygiene ran 1 0 Maintained (related)
dbt-packages-unlocked Repository hygiene not applicable 0 0 — the project declares no dbt packages, so there is nothing to lock
dbt-no-require-version Repository hygiene ran 1 0 —
ai-dependency-unpinned AI lifecycle not applicable 0 0 — no recognised AI or ML library is declared in the manifests collected
ai-training-without-tracking AI lifecycle not applicable 0 0 — the manifests collected declare no training library, so this does not apply
ai-llm-without-evaluation AI lifecycle not applicable 0 0 — the manifests collected declare no model SDK, so this does not apply
ai-llm-without-observability AI lifecycle not applicable 0 0 — the manifests collected declare no model SDK, so this does not apply
ai-notebook-outputs-committed AI lifecycle not applicable 0 0 — the repository contains no notebooks
orchestration-undeclared Orchestration & reliability ran 1 1 —
model-date-ambiguous Documentation not applicable 0 0 — no model feeds a declared consumer and none sits in a marts directory, so there is no set of core models to hold to a higher bar
core-model-columns-undocumented Documentation not applicable 0 0 — no model feeds a declared consumer and none sits in a marts directory, so there is no set of core models to hold to a higher bar
core-model-grain-undeclared Modelling correctness not applicable 0 0 fct_missing_primary_key_tests (narrower) no model feeds a declared consumer and none sits in a marts directory, so there is no set of core models to hold to a higher bar

Where these checks come from

  • dbt_project_evaluator (dbt Labs) — 13 of its 29 rules were answered by checks in this review. A further 12 have checks that could not run on the artefacts supplied — see the coverage table for which, and why. https://dbt-labs.github.io/dbt-project-evaluator/
  • OpenSSF Scorecard (Open Source Security Foundation) — 3 of its 5 rules were answered by checks in this review. https://scorecard.dev/

The 6 rules not checked, and why

Listed rather than left out. Each is a position you can disagree with, not a gap being glossed over.

Rule Not checked because Reasoning
fct_too_many_joins it needs evidence this review does not collect dbt applies its join threshold to COMPILED SQL. This review holds each model's raw code with its Jinja unrendered, so a join count taken from it would be wrong wherever a macro expands to a join — and picking our own threshold to compare it against would be an invented bar wearing somebody else's citation.
fct_documentation_coverage it is a project-wide measure, not an assignable defect A project-wide documentation percentage has no entity to attach to and nobody to assign. The underlying defect is reported per model by model-undocumented and model-columns-undocumented, which name which models and can be worked through.
fct_source_directories checking it would impose a layout you did not choose The rule requires each source to be defined in a staging subdirectory named after it. That is dbt Labs' preferred layout, not a correctness property, and a project keeping one sources.yml per staging folder is not wrong. Unlike layer naming and test placement — both of which this review measures before enforcing — a project with a handful of sources gives too weak a signal to tell a deliberate layout from an inconsistent one.
fct_model_directories checking it would impose a layout you did not choose Same ground as fct_source_directories: it requires staging models to sit in folders named after their source. layer-naming-mismatch covers the part of this that can be self-calibrated — whether a project applies its OWN naming convention consistently — without asserting which convention it should have chosen.
Code-Review it needs evidence this review does not collect Scoring it needs the pull-request approval history. This review requests a read-only metadata token and collects the repository tree, languages and contributor count — deliberately not the review history, which is a wider grant than a technical review needs.
Dangerous-Workflow it needs evidence this review does not collect It requires reading the CONTENTS of CI workflow files. This review reads file contents only for named dbt configuration files and never for anything else, which is the constraint that lets it promise a client's source is never fetched. repo-no-ci reports whether CI exists, from the file listing alone.

17 checks here correspond to a rule published by somebody else. Each is named in the table above, so you can look it up and disagree with the criterion rather than with us. The other 12 have no published counterpart. They cover how the last run went, whether the warehouse matches what the project declares, whether the build is reproducible, and who is accountable for each asset.

Correspondence, not conformance. Citing a rule does not make its publisher a party to this review, and nothing here is a certification against any standard.

Ask about a review of your platform