The spec database
Why the specification stopped being a file and what that bought
The spec database
Trove used to keep specifications as Markdown files in the repository, on a branch, edited in a worktree. They are rows in a database now. This explains what that changed and why it was worth changing.
What a document could not do
A specification is a living thing: it gets refined while it is being
implemented, argued with, partially finished, and revisited. A .md file is a
poor container for that, in four specific ways.
Status has nowhere to live. You can write "done" beside a heading, but nothing can check it, nothing can count it, and two people can disagree about what it covers. Progress across twenty units means reading twenty paragraphs.
Identity is positional. Renumber a section and every reference to "§3.2" silently means something else. The thing you were pointing at has not changed; your way of naming it has.
Concurrent edits collide. A session implementing the spec and a person refining it are two writers on one file. That is what the old two-worktree lane was for — an entire mechanism, with its own rebase-and-merge choreography, existing to keep two editors of the same document apart.
History is coarse. Git records that a file changed. It does not record that this unit's definition of done changed, which is the question you have when a "done" result looks wrong.
What a database does instead
Every spec, section and work unit has a stable key the database issues and
nobody chooses. Position becomes display: CSCC.EFC.3 is derived from where a
unit currently sits, and renumbering changes the address without touching the
identity. References point at the key underneath.
Status lives on the unit, so progress is a query rather than a reading exercise. A plan holds no progress of its own — it is computed from its units every time it is asked. Nothing has to be kept in sync, which means a spec can change mid-implementation and nothing goes stale behind your back.
History is per field, appended, and never altered. "What changed in this unit, and who changed it" is an exact answer rather than a reconstruction.
Concurrency stops being a document problem. Two sessions updating two units are two row writes. The two-worktree lane went away with the problem it solved.
Nothing is ever deleted
Delete is a flag. The row stays, the key still resolves, and the history is intact. This sounds like hoarding until the first time you need to know what a unit said before somebody removed it.
The database is not reachable except through tasks
No session opens the file. Every read and write goes through the spec.* OPAL
tasks, which means every access is mediated, permissioned and attributed to
whoever made it. A session reaching in directly would bypass all three.
It also makes the surface deliberately narrow. There is no batch mutate, no regex write, no "update all matching" — the calls that let one mistake corrupt fifty rows are simply not offered.
One database per identity, per machine
There is exactly one spec database per (sentient, device) pair. The same person on another machine gets a different corpus. They are isolated, never sync, and may run at the same time.
That is a deliberate refusal rather than a missing feature. Replicating an append-only history across devices would need exactly the merge-and-reconcile machinery this design exists to avoid, and it would need it for a problem nobody has yet.
Then why publish Markdown at all?
Because somebody reading the repository in a year deserves to find something.
spec.publish renders a spec into a .md that lands with the code — a
re-derivable snapshot that says so in its own header, publishes finished work,
and states how much it left out.
The file is not the source. Editing it changes nothing, and it says that where an editor will see it, because the one mistake that would quietly undo this whole design is somebody carefully improving the markdown and expecting the database to notice.
What did not change
Your existing .md specs are exactly where they were. Nothing migrated them
automatically and nothing will without being asked. Bring them across when you
want to, on your own terms.