Docs & Code Guide

Documentation freshness metrics: what to measure from git and wiki APIs, and which numbers predict rot

Freshness is the measurable side of documentation health: how old a page is, how recently a human vouched for it, and how its edit rate compares to the system it describes. Five numbers cover it, all pullable from git or a wiki API in an afternoon. Only some of them predict rot, so it is worth knowing which before you build the dashboard.

8 min readFor platform and docs leads building a freshness dashboard

See it as a diagram

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

235/20003 credits left
Try:

No account needed · Editable canvas, not a picture

The five metrics worth collecting

Age since last edit: days since anyone changed the page. Age since last review: days since a human explicitly attested the page is accurate, which is a different event, because a typo fix resets the first clock without touching the second. Edit-to-code-change ratio: over a window, edits to a doc divided by commits to the code it describes. View-to-edit ratio: how many reads the page gets per edit it receives, separating load-bearing pages from write-only ones. Broken internal link count: links on the page pointing at moved or deleted targets.

Everything else commonly proposed, word counts, page counts, contributor counts, measures volume, not freshness. Volume grows while a wiki rots.

Last edit and last review are different clocks

The edit date is free: git and every wiki record it. The review date has to be created deliberately, because no system can infer that a human read the page and confirmed it against reality. In a repo, the convention is a last_reviewed field in front matter, updated only when someone actually verifies content. In Confluence, a page property or label serves the same role; in Notion, a dedicated date property on the database entry.

The distinction matters because the edit date lies in both directions. A page edited yesterday can be wrong, the edit was a formatting pass. A page untouched for two years can be right, the system it describes has not changed. The review date is the only one that means what readers hope the edit date means.

Pulling the numbers from git

For repo-hosted docs, git log answers everything about edits. The per-file last edit is one command; the edit ratio is two counts over the same window; the stale list is a loop sorted by date. The broken link count comes from a link checker run rather than git itself, lychee or markdown-link-check in a scheduled job, counting failures on internal targets.

# Age since last edit for one page
git log -1 --format='%cs %h' -- docs/architecture.md

# Docs-to-code edit ratio over the last 90 days
docs=$(git log --since='90 days ago' --oneline -- docs/ | wc -l)
code=$(git log --since='90 days ago' --oneline -- services/ | wc -l)
echo "docs:$docs code:$code"

# Every doc not edited in a year, oldest first
git ls-files docs/ | while read -r f; do
  echo "$(git log -1 --format=%cs -- "$f") $f"
done | sort | awk -v cutoff="$(date -d '1 year ago' +%F)" '$1 < cutoff'

Pulling the numbers from Confluence and Notion

Confluence Cloud exposes the edit clock through its v2 REST API: GET /wiki/api/v2/pages/{id} returns the current version with its createdAt timestamp, and the versions endpoint gives the full edit history for computing edit frequency. View counts come from the analytics REST API on Confluence plans that include analytics, which is what makes the view-to-edit ratio computable there.

Notion returns last_edited_time on every page object retrieved through its API, so a script paginating a wiki database can build the full age distribution. What Notion's public API does not expose is view counts, so the view-to-edit ratio has to come from the in-product analytics rather than a script. Review dates exist in neither API by default; both need the explicit property convention from the previous section.

Which numbers actually predict rot

Review age and the edit-to-code-change ratio are the predictive pair. A page describing a service that took forty commits this quarter while the page took none is diverging almost by definition. Raw edit age alone is weak, because stable systems produce old-and-correct pages, and flagging those trains people to ignore the dashboard. Broken internal links are a lagging indicator but a strong one: they mean the pages around this one moved on and nobody maintaining this page noticed.

One scope note keeps the dashboard honest: freshness measures age and attention, not truth. Whether the content still matches the system is a different question with different measurements, covered in documentation drift metrics. A freshly reviewed page can still be wrong; freshness just makes it much less likely.

From metrics to consequences

Numbers without thresholds decorate. The thresholds belong in a freshness policy, 90-day review for critical pages is a common anchor, and the enforcement belongs in a documentation SLA with a named owner per page. For architecture diagrams specifically, the cheapest way to keep the freshness numbers green is to make the update itself small: a diagram embedded by URL propagates an edit to every page showing it within minutes, and an agent connected to Datadef's MCP server can redraw it from the repo on request. Datadef does not watch the repo or detect changes itself; the metrics above are what tell you it is time to invoke it.

FAQ

What are documentation freshness metrics?

Measurable signals of how current documentation is: age since last edit, age since last review by a human, the ratio of doc edits to code changes over a window, the ratio of views to edits, and the count of broken internal links. They measure age and attention rather than accuracy, which is the separate concern of drift metrics.

How do I measure documentation freshness in git?

git log -1 --format=%cs -- path gives the last edit date per file, and comparing commit counts on docs paths versus code paths over the same window gives the edit-to-code-change ratio. A loop over git ls-files sorted by last edit date produces the stale list. Review dates need a front matter convention such as last_reviewed, since git only records edits.

What is the difference between documentation freshness and documentation drift?

Freshness is about age and attention: when the page was last edited and last reviewed. Drift is about divergence: whether the content still matches the system it describes. A page can be fresh and wrong, or old and correct. Freshness metrics are cheap and predictive; drift has to be checked against the source, by comparing documented components to actual ones.

What is a reasonable freshness target for documentation?

A common shape: pages marked critical reviewed every 90 days, standard pages every 6 to 12 months, and anything unreviewed past its window flagged on the page itself. Targets on the edit date alone tend to misfire, because stable systems legitimately produce old pages; target the review date instead.

Can I get last-updated dates out of Confluence and Notion programmatically?

Yes. Confluence Cloud returns the current version and its createdAt timestamp from GET /wiki/api/v2/pages/{id}, with full history on the versions endpoint. Notion returns last_edited_time on every page object in its API. Neither exposes a review date natively, and Notion's public API does not expose view counts, so those need a property convention and in-product analytics respectively.