ADR-0086: Requirement Traceability Chains — End-to-End Path View + Flat Path Export¶
- Status: accepted (Nicolas 2026-07-20: "ADR-0086 looks good to me")
- Date: 2026-07-20
- Deciders: Nicolas Burri (question: "might we also create an actual matrix where we can track the entire paths? I guess this is not so simple as the chains will probably not all have the same elements?"), design by Claude.
- Relates to: ADR-0077 §6 + Clarification §4 (item coverage; satisfies evidence), ADR-0078 (type-agnostic trace items), ADR-0079/0082 (the risk chain view — the shape precedent), ADR-0080 (traceability workspace + per-view gating), ADR-0061 (CSV validation package — a consumer), ADR-0083 (export machinery), ADR-0085 (relation-layer consolidation, proposed — this view reads ITEM trace links only, no dependency).
- Refined by: ADR-0088 (the coverage evidence classes these chains read — planned vs verified via a per-type evidence flag)
Context¶
Each traceability hop is independently derivable and gap-flagged today (coverage counts, link
cards), which satisfies the norm minimum — but the auditor's actual motion is walking a chain
end-to-end: stakeholder requirement → satisfying software requirements → verification evidence.
Today that takes three page-visits. Nicolas's instinct about the difficulty is correct and is the
design driver: chains branch and have unequal depth (one NA item feeds five software
requirements, each with 0..n verifications; some GA items map to architecture requirements that
legitimately end without a verification hop) — a rectangular grid would be mostly empty cells.
The risk side already solved this exact shape: RiskTraceabilityService derives heterogeneous
chains (risk → controls → implementation → verification) with per-stage gap flags and
"legitimately ends here" semantics. The requirements side deserves its mirror image.
Decision¶
- A derived requirement-chain read model (no schema change; derived live, never stored —
the house doctrine): rows = the scope's
kind="stakeholder"requirement items; each expands to its satisfying software requirements (inboundsatisfies), each of those to its verification evidence (inboundverifies). Suspect state is surfaced PER HOP (the link-level machinery already computes it; the chain view makes it visible where it interrupts a path). - Roll-up flags per chain, honest and non-suppressible: not satisfied (no inbound satisfies), satisfied but unverified (≥1 satisfying software requirement without inbound verifies — reported per software requirement, not averaged away), suspect on the path (any hop's link suspect). No "accepted gap" marker is invented here — if legitimate terminal chains (e.g. GA items with no software counterpart) prove noisy in practice, an acceptance mechanism is its own future decision, not a silent default.
- UI: one sub-page in the traceability workspace (ADR-0080 pattern: hub tile + focused page,
VIEW_TRACEABILITY-gated like its siblings). Expandable rows (the branching structure), reusing the risk panel's visual language: state chips, quiet evidence labels, gap pills with remedy hints naming the in-place affordance where one exists. - The flat "matrix" is an EXPORT, not the screen: one row per complete path (stakeholder key → software key → evidence document/version, plus per-hop suspect state and the roll-up flag) as CSV download from the sub-page. This is the artifact auditors (and the Requirements-Yogi expectation) mean by "traceability matrix"; it feeds the ADR-0061 C-V1 validation-report generator. A print/PDF form may join a later slice via the ADR-0074 renderer.
- Implementation rides the coverage-engine consolidation (2026-07-20 review finding): the
generic
TraceCoverageengine widens to an edge-type SET ("covered = ≥1 inbound of any listed type"), the shippedcoverage()path routes through it, and the chain assembly reuses the single-pass multi-type registry build (the same pass also fixes the risk-side triple-parse finding). One slice, three consolidations — the chain view gives the generic engine its first real production consumer. - Deliberately rejected: a configurable chain-definition engine. The edge vocabulary is closed and the meaningful chains are FIXED shapes (this one, and the existing risk chain). A generic "chain configurator" is configuration at an unproven variation point — the opinionated posture applies.
Consequences¶
- Purely derived: no migration, no stored state that can drift; RLS bounds every hop's read (an invisible link target degrades exactly as it does in the one-hop views).
- REQ rows join the pending requirements block (extends REQ-REP-009's territory) at the baseline that ships the slice.
- e2e + screenshot scenes for the sub-page; the export gains a golden-file test.
- The PULSEMED corpus is the acceptance fixture: 61 satisfied / 11 unsatisfied stakeholder requirements and the 36-verifies software layer give real branching, real terminal chains, and real gaps on day one.