Skip to main content
Welcome. This site supports keyboard navigation and screen readers. Press ? at any time for keyboard shortcuts. Press [ to focus the sidebar, ] to focus the content. High-contrast themes are available via the toolbar.
serard@dev00:~/cv

Appendix C — Bibliography and Prior Art

No DSL is invented from nothing. This appendix names the fifteen debts @frenchexdev/requirements carries, and draws the short line from each debt to a specific piece of the package.

The package this series describes is small — a handful of decorators, a registry, a style enum, a compliance report. Its intellectual surface is not. Every design decision it makes is an echo, a translation, or an inversion of someone else's prior idea. This appendix is the honest ledger of those debts.

The shape of the ledger is deliberate. I do not list a hundred adjacent references and let the reader extract the influence. Instead I name fifteen sources that actually shaped code that exists in the repository today, and for each one I give three to five paragraphs explaining how the influence landed: who the author is, what the core idea is, how it appears in the DSL, and — this is the load-bearing part — what the DSL deliberately does differently. An influence is not imitation. Tracing the divergence is how you tell the two apart.

A short closing section notes what is not here. Petri nets, Z, VDM, and a handful of other formalisms are adjacent to this work but did not shape it. Pretending otherwise would be academic signalling. The omission is itself a design statement.


1. Bertrand Meyer — Eiffel and Design by Contract

Bertrand Meyer is the Swiss-French computer scientist who designed the Eiffel language in the mid-1980s and, in Object-Oriented Software Construction (1988, second edition 1997), made the case that correctness is a relation between specification and implementation, not a property of code alone. His central mechanism — preconditions, postconditions, class invariants, all expressed as executable boolean assertions attached to methods and classes — became known as Design by Contract. I read the second edition in my early twenties. It is the single most formative programming book I have ever encountered, and its fingerprints are on every piece of the DSL discussed in this series.

The core move Meyer makes is to reject the software engineering folklore that specification is fuzzy and code is precise. In his formulation, both are precise, both are executable, and both live in the same file. A routine that claims require x > 0 and ensure result * result = x is not merely documented — it is legally bound. The contract is the signature. Callers have a right to it. Implementations have a duty to it. Violations are runtime exceptions in Eiffel, but the epistemological point is deeper: the contract is where the meaning lives, and the body is simply one of infinitely many possible ways to satisfy it.

The ACResult pattern carried across from typed-specs and extended in @frenchexdev/requirements is a direct translation of this idea into TypeScript. Each acceptance criterion on a Feature is a method. Each method returns a result that is either "satisfied by this artefact" or "not yet". The decorator @Satisfies(Requirement) attached to a Feature class is, literally, a contract assertion: this Feature claims to discharge those Requirements. The compliance report is the runtime check. When the report says satisfies(FEAT-X, REQ-Y) = true because AC-3 of FEAT-X returned satisfied, it is performing exactly the check Eiffel performs at the method boundary — only now the "method boundary" is the boundary between the Feature stratum and the Requirement stratum.

Where the DSL diverges from Eiffel is in who writes which half. In Eiffel the programmer writes both the precondition and the body, and the contract is local to a single class. In the DSL the Requirement is written by the specification author (often a different person, often at a different time, sometimes by a legal or regulatory authority) and the Feature is written by the engineer. The contract is explicitly not local: it crosses a stratum boundary. This is why the package models Requirements as their own first-class decorated classes rather than as assertion strings on Feature methods. A contract between two strata needs two parties. Meyer wrote both halves in the same file because his target was one person writing robust code; the DSL targets two teams writing aligned artefacts, and the asymmetry shows.

A small homage worth naming: Meyer's insistence that comments are contracts you cannot trust — that anything important enough to say in prose should be expressible in executable form — is the direct ancestor of the @Satisfies decorator replacing the phrase "implements REQ-X" in prose. Every chapter in this series that complains about rhetorical requirements ("the word was already there, the type never was") is, underneath, repeating a point Meyer made in 1988.


2. John Sowa — Conceptual Graphs

John F. Sowa is the American computer scientist who, in Conceptual Structures: Information Processing in Mind and Machine (1984), introduced Conceptual Graphs — a graph-theoretic knowledge representation that fuses Charles Sanders Peirce's existential graphs with the frame-and-slot semantic networks of 1970s AI. I met Sowa at eighteen, in circumstances I have written about elsewhere on this site. The meeting did not make me a logician, but it did make me take seriously the idea that knowledge is a relation, not a list.

Conceptual Graphs model a domain as a bipartite graph of concepts (the nodes that name things) and conceptual relations (the nodes that name how things are related). A sentence like "a cat is on a mat" becomes three nodes — CAT, ON, MAT — with the relation node connecting the two concept nodes. The power of the representation is that it scales: complex propositions compose into larger graphs by attaching relation nodes to concept nodes to relation nodes, recursively, without ever needing a distinction between "data" and "metadata". Everything is graph. Queries are subgraph matches. Inference is graph transformation.

The REQ refinement tree in @frenchexdev/requirements is a deliberately modest descendant of this idea. A parent Requirement and its children are concept nodes; @Refines(Parent) is a conceptual relation; the relational surface is walkable, queryable, and transformable by the same code regardless of which Requirement you start from. When the compliance report answers "which Requirements does FEAT-X ultimately satisfy, including ancestors reached by transitive @Refines?" it is performing a subgraph match in the Sowa sense. The traceability graph discussed in Chapter 12 is, structurally, a small Conceptual Graph.

What the DSL does differently — and this is a conscious simplification — is refuse the full generality of Conceptual Graphs. Sowa's graphs allow arbitrary n-ary relations, quantifiers, contexts (graphs nested inside other graphs), and a typed hierarchy of both concepts and relations. The DSL allows only two relations (@Refines parent-child, @Satisfies feature-to-requirement) and flat typing. The reason is not purity; it is readability. A monorepo with three hundred Requirements and a hundred Features needs a relational model a junior engineer can hold in their head in five minutes. Sowa's full calculus cannot be held in anyone's head in five minutes. The DSL takes the shape of the idea (graph of typed relations, queryable in code, no prose) and refuses its depth (contexts, quantifiers, higher-order relations). The divergence is the point.

A specific echo worth calling out: Sowa's insistence that a knowledge representation must be both logically adequate and cognitively plausible — formal enough to reason over, humane enough to read — is the exact tension the DSL lives inside. The TypeScript decorator syntax is the cognitive-plausibility concession. The registry, the FSM, and the compliance report are the logical-adequacy concession. Neither wins. Both are necessary.


3. Leslie Lamport — TLA+ and Specification as Executable Mathematics

Leslie Lamport, the American computer scientist behind Paxos, LaTeX, and the Lamport timestamp, designed TLA+ (the Temporal Logic of Actions) in the 1990s and spent the next thirty years arguing that engineers should write specifications the way mathematicians write proofs: in a formal language, with a mechanical checker, before writing any code. His book Specifying Systems (2002) and his essay Thinking for Programmers make the case with a patience that is, even two decades on, rare in the field.

The central move TLA+ makes is to describe a system as a set of states and a next-state relation, and to express safety and liveness properties as temporal logic formulas over traces of states. The TLC model checker then exhaustively explores the state space and reports any trace that violates a property. This is not testing — testing samples; TLA+ enumerates. It is also not proof — proof is deductive; TLA+ is operational. It sits in between, and that in-between position is exactly the niche the Scenarii FSM in @frenchexdev/requirements tries to occupy.

The Scenarii FSM described in Chapter 15 is a small, typed, statically-declared state machine attached to a Requirement. Its states are labelled phases of an acceptance scenario — initialising, ready, user-action-pending, verifying, accepted, rejected — and its transitions are labelled by the events the Feature must handle. The FSM is not a mere diagram: it is a typed value in the @frenchexdev/typed-fsm package, and the compliance report walks it the same way TLC walks a TLA+ spec, verifying that every declared transition has a corresponding acceptance criterion on the Feature.

Where the DSL diverges from TLA+ is in scope and ambition. TLA+ models the whole system, including concurrency, message passing, and timing. The Scenarii FSM models one scenario of one Requirement. TLA+ proves safety and liveness by exhaustive exploration. The Scenarii FSM merely checks that the Feature has a code path for each declared transition. The DSL is to TLA+ what a kitchen timer is to a cesium clock: same underlying intuition about the shape of time, radically different scale. Lamport would, I suspect, regard the Scenarii FSM as a specification in the trivial sense — a description of the happy path plus a few error branches. That judgement is fair. The DSL's bet is that trivial specifications, made ubiquitous by a decorator syntax cheap enough to attach to every Requirement, beat sophisticated specifications nobody writes.

The deepest debt is not technical but attitudinal. Lamport's refrain — "if you don't start writing specifications before you start writing code, you are not engineering, you are coding" — is the sentence this entire blog series is an extended response to. The dog-food discipline (zero describe, zero it, every test annotated with @FeatureTest / @Verifies) is a way of making that refrain operational in a JavaScript shop that will not adopt TLA+. The Scenarii FSM is the most Lamport-shaped thing in the package; the rest of the package is an attempt to import Lamport's posture into a tradition that historically resisted it.


4. Daniel Jackson — Alloy and Relational Specification

Daniel Jackson is the British-born MIT computer scientist who designed Alloy in the early 2000s and wrote Software Abstractions (2006, second edition 2012), the canonical text on lightweight relational specification. Alloy is a specification language based on first-order relational logic, with a model finder (the Alloy Analyzer) that exhaustively searches for instances — tiny example worlds — that satisfy or violate a claim. Where TLA+ focuses on state traces, Alloy focuses on structural invariants: does a model admit any instance at all? Does every instance satisfy this property?

The insight from Alloy most directly visible in @frenchexdev/requirements is Jackson's treatment of links as first-class citizens. In Alloy, a relation like owner: Pet -> Person is not syntactic sugar for a field on a class; it is a set of tuples that can be queried, composed, and transformed. The many-to-many link between Feature and Requirement in the DSL — where one Feature may @Satisfies several Requirements and one Requirement may be satisfied by several Features — is modelled exactly this way. The FeatureRegistry and RequirementRegistry expose the satisfies relation as a set of tuples, not as a field on either side. The compliance report is, operationally, a series of relational joins.

Jackson's methodological argument is equally important. In Software Abstractions he makes the case for incremental specification: start with a model so small you can enumerate its instances by hand, check it with the Analyzer, extend it, check again. Do not try to specify the world. Specify one corner of it, verify the corner, and let the corners accumulate. This is structurally the same advice as "ship a tiny diagnostic, see what falls out, then decide" — a principle I have internalised on this project independently of Alloy, but the convergence is not accidental. Incremental specification is the only kind that survives contact with real codebases.

Where the DSL diverges is, again, scope. Alloy has a model finder. The DSL has no model finder — it has a compliance report that checks a specific, already-constructed model against its declared constraints. Alloy can tell you whether your specification is consistent with itself. The DSL can only tell you whether your code matches your specification. The former is the deeper service. The latter is the service I can actually get a development team to adopt. Jackson, like Lamport, would regard this as a reduced ambition. The bet, again, is on adoption: a decorator is cheap, a model-finder workflow is not, and the cheap thing that gets used beats the sophisticated thing that does not.

One small homage: the appendix in Software Abstractions where Jackson lists the handful of "classic problems" Alloy handles well — the memory-model problem, the naming-environment problem, the access-control problem — is the template I used for the catalogue of styles in Chapter 08. Each style in the DSL is a classic Requirement shape the same way each problem in Jackson's appendix is a classic Alloy shape. The indebtedness is structural, not surface.


5. SysML — INCOSE and the Vocabulary of Cross-Stratum Requirements

SysML (Systems Modeling Language) is the UML profile standardised by the Object Management Group and the International Council on Systems Engineering (INCOSE) in 2007, intended to bring modelling rigour to hardware-software systems where UML alone was insufficient. I am not a systems engineer, and I have not worked in industries where SysML is the lingua franca (aerospace, automotive, medical devices). But its vocabulary is the most direct public-standard equivalent to what @frenchexdev/requirements models, and pretending otherwise would be ignorance.

The parts of SysML the DSL echoes are three specific stereotypes on its Requirement diagrams: «satisfy», «deriveReqt», and «verify». A SysML «satisfy» relation connects a design element (a block, a component, an activity) to a Requirement it discharges. A «deriveReqt» relation connects a parent Requirement to a child Requirement refined from it. A «verify» relation connects a test case to a Requirement it exercises. The correspondence with the DSL is not coincidental: @Satisfies is SysML's «satisfy», @Refines is «deriveReqt», and the @FeatureTest / @Verifies pairing from the test layer is «verify». I chose the decorator names to be translatable into SysML terms, because any reader who already knows SysML should be able to read a DSL class diagram without a glossary.

What the DSL does differently is place these relations in executable TypeScript instead of a graphical modelling tool. SysML is, in the practising-engineer's experience, almost always rendered in a tool like Cameo or MagicDraw — diagrams as the primary artefact, code generation as a secondary export. The DSL inverts this: code is the primary artefact, and the diagrams (when rendered at all) are exports. The inversion is not aesthetic. It is about the single source of truth. When a SysML diagram and a codebase drift, the team has to choose which is canonical; in practice, code wins and the diagram rots. The DSL avoids the drift by refusing to have a separate diagram to rot.

A second difference worth stating: SysML is a profile of UML, which means its Requirement type is a class stereotype rather than a first-class language construct. This matters because it makes SysML's Requirements easy to add to any UML tool but hard to constrain. In the DSL, Requirement is a first-class abstract class with a statically-typed lifecycle FSM, a Style enum, and a required Source. Tools cannot weaken these constraints without rewriting the package. SysML tools routinely allow Requirements without IDs, without parents, without verification links — "allowed but discouraged". The DSL forbids these shapes at compile time. This is what it means to be a DSL rather than a profile: the language is the enforcement mechanism.

The intellectual debt is nonetheless significant. The DSL's bet that requirements are a kind of thing worth naming in the type system, with prescribed relations to other kinds of things is the same bet SysML made twenty years ago, in a different industry, with different tools. Calling this appendix a "prior art" survey without naming SysML would be dishonest.


6. ISO/IEC/IEEE 29148 — Requirements Engineering Standard

ISO/IEC/IEEE 29148 is the joint international standard for requirements engineering, first published in 2011 and revised in 2018. It supersedes the older IEEE 830 and provides a framework for writing, managing, and verifying requirements across the stakeholder, system, and software tiers. I keep a copy of the 2018 revision on my shelf because it is the closest thing the requirements-engineering world has to a neutral vocabulary — something you can cite in a document intended for an auditor without inviting a vendor war.

The stratification the standard draws is load-bearing for the DSL. 29148 distinguishes stakeholder requirements (what the world wants from the system, phrased in the world's vocabulary), system requirements (what the system must do, phrased in system vocabulary), and software requirements (what each software component must do, phrased in component vocabulary). The three tiers exist because no single language can honestly address all three audiences. A stakeholder cannot read a software requirement; a software engineer cannot act on a stakeholder requirement. Translation across the tiers is where requirements engineering lives or dies.

The DSL's DefaultStyle is deliberately aligned with the 29148 system requirement tier: prose-centred, stakeholder-readable, but with enough structure (ID, source, parent, priority) to be tracked mechanically. The IndustrialStyle discussed in Chapter 09 is aligned with a subset of 29148 appropriate to safety-critical software requirements. The LeanStyle and the others are intentionally not standard-aligned — they are vocabularies chosen by specific communities (lean manufacturing, agile teams, kanban practitioners) that the standard does not privilege. Stylistic pluralism is the DSL's concession to the fact that 29148 is a minimum, not a ceiling.

Where the DSL diverges is in treating the standard as one valid style among several rather than the canonical form. A 29148-orthodox shop would regard this as heretical: the standard exists precisely to prevent stylistic drift. My counter-argument, made in Chapter 19b, is that 29148 was written for organisations that need a single shared form across decades and auditors. Smaller teams, or teams working across multiple domains (legal software, medical software, games), need a framework that admits local vocabulary without losing cross-vocabulary traceability. The Style enum is that concession. 29148 is honoured in DefaultStyle; it is not the whole package.

A specific operational debt: the standard's insistence that every requirement must have a unique identifier, a source, and a verification method is implemented literally in the DSL's abstract Requirement class. A TypeScript Requirement that omits any of the three fails to compile. The compile-time enforcement is, I believe, a stronger guarantee than any process-based enforcement 29148 itself can prescribe, because processes degrade and compilers do not.


7. Catala — Denis Merigoux, Inria, and Law-as-Code

Catala is a domain-specific language for encoding legal texts, designed by Denis Merigoux and collaborators at Inria starting around 2019, with a first public release in 2020. It is, to my knowledge, the first programming language explicitly designed to be co-authored by lawyers and engineers — its syntax interleaves the original legal article (in French, English, or Polish) with the executable formalisation, so that a reader following the law clause-by-clause can verify the code clause-by-clause. Merigoux's papers, especially Modernising French Tax Code with Catala (POPL 2021), are essential reading for anyone interested in domain-specific languages that serve two distinct professional communities at once.

The Catala team's central insight is that legal texts are already a DSL, written in a specialised natural language with conventions (definitions, exceptions, derogations, default-case structures) that closely mirror programming-language constructs — but that the specialisation is opaque to engineers, and the executable gap between a tax law and a tax engine is, in practice, where billions of euros of compliance cost live. Catala closes the gap by making the gap visible: every legal article appears in the source file, and every derogation is a pattern-matched exception in the executable.

The influence on @frenchexdev/requirements is not at the syntactic level — the DSL is not a mixed natural-language / code file, and it has no ambition to encode statute. The influence is at the discipline level. Catala taught me that a DSL whose target domain has its own literate register should preserve that register in the source, not translate it into a neutral programmer-idiom. The Style enum is the direct consequence. A Requirement authored in the industrial tradition should sound industrial when read back; a Requirement authored in the lean tradition should sound lean. The DSL does not normalise these registers into a single "Requirements English". It preserves them and gives each its own printer.

The second influence is methodological: the Catala team ships their language alongside real legal corpora — the French tax code, the French family allowance code — and measures the language's adequacy by whether lawyers can read the result back. The DSL makes the same bet at smaller scale. The test of IndustrialStyle is whether a safety engineer trained in IEC 61508 can read a Requirement authored in it without feeling translated-at. The compliance report, when rendered for an industrial-style Requirement, preserves the SIL vocabulary. This is the Catala move, adapted.

Where the DSL diverges is in refusing Catala's depth. Catala is a language with its own parser, its own compiler, its own default-logic semantics (derived from Sarukkai and Shin's default logic). @frenchexdev/requirements is a set of TypeScript decorators. Catala's domain demands its depth: you cannot encode French tax law in decorators. The DSL's domain does not: you can encode a software Requirement in decorators, provided the decorators are the right ones. Recognising which problems demand a new language and which demand a good library is itself part of the Catala lesson, and one I hope to have applied with some discipline.


8. Bertrand Russell — Principia Mathematica and Type Theory

Bertrand Russell's contribution to the foundations of mathematics — in the three volumes of Principia Mathematica, co-authored with Alfred North Whitehead between 1910 and 1913 — is far outside the professional territory of a software engineer. I invoke it here because the specific idea of type theory, as Russell developed it in response to his own paradox about the set of all sets that do not contain themselves, is the deep philosophical root of the thesis underlying the entire DSL: requirements are not documents; requirements are types.

The Russellian move is subtle. When you try to define the set of all sets that do not contain themselves, you generate a paradox: such a set both contains itself and does not. Russell's response was to introduce a hierarchy of types — individuals at level zero, sets of individuals at level one, sets of sets at level two, and so on — and to forbid self-reference across levels. A set cannot contain itself because containment is a relation between a level-n set and a level-(n-1) object. The paradox dissolves not by cleverness but by stratification.

Every modern type system — Hindley-Milner, System F, Martin-Löf, Haskell's, TypeScript's — descends from this insight. A value has a type, a type has a kind, a kind has a sort. The hierarchy is the mechanism that keeps meaningful statements meaningful. And here is the specific claim the DSL makes: a requirement has the same epistemic role in a project that a type has in a program. It is not data. It is not documentation. It is the predicate that tells you whether an artefact (a Feature, a test, a commit) is or is not an instance of what the world asked for.

This is what it means for @frenchexdev/requirements to model Requirements as TypeScript abstract classes. A class in TypeScript is, precisely, a type. A @Satisfies(ReqDogFood) decorator is, precisely, a predicate of type-membership: this Feature is an instance of the kind of thing that discharges this Requirement. The compiler can check the shape; the registry can check the link; the compliance report can check the transitive closure. Parse, don't validate — the phrase Alexis King made famous in 2019 — is the direct operational descendant of Russell's stratification. A validated document is data about data; a parsed type is the thing itself.

Where the DSL diverges from the full depth of type theory is in refusing dependent types. A dependent type system (Coq, Lean, Agda) could express Requirement-level propositions of arbitrary complexity — "for every user X and every input Y, this Feature produces an output satisfying predicate P(X, Y)" — and mechanically check them. The DSL expresses a much weaker class of propositions: "this Feature declares satisfaction of this Requirement, and its tests cover the declared acceptance criteria". This is a Russell-shaped idea with Meyer-shaped ambition. The full Russell programme waits for a reader willing to adopt Lean or Agda; the DSL is the entry-level version, in a language engineers already use.


9. Toyota Production System / Lean — The Kaizen Parallel

The Toyota Production System, codified by Taiichi Ohno in the 1970s and popularised outside Japan through James Womack and Daniel Jones's The Machine That Changed the World (1990) and Lean Thinking (1996), is a manufacturing philosophy whose intellectual core is the kaizen loop: small, continuous, employee-driven improvements to the process itself, anchored in respect for the people doing the work. I have no manufacturing background. The influence on the DSL is, nonetheless, specific and named.

The LeanStyle vocabulary exposed in Chapter 10muda (waste), poka-yoke (error-proofing), jidoka (automation with a human touch), heijunka (levelling), the distinction between value-adding and non-value-adding activity — is not a cosmetic translation. Each term names a kind of Requirement that a lean-trained organisation knows how to write and verify. A muda Requirement is, literally, a Requirement that a specific class of waste not occur: excess inventory, over-production, unnecessary motion. A poka-yoke Requirement is a Requirement that a specific error be made mechanically impossible rather than merely improbable. The Style enum gives these terms a typed home rather than leaving them as prose convention.

The deeper debt is structural. The kaizen loop — observe the process, identify a small improvement, implement it, measure the effect, standardise or revert — is the same shape as the dog-food loop the package embodies. Observe the DSL by using it to specify something. Identify a small inadequacy (the Requirement type you wish you had, the decorator you wish existed, the report column you wish rendered). Implement the change. Run the compliance report against the package itself and watch whether it passes. Standardise or revert. This is the meta-circular loop described in Chapter 18, and its intellectual ancestry is kaizen, not agile retrospective — the two have similar surface rituals and radically different philosophical commitments.

Where the DSL diverges from orthodox lean is in its refusal of the human commitment. Toyota's system is inseparable from a specific labour practice: stable employment, cross-trained workers, line-stop authority for anyone. A TypeScript package cannot reproduce that; neither can any piece of software. The DSL takes the vocabulary of lean (as a Style) and the shape of kaizen (as the dog-food discipline), and leaves the political-economic substrate to the organisation adopting the tool. This is an honest limit. A reader who adopts LeanStyle without the Toyota labour practice will get a decorated vocabulary, not a productive system. Naming the limit is, I hope, more honest than the silence most software-lean literature maintains on this point.


10. IEC 61508 — Functional Safety and Safety Integrity Levels

IEC 61508 is the international standard for functional safety of electrical/electronic/programmable electronic safety-related systems, first published by the International Electrotechnical Commission in 1998 with major revisions in 2010. It introduces the concept of Safety Integrity Levels (SIL 1 through SIL 4) — quantitative targets for the probability of dangerous failure per hour of operation — and prescribes a V-model lifecycle with distinct hazard-analysis, specification, implementation, verification, validation, and decommissioning phases.

I have never worked on a SIL-rated system. The influence on the DSL is therefore indirect: a colleague who had, reading an early draft of the Requirement lifecycle FSM, remarked that my three-state draft (draft, active, retired) was laughably thin for any regulated domain. The conversation that followed — over a coffee, on a whiteboard — produced the thirteen-state IndustrialStyle lifecycle described in Chapter 09: elicited, analysed, hazard-assessed, SIL-allocated, specified, architected, designed, implemented, verified, validated, certified, in-service, decommissioned. Thirteen states because 61508 names roughly that many distinct phases, each with its own artefacts, its own reviewers, and its own gate.

The DSL does not implement any SIL-computation logic. It does not compute failure rates, does not integrate with FMEA tools, does not produce certification evidence. What it does is hold the shape of the 61508 lifecycle in a typed FSM, so that a Requirement declared with IndustrialStyle cannot skip states, cannot regress (except via a declared concession path), and cannot be reported as certified if its transition history does not include a validated state. The FSM is dumb; the discipline of forcing the Requirement through every state is the point.

Where the DSL diverges from 61508 is in scope, emphatically. The standard governs an entire safety case, including hardware, processes, personnel, and organisational practices. The DSL governs only the software-requirement lifecycle slice. A package cannot substitute for a safety case. What the package can do — and this is the entire claim — is make the software-requirement slice interoperate with a safety case authored by humans, by ensuring that the artefacts the safety case needs (traceability matrix, verification status, change history) are mechanically derivable from the DSL's compliance report rather than manually compiled into a spreadsheet. The boundary is explicit and narrow.

A methodological note: I do not recommend IndustrialStyle to teams not genuinely operating in a 61508 context. The state richness is expensive — each state demands a justification, a reviewer, a transition artefact — and in a non-regulated context the cost is pure overhead. The Style enum exists precisely so that teams can choose a lighter register (Default, Agile, Lean) without giving up the traceability core. Over-applying IndustrialStyle is, itself, a form of muda.


11. EARS — Alistair Mavin and the Easy Approach to Requirements Syntax

Alistair Mavin, at Rolls-Royce in the late 2000s, developed EARS — the Easy Approach to Requirements Syntax — as a response to the chronic ambiguity of natural-language requirements in the aerospace domain. His 2009 paper, EARS: The Easy Approach to Requirements Syntax, identifies five (and only five) sentence patterns that a well-formed Requirement ever needs, and gives each a keyword: Ubiquitous ("The system shall..."), Event-driven ("When [trigger], the system shall..."), State-driven ("While [state], the system shall..."), Optional-feature ("Where [feature present], the system shall..."), and Unwanted-behaviour ("If [undesired condition], then the system shall...").

The contribution EARS makes is almost embarrassingly small. It is not a logic. It is not a language. It is five templates. And yet the templates solve, empirically, the bulk of the ambiguity problem in industrial requirements because they force the author to specify which kind of statement they are making before filling in the content. A sentence that does not fit any of the five patterns is usually either over-specified, under-specified, or not actually a requirement at all.

The DSL encodes EARS directly, as a discriminated union type in AgileStyle and partially in DefaultStyle. A Requirement declared with EARS conformance must tag itself with one of the five pattern keywords, and the rest of its statement field is type-narrowed to the fields that pattern needs (an event-driven EARS Requirement requires a trigger field; a state-driven EARS Requirement requires a precondition field). The narrowing is compile-time, which means a typo that would have passed a prose review fails a TypeScript build. Chapter 11 walks through the exact type surface.

Where the DSL does more than EARS is in making the pattern introspectable at runtime. A plain-English EARS statement in a PDF requirements document is readable but not queryable — you cannot ask "how many state-driven Requirements are in the system?" without re-parsing the PDF. In the DSL, the pattern is a typed field on the Requirement, so the compliance report can tabulate pattern distribution, flag anomalies (a single event-driven Requirement in an otherwise ubiquitous project is often a smell), and enforce project-level pattern budgets if a team wishes. EARS gains, by being a type, the analytic traction it lacks as a convention.

Where the DSL does less than EARS — and this is worth naming — is in refusing Mavin's full guidance around requirement authoring workshops. EARS is, in its original context, a human process: a facilitator walks engineers and stakeholders through the five patterns and negotiates each Requirement into one of them. The DSL cannot facilitate workshops. It can only hold the result. This is a generic limit of any tooling-based approach to a fundamentally conversational activity, and acknowledging it keeps the DSL honest.


12. Kent Beck — Extreme Programming and Test-First as Tacit Constraint

Kent Beck, the American programmer best known for Extreme Programming (XP) and the JUnit test framework, formalised Test-Driven Development (TDD) in Test-Driven Development: By Example (2002) and the broader XP discipline in Extreme Programming Explained (1999, second edition 2004). The specific influence on @frenchexdev/requirements is narrow and important: Beck's insistence that a test is not a post-hoc verification artefact but a specification written in code is the tacit constraint underlying the entire decorator design.

TDD as Beck practises it is a three-step loop: red (write a failing test for a behaviour you do not yet have), green (write the minimum code that makes the test pass), refactor (improve the design without changing behaviour). The load-bearing claim is not about testing discipline; it is about what the test means. A test written before the code is not a check on correctness — the code does not exist. It is a specification of what correctness will be when the code does exist. The test is, in the language of this blog series, a Feature-level acceptance criterion.

The DSL's @FeatureTest / @Verifies pairing, described in Chapter 07, is the direct encoding of this interpretation. A test class in the package does not use describe / it — those verbs presuppose that the test is a narrative about code that exists. Instead, the test class declares @FeatureTest(SomeFeature) at the class level and @Verifies(AC.someCriterion) at each method, which reads as: this test asserts the specification of that acceptance criterion of that Feature. Whether the Feature's code exists yet is irrelevant to the test's meaning. The test is a specification artefact first and a regression check second.

Where the DSL diverges from XP orthodoxy is in which rituals it keeps. XP bundles TDD with pair programming, continuous integration, small releases, collective code ownership, and a metaphor-driven design practice. The DSL imports none of these rituals — they are orthogonal to a type-system-based specification tool, and endorsing them would overreach. What the DSL does keep, and keeps deliberately, is the epistemic stance that tests are specifications and that writing tests after the fact is a category error. The ban on describe / it is that stance made mechanical.

A small personal note: XP arrived in France, in the shop I was working in at the time, around 2002. I read the second edition the year it came out. Twenty-four years later the specific ritual I still practise is the epistemic one — test-as-specification — and not the social ones. The DSL is, partly, a record of that filtered inheritance.


13. Eric Evans — Domain-Driven Design and the Policy Chapter

Eric Evans's Domain-Driven Design: Tackling Complexity in the Heart of Software (2003) is the canonical text on building software whose structure matches the structure of its business domain rather than the structure of its persistence layer. The influence on @frenchexdev/requirements is concentrated in a single chapter of the book — Chapter 20, on large-scale structure — which introduces the notion of Policy as a distinct kind of domain object.

Evans distinguishes Entities (things with identity over time), Value Objects (things defined by their attributes), Aggregates (consistency boundaries), Services (stateless operations), and Policies (decisions that cross multiple aggregates and are often configurable by the business). Most of the book, and most of the DDD literature that followed it, concentrates on the first four. Policy gets a few pages, and in the years since 2003 it has usually been folded into Service or into the application layer. I think this is a mistake, and the DSL is an attempt to correct it.

The claim the DSL makes — and the framing in Chapter 20 of this series — is that a Feature in the DSL sense is, approximately, a Use Case in Jacobson's sense, and a Requirement in the DSL sense is, approximately, a Policy in Evans's sense. A Use Case describes what the system does when invoked. A Policy describes what the system must be true of regardless of invocation. Requirements are true independently of any particular Feature; they constrain the family of Features that may exist. This mapping is not watertight — Evans did not define Policy with the precision the DSL needs, and the DSL's Requirement is more structured than Evans's Policy — but the mapping is load-bearing enough that DDD-literate readers usually find the DSL orienting rather than alien.

Where the DSL diverges from DDD orthodoxy is in making Policies first-class code artefacts with their own registry and their own lifecycle. In most DDD implementations Policies are conventions on top of plain classes, distinguishable from Services only by comment or naming convention. In the DSL a Requirement is an abstract class with a statically-typed Style, a lifecycle FSM, a parent pointer, and a registry entry. The Policy-concept becomes infrastructure. DDD purists may regard this as over-engineering; I regard it as correcting the chapter-length under-investment in Policy that has afflicted the DDD canon for twenty years.

A second, smaller debt: Evans's Ubiquitous Language — the practice of ensuring that domain terms appear identically in code, in documentation, and in stakeholder conversation — is the root of the Style enum's refusal to normalise vocabulary. A Requirement written for a lean shop should contain the word muda and should still contain the word muda when rendered in the compliance report. Translating muda to waste for "accessibility" breaks the ubiquitous-language discipline. The DSL enforces the discipline at the type level.


14. David Anderson — Kanban Method and Classes of Service

David J. Anderson, the British-American author of Kanban: Successful Evolutionary Change for Your Technology Business (2010), adapted Toyota's physical kanban signalling to knowledge work and, in the process, formalised a vocabulary for managing the flow of work items through a development system. The specific contribution relevant to the DSL is his concept of Classes of Service: a categorisation of work items by the shape of their expected value delivery over time, with four canonical classes — Expedite, Fixed Date, Standard, and Intangible.

Each Class of Service has a distinct service-level expectation. Expedite items bypass the queue and are pulled immediately, at the cost of allowing only a small number of them in the system at once. Fixed Date items have a hard deadline after which their value decays sharply. Standard items follow the system's ordinary cycle time with predictable variance. Intangible items are long-term investments — technical debt, research, infrastructure — whose value is real but difficult to attribute to a particular delivery. The categorisation does not describe the work; it describes the value curve of the work, which is what informs prioritisation.

KanbanStyle in the DSL, described in Chapter 11, makes each Class of Service a typed discriminant on the Requirement. A Requirement declared with Class-of-Service Expedite is statically required to carry a trigger field (what caused the expedite?), a bypass-authority field (who authorised the queue bypass?), and an impact-assessment field (what other work is displaced?). A Fixed Date Requirement is required to carry a date and a value-decay curve. The type narrowing is strict, because Anderson's methodological claim is strict: Classes of Service are only useful if they are enforced, not merely suggested, and enforcement in a software specification must be compile-time to be trustworthy.

Where the DSL diverges from Anderson's Kanban Method is in making no claim about flow measurement. The Kanban Method, in Anderson's formulation, is inseparable from continuous measurement of lead time, cycle time, and throughput, rendered as Cumulative Flow Diagrams and used for evolutionary process improvement. The DSL measures none of this. It only categorises Requirements by Class of Service; what a team does with the categorisation is its own business. This is, again, an honest limit: a decorator package can hold a category; it cannot replace a team's work-tracking system. The Class of Service field integrates with a team's existing flow tooling by being a queryable type rather than by replacing the tooling.

A smaller debt: Anderson's emphasis that change should be evolutionary rather than revolutionary — start with what you do now, make the invisible visible, then improve incrementally — is the methodological twin of the kaizen loop noted under Toyota, and the exact methodology the DSL itself evolved under. The package did not spring fully formed; it started as a Feature-only ancestor (typed-specs), gained Requirements when a specific project demanded them, and acquired Styles when real-world teams resisted DefaultStyle. Anderson would, I think, recognise this as orthodox kanban in its own right.


15. Donald Knuth — Literate Programming and the Readable Artefact

Donald Knuth's Literate Programming (1984 essay, 1992 book) advances the claim that programs should be written to be read by humans, with the machine execution as a secondary consequence. His WEB and CWEB systems interleaved Pascal (later C) with TeX prose in a single source file that could be tangled into executable code or weaved into typeset documentation, with both artefacts guaranteed to be in sync because they shared a source.

The influence on @frenchexdev/requirements is not at the syntactic level — the DSL is plain TypeScript, not a literate-programming system — but at the level of what the compliance report is. The compliance report, described in Chapter 13, is not a log, not a test result, not a CI artefact. It is a readable document, structured by Feature and Requirement, with narrative context extracted from the source, that a non-programmer stakeholder can read end-to-end and understand the state of the specification. The report is generated; the source is code; but the target audience of the report is a human reader who will never open the code, and the report's register is chosen accordingly.

This is the Knuth move translated from documentation-of-implementation to documentation-of-specification. Knuth wanted the program to be readable as prose. The DSL wants the specification to be readable as prose. Both insist that the readable artefact and the executable artefact share a single source and cannot drift. Both refuse the common alternative in which specification lives in a Word document, code lives in a repository, and a human being is responsible for keeping them aligned. That human-in-the-loop is, in Knuth's and the DSL's shared view, the exact wrong place to locate the synchronisation.

Where the DSL diverges from Knuth is in refusing the full literate-programming commitment. A Knuth-orthodox source file is a prose document with code chunks embedded in it; a DSL source file is a code document with prose (in JSDoc, in decorator arguments, in Source fields) embedded in it. The inversion matters because the DSL's primary author is an engineer who writes TypeScript fluently, and asking them to write TeX interleaved with their code would have been a non-starter. The prose appears in the ecological niches engineers tolerate (doc-comments, string literals, structured frontmatter) rather than as the primary medium.

A personal homage: Knuth's essay Theory and Practice and his dictum that a programmer should be explaining the program to a person rather than to the compiler is, along with Meyer's Design by Contract, the older of the two books that most shaped how I think about source files. Every time the DSL refuses a compact-but-opaque feature in favour of a verbose-but-readable one, it is Knuth's voice I hear. The compliance report's long-form Markdown output is the most Knuth-shaped piece of the package.


What this bibliography omits

A few adjacent traditions do not appear above, and their absence is deliberate rather than accidental.

Petri nets (Carl Adam Petri, 1962) are a graph-theoretic model of concurrency with a rich theory of reachability and liveness. They are an obvious formal tool for the kind of FSM work in the Scenarii layer, and I considered grounding Chapter 15 in Petri-net vocabulary. I did not, because the Scenarii FSMs in the DSL are sequential and single-threaded by design — the concurrency dimension that makes Petri nets useful is absent from the problem the DSL solves. Citing them would be signalling.

Z notation (Jean-Raymond Abrial, 1977 onwards) and VDM (IBM Vienna, 1970s) are formal specification languages that predate Alloy and cover adjacent territory. I have read neither closely. The DSL takes nothing from them directly, and it would be dishonest to claim otherwise; a reader pursuing the deeper formal-methods lineage should consult Jackson's Software Abstractions bibliography, which treats them with the seriousness they deserve and which I cannot match.

BDD (Behaviour-Driven Development, Dan North 2006) and its Gherkin syntax (Given/When/Then) are an obvious cousin of EARS and the Scenarii FSM. The DSL consciously does not adopt Gherkin. Chapter 19b explains the reasoning: Gherkin tries to be readable by non-programmers at the cost of being inert to programmers, and the DSL inverts the trade-off, prioritising compile-time enforcement over stakeholder readability. BDD influenced the rejection, not the adoption, of a scenario syntax — which is influence of a kind, but not the kind this bibliography catalogues.

Jira and the commercial requirements-management tools (DOORS, Polarion, Jama) are, similarly, a present absence. They shape the DSL by being the default-world against which the DSL is a counter-proposal, but they do not shape the DSL's internal mechanics. The argument with them is fought in Chapter 19b, not in this appendix.

UML more generally — beyond the SysML profile — is another present absence. The DSL owes SysML the specific stereotypes named above; it does not owe UML class-diagram methodology anything further. Citing UML would conflate the debt I actually carry (SysML) with a much larger tradition I do not.

Naming omissions is, I think, a more honest close to a bibliography than silently padding the citation list. What follows from that honesty is the next reader's responsibility: if you believe one of these traditions should have shaped the DSL more than it did, that is a critique worth making, and I would rather hear it than preempt it with a false citation.


⬇ Download