spec-editor Pro is in early access. Request access

Articles

The model should describe the system as it is, and leave the history to git

· First published on LinkedIn

The first decision gave every requirement an address. The second decided what the text at that address says. It turned out to be the harder one.

The natural way to write a requirement is as a change: add a retry to checkout, make the retry idempotent, disable it for cards. Every ticket, every pull request and most spec-driven kits work this way. Each statement is true on the day it is written. A month later you have a pile of true statements and no answer to the only question anyone asks: what does checkout do today?

A person copes, by reading the pile and reconstructing the present in their head. An agent does the same and gets it wrong often enough that you stop trusting it. Our first files were written as changes, and they went stale the moment the change shipped.

We looked at three ways out:

  • Keep the pile and add a changelog on top.
  • Keep a decision log alongside.
  • Hold one description of the current state and rewrite it whenever the system changes.

We chose the third. A requirement file describes the system as it is now. The history is not lost, it just lives where history belongs: in git, in the journal, in the logs. A request to change something is a temporary thing; once it is delivered it goes to the archive, and the file it touched now simply says the new truth.

Two panels. A history of changes: five dated tickets about a checkout retry, four closed and one open, with the note that none of them says what checkout does now. A description of the current state: one requirement, Checkout retry, status confirmed, saying wallet payments are retried up to three times with the same idempotency key and card payments are never retried, with three acceptance criteria. The image is marked as an illustrative, invented example.
The same month of work, kept as a history of changes and as one description of the current state. Figure by the author. Illustrative example; the checkout retry is invented.

This is an old idea in a new place. Infrastructure went through it ten years ago: Terraform and Kubernetes describe the desired state, and the tool works out the steps. Reading a state is cheaper than replaying a history. The same is true for requirements, and the agent is the one paying the difference.

The rule has teeth. We removed two kinds of files we had started with because they described the past: change requests and separate test cases. What remained is a model where every file can be read without knowing what came before it.

The price falls on whoever writes. Rewriting an existing file is harder than appending a new one; it forces you to decide what is still true. The analysts, human or agent, have to read before they write. And rewriting only works if the file says how to check itself. That is what the next post is about.