Skip to content

Keeping Documentation Up to Date

Code often changes first, and the documentation lags behind. The next coding agent reads the document anyway and works from a description the code no longer matches.

I have caught the more dangerous version during PR review. A feature introduces a framework or changes a design boundary, but the PR presents the choice as implementation detail. The team never accepted the decision, and no ADR or design document records it. Later an agent finds both the old and new framework in the codebase and uses both. From the agent's view, both are established patterns.

The smaller cases are merely annoying. I have seen an outdated instruction make the agent build and test the entire codebase after a Markdown or configuration edit. You notice because you sit there waiting for work nobody wants. An undocumented framework decision is harder to catch. By the time it surfaces, the wrong choice looks like an ordinary part of the implementation.

Tests fail when they stop matching the code. Prose usually does not, and an absent decision has no file to become stale. This chapter addresses the part a deterministic check reaches. The missing-decision problem still depends on review and team discipline.

This chapter covers one narrow extension of verification: give important documentation a feedback loop. Not semantic understanding. Not model grading prose. A tripwire that turns silent drift into a visible signal.

A release should leave the codebase ready for the next agent session. This chapter covers the cheap part of that work. It does not decide whether the architecture overview is correct. It tells you which documents became suspect after the source moved.

Sources: AgentPatterns.ai, "Evaluating AGENTS.md: When Context Files Hurt More Than Help" (last reviewed June 13, 2026), stale instruction files and context drift as current agent failure modes. The release-to-next-session boundary is this book's synthesis.

The asymmetry

Tests already have the property documentation lacks. When the code changes and the test no longer matches, the suite fails. The failure is noisy. Somebody has to deal with it.

Documentation has no equivalent check by default. A design note describing an old retry policy does not fail. An agent instruction file pointing at a renamed file passes every check unless a structural link validator catches it, and a README documenting last month's module boundary still renders cleanly on GitHub.

Generated code changes fast. The surrounding prose drifts at human speed, without producing an error.

The failure is not only reader confusion. The next agent session starts from false inputs. A stale architecture note makes the agent add a layer the system no longer uses or follow a codebase rule the team already removed because the instruction file still lists it.

This is cognitive debt in its narrowest form: one stale document feeding directly into the next implementation session.

Sources: ThoughtWorks, Technology Radar Vol 34 (April 2026), cognitive debt as undocumented or stale reasoning in agentic delivery. AgentPatterns.ai, "Evaluating AGENTS.md: When Context Files Hurt More Than Help" (last reviewed June 13, 2026), stale instruction files and context drift as a practical agent failure mode.

The verification move is familiar by now. Do not match text. Match identity.

AC IDs and Coverage made tests durable by linking each acceptance scenario to a stable Acceptance Criterion ID (AC ID). The scenario text gets rewritten, and the test moves files, but the ID remains stable, so the link between intent and evidence remains intact.

Documentation needs a lighter version of the same move. Each important document carries a small frontmatter block naming the code paths the check watches, the date somebody last checked it against those paths, and any outside systems still pointing at it:

yaml
---
tracked-paths:
  - services/payments/src
  - services/payments/build.gradle.kts
content-verified-at: 2026-06-25
referred-by:
  - system: jira
    id: PAY-1842
    url: https://jira.example.com/browse/PAY-1842
    reason: Implementation ticket links to this design doc
  - system: confluence
    id: ARCH-221
    url: https://confluence.example.com/x/ARCH-221
    reason: Architecture index links here
referrers-verified-at: 2026-06-20
---
  • tracked-paths lists the repo paths whose changes might invalidate the document.
  • content-verified-at records the last date somebody checked the document against those paths.
  • referred-by lists outside records still pointing at the document.
  • referrers-verified-at records the last date somebody checked those external referrers still needed the document.

Once the fields exist, the check stops guessing. The questions are mechanical: did one of the tracked paths change after content-verified-at, and does an outside system still depend on this file staying where the referrer expects after referrers-verified-at?

This is not a field standard. I use it here as a working synthesis of the AC-ID idea for prose: one stable marker in the prose, one reference target in code or docs, and one check that verifies the link.

Sources: The frontmatter marker and field names are this book's synthesis from AC-ID verification logic applied to prose.

What the check looks for

The minimum useful validator is content-blind and deterministic. Content-blindness is what keeps it cheap enough to run on every change.

First, verify the reference itself. Every entry in tracked-paths must resolve. A document pointing at code no longer present is already wrong in one concrete way.

Second, compare the review date to the source history. If the latest commit touching one of those paths is newer than content-verified-at, the document is now suspect. The check does not claim the prose is false, only that nobody has confirmed it since the source changed.

Three states are enough for the repo-local documentation drift check:

  • broken-ref: a declared source path no longer resolves
  • stale: a tracked path changed after content-verified-at
  • untracked: a handwritten document has no marker yet

broken-ref should fail the build. stale is better as a warning at first, then a build failure later if the team wants a ratchet. untracked stays warn-only so adoption does not turn into a migration project before the first signal appears.

The useful twist is diff scoping. Checking only documents changed in the Pull Request (PR) fails the moment somebody forgets the doc update. The validator should also pull in tracked documents whose tracked-paths entries intersect the code changed by the PR.

Sources: The tracked-paths, content-verified-at, state names, fail/warn policy, and diff-scoping rule are this book's synthesis from AC-ID verification logic applied to prose.

External referrers change the retention rule

Documents under docs/ have a second failure mode. The file is still linked from Jira, Confluence, an internal wiki, or some other system outside the repo. Delete the document, rename it, or move it without updating those links, and the codebase stays green while the next developer lands on a dead reference.

This check differs from local drift. tracked-paths asks whether the document still matches the code. referred-by asks whether some outside system still depends on the document existing at this path.

The base pattern here is an inventory. The checker does not crawl for backlinks or discover them on its own. It validates a declared list of known referrers:

  • system: where the reference lives, for example jira or confluence
  • id: the stable identifier in the external system
  • url: the direct link
  • reason: why the external record points at this document

This book uses two extra states for the inventory:

  • unknown-ref: a referred-by entry is malformed or incomplete
  • live-ref: one or more referred-by entries still exist, so deletion or rename is blocked until those entries are cleared

unknown-ref should fail because the inventory is already broken. live-ref is not a failure on an ordinary edit. It becomes a failure when a PR deletes or renames the document while external referrers still exist.

The retention rule follows from the inventory. A file in docs/ with live referred-by entries stays put until the team removes or updates those external links and then clears the inventory entry in the same change. Local docs drift silently. Dead backlinks drift silently too, and they break a different reader.

Sources: The referred-by inventory and retention rule are this book's synthesis for repository documents with declared external backlinks.

Runbooks under test

Some documents are operational dependencies, not background reading. A deployment runbook, an incident checklist, a rollback guide, or a release README tells the operator what to type. If the rollback command is missing, the document is wrong.

This book recommends one narrow extension: test the required facts directly. Not the writing, not completeness, only the details an operator needs in front of them.

java
@Test
void runbookListsRollbackCommand() {
    assertTrue(readme.contains("kubectl rollout undo"));
}

@Test
void runbookExplainsWhereToFindFailureLogs() {
    assertTrue(readme.contains("kubectl logs"));
}

The same pattern works for a release runbook that must name the rollback command, the artifact location, and the first log command. Test those three facts directly. If one disappears in an edit, the suite fails before the next release leaves someone guessing in a live incident.

This is weaker than a behavior test. The test does not verify the command still works. It verifies the document still names the command. For operational prose, that already moves far beyond silence.

Testing runbook content like this is a narrow extension this book recommends. It is not presented here as common industry policy.

Three layers again

This book reuses the pattern from Skills, Commands, and Hooks here.

Layer one is the instruction. Tell the agent which documents need markers, what the marker means, and what to do when a code change trips a stale warning.

Layer two is the on-demand check. A skill or script the agent runs mid-task gives fast feedback before the change reaches Continuous Integration (CI).

Layer three is the build gate. The CI job checks tracked documents on every Pull Request and blocks on hard failures such as broken references. The same gate blocks a delete or rename when a docs/ file still has live referred-by entries. Put this in CI because delete-and-fix-later nearly always turns into delete-and-never-fix.

Nothing here depends on one tool. The practice is broader: one rule the agent reads, one fast self-check, one hard backstop independent of memory. A deterministic checker reaches this much. The rest still needs review.

Sources: The three-layer placement is this book's synthesis from the instruction, command, and hook pattern applied to documentation drift.

Why this belongs in verification

This is not a general documentation chapter in disguise. The scope is narrower: keep the files agents load aligned with the code agents are changing.

Docs > Specs > Code argued for design intent above code because this book treats generated code as the more disposable artifact. Once you accept that order, stale documents stop being a writing problem. They become a quality problem.

Verification closes the code gap with tests. A documentation drift check closes part of the prose gap. Both follow the same control pattern:

  • attach a stable link to the artifact under review
  • run a deterministic check against the link
  • expose failure where the team already pays attention, in CI

The check does less than a test. A test verifies behavior. A documentation drift check only verifies nobody reviewed the prose after the source moved, or that an outside record still depends on the file staying put. That weaker claim still earns its keep because the default is silence.

Limits worth naming

The signal is blunt. A commit touching a tracked directory marks the document stale even when the change was a rename, a comment edit, or an internal helper the document never mentioned.

The dates are bookkeeping markers, not evidence of careful reading. Bumping content-verified-at or referrers-verified-at silences the warning.

Cross-cutting documents are awkward. A design note covering four subsystems and two team boundaries has no tidy sibling path list. Those documents need manual tracked-paths entries, and many teams will defer the work.

The external inventory is only as good as the discipline behind it. A missing referred-by entry means the checker never knows the outside link exists. As of mid-2026, teams with Model Context Protocol (MCP) connectors into Jira or Confluence might confirm some records through APIs, but API confirmation is a higher-maturity extension and a perishable one. I would not make the basic control depend on a connector. Connectors to ticket and wiki systems still add latency and another unstable network boundary to a check that should be fast.

These limits are why I still regard documentation freshness as one of the largest unresolved parts of the practice. The control is a tripwire, not semantic verification. It points at prose somebody needs to inspect. It cannot tell whether an important design change is missing. It will also accept a new date from somebody who never read the file.

The before-gate in Before, During, After Checkpoints asks whether architecture and instructions are still current. This chapter adds a tripwire for part of that question.

Sources: Model Context Protocol documentation, connector pattern for reaching external systems during agent work. Atlassian Rovo MCP Server and sooperset mcp-atlassian documentation (mid-2026 snapshot), Jira and Confluence connector availability as a perishable tooling example. This chapter's extension of AC-ID verification logic from tests to prose is this book's synthesis.