Docs & Code Guide

Documentation drift metrics: measure divergence from reality, not age, with scriptable checks

Drift metrics measure divergence: whether what a document says still matches what the system is. That is a different axis from freshness, which measures when the document was last touched, and the two disagree in both directions: a two-year-old page about a stable system can be perfectly accurate, and a page edited yesterday can still describe a service renamed last quarter. Three divergence signals are scriptable today: identifiers in docs that no longer exist in code, deep links that no longer resolve, and counts that must match between the system and its documentation.

7 min readFor platform engineers who want drift on a dashboard

See it as a diagram

Everything below, as a diagram you can edit. Describe yours and see it in seconds.

144/20003 credits left
Try:

No account needed · Editable canvas, not a picture

Drift is divergence, not age

The boundary with freshness matters because the two metrics answer different questions and trigger different actions. Freshness, covered in documentation freshness metrics, asks when was this touched and is computed from timestamps alone; it is cheap, continuous, and blind to content. Drift asks is this still true and requires comparing the document against the system it describes; it is more expensive per check and it is the metric readers actually feel. A freshness dashboard flags suspects; drift checks convict.

The concept itself, why divergence accumulates and what it does to a team, belongs to the anchor guide on documentation drift. This page is the measurement layer: signals you can script and put on a dashboard.

Check 1: names in docs that no longer exist in code

The strongest cheap signal is a dangling identifier: a service, table, topic, or config key that the docs mention and the codebase no longer contains. Renames and removals leave these behind reliably, and each one is a concrete lie a reader can hit. The check is grep-shaped: harvest code-formatted terms from the docs, then ask git grep whether each still exists in the source tree.

Expect noise on the first run, prose words caught in backticks, vendored names, and tune with an allowlist. The count matters less than the trend: dangling identifiers per 100 pages, week over week, is a drift rate.

# Dangling identifiers: mentioned in docs, absent from the codebase.
# Harvest backticked terms from docs, check each against git grep.
grep -rhoE '`[A-Za-z][A-Za-z0-9_.-]{2,}`' docs/ \
  | tr -d '`' | sort -u \
  | while read -r name; do
      git grep -q --fixed-strings "$name" -- src/ services/ infra/ \
        || echo "dangling: $name"
    done

Check 3: counts that must match

Some documentation makes countable claims, and counts can be compared mechanically. The classic data-team case: the orders table has 31 columns in information_schema and 24 rows in its data dictionary page, so seven columns are undocumented and the dictionary has drifted. The same pattern applies to services in the catalog versus services with an architecture page, endpoints in the OpenAPI spec versus endpoints in the reference, and queues in infra code versus queues on the platform diagram.

Count mismatches are the gentlest drift metric to socialize because they carry no blame, only a number and a diff, and they decompose directly into a to-do list.

-- Columns the schema has vs rows the data dictionary documents
SELECT COUNT(*) AS actual_columns
FROM information_schema.columns
WHERE table_schema = 'analytics'
  AND table_name = 'orders';
-- Compare with the documented-column count for the same table;
-- a mismatch is a drift item with a ready-made worklist.

Diagrams drift too, and the check differs

A diagram's drift check is a set comparison: nodes depicted versus services deployed, edges drawn versus dependencies in the infra code. Scripting that comparison against a hand-drawn image is impractical, which is why diagram drift is usually caught by a human squinting, late. The techniques that do exist are collected in how to detect stale diagrams.

The structural alternative is making the comparison the update: an agent connected to the Datadef MCP server reads the repository and redraws the diagram to match, so depicted-versus-deployed converges every time the loop runs, one command after a merge or in CI, never by automatic repo watching. For diagrams, regeneration is the drift metric that fixes what it measures.

Whichever checks you adopt, report them next to freshness as one score, the shape described in how to measure documentation health: freshness flags the suspects cheaply, drift checks convict precisely.

Three numbers for the dashboard

Dangling identifiers per 100 pages, dead deep links per page, and open count mismatches. Trend them weekly; the trend is the drift rate.

FAQ

What are documentation drift metrics?

Measures of divergence between documentation and the system it describes, as opposed to freshness metrics, which only measure when a page was last touched. The three most scriptable drift signals: identifiers mentioned in docs that no longer exist in the codebase (checkable with grep against the source tree), deep links that no longer resolve (checkable with a link checker like lychee), and counts that must match, such as schema columns versus data dictionary rows.

What is the difference between drift and freshness in documentation?

Freshness is about time, drift is about truth. Freshness reads timestamps, git commit dates or wiki last-edited fields, and is cheap and continuous but blind to content: an edit yesterday can leave a page describing a service renamed last quarter. Drift compares content against reality and catches that lie, at higher cost per check. A healthy setup uses freshness to flag suspects and drift checks to confirm.

How do you detect documentation drift automatically?

Script the divergence signals: harvest code-formatted terms from the docs and git grep each against the source tree to find dangling identifiers, run a link checker such as lychee over the docs tree in CI to find dead deep links, and compare countable claims mechanically, for example information_schema column counts against data dictionary rows. Each check emits a number that can sit on a dashboard and trend weekly.

Can documentation drift be measured for diagrams?

Partially. The check is a set comparison, nodes depicted versus services deployed, but scripting it against a hand-drawn image is impractical, so diagram drift usually surfaces through human review. The structural fix is regeneration: a diagram redrawn from the repository by an MCP-connected agent converges on reality every time the loop runs, making the drift check and the update the same operation.

What is an acceptable level of documentation drift?

Zero dangling identifiers and dead links in runbooks and onboarding paths, because those are read under pressure or by people who cannot detect lies. Elsewhere, judge the trend rather than the absolute: a backlog being worked down is healthy, a rising count of dangling identifiers per 100 pages is the early warning. Gate CI on new breakage only, so the historical backlog does not block shipping.