ADR-0078: Generalized Trace Items (Traceability Model — Stage A)¶
- Status: accepted (Nicolas 2026-07-18, decision D-1 in docs/planning/traceability-model.md: "generalize the item node now, so risk/validation/GSPR are types not subsystems")
- Date: 2026-07-18
- Deciders: Nicolas Burri, design by Claude.
- Extends: ADR-0077 (the requirement item becomes trace-item type=requirement).
- Relates to: docs/planning/traceability-model.md (the model this enables), ADR-0057 (frozen content — the hard backward-compat constraint), ADR-0021/0049 (document relations), the opinionated-by-default principle in conventions.md.
Context¶
The traceability model (traceability-model.md) needs several item-level node types — risk, risk-control, design-element, verification-case, validation-case, regulatory-ref — beyond the requirement item ADR-0077 built. Adding each as a sibling subsystem would duplicate the registry, link, suspect and coverage machinery. Stage A pays the generalization cost ONCE so every later type is additive.
Decision¶
- A TraceItem is a keyed item inside a controlled document, discriminated by TYPE, with a
FIXED per-type attribute schema (no custom-attribute engine — the opinionated rule). ADR-0077's
requirement is retroactively
type = requirementand remains the SOLE concrete type in this stage. - The engines become type-agnostic: extraction, the registry, links (endpoints are typed items of any type), suspect-flagging, coverage, and per-scope key uniqueness are all parameterized by item type (+ edge type for coverage). Adding a type later = register a node-type + fence + attribute schema; the engines do not change.
- Backward compatibility is non-negotiable (ADR-0057): existing FROZEN content and the
:::requirementprojection serialization are UNCHANGED (byte-exact reproduction; the migrated PULSEMED requirements keep parsing and displaying). Requirement authoring, registry, links, and coverage behaviour are PRESERVED — the ADR-0077 test suite is the spec and stays green unchanged (a needed change to a behavioural assertion is a red flag, not a task; pure renames of test-internal symbols are fine). - Per-type nodes + per-type fences (requirement stays the
requirementnode /:::requirementfence — never renamed, or frozen trees break); a shared type-aware backend extraction over a node-type REGISTRY. Keys are unique per scope across ALL types (a natural fit — the prefix conventions already separate them). - Trace-neutral naming where it removes debt without changing endpoint semantics or frozen
content:
requirement_link→trace_linketc. via a data-preserving rename migration; the requirement UI stays behaviour-identical; the importer keeps working (its transform output and the endpoints it calls stay compatible, or are updated in lockstep).
Non-goals (this stage)¶
No new user-facing item types (risk is Stage B); no new requirement attributes; no user-visible behaviour change beyond internal endpoint/table generalization.
Definition of done¶
A test registers a SYNTHETIC second trace-item type and demonstrates the registry, links, suspect flags and coverage all work across types with ZERO engine changes — the proof the abstraction is real and Stage B (risk) is genuinely additive.
Consequences¶
- Stage B (risk + risk-control types + score recording) becomes purely additive.
- The registered ADR-0077 coverage-rule generalization rides the now type-aware coverage engine.
- A rename migration (Vnn) applies in place on existing data (ALTER … RENAME preserves rows) — a fresh re-import is NOT required; restore-or-running-stack both migrate forward.
- Each later type/axis (Stage B/C/D) is its own ADR; this one is the substrate.