"""Requirements-to-architecture traceability matrix."""
from dataclasses import dataclass, field
from typing import List
@dataclass
class SystemRequirement:
req_id: str
description: str
asil: str
allocated_to: List[str] = field(default_factory=list) # component IDs
@dataclass
class ArchComponent:
comp_id: str
name: str
ecu: str
justified_by: List[str] = field(default_factory=list) # req IDs
def check_traceability(reqs: List[SystemRequirement],
comps: List[ArchComponent]) -> dict:
"""Find forward and backward traceability gaps."""
comp_ids = {c.comp_id for c in comps}
req_ids = {r.req_id for r in reqs}
# Forward: requirements with no allocation
unallocated_reqs = [r for r in reqs if not r.allocated_to]
# Forward: allocation to non-existent component
bad_allocations = [
(r.req_id, cid)
for r in reqs
for cid in r.allocated_to
if cid not in comp_ids
]
# Backward: components with no requirement
unjustified_comps = [c for c in comps if not c.justified_by]
return {
"unallocated_reqs": unallocated_reqs,
"bad_allocations": bad_allocations,
"unjustified_comps": unjustified_comps
}
# Example
reqs = [
SystemRequirement("SYS-001", "AEB shall detect stationary vehicle at >= 40m",
"ASIL-B", ["COMP-AEB-DETECT", "COMP-RADAR-DRV"]),
SystemRequirement("SYS-002", "Vehicle speed available on backbone within 10ms",
"ASIL-B", ["COMP-SPEED-SVC"]),
SystemRequirement("SYS-003", "OTA update shall complete without driver interaction",
"QM", []), # <-- unallocated gap!
]
result = check_traceability(reqs, [])
print(f"Unallocated reqs: {[r.req_id for r in result['unallocated_reqs']]}")