翻訳待ち:When AI Writes the Code, Specifications Need an Exit Strategy
AI サービスが一時的に利用できないため、復旧後に翻訳を補完します。ソース概要:The following article has been extended and rewritten by Markus Eisele from The Main Thread and is being republished here with the author’s permission. Open a repository after six months of spec-driven agent work and you may find a second system sitting next to the code. Requirements, research notes, high-level designs, low-level designs, implementation plans, […]
AI サービスが一時的に利用できないため、復旧後に翻訳を補完します。
The following article has been extended and rewritten by Markus Eisele from The Main Thread and is being republished here with the author’s permission. Open a repository after six months of spec-driven agent work and you may find a second system sitting next to the code. Requirements, research notes, high-level designs, low-level designs, implementation plans, task lists, review reports, and a growing stack of Markdown files that explain what the code is supposed to mean. Even if the code changed significantly last Tuesday, the last documentation update was weeks ago. I understand how teams get there. And it’s not a really new effect after all. We had software evolving parallel to documentation since I can remember. Now that agents produce code so quickly, we try to control the drift and the code generation by moving more thought in front of implementation. Instead of documenting code, we try to drive code generation with it, making Markdown files with requirements, decision records, design approaches, and acceptance criteria the center of gravity and turning them into our workflow drivers. What effectively is becoming a very large prompt can easily fill a significant portion of the context window even of modern agents before any relevant source code gets added to it. Natural language specification is a weak system for agents to synchronize a codebase with. Without additional attention and diligence, most agents I work with slowly shift attention away from it quickly and focus on the stronger signals in the codebase, forgetting to update the specification eventually. Even if it sounds like it, I am not advocating for one-shot prompting or vibe coding here. We still need some specifications to build successful software. The mistake is treating a specification as a permanent natural-language copy of the software. A useful spec describes the next change, documents the decisions that drive the change, sets boundaries, and gives us and the agents enough verification surface. But as soon as the change ships, most of it should be removed. What remains should move into the artifacts software teams already know how to maintain. First and foremost, obviously, the code. But I also count schemas, configuration, and policies as relevant artifacts. They carry meaning about domain knowledge and system configuration. Two categories that I value highly get easily forgotten: tests as the stable verification layer and runtime telemetry. In fact, I do let my agents look at evidence from all these places not only to hunt for errors but also to continuously optimize existing codebases. Oh, and I do keep decision records. But only a small number and only when their content really has no other place in any of the mentioned artifacts. They can even look like Javadoc, but that will be another article someday. A change specification should be temporary by default. After implementation, durable information moves into code, schemas, tests, policies, and operational signals. The rest leaves the active context. Code is the fact Code is actual behavior. Once code is deployed to production, users and connected systems are depending on it. Even a mistake can become an observed contract because it has behaved the same way for three years. The runtime behavior takes precedence in this contract because nobody checks the specification anymore, even if it defines a very different behavior. This is the strongest signal for me to start with the actual code in the production system. Reading a natural-language summary instead of the implemented truth cannot accurately reflect runtime behavior. Code to me is the ultimate, executable specification. Just written in a very specific and deterministic language. What production code cannot drive though is the next version or iteration of a feature. While agents can infer technical patterns from well-structured codebases, there’s no way they could predict policy changes or future feature requests. Neither can they know about regulatory requirements like retention periods or other specific exceptions, such as why one export runs every night for only one customer. That specific context has to come from somewhere else. But it does not require us to keep a permanent prose description of the whole system. We need just enough context to decide the delta: the difference between what exists and what should exist next. Written words are for the delta A change specification should exist when it helps a team decide and review that delta. It should name the outcome, non-goals, constraints that differ from current behavior, and the evidence required for acceptance. It might even contain technical design elements when new features cross architectural boundaries or introduce new patterns that are not present in the code yet. Sometimes it is also worth thinking about how expensive reversing the change is, especially if the existing system has various implementations for a certain pattern and the risk is high that an agent might invent another new version. The list necessary for changes is very short: The intended outcome and non-goals (where necessary) Known unknowns and decisions that need human judgment Affected system boundaries and authoritative interface artifacts Functional and nonfunctional constraints that differ from today Acceptance criteria/test scenarios covering the risky path I prefer calling this a “change brief” instead of a “specification.” Specification carries too much negativity. It sounds heavyweight and reminds me of times long past. It also pretends to be complete. And this completeness is making it very expensive. We have tried exhaustive specifications before and produced requirement documents and other high- and low-level designs, followed by architecture decision records for everything. I remember reading folders full of paper over the weekend to get started on a new project on Monday. Way before AI even entered all our lives and codebases. We called this waterfall back in the day, and the approach still has the same negative side effects today. The documentation was complete in an administrative sense and was mostly useless in the engineering sense. We all have seen this happening. Agents easily recreate the same erratic results from overflowing documentation, like we did back in the day. One particular risk I am seeing with many teams is that they let agents generate the initial version of the spec. A long workflow run produces not only the research but directly derives the requirements, design, and planning, and reviews artifacts on top. While the completeness makes everything look very controlled and defined, it also generates a lot more material to be reviewed and approved. Even if models and harnesses continue to evolve at breathtaking speed, it is still challenging for them to generate real cohesiveness out of chaos. The chance they put the wrong attention on some tempting repetitive words is high. This results in an even higher burden on the human reviewer and makes it endlessly harder to keep the various documents aligned. I think that additional prose like research notes, prototypes, and design records should only be added to a software project when uncertainty justifies them. They resolve a specific problem. Or help navigate the terrain. I wrote about this before. They should absolutely not become required stages for every pull request. The map will always be incomplete A prompt, ticket, or change brief captures what we know before the work starts. The codebase, runtime information, configuration, connected systems, and years of accumulated decisions glued into code hold the rest. Some of those decisions were never written down. When agents get to work they expose the missing information. Reading a module reveals an unexpected dependency. A prototype shows that a specific user-interaction is awkward. A test uncovers an edge case. Production data contradicts an assumption in the design. This field guide on finding unknowns in agent work describes the problem well. We can identify some unknowns at the start. Others appear only after we inspect the references, build a prototype, or review a result using judgment that was difficult to write down in advance. Discovery happens and continues during the work: Before implementation, inspect the current system and identify decisions that could change the architecture or user experience. When preferences are difficult to describe, build a cheap prototype. During implementation, record meaningful deviations. Stop and reassess when a new unknown changes the risk or direction. After implementation, read the code, run the checks, and compare the result with the original intent. The change brief remains part of this loop. It provides the starting point and records the intent, while the work supplies the information needed to complete it. Only promote durable constraints. Keep durable facts in their native form When I say “promote durable constraints,” I do not mean turning every decision into permanent Markdown. That gives us the same stale documentation problem in a different way. Software engineering already provides better versions for most of the necessary, durable facts: API shape and compatibility belong in OpenAPI, AsyncAPI, protocol schemas, types, and compatibility tests. Data invariants belong in types, database constraints, validation, and migration checks. Security rules belong in access policies, static analysis, dependency policies, and runtime enforcement. Architecture boundaries belong in module structure, dependency rules, and focused architecture tests. Reliability requirements belong in load tests, service objectives, telemetry, and alerts. Release rules belong in continuous integration and deployment policies. These artifacts are already part of delivery. A failed schema check or alert needs to be fixed and handled while the corresponding paragraph in an old design folder does not. Natural language and specification still have a place in software. Specific domain knowledge like business policy, trade-offs, and even architectural rationale do not always fit into an executable artifact or annotation. I keep that prose short and close to the thing it explains. A small architecture decision record is worth keeping when a future team might otherwise repeat an expensive investigation and a code comment cannot justify the implementation. Recording every local choice just hides the few decisions that matter and confuses the agents that are supposed to build the software. Ask which fact must survive and what its authoritative form should be. Briefs and design notes support ongoing changes. Native engineering artifacts carry the constraints and evidence that remain relevant after a release. Judgment belongs in the workflow Heavyweight specification methods try to control quality by prescribing the path. Every change goes through the same documents, reviews, and test categories. That approach creates a lot of attention on low-risk work while avoiding the deep technical judgment needed for harder changes. A copyedit and a payment-flow change should not have to follow the same process or testing strategy. Simon Willison describes a simpler approach: give the coding agent the outcome and let it judge how much process the task requires. His examples include deciding whether a change warrants automated tests and whether routine implementation can be delegated to a cheaper model while keeping judgment-heavy work in the main loop. This replaces a growing list of procedural branches with one expectation: Choose tactics that fit the work. That matches how I want these systems to operate. And I think it extends to specification and how we document intent. Agentic changes still require clear boundaries. The team defines the outcome, safety constraints, ownership, and who has authority to accept the result. Within those boundaries, the age [truncated for AI cost control]