Everything Drifts: Making the Documentation Tell On Itself

What is in Git, what is live, the working notes, and the official docs are four pictures of the same system — and they drift apart. So I made the knowledge base the source of truth, wrote machine-readable contracts into the docs, and built workers that reconcile the gap and text me when it appears.

Everything Drifts: Making the Documentation Tell On Itself

Here is a quiet truth about any system that has been alive for more than a week: the documentation is already lying to you. Not on purpose — it just drifts. What is in your repository, what is actually running in production, what your working notes say, and what your official documentation claims are four different pictures of the same system, and they wander apart the moment you stop staring at them.

I learned this the way everyone learns it. Three scheduled jobs on my system died and stayed dead for eight days — no alarm, no error, nothing. I only found out because I happened to go looking. Nothing was watching the gap between "this is supposed to run" and "this is actually running." That is drift, and drift that nobody watches is just an outage with a delay.

Four versions of the truth

Once I started looking, the problem was bigger than a dead cron. There were four pictures of the system, and any two of them could disagree: the code in Git, the workers actually deployed and live, my running project notes, and the official knowledge base. Each drifted on its own schedule. A hotfix went straight to production and never made it back into the repo. A note captured a decision that the docs never absorbed. The knowledge base described a worker that had been quietly retired months ago. Four sources, four truths, and no referee.

Pick one to be the truth

You cannot keep four things in sync by willpower, so I stopped trying and picked a winner. The knowledge base became the single source of truth — the one authoritative statement of what the system is supposed to be. Everything else is measured against it. Truth flows one direction, from the knowledge base outward. When live disagrees with the knowledge base, that is not the knowledge base being wrong; it is a signal that live has drifted, and now there is a fixed point to measure the drift from.

Contracts, written into the docs

This is the part I am proud of. Every worker has a knowledge-base article — a human-readable page that explains what it is and why it exists. Inside that article sits a small, machine-readable contract: a block that states, in plain data, what the worker must be — its address, its schedule, its permissions, its shape. The contract lives inside the documentation, in the same file as the prose, so the explanation and the specification cannot drift from each other. They are the same page. A worker is allowed to be exactly what its contract says it is, and a reconciler can read that contract and hold reality to it. The document stopped being a description and became a constraint.

The workers that watch for drift

Then I built the boring, load-bearing part: workers whose only job is to notice drift. A reconciler reads three pictures — what is actually live, what the contracts in the knowledge base say should be live, and what the operator-facing overview in the repo claims — and flags every disagreement. A live worker with no contract. A contract with nothing live behind it. A live worker missing from the overview. It is read-only, and deliberately so: it does not fix anything. A silent auto-correction is just a quiet way to paper over a real problem, and it trains you to trust a green light you never earned. So it surfaces the gap and hands the decision to a human.

Fifteen minutes, and a text message

A separate monitor runs every fifteen minutes and checks a real freshness signal for every critical scheduled job — not "did the cron fire," but "did the thing it was supposed to produce actually show up." When something goes stale, or the daily reconcile turns up drift, it does two things. It hits a small notify service — one endpoint, one API call, a POST to /alert — that sends a text message to my phone, rate-limited so a bad day cannot turn into a hundred texts. And it writes the finding into the task backlog, so the drift is not just a text I can thumb away; it is an open item that stays open until someone closes it.

Governance is just this, done on purpose

That last part is the whole point, and it is the part most people skip. Detection without a backlog is noise. So drift findings and ordinary work land in the same governed list — what broke and what is left to build, tracked together, in the open, each with an owner. The knowledge base states what should be true; the contracts make that machine-checkable; the reconciler checks it; the monitor watches the clock; the text message interrupts me; and the backlog makes sure nothing quietly falls off the edge. That loop is what governance actually is. Not a policy document that sits in a drawer — a policy that runs every fifteen minutes and texts you the moment it is violated.

Why I bother

Documentation that nobody checks is a wish, and I did not want wishes running the businesses I run. So I built the thing that checks. The docs still drift — everything drifts, that is not a solvable problem — but now they tell on themselves within fifteen minutes, and the gap between what I wrote down and what is actually true has my phone number. That is the trade I will take every time: not a system that never drifts, but one that is honest about it fast enough to matter.