Running it

Documentation that survives the person who wrote it

Most automation documentation rots because it describes state instead of decisions, and lives where no change ever forces anyone to open it. Both problems are fixable in an afternoon.

On this page
  1. The short answer
  2. Why documentation rots, mechanically
  3. The Three Shelves
  4. Decision records that name their own expiry
  5. The staleness gate
  6. Runbooks are written for 2am
  7. Where it lives, and the no-code problem
  8. The minimum set, and the section everyone leaves out
  9. What eighteen months does to a document
  10. The vocabulary, used precisely

The short answer

The short answer

Write down only what cannot be recovered from the system itself: the decisions, the exceptions, and the things you deliberately chose not to build. Generate everything else, because anything a script can produce will be wrong the moment a human types it by hand. Put the written part in the repository beside the thing it describes, give each document a list of the files it covers and a date it was last verified, and fail the build when a covered file changes and the date does not. Documentation does not survive because people are disciplined. It survives because something breaks when it goes stale.

  • 3 shelvesgenerated, derived and decided. Only the third is worth a human's writing time
  • covers + verified_onthe two front matter fields that turn staleness from a feeling into a failing build
  • Review triggerthe field missing from almost every decision record: the condition that should force a revisit
  • "HTTP Request 4"the cheapest documentation debt in any automation, and the easiest to never take on
  • The 2am testa runbook is written for someone with no context, one hand on a phone, and no time to read prose

This is the least glamorous part of running automation and the one that decides whether the system outlives its author. The good news is that it is mostly mechanical. Almost every documentation problem is either a placement problem or a class problem, and both have concrete fixes rather than a call for better habits.

Why documentation rots, mechanically

Documentation does not decay through neglect. It decays because of three structural properties, and each one is a property of where and what you wrote rather than of the person who wrote it. This matters most on long-running work such as business process automation, where the system outlives everyone who touched it.

  1. The cost is paid by the wrong person. Whoever changes the code pays the cost of updating the document, and whoever reads it six months later gets the benefit. Any system that separates cost from benefit degrades, so the fix is to make the cost land in the same commit as the change.
  2. It describes state rather than decisions. State changes constantly: node names, thresholds, endpoints, field lists. Decisions barely change at all. A document full of state has a half life measured in weeks, and every one of those facts is recoverable from the system anyway.
  3. It lives where no change forces you to open it. A wiki page is never in the path of a code change. Nothing about editing a workflow makes anyone visit it, so it drifts silently and is discovered wrong at the worst possible moment, usually by someone debugging at speed.
ArtifactWho reads it and whenRot rateWhere it belongsHow staleness gets caught
Node or step inventoryAnyone tracing a flow, weeklyVery highGenerated at build time from the workflow definitionIt cannot go stale, because it is regenerated
Environment and config referenceWhoever is deploying, monthlyVery highGenerated from the config schemaThe generator fails if a key has no description
Decision recordWhoever proposes to change the design, rarely but urgentlyLowRepository, beside the code it coversCovered file hash changes without verified_on moving
Exception policyException queue owner, weeklyMediumRepository, next to the rules it describesReview on the same cadence as the queue itself
RunbookOn-call at 2am, hopefully neverMediumRepository, linked directly from the alert payloadExecuted in a rehearsal at a stated cadence
What it does not handleAnyone proposing new scope, monthlyLowRepository, in the readme, near the topReviewed at every scope change
Six documentation artifacts, their real readers, and where each one has to live to stay true.

The Three Shelves

Sort every piece of documentation onto one of three shelves before writing a word. The shelf decides who writes it, how often it is refreshed, and whether a human should be touching it at all.

Framework

The Three Shelves

Sorted by one question: can this be recovered from the system itself, and at what cost?

01
Shelf one, Generated

Recoverable exactly, for free. Node lists, environment variables, tool signatures, API endpoints, schema fields, the current prompt text. Never write these by hand. Emit them at build time into a file marked do not edit, and make the build fail if a field lacks a description. Hand-written state is not documentation, it is a second copy of a number, and two copies of a number always disagree eventually.

02
Shelf two, Derived

Recoverable, but needing interpretation to be useful. Dependency maps, data flow diagrams, cost breakdowns per stage, the list of which automations write to which system. Regenerate on a schedule rather than on demand, and make the generator fail loudly when a source it depends on has moved instead of silently producing a smaller diagram.

03
Shelf three, Decided

Not recoverable at any price. Why this vendor, what you deliberately excluded, which exception you chose to leave manual, what a rule was protecting against, the failure that caused the retry count to be three. This is the shelf that pays for itself, it barely rots, and it is where every hour of writing effort should go.

04
The bin

Prose that is actually configuration: thresholds, retry counts, schedules, recipient lists, cutoff times. It looks like documentation and behaves like a bug, because the moment the config changes you have two versions of the truth. Move the value into the config file, reference the file, delete the sentence.

If a script can grep it out of the system, do not type it

This single rule removes most of the maintenance burden from an automation's documentation. The test is quick: could a short script produce this paragraph from the workflow definition, the config file or the code? If yes, write the script once instead of writing the paragraph every quarter. The script is also self-correcting, because when it breaks you find out immediately, whereas a stale paragraph waits patiently to mislead someone.

Decision records that name their own expiry

A decision record captures why, which is the one thing the system cannot tell you. The standard format is nearly right, and it is missing one field: the condition under which the decision should be revisited. Without it, every record is either defended forever or quietly ignored, and neither is a review.

A decision record with front matter and a review triggermarkdown
---
# front matter is what makes this document checkable by a machine
id: ADR-014
title: "Invoice PDFs are parsed with a layout model before any LLM call"
status: accepted            # proposed | accepted | superseded-by ADR-0xx
date: 2026-06-18
owner: "Priya Nadar"
covers:                     # paths whose change should force a re-read of this decision
  - src/ingest/parse_invoice.py
  - config/model_aliases.yaml
covers_hash: "sha256:9f2c...c41a"   # written by the staleness gate, never by hand
verified_on: 2026-08-12
max_age_days: 180
---

## Context
Suppliers send four input shapes: native PDFs, scans, photographs of printed
invoices, and emails with the figures in the body and no attachment at all.
Feeding raw text of a scanned two-column invoice to a model produced correct
figures attached to the wrong supplier, because reading order collapsed the
columns. The failure was silent: every field was plausible.

## Options considered
1. Model only, whole page as text. Cheapest, and the column failure is invisible.
2. Layout model first, then a model call per detected region. More moving parts.
3. Template rules per supplier. Accurate for the top twenty, unmaintainable at 400.

## Decision
Option 2. Layout extraction runs first and hands the model bounded regions with
coordinates. Region confidence below the threshold routes to the human queue
instead of being guessed.

## Consequences
Cost per document rises because of the extra stage. Latency rises by roughly a
second. Two-column and stamped invoices stop producing confident wrong answers,
which was the failure that mattered.

## Reversal cost
About two days. The model-only path still exists behind a flag. Nothing is
migrated or destroyed, so reverting loses no data.

## Review trigger
Revisit if any of these becomes true, and do not wait for the review date:
- a model we can use accepts page images directly with reliable region grounding
- scanned share of input drops below 10 percent for two consecutive quarters
- per-document cost of the layout stage exceeds the cost of the model call
  • Options considered must include the one you rejected, and why. The next person will propose exactly that option, and without the reason they will implement it and lose a week to the same problem.
  • Reversal cost is stated in time and data. Two days with nothing lost is a different decision from two weeks and a migration you cannot undo.
  • The review trigger is a condition, not a date. Dates get rescheduled. A condition such as scanned input dropping below a tenth of volume is something a dashboard can watch, so the document pages you instead of waiting to be read.
  • Record the failure, not just the choice. The sentence about columns collapsing and figures landing under the wrong supplier is worth more than the decision paragraph, because nobody could reconstruct it.
  • Supersede, do not edit. Write a new record and mark the old one superseded. Editing history destroys the only account of why the previous version made sense.

The staleness gate

This is the mechanism that makes the rest of it work. A document declares which files it covers. Continuous integration hashes those files. When the hash moves and the document's verified date does not, the build fails and names the document. It takes an afternoon to build and it converts documentation from a virtue into a constraint.

  1. Add front matter to the documents that matterone hour

    Not every document opts in. Start with decision records, exception policies and runbooks for tier critical automations. Each gets a covers list, a verified_on date, an owner and a max_age_days.

  2. Fail on dead references firstcheapest win

    Resolve every glob. A pattern matching nothing means the document points at a renamed or deleted file, the most common rot and the easiest to detect. Ship this check alone and you will find stale documents on day one.

  3. Hash the covered files and store the digestthe core of it

    Concatenate covered files in sorted order, hash them, keep the digest in front matter. The gate writes this value and a human never does, so there is exactly one way to acknowledge a change.

  4. Fail when the code moved and the document did notthe constraint

    A differing digest fails the build and prints the new one. The author re-reads, edits if needed, bumps verified_on and pastes the digest. Acknowledging that nothing changed is one line, which keeps compliance cheap.

  5. Add a shelf life sweepweekly job

    Anything older than its own max_age_days gets a ticket for its owner. This catches documents whose covered files never change while the reality around them does.

docs_gate.py, the whole gate in about forty linespython
#!/usr/bin/env python3
"""docs_gate.py -- run in CI. Fails when a document's covered code moved and
the document did not. Catches the two rots that matter: dead references and
silent drift."""
import glob, hashlib, pathlib, re, sys, datetime, yaml

FAILS = []
TODAY = datetime.date.today()

for doc in glob.glob("docs/**/*.md", recursive=True):
    text = pathlib.Path(doc).read_text(encoding="utf-8")
    m = re.match(r"^---\n(.*?)\n---\n", text, re.S)
    if not m:
        continue                       # not every doc opts in, and that is fine
    fm = yaml.safe_load(m.group(1)) or {}
    covers = fm.get("covers") or []
    if not covers:
        FAILS.append(f"{doc}: front matter present but covers is empty")
        continue

    # rot 1: the document points at something that no longer exists
    paths = []
    for pattern in covers:
        hits = sorted(glob.glob(pattern, recursive=True))
        if not hits:
            FAILS.append(f"{doc}: covers '{pattern}' matches nothing")
        paths += hits

    # rot 2: the covered code changed and nobody re-read the document
    h = hashlib.sha256()
    for p in paths:
        h.update(pathlib.Path(p).read_bytes())
    digest = "sha256:" + h.hexdigest()
    if fm.get("covers_hash") != digest:
        FAILS.append(f"{doc}: covered files changed. Re-read it, then bump "
                     f"verified_on and set covers_hash to {digest}")

    # rot 3: nobody has looked at it inside its own stated shelf life
    verified = fm.get("verified_on")
    max_age = int(fm.get("max_age_days", 365))
    if verified and (TODAY - verified).days > max_age:
        FAILS.append(f"{doc}: verified_on is {(TODAY - verified).days} days old, "
                     f"max_age_days is {max_age}")

for f in FAILS:
    print("STALE", f)
sys.exit(1 if FAILS else 0)
Scope the gate or people will route around it

A gate applied to every document in the repository turns every small change into a documentation chore, and within a month somebody adds a skip flag that becomes permanent. Apply it only to documents that opted in with front matter, and only to the automations you have tiered as critical. A gate covering six documents that nobody bypasses is worth more than a gate covering sixty that everyone does. The same logic applies to prompts, which are code and deserve the same treatment, as covered in prompts as code.

Runbooks are written for 2am

A runbook is a different genre from documentation and should not be written by the same instinct. Its reader has been woken up, has no context loaded, is possibly reading on a phone, and needs to act rather than understand. Everything explanatory belongs somewhere else, linked, and the link should not be needed.

  • Open with how to tell whether this is the right runbook. One symptom list. The reader arrived from an alert and needs three seconds to confirm they are in the right document.
  • One action per line, in the imperative. No paragraphs. No background. If a step needs justification, the justification is a decision record and it can wait until morning.
  • Exact commands, exact URLs, exact button labels. Not "go to the admin panel". A tired reader cannot search a menu tree, and a phone screen makes it worse.
  • State the expected output of each step. Without it the reader cannot tell success from a silent failure, and will happily continue past the step that did not work.
  • Give every step a branch for failure. The sentence "if that returns nothing, go to step 7" is the difference between a runbook and a wish.
  • Close with how to confirm it is fixed, and what to write down. The incident note is what turns tonight's outage into tomorrow's decision record.

Then test it the only way that works. Hand the runbook to someone who has never touched the system, ask them to execute it against a staging copy, and time them without helping. Every place they hesitate is a defect. A runbook that has only ever been executed by its author is a draft, no matter how carefully it was written, because the author silently supplies the missing steps from memory. Run that rehearsal on a cadence, because a runbook written against last year's console is a runbook that will fail exactly when it is needed.

Where it lives, and the no-code problem

Put the written documentation in the repository next to the code. This is not a preference about tools. It is the only arrangement where changing the system puts the document in front of the person changing it.

Wiki or shared driveRepository, beside the code
Does a code change force you to open itNo, neverYes, it is in the diff and in the review
Change historyA revision list nobody readsThe commit that changed the behaviour and the document together
Staleness detectionSomeone noticing it is wrongA build that fails and names the file
Survives a tool migrationUsually exported to a folder of orphaned HTMLMoves with the code, because it is the code's neighbour
Discoverable by non-engineersGenuinely better, this is its real advantageWorse, and worth fixing by publishing a rendered view
Right useOnboarding, policy, anything with a wide non-technical readershipAnything describing how a specific system behaves

If the automation lives in a visual tool with no repository, you have a harder version of the same problem, and there is a fix. Export the workflow definition on a schedule and commit it. The diff is the change history you otherwise do not have, and it is the only way to answer the question you will eventually be asked, which is what changed on the fourteenth. Strip credentials before committing, commit only when the export differs, and alert if the export job itself stops running, because a silent exporter looks exactly like a workflow nobody has touched. The same discipline is why mapping a process before you automate it pays off later: the map becomes the document the tool cannot produce.

The minimum set, and the section everyone leaves out

Six documents per automation. Any more and none of them are maintained. The last one on this list is the one that is always missing and the one experienced people read first, because knowing the edges of a system is faster than inferring them.

The documentation set for one automation
0 of 9 done

The what it does not do section deserves its own paragraph because it is the highest value writing in the set and it takes twenty minutes. List the input classes that route straight to a human, the failures that produce no alert, the step somebody still does by hand every Friday, and the thing that looks automated but is a scheduled reminder to a person. Each item is something a newcomer would otherwise discover by assuming coverage that does not exist, which is the most expensive assumption in automation work. It also stops scope creep in meetings, because it turns a vague worry into a specific gap somebody can decide about.

What eighteen months does to a document

Rot is not gradual and even. It arrives in identifiable events, and each one has a countermeasure. This is the shape of it for a document with no gate.

Week 1
Accurate and unread

The document matches reality perfectly and nobody needs it, because the author is sitting there answering questions faster than anyone can read.

Month 2
First silent divergence

A threshold changes in config during an incident. The document still names the old value, and nothing announces the gap.

Month 5
A rename orphans a section

A step is renamed and two paragraphs now describe something that no longer exists. A dead-reference check would have caught this in one build.

Month 9
The author moves on

Handover happens against the document, so whatever it says becomes the official account, including the threshold from month two.

Month 12
The trust collapse

Someone follows it, hits the divergence, and tells the team it is out of date. Nobody reads it after that, so nobody corrects it either.

Month 18
Rediscovery by incident

An outage forces a reconstruction of how the system actually works, at a cost of several engineer days, producing a document that will follow the same path unless staleness now fails loudly.

The vocabulary, used precisely

Documentation terms, defined
Decision record
A short document capturing why a design choice was made, the options rejected and the cost of reversing it. It records the one thing that cannot be recovered from the system itself, which is intent.
Review trigger
A condition, not a date, under which a decision should be revisited. Written as something observable such as a volume threshold or a vendor capability appearing, it lets a dashboard raise the review instead of relying on someone remembering.
Staleness gate
A continuous integration check that fails the build when the files a document declares it covers have changed and the document's verified date has not. It moves the cost of stale documentation from the future reader to the present author.
Covered path
A file or glob listed in a document's front matter, declaring that the document describes that code. Dead covered paths are the fastest detectable form of documentation rot.
Runbook
A procedure written for a person acting under pressure with no context, consisting of imperative steps, exact commands, expected output per step and a failure branch for each. It is not documentation and should not read like it.
Tribal knowledge
Operational fact that exists only in someone's head, usually an exception rule or a workaround. It is invisible until that person is unavailable, and converting it into decision records is most of what a good handover is.

The honest summary is that documentation quality is an engineering problem with an engineering fix, not a character problem with a cultural fix. Nobody in your team is lazy. They are responding rationally to a system where writing the document is costly, skipping it is free, and the consequence lands on a stranger. Change those incentives with a gate, a repository location and a rule about what is worth writing at all, and the documents stay true without anybody becoming a better person. Pair it with a real owner per surface, as in who owns the automation after launch, and the system survives its authors.

Cite this

ChatGPTalker, "Documentation That Survives the Person Who Wrote It" (2026). Sort documentation onto three shelves, generated, derived and decided, and hand-write only the third. Give each document a covers list and a verified date, and fail the build when covered code changes without the document being re-read.

Questions readers ask next

How much documentation does one automation actually need?
Six artifacts: a three line readme, a generated inventory, decision records for anything surprising, an exception policy, a runbook per likely failure, and a list of what the automation does not handle. That set fits in an afternoon and stays maintainable. Anything beyond it tends to be state that should have been generated, and generated state typed by hand is worse than no document at all.
Should we use a wiki or keep documentation in the repository?
Both, for different readerships. Anything describing how a specific system behaves lives in the repository, because that is the only place where changing the system puts the document in front of the person changing it. Anything with a wide non-technical audience, such as policy or onboarding, belongs in the wiki. If repository documents need non-engineer readers, publish a rendered view rather than maintaining a second copy.
What if the automation is built in a no-code tool with no repository?
Export the workflow definition on a schedule and commit it to git. The diff becomes the change history the tool does not give you, which is what you need the day somebody asks what changed last Tuesday. Strip credentials before committing, commit only when the export differs, and alert if the export job stops running, because a silent exporter looks exactly like a workflow nobody has touched.
Will a staleness gate slow every change down?
Only if you apply it to everything, which is the mistake that gets it removed. Scope it to documents that opted in with front matter, for automations tiered as critical. Acknowledging that a document still holds after a code change is a one line edit, cheap enough that nobody builds a bypass. A gate covering six documents nobody skips beats one covering sixty that everyone does.
How do we capture knowledge from someone who is already leaving?
Interview them against failures rather than against the system. Ask what breaks, what they check first when it does, which cases they route to a human, and what they would warn a successor about. Record it and write the decision records yourself. People holding operational knowledge are usually poor at writing it down and excellent at answering a specific question about a specific failure.
Are AI generated summaries of a codebase a substitute for documentation?
They substitute well for shelf one and badly for shelf three. A model can describe what the code does today, which is exactly the class you should be generating anyway. It cannot tell you why an option was rejected, what a rule was protecting against, or which exception was deliberately left manual, because none of that is in the code. Generate the recoverable and spend human hours on the rest.
Cite this

ChatGPTalker. "Documentation That Survives the Person Who Wrote It." chatgptalker.com, 2026-08-26. https://chatgptalker.com/guides/documentation-that-survives/

Rather have it built than read about it?

Send the process you want automated. You get a scoped plan back, with the build shape, the stack and a realistic timeline.

Start a project