River
Y CombinatorBacked by Y Combinator
FREE TEMPLATE

Data Dictionary and Metric Catalogue

A field register that counts coverage against every column in your warehouse, plus the metric register and ambiguity log that settle a contested number.

Free download  ·  No account needed

Field Register

One row per column that exists, not one row per column somebody chose

The denominator is read out of the warehouse. A column added on Tuesday is an undefined row on Tuesday, and coverage can fall without anybody deleting anything.

The columns every dictionary has

Table, column, data type transcribed verbatim from the engine, owner, consumers, grain. Nothing controversial, and nothing here decides whether the row is worth anything.

Definition, and then Definition Class

The prose, and then the verdict on the prose. Meaning, Restates Name, Storage Only, Contradicted, Empty. The test is mechanical rather than editorial: could this have been written without opening a query. Only Meaning counts toward real coverage.

Warehouse Comment, verbatim

What the database actually holds for that column, right now, including empty. A definition written in a transformation project does not reach the warehouse unless somebody turned persistence on for that resource, so the analyst reading the column in a console sees a different thing than the sheet does. Comment State reconciles them as Matches, Stale, or Absent, and stale is the worse one.

Reads, First Seen, Undefined Days

Read count over ninety days, the date the column first appeared, and the gap between that date and the day a real definition landed. Sort by reads descending, filter to class not Meaning, and the work queue is the first forty rows. This is the section that turns a thirteen-hundred-row backlog into an afternoon.

Notes

Where the definition came from, which model populates the column, and what would settle it if nothing does. An orphan row keeps its prose here rather than being deleted, because most orphans are renames and the definition usually still holds.

Every data dictionary reports its coverage against its own row count, which is why they all improve and none of them settle an argument. Somebody chooses the fields, writes definitions for most of them, and quotes the ratio. The warehouse has the real denominator and gives it up in one query: BigQuery's column metadata view lists every column with its type, nullability, partitioning and default, and not one of its twenty-odd fields is a description. The count is free. The definitions are the job.

So the Field Register is populated from the engine, and a second column carries the verdict on each definition rather than only the prose. The test is mechanical: could this have been written without opening a query. A column named shipment_created_at, documented as the date and time the shipment was created fails it, and that row is the commonest one in any dictionary you inherit. Canonical definitions and the comment the database actually holds sit in separate columns, because persisting descriptions into the warehouse is off by default.

Latimer Freight, a fictional brokerage, ran it across 1,412 columns. Raw coverage 34.4 percent, meaning-class 15.0 percent, and 9.3 percent once weighted by a year of column-level read history. Three of the fifty most-read columns had a real definition. The same register priced on_time_rate, live four ways, at 94.1 down to 88.5 percent against a 92 percent contract. It sits beside the pipeline contract that documents how those numbers are produced, and pushing one into a CRM raises a separate question, covered by reverse ETL overwrite rules.

Coverage of 34.4 percent, or 9.3 percent, from one register

The Field Register's coverage arithmetic, the Ambiguity Log, and the new-column sweep.

Coverage, three ways

Latimer Freight, a fictional freight brokerage. 108 tables and views, 1,412 columns, and an inherited dictionary that reported 95 percent.

FractionNumeratorDenominatorResult
The contractor's sheet486 described rows512 rows in the sheet94.9%
Raw coverage486 with any description1,412 columns in the warehouse34.4%
Meaning-class coverage212 that survive the test1,412 columns in the warehouse15.0%
Read-weighted coverage296,524 reads on a defined column3,184,000 column reads, 90 days9.3%
Definition ClassColumnsWhy it does not count
Meaning212It counts. Says what the value represents, what sets it, what it excludes, and at which grain.
Restates Name189Content words already in the column name. shipment_created_at as "the date and time the shipment was created."
Storage Only71Transcribed from the schema. The data type column already carries it.
Contradicted14A real business sentence the code disagrees with. Reads as the best rows in the sheet.
Empty926No description at all.

The 25-point gap between raw and read-weighted is the finding. Warehouse reads are skewed hard: the 50 most-read columns carry 61 percent of all reads, and 3 of those 50 have a meaning-class definition. They are join keys, status enums, and timestamps whose names look self-explanatory, which is exactly why nobody wrote them down.

Twenty-six of the 512 rows describe a column that no longer exists. Renames from a migration eleven months ago. Measured against itself a dictionary always improves, and part of that improvement is prose about fields nobody can query.

Sort by reads descending, filter to class not Meaning, work down. Forty-seven rows moves the third number further than the last fourteen months moved the first.

on_time_rate, March 2026

Four live implementations of one metric name. 43,190 delivery events, 1,330 of them second attempts, 41,860 first attempts. The customer contract commits to 92 percent.

SurfaceClock stops atSecond attemptsCalculationRatevs 92%
Operations dashboardyard arrivalexcluded39,392 / 41,86094.1%clears
Customer SLA reportsignatureexcluded38,220 / 41,86091.3%misses
Carrier scorecardyard arrivalcounted39,392 / 43,19091.2%misses
Board packsignaturecounted38,220 / 43,19088.5%misses

One of the four clears the commitment. The spread is 5.6 points, and the one that clears is the one on the wall in the operations room. Two binary clauses, which event stops the clock and whether a second attempt is a separate event, with all four combinations live. Four queries is a mess. Two clauses is a decision.

The customer SLA report and the carrier scorecard land 0.1 points apart while disagreeing on both clauses. Anybody comparing those two dashboards would conclude the numbers reconcile. They coincide, for one month, and they separate as soon as the second-attempt rate moves. It is the whole argument for logging the clause rather than the difference.

The board pack calculation was adopted, and it is the lowest of the four. The note records that this was not the reason, which is what stops the choice being reopened as a presentational one six weeks later. Eleven metric names on this warehouse resolve to 27 distinct implementations.

A clause nobody can price is a clause nobody prioritises. Every row carries the number its implementation produces for one agreed period.

The sweep that keeps it alive

The same 90 days, run against the warehouse rather than against the sheet. A dictionary decays because its row list is fixed and the warehouse's is not.

What changedCountWhat happens to the row
New columns in the warehouse63Added as Empty, with First Seen. No definition written from the name.
New and already read by a dashboard9Live risk rather than backlog. Ranked first.
New and present in the old dictionary0Not an oversight. Its row list was fixed fourteen months ago.
Orphans, column gone26Kept. Check for a successor column and move the prose across before closing.
Type changed under an existing definition4Flagged where the definition mentions a range, a precision, or a unit.

Nine of the 63 are already feeding something. One of them, tender_rejection_reason, is 34 days old and sits behind two tiles on a carrier performance board. A column that is undefined and unread is a backlog item. A column that is undefined and already on a dashboard is a different thing.

Coverage going down is the correct behaviour. Sixty-three new columns and no new definitions moves all three numbers the wrong way, and a register that cannot do that is a register measuring itself. Say it out loud in the sweep so nobody reads it as a regression in the documentation.

Median age of the 1,200 columns with no meaning-class definition: 412 days. That single figure is the honest answer to whether the catalogue is being kept up, and it is the one to put in front of whoever asked for one.

Orphans are evidence, not waste. Somebody understood that field well enough to write about it, and most of the time the column was renamed rather than removed.

What's in the pack

01

Field Register

One row per column in the warehouse, carrying the canonical definition beside the comment the database actually holds.

02

Metric Definition Register

One row per metric name that reaches a surface, with its clock, its grain, and a count of live implementations.

03

Ambiguity Log

One row per implementation of a contested metric, each carrying the number it produces for one agreed reference period.

04

How Coverage Is Counted

The arithmetic: where the denominator comes from, the five definition classes, and why three coverage figures beat one.

05

Definition Standard

The four parts a field definition needs, the six a metric needs, and two before-and-after pairs.

06

Ownership Model

Why a field belongs to whoever controls the code that sets it, and a metric to whoever answers for it.

07

Worked Dictionary

A brokerage warehouse classified end to end, including the fourteen definitions its own models contradicted.

08

Ambiguity Resolution Note

The one-page note that settles a contested metric, and the line recording why the lowest number won.

How to use it

  1. 1

    Open in River, or take it blank

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

  2. 2

    Set the scope and the owners

    Which layer counts as the denominator, who owns a field definition, who owns a metric, and what the default owner is for columns nobody claims.

  3. 3

    Send whatever you have

    A schema dump, an information-schema query result, a transformation project and its YAML, a BI export, or the spreadsheet a contractor left behind.

  4. 4

    Read the three numbers, then the top fifty

    The gap between raw and read-weighted coverage is the finding. The undefined columns inside the most-read fifty are the queue, and the sweep keeps adding to it.

Frequently asked questions

Is this template free?

Yes, and the download needs no account, no card and no email address. Edit with AI is the optional half and the one that does the reading: it takes your warehouse metadata, classifies whatever definitions already exist, and reports all three coverage figures. The rest of the template library works the same way.

What format are the downloaded files?

A single zip holding five .docx documents and three .csv registers. Word, Pages, Google Docs, Excel, Numbers and Sheets each open them directly, with no importer and no conversion step. Each register keeps its worked rows, one per state that column exists to record.

Our catalogue tool already generates a dictionary. Why this?

A catalogue tool tells you a description exists. It cannot tell you the description restates the column name, that the code populating the column disagrees with it, or that the columns carrying most of your query volume are the undefined ones. Those are judgements about the prose, not inventory.

What is a definition class, and who decides it?

Nobody decides it by taste. Strip the description to its content words, compare them against the tokens in the column name, and if the first set sits inside the second the class is Restates Name. The other classes are Meaning, Storage Only, Contradicted and Empty.

Can it tell us which metric definition is the right one?

It computes what each live implementation produces for one period you agree on, and says which of them clear any threshold sitting inside that spread. Choosing is the metric owner's call, and the pack's resolution note is the shape that decision goes in. Whether the question needing that metric is answerable from the tables you have is a separate request specification.

Does it work if we do not use dbt or Snowflake?

Yes. Every engine exposes a metadata view listing its columns, and most expose read history under a different name. Send whatever schema and configuration files you have. Where the transformation code is undocumented, reading it out of the database comes first.

Our schema and query history cannot leave our network. Can we still use this?

Then run it inside a private AI workspace, where column names, table names and read history stay in your own tenancy. Nothing about the arithmetic changes, and any organisation carrying a governance restriction on warehouse metadata takes that route.

Find out what your coverage figure actually is

Start from the blank registers, or let River read your warehouse and report coverage three ways against a denominator nobody chose.

Edit with AI