The tool, and the contract
Throughline is a Git-native requirements tool. Every requirement is one small YAML file with a permanent UID. Every non-root item must ground upward, through a typed link, to a root that justifies it: an intent, a legal constraint, a risk. A validator, tl check, fails the build on an orphan, a dangling link, an illegal status move, or a document that no longer matches the graph. A companion, tl-compose, lets one graph borrow items from others by tag, so a project cites WCAG or the UK GDPR as items rather than restating them.
What made it a foundation for two parties rather than a file format was a small contract, followed without exception across the three days:
- The AI authors every item with
origin: ai. Such an item is born proposed and counts for nothing until a human ratifies it. Ratification writes the human's name and a fingerprint of the content into the file; change the content and the gate reports the signature stale. - The human never edits an item by hand. They ratify, reject, or ask for a change. The AI never runs
tl ratify. - Every commit names the item it serves. Every document that residents or regulators read is generated from the graph and gated: an item changes, the document is stale until regenerated.
- A claim about the law or a standard is a
satisfieslink to a clause that was read. The gate proves the link resolves; only reading proves it is true.
Two graphs, and what they compose
The work ran on two graphs in two repositories. The specification holds the intents, constraints, risks, assumptions, non-goals, requirements, journeys, pages and tests, and composes seven public sources by tag. The implementation, in the service's own repository, pins the specification at a tagged edition and borrows two more sources of its own. Every link that crosses from one graph into another is stamped with a fingerprint of its target, so an amended clause or a moved source marks its dependants suspect in the graph that cites it.
The specification graph
Seven sources were composed over the three days, each pinned by tag: WCAG 2.2 cited at A and AA only; OWASP ASVS 5.0.0 at Levels 1 and 2 only; the SOLID principles as the bar for how the code is written; plain-language and general-reader writing rules for everything a resident reads; the UK GDPR as a law source; and a pattern source for erasure and anonymisation written that week. Every one of the 150 satisfies links names a clause whose text was read first.
Two things happened that only a composed graph allows. When the law source gained the erasure and time-limit articles, two local constraints that restated them were retired and the items beneath them re-grounded on the source's own obligations. And when the pattern source's vault rule turned out not to fit a resident with several notices, the fix went into the source first, the source was re-tagged, and the register re-pinned and cited the new rule. The AI also learned it had been wrong about a tool limit: transitive sources are handled by re-export from the source that composes them, and the correction went into its memory the same hour.
Registers rebuilt: journeys and pages as items
The graph began with one requirements register. When the human asked for user and system layers, journeys and a site map, nothing was yet ratified, so the registers were rebuilt rather than tombstoned: ten user requirements grouped by journey, the system requirements keeping their numbers, then a JNY register whose items carry an ordered list of steps, and a PAGE register whose items carry a route and an access level. A journey refines the user requirement it serves and each step names the page it lands on.
The journeys immediately found two holes the system requirements alone had passed every check with. A journey promised a fresh link that no requirement offered. A journey and a page walled the controller area behind sign-in that no requirement required. Both became system requirements with tests. A graph of behaviours is checked by walking it; a graph of requirements is only checked by reading it.
The constraint register shows the other kind of rebuild. Twenty-one constraints were authored across the three days; two were retired, not deleted, when the composed law source absorbed what they restated. Their UIDs are never reused, and the items that had derived from them were re-grounded on the source's own clauses in the same commit.
The implementation graph
The implementation lives with the service's code and is the smaller graph: requirements that implements a clause of the pinned specification, architecture decisions that derives_from those requirements, and a test for every requirement, one test file per specified test, 142 of them at v0.7.1. Its throughline.toml pins the specification by tag and borrows two sources of its own for how the code is written.
Its gate is stricter than the specification's in one respect: it stamps every link into the specification and refuses to build when the controller's sign-off dates on the generated documents fall behind the pinned commit. A specification that moves without the implementation cannot be built against, by construction.
One instruction from the human, all data encrypted at rest and in transit, produced three implementation requirements with tests and decided the database question: a dedicated instance on an encrypted volume rather than the shared one whose administrative credential sat in fifty namespaces.
Documents generated from the graph
The legitimate interests assessment, the record of processing, the privacy notice, five escalation covering letters and six resident letter templates were all generated with tl docs: hand-written prose around regions injected from the items, so a change to a retention clock stales the record of processing until it is regenerated, and tl docs --check fails the build until it is. The privacy notice was measured against the reading-age target the graph's non-functional requirement set: the first draft scored about fourteen, the rewrite about nine. The check that measured it became a script in the repository, then a test in the built service.
The human's three wording faults, "address" read as postal, a notice that overstated what the register does, a sentence pointing residents at a repository, became four naming rules in the writing requirement, then a checkable function in the test suite, which on its first run found two more faults nobody had noticed.
The challenge pass
A sibling tool, throughline-challenger, exists to find what a structural gate cannot: a child stronger than its parent, a UID mentioned in prose with no edge, two names for one thing, a universal claim with one narrow child, a rationale that would break a sibling, a requirement with no failure clause. Its nine checks were run by hand five times, each after a change large enough to hide something.
The first pass found eighteen items citing others in prose with no link, five priorities that understated a statutory duty, and a pack that would have sent per-case detail to the press. The fifth found one contradiction between the vault rule and the records list, by holding two ratified items side by side. Each pass was cheaper than the last.
Editions, ratification, and the gate
| Edition | When | What it held |
|---|---|---|
| v0.1.0 | 9 Sep | 164 items, all ratified in one sitting |
| v0.2.0 – v0.6.6 | 9–10 Sep | the human's iterations, each amendment re-ratified before the next tag |
| v0.7.0 | 11 Sep | naming rules; residents send the pack |
| v0.7.1 | 11 Sep | the notice's maintainers' note moved |
Ratification is tl ratify <UID>: it writes the ratifier's name and a fingerprint of the item's normative content into the file. Amend the item and the gate reports the fingerprint stale until the human ratifies again; that is what made twenty editions safe to iterate on. Within one day of the first commit the human had ratified every item, twelve constraints while the AI was still mid-turn, which the AI's git add -A swept into its own commit. The fix was a habit, stage explicit paths, and a memory note.
The gate ran on every commit in both repositories:
--strict turns a proposed item or a stale ratification into an error rather than a warning, so a specification with anything unaccepted in it cannot be tagged.
What the tooling taught
--strict said so on every run.satisfies link is a claim. Reading the clause first turned two standards into design changes nobody had planned: deletion confirmation from WCAG and per-record keys from the pattern source.docs --check holds them there.git add -A will claim their signatures.