Traceability is the spine that links product decisions to running code through the requirement layer. System requirements are the parent of domain models: every domain element declares which requirement IDs it satisfies, and every requirement optionally declares its provenance upstream in a PRD. The two bridges together give each obligation a resolvable origin and a verifiable realization — nothing is anonymous, and nothing is unaccounted for.
The Traceability Bridge
System requirements are the parent layer. Domain models (defined in the domain metamodel) reference requirements bottom-up via the satisfies attribute on each domain element. The requirement layer does not reference domain elements — it declares obligations without prescribing realization. This asymmetry is deliberate: one set of system requirements may be realized by multiple domain models — different implementations, different technology stacks, or different bounded contexts. The requirement is the contract; the domain model is one valid way to honor it.
Example:
A domain Operation placeOrder inside OrderContext might declare satisfies [REQ-ORD-002, REQ-ORD-003, REQ-ORD-004] — telling the toolchain that this one operation realizes the order-placement event-driven requirement, the suspended-customer guard, and the out-of-stock rejection. The requirements themselves do not name placeOrder — they stay above the implementation. See Requirement Traceability (domain side) for how satisfies is declared on domain elements.
Coverage Analysis
Coverage analysis answers: which requirements have no domain element satisfying them? A requirement whose ID appears in no satisfies list is unsatisfied. Unsatisfied requirements are either a modeling gap — the domain model is incomplete — or a premature requirement, written before the domain was understood enough to model it. Either way, the tooling surfaces a list and forces a conversation.
Coverage is executed from the domain model side by traversing every domain element’s satisfies list and computing the complement against the declared requirement IDs. Specy’s Check loop treats an unsatisfied must or should as a failure; an unsatisfied could as a warning; an unsatisfied wont — unexpected — as an inconsistency.
Example:
If REQ-ORD-006 ("Where express shipping is available…") has priority could and no domain element declares satisfies [REQ-ORD-006], the Check loop warns but does not fail. If REQ-ORD-001 (the ubiquitous quantity floor, priority must) has no satisfier, the Check loop fails: a regulated invariant has no enforcer.
Orphan Analysis
Orphan analysis answers the symmetric question: which domain elements satisfy no requirement? A domain element with an empty satisfies list is an orphan. Orphans are either over-engineering — code that exists without a stated reason — or a missing requirement that was never written down.
Orphan analysis is especially valuable during legacy extraction, where existing code contains implicit requirements that never made it into a document. Flagging orphans forces teams to either delete the code or back-fill the requirement. In a greenfield project, persistent orphans are usually a smell: someone is building without intent.
Not every empty satisfies is a real orphan. Some element kinds legitimately carry no direct requirement link:
- Indirect satisfiers — a value type or a helper domain service used exclusively by elements that do carry
satisfiesIDs. The dependency chain transitively justifies the element. Tooling should flag these as indirect rather than unsatisfied. - Infrastructure adapters — the concrete adapter behind an infrastructure-service interface. The interface carries the
satisfieslink; the adapter is an implementation choice, not a new obligation. Exclude adapters from the orphan count when the interface they implement is satisfied. - Test fixtures, builders, and seed data — scaffolding that exists only to support verification. These should be excluded from the domain-model orphan count by convention (e.g., a
test/folder filter or a#[fixture]annotation).
A real orphan is an element whose role is to produce business behavior and which has no justification upstream. The canonical example is a domain service implementing a capability no requirement asked for. Those are the ones to either delete or back-fill a requirement for.
Example:
A service recomputeLoyaltyPoints inside OrderContext with satisfies [] might be an artifact of an abandoned loyalty feature. Either a REQ-ORD-009 is missing, or the service should be removed. Neither option is neutral.
Conflict Detection
Two requirements linked by conflicts-with create an explicit tension. The tooling does not silently accept the pair — it requires the resolution strategy to be documented. Typical resolutions are:
- Priority-based — the higher-priority requirement wins; the lower-priority one is honored only when the higher is satisfied.
- Mediating policy — a third requirement, usually a domain policy or operational rule, arbitrates between the two at runtime.
- Agreement — a cross-context coordination rule, typical for conflicts that span bounded contexts.
Unlike coverage and orphan analysis, conflict detection lives in the requirement layer itself — it only needs requirement-to-requirement links, not domain metadata.
Example:
REQ-ORD-008 ("When an order is confirmed, the system shall immediately initiate fulfillment.") declares conflicts-with REQ-ORD-005 (the credit-hold requirement). The rationale on REQ-ORD-008 says it out loud: “Ops wants auto-ship; Finance wants credit hold — resolved by priority.” Priority should loses to priority must — the hold wins, and the conflict is resolved.
The Upstream PRD Bridge
Above system requirements sit product requirements — the .prd artifacts that capture features, user stories, acceptance criteria, constraints, and business goals. Specy connects the two layers through two coordinated fields:
prd-source— set at the requirement-set level. Declares the relative path to the.prdfile the set was derived from. When present, everysourcefield inside the set is interpreted as a reference into that file.source— set at the individual requirement level. A free-text string identifying the PRD element that originated this requirement: a feature name and acceptance criterion, a user-story ID, a goal, or a regulatory clause.
Together they create a file-resolvable chain: an agent or tool can follow prd-source to open the PRD, then match each requirement’s source to the corresponding PRD element. Free-text source allows provenance to outlive PRD schema changes while prd-source gives the reader a starting file.
Example:
requirements "Order Processing" scoped-to OrderContext {
prd-source "specs/order.prd"
REQ-ORD-007 "Order confirmation" : event-driven
depends-on REQ-ORD-002
source "PRD v2.1 §3.4 — Payment-gated order flow"
"When payment is verified, the system shall confirm the order."
priority must
}
Typical source conventions include "Feature: Checkout — AC: payment-gated confirmation", "US-347 — Credit-limit hold", "Goal: reduce chargebacks by 30%", and "Regulation: PCI-DSS 4.0 §3.2.1". See PRD Releases & Traceability for the PRD side of the bridge.
The Complete Provenance Chain
Three files, three references, one chain. The domain model declares requirements-source pointing at a .sysreq file. The .sysreq file declares prd-source pointing at a .prd file. Each requirement inside the .sysreq declares a source string into the PRD, and each domain element declares satisfies [IDs] up to the .sysreq. Every obligation that ends up as running code can be walked backward from code to requirement to product decision, with no break in the chain.
Example:
Domain model: requirements-source "specs/order.sysreq"
System reqs: prd-source "specs/order.prd"
At the endpoint: a method on an aggregate declares satisfies [REQ-ORD-002], which resolves to a When-pattern statement in specs/order.sysreq, which carries source "Feature: Checkout — AC: OrderPlaced event emitted", which resolves to a named feature inside specs/order.prd. The chain is the point.