Skip to content

The missing layer: spec-as-source needs a steward

· By Jean-Noé Kollo

Specs drive the first implementation, then quietly become a polished lie. Five days chasing drift detection led somewhere else: the missing piece is a role.

A developer ships a feature on a Friday afternoon. The code works. The tests pass. The PR gets approved.

And the spec — the document that says what the system is supposed to do — still describes last week's behaviour. Nobody notices for three sprints.

That's the quiet failure of every spec system I've seen. Specs drive the initial implementation, then code starts evolving faster than documentation, and the spec becomes a polished lie. With AI agents writing more and more of the code, the gap widens faster than ever.

I spent five days — and a frankly embarrassing number of tokens — trying to solve this. Here's the honest version of that journey: the false starts, the dead ends, and the idea I landed on that I think actually matters.

The trap: a mapping file nobody wants

It started with what felt like a breakthrough. If specs are the source of truth, there should be a way to detect when code drifts away from them. Bidirectional drift detection — not just specs driving code, but code changes flagging spec updates. The concept was seductive, and when I described it to colleagues, they got it instantly.

The idea looked like this: use git history to map commits to code changes, then map those commits to one or many specs. Elegant on a whiteboard. Then I tried to implement it, and the real problem surfaced.

How do you map code to specs? One spec covers many files. One file gets touched by many specs. This many-to-many relationship was the breakdown point. Every solution I sketched required a mapping file — a specs/mapping.yaml — that would need to be maintained. By developers. Manually.

I was asking developers to maintain a second index of their own codebase. Nobody would do it. And if nobody maintains it, drift detection becomes drift generation: one more stale file in the repo.

So my first real insight was negative. I was drifting away from the specs myself, copying git's data model instead of solving the governance problem. The idea was good. The implementation was a dead end.

The pivot: tests are the mapping

Then it hit me, and I'll admit it was almost embarrassing how obvious it was in hindsight.

The mapping between specs and code already exists. It's called the test suite.

BDD, TDD, Gherkin — these traditions have been solving the same problem for years. A test is a machine-readable assertion that a spec requirement holds true. The mapping is baked into the structure: a Given/When/Then scenario in a spec file maps to a test case in the codebase. You don't need a separate index. You need a convention.

Here's what I landed on. Take the requirement IDs from the spec (say REQ-005-07) and put the same IDs as comments above the corresponding tests. That's it. The spec says what the system should do. The test proves it does. The ID links them. No mapping file. No YAML. No extra maintenance burden.

From there, a basic enforcement layer — what I started calling a Drift Guard — falls into place naturally. A spec requirement with no corresponding test blocks the commit. A test with no requirement ID blocks. A code change that touches files related to a requirement without updating the changelog gets flagged. The tooling is familiar: pre-commit hooks, linters, CI checks. Nothing exotic.

But then I hit the next wall. Unit tests map to small implementation details. End-to-end tests map to product-level behaviour. A spec that works for stakeholders — human-readable, high-level goals — is useless for a linter. A spec that works for a linter — structured IDs, machine-parseable constraints — is unreadable for a product owner.

You need a hybrid spec. And that's where things get genuinely hard.

What a spec is, and who it's for

I took a break. I talked to people. I read what had already been done. And I realised I'd been thinking about specs as if they were a single artifact, when in reality they span the entire development lifecycle — from a vague product vision down to a line-level assertion.

A spec answers three questions, and each one belongs to a different audience at a different stage.

Why — the business goal, the user need, the reason to build. Product owner territory: PRDs, journey maps, success criteria. It gets frozen after sign-off and rarely changes.

What — the functional requirements, the acceptance scenarios, the API contracts. Developer territory: structured markdown with Given/When/Then, requirement IDs, data schemas. It evolves with the code.

How — the implementation guardrails, the changelogs, the mapping metadata. System territory: auto-tracked, ephemeral, machine-readable. It changes on every commit.

And specs are everywhere. They're not just your 005-ideation-brief.md files — those are the most visible form. A spec is any artifact that captures a decision the code must respect.

Two families of frameworks, one gap

Once I saw this, I went deep into the existing landscape — BMAD Method, Kiro, OpenSpec, GitHub Spec Kit. What I found was clarifying, and frustrating. Two distinct categories exist, and they're almost completely orthogonal.

SDD frameworks — Spec Kit, OpenSpec, Kiro, Tessl — answer "how do I write and maintain specs that drive code?" They're about authoring, format and workflow. The spec is the product. OpenSpec gives you delta-based iteration and brownfield support. Tessl pushes toward full spec-as-source, where code is generated and never hand-edited. Spec Kit provides phased workflows with checkpoints. They're all useful. None of them solve what happens after the spec is written and the code starts evolving.

Agentic frameworks — BMAD, Xebia ACE — answer "how do I organise AI agents to simulate a dev team?" They're about orchestration, roles and process. BMAD gives you specialised personas that hand off structured artifacts. ACE embeds AI across the full lifecycle. They produce specs as artifacts, but they don't govern their integrity over time.

The foundational SDD paper on arXiv (Piskala et al., 2026) lays out three levels of rigour: spec-first, spec-anchored, spec-as-source. Birgitta Böckeler's analysis on Martin Fowler's blog describes the same gradient by comparing Kiro, Spec Kit and Tessl side by side. But even at the most ambitious level, none of the existing tools answer the question that started this whole journey: when code and spec diverge, who catches it?

BMAD produces specs but doesn't watch them after implementation. OpenSpec archives deltas but doesn't check whether the delta matches the actual diff.

The missing piece isn't a tool. It's a layer.

Spec Steward and Drift Guard

Here's where I ended up, and it's not where I expected.

The problem isn't that we lack frameworks for writing specs — we have plenty. It isn't that we lack frameworks for orchestrating agents — those exist too. The problem is that nobody governs the spec across the full lifecycle: build, deploy, run.

Each phase has its roles. Product owners write the why. Developers write the what. CI systems track the how. But no single role, human or automated, owns the question that ties them all together:

Is the system doing what we agreed it should do, and can we prove it?

At every commit, every merge, every deploy and every incident, the answer should be yes — or it blocks. That's the function I'm calling the Spec Steward: a governance role that spans the three phases, ensures the rules are applied, collects feedback from the collaboration process, and uses generative AI to facilitate the parts that don't need human judgment.

Benoît Lamouche describes a similar "Spec Curator" profile in his analysis of emerging AI-era roles — someone who structures and governs reusable knowledge across projects. I'm pushing the idea further. The Steward doesn't just curate specs as artifacts. They enforce them as living contracts across the full lifecycle.

The Drift Guard is the tooling that makes the Steward's job possible. It's not one tool, it's a layer. Pre-commit hooks that check requirement ID coverage. CI jobs that feed diffs and specs to an LLM for semantic validation. On-demand developer skills that propose changelog entries. Each layer has a different trigger, a different decision weight — block, warn, suggest — and a different audience.

The lifecycle was built for humans. We're now in something closer to an agent-augmented lifecycle, where AI agents write code, propose specs, run reviews and iterate autonomously. Kief Morris, writing on Martin Fowler's blog, frames this shift as the move from humans in the loop to humans on the loop: instead of inspecting every line of code, you build and maintain the harness that shapes what agents produce. The Spec Steward is the role that owns that harness for spec governance.

The Steward doesn't replace the product owner, the developer or the QA engineer. It sits across all of them, doing the job none of them can do individually: keeping the spec a living, enforceable contract.

Not another framework

What I'm not building is another SDD framework or another agentic orchestrator. Everything exists. But the glue between "govern specs" and "orchestrate agents" doesn't.

Not a new way to write specs — Tessl, OpenSpec and Spec Kit handle that. Not a new way to run agents — BMAD and ACE handle that. The validation and enforcement layer that completes them. A system that collects feedback from the collaboration process, ensures the rules are well applied, and uses generative AI for the parts that don't need human judgment.

The authoring conventions are what SDD frameworks already solve. The orchestration is what agentic frameworks already solve. What remains is the governance: proving, at every checkpoint, that the system is doing what we agreed.

That's a smaller problem than building a whole framework. But it might be the one that actually matters.

This article grew out of thinking notes captured during brainstorming sessions with Claude, using a custom /thought skill that synthesises surprising model answers into granular files. Discussion, plan, review — each phase passed to a different agent. It mirrors the workflow I'm trying to govern. The irony is not lost on me.