A series about a package that tests itself with itself
There is a TypeScript package in the @frenchexdev monorepo called requirements. It ships a set of decorators — @Requirement, @Feature, @FeatureTest, @Verifies, @Satisfies, @Refines, @Expects, @Exclude — which together let a codebase bind acceptance criteria to tests at compile time. The decorators are straightforward on paper. What makes the package unusual is that it uses its own decorators to declare its own requirements, its own features, and its own tests. The DSL validates itself with itself.
This series is a thirty-three-file, roughly thirty-two-thousand-line tour of that construction. It is the first long-form piece of writing that treats the package in full: the twenty-two requirements it declares, the twenty-five features that satisfy them, the fifty-four test classes that verify those features, the five styles it supports, the three finite state machines that drive its scenarii replay, and the meta-circle that closes when all of that machinery is pointed at itself.
It is also the first piece of writing that addresses an honest gap left by the earlier typed-specs series: the word Requirement appeared in that series' tags, descriptions, and titles, but the layer only ever modelled Feature. Requirement was rhetoric there. Here it becomes a type.
The historical path — Feature first, Requirement later
Feature has been a first-class citizen of this codebase for months. The typed-specs series in March 2026 made that citizenship public: features as abstract classes, acceptance criteria as abstract methods, three decorators to bind them to tests, a compliance scanner to catch drift. That architecture covered 112 out of 112 acceptance criteria in the SSG at the time. By any reasonable measure it worked.
What that architecture did not model — what its name suggested but its types did not carry — was Requirement as a concept separate from Feature. In typed-specs, a Feature is the requirement it addresses: there is no base class for Requirement, no relation between requirements, no way for one feature to satisfy several requirements or one requirement to be covered by several features. The vocabulary said requirement; the model said feature.
The @frenchexdev/requirements package is the move that closes that gap. It introduces a Requirement base class, twenty-two concrete subclasses, a @Satisfies relation from Feature to Requirement, a @Refines relation from Requirement to Requirement, a Style dimension that lets the same Requirement speak in five different industrial registers, and a @FeatureTest / @Verifies pairing that keeps test classes bound to Feature acceptance criteria at compile time. Then it turns all of that onto itself.
This series is the story of that delta. Each chapter answers, in one form or another, the same question: what does the word "requirement" in typed-specs mean, now that it has a type?
Why this series exists
Three reasons, stacked.
The first reason is pedagogical. The package has grown to twenty-two requirements, twenty-five features, and fifty-four test files, all bound by decorators with load-bearing semantics. Reading the source alone will not tell you why the @Refines relation exists, why there are five Styles rather than one, why the scenarii replay uses three cooperating state machines rather than one, or why the package insists on @FeatureTest and @Verifies instead of describe and it. Those decisions come from a place that the source code does not narrate. This series narrates them.
The second reason is corrective. The typed-specs series, for all its clarity, used the word Requirement in a way the model did not support. That was not a mistake of carelessness — it was the reality at the time, and the word was the right word for the direction the work was heading in. But it left a reader, who walked away from typed-specs, believing that Feature and Requirement were the same thing. They are not. This series fixes that.
The third reason is meta-circular. A requirements DSL that does not validate itself with itself is suspicious by construction. If the tool is not good enough for its own house, it is probably not good enough for yours either. The package's cornerstone requirement, REQ-DOG-FOOD, mandates exactly this self-application. Documenting that application in full is the only honest way to argue that the package is worth using outside its own walls.
Prerequisites
This series assumes a handful of things.
- You know what typed-specs is, at least in outline. If you do not, read typed-specs/01-why.md first — it sets up the problem the whole family is addressing. Come back here when you have read it.
- You agree that features and requirements are different things, even if you have not yet seen them separated in code. requirement-vs-feature.md makes the case. That post is a one-sitting read. It is the philosophical anchor for everything that follows.
- You are comfortable with TypeScript — generics, abstract classes, decorators, and the
keyof Ttrick are used throughout. If decorators orkeyofare unfamiliar, chapter03bis a fifteen-minute refresher that bridges the gap. - You have encountered Domain-Driven Design at a conversational level. The series references bounded contexts, use cases, and policies without introducing them from scratch. Chapter 20 revisits DDD through the REQ lens, but it assumes you have heard of Evans's book.
- You are not required to know Finite State Machines, SysML, SIL, ISO 29148, BDD, or Catala. These come up when they come up; chapters that lean on them introduce them.
A minimal pre-reading set, if you want to ground yourself:
- typed-specs/01-why.md — the motivation.
- typed-specs/04-features.md — the Feature-as-abstract-class move.
- typed-specs/05-decorators.md — the three-decorator toolkit.
- requirement-vs-feature.md — the definitional distinction.
That is under an hour of reading, and it makes the whole series easier.
Four reading paths
The series is long. No one reads thirty-two thousand lines linearly. These four paths pull three to five chapters each out of the whole, oriented toward what a reader in that role actually needs.
The engineer's path
If you are the person who will write @Requirement and @Feature decorators in your own codebase next week, read:
- Chapter 00 — Named but not modelled. The gap that motivates everything. Without this, the rest is mechanics without reason.
- Chapter 03 — The decorator surface. The full API tour. If you stop reading here, you can still write code.
- Chapter 03b — Newcomer primer. If TypeScript decorators or runtime registries are unfamiliar, take fifteen minutes.
- Chapter 13b — Developer experience. What using the package day to day looks like. Wizard, watch mode, trace explorer.
- Chapter 22b — A day in the life of a new requirement. End-to-end: scaffold, satisfy, test, commit, gate green.
Five chapters, roughly five thousand lines, one evening. If you do not know what to do on Monday after reading them, something has gone wrong.
The architect's path
If you are deciding whether to adopt this pattern, or adapt it, or reject it for your shop, read:
- Chapter 00 — Named but not modelled. The diagnostic.
- Chapter 01 — From typed-specs to typed requirements. The migration map. What changed, what stayed.
- Chapter 01b — The historical path. Why Feature came first and Requirement came later. This is the chapter that tells you when a project is ready for the REQ stratum and when introducing it would be premature.
- Chapter 08 — Styles: a plural rhetoric. Because your organisation has a register — industrial, lean, agile, kanban, or none of the above — and the series should meet yours.
- Chapter 19 — Lessons and anti-patterns. The failure modes you will inherit if you adopt the pattern wrong, and the when NOT to use this DSL section that tells you when the whole thing is overkill.
- Chapter 19b — External vocabulary. How the DSL maps to Jira, SysML, ISO 29148, BDD. Needed if you are comparing it to what your team already has.
Six chapters. The architect's decision usually hinges on chapters 01b and 19: is my project at the stage where this pays off, and is my shop willing to live with its constraints?
The auditor's path
If you have to decide, from the outside, whether the package's claims are true — or if you are writing compliance reports for a regulated domain and want to see what a traceable codebase looks like — read:
- Chapter 06 — Twenty-five features mapped. The
@Satisfieschains, in full. - Chapter 12 — Traceability graphs: the big picture. The REQ → FEAT → TEST graph, globally and per cluster. This is the chapter a regulatory auditor wants to see.
- Chapter 13 — Quality gates and compliance. How the gate blocks merges on orphan features, stale
@Satisfies, coverage drops. - Chapter 13c — When compliance fails. What the gate prints and how to read it. This is the chapter that tells you what a real red build in this system looks like.
- Chapter 09 — Style deep-dive: industrial / SIL. If you work in safety-critical domains, this is the register that makes the package's claims legible in your vocabulary.
- Appendix B — FAQ. The questions you will ask that the chapters do not answer directly.
Six chapters. Auditors generally read 12, 13, and 13c first and then decide whether the rest is worth their time.
The team lead's path
If you are the person who has to decide whether to spend three weeks rolling this out across your team, read:
- Chapter 00 — Named but not modelled. The story you will tell your team to motivate the change.
- Chapter 01b — The historical path. To calibrate where your own team is on the Feature → Requirement journey.
- Chapter 13b — Developer experience. To judge whether your team will tolerate the tooling day to day.
- Chapter 21 — Requirements meet the human side, revisited. Because rolling out traceability without humane defaults produces ceremony, not outcomes.
- Chapter 22b — A day in the life of a new requirement. The end-to-end you will demo to your team.
- Appendix B — FAQ, specifically the retrofit and migration questions.
Five chapters plus an appendix. If the team lead is also doing the architect's decision, swap in chapter 01 and chapter 19.
If you only read three chapters
The short list, in order:
- Chapter 00 — Named but not modelled. The gap. The thesis. The reason the series exists.
- Chapter 13b — Developer experience. What using the package feels like. The wizard, the watch, the TUI. If this chapter puts you off, the rest will not recover you.
- Chapter 22b — A day in the life of a new requirement. The full loop, from scaffold to green gate, concretely.
If these three do not convince you, the series is not going to. If they do, you can come back for the rest at leisure.
The running example
A thirty-two-thousand-line series cannot be carried on abstractions alone. Every structural claim in this series grounds itself in one of two specific features from the @frenchexdev/requirements codebase, threaded through the chapters so the reader always has a concrete target to refer to.
Primary thread — FEATURE-TRACE-EXPLORER-TUI
The primary thread is FEATURE-TRACE-EXPLORER-TUI. Four acceptance criteria. Thirty-five lines of source. Two @Satisfies links: to REQ-DISCOVERABLE-TRACEABILITY and to REQ-TUI-MODERN.
It is chosen deliberately. The feature is small enough to quote in full anywhere in the series, and its two-requirement @Satisfies chain is the smallest example in the whole package of a genuinely many-to-many link. Threads of length one — one feature satisfying one requirement — are trivial; they tell you nothing about why the DSL needs more than typed-specs had. Threads of length two or more are what the whole series is about.
FEATURE-TRACE-EXPLORER-TUI appears, named, in chapters 00, 01, 01b, 03, 06, 07, 13, 18, and the epilogue. Each of those chapters opens with a short running example reminder block and closes with a what this chapter added to our understanding of FEATURE-TRACE-EXPLORER-TUI paragraph. If you want the series in skim form, read just those paragraphs across those chapters and you will have a coherent thread.
Showcase — FEATURE-NEW-COMMAND
The showcase feature is FEATURE-NEW-COMMAND. Eighteen acceptance criteria. Seventy-five lines of source. Seven @Satisfies links, including — importantly — REQ-DOG-FOOD itself.
It is used only in two chapters: 13b (developer experience) and 22b (day in the life). Those chapters need a rich example — something big enough to carry a full scaffold-to-green-gate walkthrough, something whose @Satisfies fanout shows off what the DSL can do at full stretch. FEATURE-NEW-COMMAND is that example.
The thirty-three files
The full manifest. Each chapter links below to its own page. The brief description is the one-sentence summary the chapter owns; the line-count target is approximate.
| Order | Chapter | Description |
|---|---|---|
| 60 | index.md | This page. |
| 61 | 00-named-but-not-modelled.md | A close reading of the typed-specs series: the word Requirement was in the frontmatter, the model was always Feature. The five-axis level-up thesis. |
| 62 | 01-from-typed-specs-to-typed-requirements.md | Construct-by-construct migration map between the two designs. What carried over, what is net-new. |
| 63 | 01b-historical-path-feature-first-requirement-later.md | The chronology. Why Feature came first and Requirement came later. Why the 1:1 collapse kept Requirement invisible for months. |
| 64 | 02-why-dogfood-a-requirements-dsl.md | REQ-DOG-FOOD as axiom. The meta-circular paradox and its resolution. How the decorator-level loop deepens what tspec's own dog-fooding post gestured at. |
| 65 | 03-the-decorator-surface.md | The full API tour. Eight decorators. Runtime registry. AST pickup. keyof T enforcement. |
| 66 | 03b-newcomer-primer-abstract-classes-decorators-registries.md | A fifteen-minute TypeScript refresher for readers from other stacks. |
| 67 | 04-twenty-two-requirements-part-one.md | Requirements one through eleven. Dog-food, bootstrap, spec-source-of-truth, round-trip, editor, TUI, live-feedback, visual, discoverable, low-friction ACs, orthogonal toggling. |
| 68 | 05-twenty-two-requirements-part-two.md | Requirements twelve through twenty-two. Property invariants, refactor-safe, versioned, scenario-driven, multi-FSM, scaffold-extensibility, audit-trail, AI-as-implementer, vocab-industry-aligned, parallel deliverable, DSL complete. |
| 69 | 06-twenty-five-features-mapped.md | Every Feature in the package with its @Satisfies chain. Acceptance-criterion counts. ACResult patterns. Trace pointers into tests. |
| 70 | 07-fifty-four-tests-only-decorators.md | Every test class using @FeatureTest and @Verifies<T>. The zero-describe/it rule. How the compiler catches typo'd AC names. |
| 71 | 08-styles-a-plural-rhetoric.md | The five styles. Open/closed via registry. The same Requirement rewritten in all five registers, side by side. |
| 72 | 09-style-deep-dive-industrial-sil.md | The SIL / industrial register. When safety-critical vocabulary earns its weight. The hazard-analysis tie-in. |
| 73 | 10-style-deep-dive-lean.md | The lean style. Value stream, waste categories, flow metrics in REQ metadata. The kaizen loop next to the dog-food loop. |
| 74 | 11-style-deep-dive-ears-agile-kanban.md | The other three. EARS clauses, agile user stories, WIP-limited kanban REQs. |
| 75 | 12-traceability-graphs-the-big-picture.md | The mermaid chapter. The global REQ → FEAT → TEST graph and six per-cluster graphs. |
| 76 | 13-quality-gates-and-compliance.md | compliance --strict. One-hundred-percent coverage. Property tests at sixteen laws times two hundred runs. The 778-test suite. How the gate actually blocks merges. |
| 77 | 13b-developer-experience-tui-wizard-live-feedback.md | The DX chapter. requirements new, requirements watch, requirements trace explore. Full CLI transcripts. FEATURE-NEW-COMMAND walked end-to-end. |
| 78 | 13c-when-compliance-fails-diagnostics-and-recovery.md | The failure-modes chapter. Orphan Feature. Requirement-less feature. Stale @Satisfies. Missing @Verifies. Typo'd AC name. Coverage underflow. Real transcripts and recovery recipes. |
| 79 | 14-ast-extraction-and-registry.md | Declaration → descriptor → graph. How decorators register at runtime. How the scanner builds the trace index from source. |
| 80 | 15-scenarii-and-the-three-fsms.md | ProjectLifecycleFsm, PerFeatureFsm, PerAcFsm. Scenario replay. Cross-FSM guards. |
| 81 | 16-cross-package-adoption-typed-fsm.md | How @frenchexdev/typed-fsm declares its four REQs and seven FEATs using the package it complements. The circular dependency that isn't. |
| 82 | 17-cross-package-adoption-monorepo-sweep.md | A tour of the thirteen-plus other packages adopting the pattern. |
| 83 | 18-the-meta-circle-in-diagrams.md | The dog-fooding circularity from five angles: source, registry, scanner, compliance, audit. Requirements validate the validator that validates the requirements. |
| 84 | 19-lessons-and-anti-patterns.md | What goes wrong without this: describe/it drift, string-magic AC refs, orphan tests, stale @Satisfies, requirement-less features, feature-less requirements. Plus a section on when NOT to use this DSL. |
| 85 | 19b-external-vocabulary-jira-sysml-iso-29148-bdd.md | The map-placement chapter. Jira Epic/Story, SysML «satisfy»/«deriveReqt», ISO 29148 stakeholder/system/software strata, BDD Feature/Scenario. Where the mappings hold; where they break. |
| 86 | 20-requirements-meet-ddd-revisited.md | The DDD slot map revisited. Bounded context = FEAT. Use case = AC. Policy = REQ. The missing DDD slot that typed-specs could not fill. |
| 87 | 21-requirements-meet-human-side-revisited.md | Keeping the tool humane when REQ count scales. Friction budget. AC suggestion heuristics. The bootstrap command as a politeness. |
| 88 | 22-roadmap-and-open-questions.md | REQ-AI-AS-IMPLEMENTER-ADAPTER, REQ-VERSIONED-TRACEABILITY, REQ-AUDIT-TRAIL-HOOKS. What's next. The typed-specs v2 roadmap items that are and aren't addressed. |
| 89 | 22b-a-day-in-the-life-of-a-new-requirement.md | The end-to-end worked example. Scaffold a new REQ. Wire a Feature. Write the test. Watch the gate flip red → green. Commit by commit. |
| 90 | appendix-a-glossary.md | Alphabetical glossary. Every REQ, FEAT, Style, decorator, and vocabulary term. Each entry deep-linked to its defining chapter. |
| 91 | appendix-b-faq.md | Twenty-five practical questions. Retrofit? Vitest? Jira? Transitive @Refines? Migration? |
| 92 | appendix-c-bibliography-and-prior-art.md | The intellectual map. Meyer, Sowa, Lamport, Alloy, SysML, ISO 29148, Catala, Russell. Each with how it shapes the DSL. |
| 93 | epilogue.md | typed-specs was a ladder; this is the roof. A short close. |
Three appendices, in short
The appendices are reference material, not narrative.
Appendix A — Glossary is the alphabetical index. If you lose track of which Requirement is which, or which Feature @Satisfies which REQ, or which decorator returns what, A is where you look. Every entry is deep-linked into the chapter that defines it.
Appendix B — FAQ answers the twenty-five or so questions that readers actually ask. Can I retrofit this on an existing project? What if I don't use vitest? Why not just use Jira Epics? Does @Refines compose transitively? Can features have parents? Can I plug my own Style? Each answer is short and points at the chapter that explains it in full.
Appendix C — Bibliography and prior art places the DSL on the intellectual map. Bertrand Meyer's Design by Contract. John Sowa's Conceptual Graphs. Leslie Lamport's TLA+. Alloy. SysML. ISO 29148. Catala. Russell's type theory. Each entry is paired with how it shapes the DSL — not generic citation, directed citation.
Next steps after finishing
If you finish the series, the series has not done its job. The series exists so that you can do something else. Here are the something-elses, in recommended order.
Clone the monorepo. Build and run it locally. Open packages/requirements/. Look at the source. Verify that what the series claims about the source is true. If you find a divergence, the source is the truth — update your mental model, and send a correction.
Run
requirements newinside the package itself. Scaffold a throwaway requirement. See the wizard. See the generated.spec.json. See the TypeScript file it produces. Throw it away. You will never read about the wizard the same way again.Run
requirements compliance --strict. Watch it pass. Then break something intentionally — delete a@Satisfies, rename an AC, remove a@FeatureTest. Run it again. Watch it fail with the kind of error message you wish every test runner produced.Look at your own project. Open its test suite. Count the
describeblocks. For each, ask: what Requirement does this Feature satisfy? If the answer is a URL to a Jira ticket, or a Confluence page, or nothing at all, you have just found the first candidate for@Requirement.Write the smallest possible Requirement class. One AC. One Feature that satisfies it. One
@FeatureTestthat verifies it. Fifty lines of TypeScript, total. Run it. See that it works. You now know the DSL in the only way that matters.Read the earlier work. typed-specs/, typed-specs-product/, typed-specs-vs-others/. Not as prerequisites anymore — as back-story. You will read them differently now.
A note on scope
Thirty-two thousand lines of markdown across thirty-three files is a lot. The decision to write it at that length was deliberate.
The material is genuinely layered: there are at least five concerns (definitions, decorators, enumeration, styles, FSM orchestration) that interact, and each one rewards patience. A shorter piece would have had to pick one and ignore the others; it would have taught you the tool partially, and the most important thing about the tool — the way its concerns fit together into a meta-circle — would have disappeared.
The alternative to writing this once, at length, was writing it five times, partially, across five years. That has been the pattern of the corpus so far. This series breaks the pattern.
That said: the series is written so that you can not read it linearly. The four persona paths above pull out three-to-five-chapter paths for specific readers. The three appendices are reference material you can return to without re-reading the narrative. The running examples let you skim for concrete material without losing the thread. Read it the way that serves you.
A note on style
The series is dense where the material is dense and plain where it isn't. It does not try to be clever. Where a sentence has to carry three concepts, it carries three concepts; where it only needs to carry one, it carries one. This is a stylistic choice — not a concession to brevity.
The goal of the writing is that a reader who finishes the series can explain the DSL to someone else without re-reading the source. That is a higher bar than can understand the DSL. Understanding is the floor. Explanation is the ceiling. Everything in between is craft.
On meta-circularity
A closing paragraph for this page — the rest of the series will have many more.
A requirements DSL that does not validate itself with itself is suspicious by construction. The reasoning is not subtle. If the tool's authors were unable, or unwilling, to apply the tool to their own work, then either the tool is too inconvenient to use (in which case it will also be inconvenient for you) or the tool is not actually good enough to produce the guarantees it claims (in which case it will not produce them for you either). The authors' willingness to eat their own dog food is weak evidence — weak because the authors are biased — but it is the strongest evidence available. A tool that fails this test fails the floor.
@frenchexdev/requirements passes the test. Twenty-two requirements. Twenty-five features. Fifty-four test classes. Zero describe. Zero it. A compliance --strict gate that returns PASS. One hundred percent coverage. Sixteen algebraic invariants checked two hundred times. The decorators declared above are the decorators applied below. The scanner that audits consumer projects audits this workspace. The same code path that tells your team that your own @Satisfies link is stale tells this package that its own @Satisfies link is stale. The loop closes.
The rest of the series is a tour of that loop.
Start at chapter 00.
Related Reading
- requirement-vs-feature.md — the definitional post the series leans on as prerequisite.
- typed-specs/index.md — the predecessor series; read its introduction before starting chapter 00.
- typed-specs-product/10-dogfood.md — the tspec-product take on dog-fooding; chapter 02 complements it rather than duplicating it.
- typed-specs-vs-others/index.md — the comparison hub; chapter 19b builds on it with an additional set of vocabularies.
- a-style-is-a-tiny-compiler.md — the philosophical anchor for the styles arc (chapters 08 through 11).
- finite-state-machine.md — the FSM anchor for chapter 15.
- requirements-meet-ddd.md — the DDD mapping; chapter 20 revisits it with the Requirement stratum.
- requirements-human-side.md — the human-factors companion; chapter 21 revisits it in the context of scale.
- closing-the-loop/index.md — the vision hub for feedback loops in software; chapter 18 is a closing-the-loop instance.