Skip to content

Working on specs

When a spec is required

Before any implementation change. Write or update the spec, get it agreed, then implement โ€” and update the spec if reality forces a change while implementing.

Exempt: typos, formatting, dependency bumps.

Before writing one

Read docs/specs/index.md first. Most of the time the topic is already covered and the change belongs in an existing spec; a second spec on the same topic leaves two documents that disagree, and neither is authoritative.

Writing one

One file per spec, <kebab-case-topic>.md, stating what and why: purpose, scope, behaviour, data shapes, edge cases, non-goals.

The line that takes the most judgement is how much of the implementation belongs in the spec. A spec may describe non-trivial interfaces, which implementations should exist, and an implementation's behaviour when that behaviour is non-trivial โ€” including the algorithm itself when the algorithm is the requirement, as with the precedence and dedup rules in layered-fs.md. What it must not contain is the code: not the concrete structure of a function, not its naming, not a snippet standing in for the real thing. Describe the algorithm so it can be judged and re-derived, not so it can be pasted.

The Non-goals section does more work than it looks like it does. Most of this project's design pressure is toward doing more โ€” merging entry contents, caching for speed, writing through to sources โ€” and a non-goal is how a spec records that the option was considered and declined, so the next contributor does not relitigate it silently.

Indexing it

Update docs/specs/index.md in the same change: a row with a one-line description and a status.

Status Means
draft proposed, not yet agreed
accepted agreed, not yet built
implemented matches the code
superseded kept for history; the row points at its replacement

make lint fails on a spec that is not indexed and on an index row pointing at a document that does not exist. See quality-gates.md.

Keeping it true

A spec marked implemented that no longer matches the code is worse than no spec, because it is trusted. When implementation forces a change, the spec changes in the same commit as the code. When a spec is replaced, mark the old one superseded and point at the replacement rather than deleting it โ€” the history of why a design was abandoned is the part nobody can reconstruct later.