← Back to list

Living documentation in SDD: spec drift, 6 traps, and the sync-owner-gate mechanism

Living documentation doesn’t die from laziness — it dies from missing a mechanism. Spec drift, 6 traps, and the sync-owner-gate trio that…

Jaroslaw Wasowski · 2026-06-12 12:10 · 2 claps · 12.5 min read paywalled
#spec-driven-development #software-engineering #programming #artificial-intelligence #large-language-models
Open on Medium ↗
Wiki topics: AI · AI · General 💻 · Programming

Living documentation in SDD: spec drift, 6 traps, and the sync-owner-gate mechanism

Living documentation doesn’t die from laziness — it dies from missing a mechanism. Spec drift, 6 traps, and the sync-owner-gate trio that keeps the spec alive.

Living documentation sounds like the best promise SDD has to offer — until your repo contains forty-seven versions of the spec and nobody knows which one describes production. The files are named spec_final_v2, spec_FINAL_THIS_ONE, spec_final_seriously_last_one, and every single one of them lies in its own way.

This isn’t a hypothetical team from a textbook. It’s the state most teams land in a few weeks after an AI agent starts generating code from an outdated specification. At first, everything works, the tests are green, the team is excited — and then the starting document quietly diverges from what actually shipped to production.

In a few minutes, you’ll see why the spec always drifts away from the code, six traps that accelerate that drift, and the mechanism — synchronization, an owner, a gate — that turns living documentation from a promise into an executable artifact.

Spec drift is accumulating erosion, not a single mistake — without a mechanism, the gap grows with every change.

Spec drift is accumulating erosion, not a single mistake — without a mechanism, the gap grows with every change.

The most important truth fits in one sentence

Living spec isn’t a property of the document — it’s a property of the pipeline around it. A specification stays alive exactly as long as something forces it to be rebuilt with every change. That requires three things at once.

First: automatic synchronization — delta specs or AI comparing the spec against the code, whatever keeps the document close to reality without relying on anyone’s memory. Second: a single, unambiguous owner — one concrete person responsible for reconciliation, not a diffuse “the team.” Third: a CI gate — the build fails when the spec and code diverge.

Remove any one of those three elements and “living documentation” slides back to a versioned Word document that nobody reads after a few sprints. The most common and cheapest mistake is believing that goodwill is enough. It isn’t, because drift is the default state of any system without a mechanism.

The best analogy is an engineering one: treat the spec like a database schema or Infrastructure-as-Code. A schema without migrations and without review drifts away from the application in a week, and nobody pretends it can be maintained through “good intentions” alone. The spec follows exactly the same logic. The problem isn’t writing the spec — it’s maintaining it, and that’s a problem of mechanism and ownership, not technology.

If you leave this article after three minutes, take one sentence with you: before you add another tool, make sure you have all three — sync, owner, gate.

With that mechanism in mind, let’s break down the drift phenomenon itself first.

Why living documentation dies in the drawer

Spec drift — the accumulating divergence between what the spec describes and what the code actually does — isn’t an accident. It’s the default state of a system without a mechanism. The spec says one thing, the code does another, and nobody notices until something breaks in production.

Drift follows predictable patterns. An API signature changes and the description stays stale. A refactoring quietly drops two fields the spec still requires. A contract changes without schema versioning and the consumer finds out from an error.

Each of those patterns is individually innocent — and that’s exactly why they’re lethal together.

The failure mechanism is painfully human. The developer knows the documentation needs updating, but falls into the next ticket, and the update lands mentally as “I’ll do it later.” In practice, “later” almost always means “never” — not from laziness, but from the physics of a process where hotfixes and deadline pressure always outrun document maintenance.

In the era of AI agents this drift compounds even further. The first week looks like coordinated optimism: the agent generates code fast, tests are green, the team is thrilled. After a few weeks, the desynchronized code becomes the base for the next round of calls, and the team starts debugging hallucinations that stem from false premises in the starting documentation. An outdated spec isn’t neutral — it actively poisons every subsequent iteration.

Then comes the quiet moment that’s worse than any bug. Past a certain threshold of inaccuracies, developers stop trusting the documentation. Every sentence needs verification against the code, and the spec shifts from a reference point to a starting point for skepticism. Documentation nobody trusts is more expensive than no documentation at all, because it still pretends to mean something.

One popular figure is worth addressing directly. The claim that “roughly 70% of teams abandon living docs” doesn’t have a credible source. The direction, however, is well-documented: analysis of over 3,000 GitHub projects found the vast majority had stale references in their documentation at some point (arXiv 2212.01479). Nearly 29% of teams using examples as acceptance criteria don’t automate them at all (Adzic 2020 study, n=339).

Developers consistently identify writing documentation as one of the tasks they most resist doing — a direction confirmed by a range of practitioner research. The core issue isn’t writing. It’s maintenance.

After this section, stop asking “how do we force the team to be disciplined” and start asking “what mechanism will enforce the update.” Since drift is inevitable, let’s look at which specific places it strikes most often.

Six traps that kill the spec

These six traps aren’t six separate problems. They’re six faces of one — a missing maintenance mechanism. Treat the list below as a diagnostic map: once you recognize which trap you’ve fallen into, you know exactly which element of the mechanism — sync, owner, or gate — is missing.

The six most common traps — almost every team falls into several at once.

The six most common traps — almost every team falls into several at once.

Six failure modes

  • Spec-in-drawer — a PRD read at kickoff and shelved forever. The document lives once, at the start, and then nobody returns to it because nothing forces a rebuild. This is the classic death-by-one-time-use.
  • Double source of truth — you version the code the agent generates, but not the spec that produced it. You’ve inverted the dependency that matters: you maintain the output while abandoning the source. After a few iterations, it’s impossible to reconstruct why the code looks the way it does.
  • No owner — everyone assumes someone else is updating it, so nobody does. Tool silos make it worse: the spec lives in Notion, the API contract in Swagger, the design in Figma, and none of them know about the others. Diffuse ownership is a silent killer.
  • No CI gate — without automatic contract assertions, divergence reaches production undetected. Drift becomes silent instead of loud, and silent drift always wins because nothing stops it in time.
  • Over-versioning, or “47 versions” — multiplying full copies instead of archiving changes. You end up with a forest of files where, as one team put it, “the newest page wins, regardless of which version of the system it describes.” That’s drift dressed up as order.
  • Manual sync — maintenance dependent on memory and goodwill. Every UI change breaks dozens of Given-When-Then scenarios written like manual scripts. Anyone who’s been through the hell of maintaining a legacy BDD suite knows that manual sync scales to zero.

Most teams I’ve seen don’t fall into one trap — they fall into three at once. The most common package is no owner, no gate, and over-versioning together. That’s not bad luck — it’s a lack of process architecture. Now that we know the six failure modes, it’s time for the antidote.

The mechanism — sync, owner, gate, and the right level of rigor

No single tool “solves” drift. What solves it is the sync + owner + gate trio, and you calibrate the level of rigor to the risk, not to what’s fashionable. The tools I’m about to name are instances of one mechanism, not competing religions. The real engineering decision isn’t “which tool” — it’s “what level of rigor.”

No tool solves drift on its own — only the sync-owner-gate trio does.

No tool solves drift on its own — only the sync-owner-gate trio does.

Delta specs and change archiving

Start with the intuition. You maintain a spec the way you maintain a database schema — through migrations, not by rewriting the whole thing. You don’t restart the entire file just because one line changed.

Delta specs are exactly that pattern: you describe the difference — what was added, what changed, what was removed — instead of the whole document. In practice, the specs/ directory holds the source of truth ("how it is today"), while changes/ holds proposals. The Propose → Apply → Archive cycle merges a delta into the spec and files the change to an archive with a date, building an audit trail. This is the same approach that defuses the "47 versions" problem: you archive changes instead of multiplying copies. There's one trap practitioners know well from delta tooling — the delta language can leak into the permanent spec, leaving behind "removed field X" entries that gradually become noise.

AI diff and the CI gate

The second element is detecting drift before it reaches production. An AI diff between the spec and the code does a semantic comparison, not a string match: the model reads the spec, analyzes the code, flags divergences, and either opens a PR or fails the build. That’s detection that regex will never provide, because divergence is rarely literal. Tools of this type are still maturing — worth verifying specific implementations before production adoption.

This has one limitation worth being honest about. Tools that operate only in CI detect drift at deployment time, not at the moment it’s actually introduced. Between deployments, divergence can accumulate invisibly.

That’s where the CI gate comes in — a pre-commit hook that requires a change in /docs whenever /src changes, or contract assertions that fail the merge when spec and code diverge. It's the simplest implementation of the Definition of Done principle: a feature isn't done until the spec is updated. The gate turns drift from silent and accumulating into loud and painful — and that's exactly the point.

Bidirectional sync — engineering or promise

The most tempting promise on the market is bidirectional sync — a change in the code updates the spec, a change in the spec updates the code, both sides stay in sync automatically. It sounds like the end of the whole problem.

A cool head is needed here. These promises come today mainly from vendor materials and haven’t been independently verified — something many of them acknowledge themselves. Skeptics from the SDD practitioner community argue that the true differentiator of a living spec isn’t bidirectionality, but executability — does the document actually verify anything, or does it just sit alongside the code as nicely formatted prose. Nobody has convincingly demonstrated that bidirectional synchronization works at scale in old, legacy codebases (brownfield). The one question you should ask any such tool as a practitioner is this: does it verify correctness, or does it merely co-edit text?

Rigor levels — when the spec is allowed to die

All of the machinery above only makes sense when you calibrate its intensity to the task. A taxonomy of three levels helps here — proposed informally by Birgitta Böckeler of Thoughtworks in an analysis of SDD tools on Martin Fowler’s blog (martinfowler.com, October 15, 2025).

  • Spec-first — the spec is allowed to die after merging. Zero maintenance overhead, but it’s a conscious acceptance of spec-in-drawer. Good for one-off explorations.
  • Spec-anchored — a living anchor that evolves with the system. Works only with the iron discipline of “spec changes before code, always.” This is the sweet spot for most production systems.
  • Spec-as-source — humans edit only the spec, code is generated. Maximum rigor, but also maximum risk of model non-determinism on the input.

The selection rule is simple: rigor to match risk and complexity — don’t use a sledgehammer to crack a nut. Most teams want spec-anchored for production and spec-first for prototypes — and very rarely anything in between.

The theory of the mechanism sounds clean. The question is what it looks like at the scale of hundreds of teams — and the answer is less magical than vendors promise.

What Mercari and MELI actually do at scale

The most important correction in this piece is this: at scale, nobody does magical spec↔code sync. The promise of “living spec maintained automatically across hundreds of teams” has no backing in the real deployments I was able to examine. What actually works is contract discipline and a human in the loop.

At scale, human-in-the-loop and contracts win — not automatic spec sync.

At scale, human-in-the-loop and contracts win — not automatic spec sync.

Mercari: AI writes the docs, a human approves them

Mercari’s approach is deliberately conservative. AI agents don’t have write access to the main branch. On merge, CI triggers a model that examines the changes and files updated documentation as a separate PR, waiting for human review. Triggers are limited to merge and release events — partly to keep costs in check at roughly fifty cents per execution. A standard, manual design-docs workflow runs alongside it: any work expected to take more than a month starts with a design document.

That’s maintaining documentation close to the code — not bidirectional spec-to-code sync.

MELI: contracts instead of sync

MELI — Mercado Libre — plays a different card: contracts. Their internal developer platform (a shared gateway through which teams deploy with pre-built gates) runs automatic quality gates, validation, and linting for code on every PR. On top of that, contract tests run on API interfaces: the service consumer defines the expected contract, and any mismatch fails the CI pipeline before the change reaches integration. That’s shift-left in its pure form — and again, there’s no trace of automated spec-to-code synchronization anywhere.

The scale is striking: tens of thousands of engineers, hundreds of thousands of deployments per day, tens of thousands of microservices. That scale is context, not proof of magical sync.

Here’s the takeaway — not a gotcha. The assumption that large companies “maintain specs at scale” was partly wrong. What they maintain is contract and gate discipline, not bidirectional synchronization. That doesn’t weaken this article’s thesis — it strengthens it: at scale, discipline wins over magic. Stop looking for a miracle “living spec as infrastructure” tool and start building what actually scales — contracts, gates, and human review.

Since even at scale discipline wins, one difficult organizational question remains: who specifically owns the spec.

Who owns the spec

“The price of greatness is responsibility.” — Winston Churchill, Statesman

Spec ownership isn’t a title — it’s an enforced responsibility. The debate I see most often — PM or tech lead — asks the wrong question. There’s no single correct model. There’s one correct principle: ownership must be explicit and enforced in review.

The classic framing comes from Joel Spolsky (2000): the spec has one named author responsible for its content. It’s still the cleanest accountability model — and a reference point even when you depart from it.

Three ownership models

In practice, you’ll encounter three ownership models. Centralized — one owner per module, like Spolsky’s named author. Distributed — responsibility spread across the team. Hybrid — a nominal owner plus shared accountability.

One nuance worth knowing: so-called collective ownership, where “everyone is responsible” without process-level enforcement means nobody feels individually accountable, and at scale it’s the first thing to break down.

Any ownership model works — provided it’s explicit and enforced in review.

Any ownership model works — provided it’s explicit and enforced in review.

Principle over model

An interesting counterpoint is Mercari, which distributes ownership across QA, Product, and Engineering — a philosophy of “quality as the responsibility of the entire Scrum team, not a single role.” Documentation works there because it’s maintained by the process, not by a role name — review and CI enforce what no single person can.

Enforcement is the key word. Changes that bypass the spec are flagged in CI. Review routinely asks “where is this documented.” And traceability through a shared ID — one REQ-123 linking the requirement, spec, code, and tests — makes divergence visible rather than default.

That requirement → spec → code → test linkage turns goodwill into a verifiable audit trail.

There’s one finding from maintenance research worth taking literally: detecting drift alone doesn’t lead to fixing it. Without an owner with real accountability, a CI alert is just another ignored notification. Diffuse ownership kills the spec faster than bad tooling. What’s left is putting it all together into one copy-paste-ready set of practices.

Summary — the checklist that keeps the spec alive

Let’s return to those forty-seven versions from the opening. The entire problem they represent doesn’t disappear when the team “tries harder” — it disappears when a mechanism is built around the spec. Living spec is a mechanism, not a declaration — sync, owner, and gate; everything else is a versioned Word document.

Here’s a copy-paste checklist for maintaining living docs, ready to use tomorrow:

  • Choose a rigor level per artifact — default to spec-anchored for production, spec-first for prototypes.
  • Keep the spec in Git as a single source of truth, alongside the code, not in a separate silo.
  • Use delta specs (ADDED/MODIFIED/REMOVED) and change archiving instead of multiplying versions.
  • Set up a CI gate: spec↔code divergence results in a build failure, via AI diff or contract tests.
  • Wire spec updates into the Definition of Done and into review — make “where is this documented” a routine question.
  • Designate one, explicit owner per module — and enforce it in review.
  • Treat vendor promises of bidirectional sync as “vendor-described” — ask whether the tool verifies or merely co-edits.

Five things to remember if the rest slips away:

Living spec is a mechanism (sync + owner + gate), not a declaration. The six traps are six faces of a missing mechanism. Calibrate rigor to risk, not to what’s fashionable. At scale, contract discipline wins over magical sync. And without an explicit, enforced owner, the spec dies regardless of the tooling.

Thank you for reading this far — it’s the most practical and least glamorous part of SDD, and I appreciate your time all the more for it. If this article changed how you think about spec maintenance, share it with someone who’s implementing SDD and doesn’t know this yet. And leave your seventh trap in the comments — the one your team actually fell into.


메타데이터
post_id
74b706c9db95
slug
living-documentation-in-sdd-spec-drift-6-traps-and-the-sync-owner-gate-mechanism-74b706c9db95
url
https://medium.com/@wasowski.jarek/living-documentation-in-sdd-spec-drift-6-traps-and-the-sync-owner-gate-mechanism-74b706c9db95
canonical_url
https://medium.com/@wasowski.jarek/living-documentation-in-sdd-spec-drift-6-traps-and-the-sync-owner-gate-mechanism-74b706c9db95
author_url
https://medium.com/@wasowski.jarek
status
ok
fetched_at
2026-06-13 00:08:42