6.2: Automated Traceability
Overview
Automated traceability reduces manual effort in maintaining bidirectional links between requirements, architecture, code, and tests. AI-powered systems can suggest, validate, and maintain trace links with minimal human intervention, ensuring compliance with ASPICE traceability requirements while significantly reducing overhead.
In safety-critical embedded systems development, traceability is not optional—it is a regulatory and process assessment requirement. ASPICE 4.0, ISO 26262, and IEC 61508 all mandate bidirectional traceability across the V-Model. Manual traceability maintenance is error-prone, time-consuming, and becomes increasingly unmanageable as system complexity grows. Automated traceability leverages AI and workflow automation to maintain these critical links with minimal human intervention while preserving the accountability chains required by safety standards.
Cross-Reference: For detailed ASPICE traceability requirements, see Chapter 13.03 Traceability Automation.
Traceability Architecture
Conceptual Model
Automated traceability systems operate across four primary layers. The following diagram illustrates these layers — from data sources through extraction, link management, and reporting — showing how each layer contributes to maintaining end-to-end traceability across the V-Model.
Bidirectional vs Unidirectional Traceability:
- Bidirectional: Links traverse both directions (e.g., REQ-001 → TC-001, TC-001 → REQ-001). Required by ASPICE for full V-Model coverage.
- Unidirectional: Links traverse only one direction (e.g., CODE → REQ but not REQ → CODE). Insufficient for safety-critical domains.
Trace Link Types:
| Link Type | Source | Target | ASPICE Requirement |
|---|---|---|---|
| Requirements Derivation | System Req | Software Req | SYS.3 BP7, SWE.1 BP6 |
| Architecture Allocation | Software Req | Software Units | SWE.3 BP7 |
| Implementation | Software Units | Source Code | SWE.3 BP8 |
| Verification | Test Cases | Requirements | SWE.4 BP7, SWE.5 BP7, SWE.6 BP7 |
| Change Impact | All Artifacts | All Artifacts | SUP.10 BP7 |
Data Flow Architecture
The following diagram shows how source systems (requirements tools, code repositories, test management) feed into the traceability engine through standardized data extraction interfaces.
Architecture Principles:
- Separation of Concerns: Extraction, processing, validation, and storage are decoupled.
- Idempotency: Re-running extraction does not create duplicate trace links.
- Auditability: All trace link creation/modification events are logged with timestamp and user.
- Scalability: Caching and incremental processing support large codebases (1M+ LOC).
Implementation Patterns
Pattern 1: Commit Message Parsing
Objective: Extract requirement IDs from Git commit messages to establish CODE ↔ REQ traceability.
Regex Patterns:
import re
from typing import List, Dict
# Pattern definitions for common requirement ID formats
PATTERNS = {
'jira': r'\b([A-Z]+-\d+)\b', # PROJ-123
'doors': r'\bREQ-(\d{4})\b', # REQ-0001
'polarion': r'\b(WI-\d+)\b', # WI-1234
'custom': r'\b(SRS|SDD|TC)-\d{3,5}\b', # SRS-001, SDD-100, TC-999
'iso26262': r'\b(FSR|TSR|HSR)-\d{4}\b', # FSR-0001 (Functional Safety Req)
}
def extract_requirement_ids(commit_message: str) -> Dict[str, List[str]]:
"""
Extract all requirement IDs from a commit message.
Returns a dictionary mapping requirement type to list of IDs.
"""
results = {}
for req_type, pattern in PATTERNS.items():
matches = re.findall(pattern, commit_message, re.IGNORECASE)
if matches:
results[req_type] = list(set(matches)) # Deduplicate
return results
# Example usage
commit_msg = """
SWE.3: Implement CAN message parser for vehicle speed
Implements requirements:
- REQ-0042: Parse CAN ID 0x123 for vehicle speed
- REQ-0043: Validate speed range 0-250 km/h
- PROJ-456: Add diagnostic error handling
Covers test cases: TC-105, TC-106
"""
ids = extract_requirement_ids(commit_msg)
# Output: {'doors': ['0042', '0043'], 'jira': ['PROJ-456'], 'custom': ['TC-105', 'TC-106']}
CI/CD Integration (GitHub Actions):
name: Traceability Link Extraction
on: [push]
jobs:
extract-traces:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0 # Full history for trace analysis
- name: Extract Requirement Links
run: |
python scripts/extract_traces.py \
--commits HEAD~10..HEAD \
--output traces.json
- name: Update Traceability Database
env:
TRACE_DB_URL: ${{ secrets.TRACE_DB_URL }}
run: |
python scripts/update_trace_db.py \
--input traces.json \
--repo ${{ github.repository }} \
--commit ${{ github.sha }}
- name: Generate Coverage Report
run: |
python scripts/generate_coverage.py \
--requirements requirements.json \
--traces traces.json \
--output coverage.html
- name: Upload Coverage Artifact
uses: actions/upload-artifact@v3
with:
name: traceability-coverage
path: coverage.html
Pattern 2: n8n Workflow Integration
Objective: Automate bidirectional trace synchronization between Jira and GitHub using n8n.
Workflow Architecture: The following diagram shows the event-driven traceability workflow, illustrating how triggers from Jira and GitHub initiate synchronization, validation, and notification actions through the n8n automation engine.
n8n Workflow JSON (Simplified Example):
{
"nodes": [
{
"name": "GitHub Webhook",
"type": "n8n-nodes-base.webhook",
"parameters": {
"path": "github-commit",
"httpMethod": "POST"
}
},
{
"name": "Extract Commit Data",
"type": "n8n-nodes-base.code",
"parameters": {
"jsCode": "const commitMsg = $input.item.json.commits[0].message;\nconst reqIds = commitMsg.match(/\\b([A-Z]+-\\d+)\\b/g) || [];\nreturn { commitSHA: $input.item.json.after, requirements: reqIds };"
}
},
{
"name": "Query Jira Issues",
"type": "n8n-nodes-base.jira",
"parameters": {
"resource": "issue",
"operation": "get",
"issueKey": "={{ $json.requirements[0] }}"
}
},
{
"name": "Calculate Similarity",
"type": "n8n-nodes-base.httpRequest",
"parameters": {
"url": "https://api.openai.com/v1/embeddings",
"method": "POST",
"headerParameters": {
"Authorization": "Bearer {{ $env.OPENAI_API_KEY }}"
},
"bodyParameters": {
"model": "text-embedding-3-small",
"input": ["{{ $json.summary }}", "{{ $json.commitMessage }}"]
}
}
},
{
"name": "Confidence Filter",
"type": "n8n-nodes-base.if",
"parameters": {
"conditions": {
"number": [
{
"value1": "={{ $json.similarity }}",
"operation": "largerEqual",
"value2": 0.90
}
]
}
}
},
{
"name": "Update Jira Link",
"type": "n8n-nodes-base.jira",
"parameters": {
"resource": "issue",
"operation": "update",
"issueKey": "={{ $json.issueKey }}",
"updateFields": {
"weblinks": {
"url": "https://github.com/repo/commit/{{ $json.commitSHA }}",
"title": "Implementation Commit"
}
}
}
}
],
"connections": {
"GitHub Webhook": { "main": [[{ "node": "Extract Commit Data" }]] },
"Extract Commit Data": { "main": [[{ "node": "Query Jira Issues" }]] },
"Query Jira Issues": { "main": [[{ "node": "Calculate Similarity" }]] },
"Calculate Similarity": { "main": [[{ "node": "Confidence Filter" }]] },
"Confidence Filter": { "true": [[{ "node": "Update Jira Link" }]] }
}
}
Pattern 3: ML-Based Trace Suggestion
Objective: Use semantic similarity to suggest trace links between requirements and test cases.
Approach:
- Embedding Generation: Convert requirement text and test case descriptions to vector embeddings.
- Similarity Calculation: Compute cosine similarity between requirement and test embeddings.
- Threshold-Based Filtering: Accept suggestions above confidence threshold.
- Human Validation: Route low-confidence suggestions to human reviewers.
Implementation (Python with Sentence-BERT):
from sentence_transformers import SentenceTransformer, util
import numpy as np
from typing import List, Tuple
class TraceabilitySuggester:
def __init__(self, model_name: str = 'all-MiniLM-L6-v2'):
"""
Initialize the traceability suggester with a sentence embedding model.
Args:
model_name: HuggingFace model identifier (default: lightweight SBERT model)
"""
self.model = SentenceTransformer(model_name)
self.confidence_thresholds = {
'auto_approve': 0.85, # Auto-link, no review needed
'needs_review': 0.70, # Suggest to human
'reject': 0.00 # Don't show
}
def suggest_traces(
self,
requirements: List[Dict[str, str]],
test_cases: List[Dict[str, str]]
) -> List[Tuple[str, str, float, str]]:
"""
Suggest trace links between requirements and test cases.
Args:
requirements: List of {'id': 'REQ-001', 'text': 'The system shall...'}
test_cases: List of {'id': 'TC-001', 'text': 'Verify that...'}
Returns:
List of tuples: (req_id, tc_id, confidence_score, action)
where action is 'auto_approve', 'needs_review', or 'reject'
"""
# Generate embeddings
req_texts = [r['text'] for r in requirements]
tc_texts = [tc['text'] for tc in test_cases]
req_embeddings = self.model.encode(req_texts, convert_to_tensor=True)
tc_embeddings = self.model.encode(tc_texts, convert_to_tensor=True)
# Calculate similarity matrix
similarity_matrix = util.cos_sim(req_embeddings, tc_embeddings)
# Extract suggestions
suggestions = []
for i, req in enumerate(requirements):
for j, tc in enumerate(test_cases):
score = similarity_matrix[i][j].item()
# Determine action based on confidence
if score >= self.confidence_thresholds['auto_approve']:
action = 'auto_approve'
elif score >= self.confidence_thresholds['needs_review']:
action = 'needs_review'
else:
continue # Below rejection threshold
suggestions.append((req['id'], tc['id'], score, action))
# Sort by confidence (descending)
suggestions.sort(key=lambda x: x[2], reverse=True)
return suggestions
# Example usage
requirements = [
{'id': 'REQ-042', 'text': 'The system shall parse CAN messages with ID 0x123 to extract vehicle speed in km/h with ±1 km/h accuracy.'},
{'id': 'REQ-043', 'text': 'The system shall validate that vehicle speed is within the range 0-250 km/h and reject out-of-range values.'}
]
test_cases = [
{'id': 'TC-105', 'text': 'Verify CAN message 0x123 parsing extracts correct speed value'},
{'id': 'TC-106', 'text': 'Verify speed values above 250 km/h are rejected with error code 0x01'},
{'id': 'TC-200', 'text': 'Verify brake pressure sensor calibration at 0 bar'}
]
suggester = TraceabilitySuggester()
suggestions = suggester.suggest_traces(requirements, test_cases)
for req_id, tc_id, score, action in suggestions:
print(f"{req_id} → {tc_id}: {score:.3f} [{action}]")
# Output:
# REQ-042 → TC-105: 0.892 [auto_approve]
# REQ-043 → TC-106: 0.876 [auto_approve]
# REQ-042 → TC-106: 0.734 [needs_review]
# REQ-043 → TC-105: 0.712 [needs_review]
Validation Mechanisms:
- Duplicate Detection: Prevent creating trace links that already exist.
- Orphan Detection: Identify requirements or test cases with zero trace links.
- Cycle Detection: Prevent circular dependencies (e.g., REQ-A → REQ-B → REQ-A).
- Coverage Calculation: Compute percentage of requirements traced to implementation/tests.
def validate_traceability_coverage(
requirements: List[str],
trace_links: List[Tuple[str, str]]
) -> Dict[str, any]:
"""
Calculate traceability coverage metrics.
Args:
requirements: List of requirement IDs
trace_links: List of (source_id, target_id) tuples
Returns:
Dictionary with coverage statistics
"""
traced_requirements = set()
for source, target in trace_links:
if source in requirements:
traced_requirements.add(source)
if target in requirements:
traced_requirements.add(target)
total = len(requirements)
traced = len(traced_requirements)
coverage_pct = (traced / total * 100) if total > 0 else 0
orphans = set(requirements) - traced_requirements
return {
'total_requirements': total,
'traced_requirements': traced,
'coverage_percentage': coverage_pct,
'orphan_requirements': list(orphans),
'orphan_count': len(orphans)
}
Tool Integration
Commercial Tools
| Tool | Traceability Features | AI Integration | API Availability | ASPICE Suitability |
|---|---|---|---|---|
| Jira | Custom fields, issue links, JQL queries | Automation rules, AI-suggested links (Labs) | REST API, webhooks | High (SUP.8 compliant) |
| Azure DevOps | Work item links, queries, traceability queries | Azure AI integration, automated suggestions | REST API, webhooks | High (ISO 26262 qualified) |
| IBM DOORS Next | Formal traceability module, link validation | Watson AI integration (premium) | OSLC API, REST | Very High (aerospace/automotive) |
| Polarion | Bidirectional traces, suspect links, coverage reports | Plugin-based AI extensions | REST API, webhooks | Very High (DO-178C qualified) |
| Codebeamer | Built-in traceability matrix, impact analysis | ML-based trace suggestions | REST API, webhooks | High (IEC 61508 qualified) |
Jira Integration Example (Python):
from jira import JIRA
import os
class JiraTraceabilityIntegration:
def __init__(self):
self.jira = JIRA(
server=os.getenv('JIRA_URL'),
basic_auth=(os.getenv('JIRA_USER'), os.getenv('JIRA_TOKEN'))
)
def create_trace_link(
self,
source_issue: str,
target_issue: str,
link_type: str = 'Relates'
):
"""
Create a trace link between two Jira issues.
Args:
source_issue: Source issue key (e.g., 'REQ-001')
target_issue: Target issue key (e.g., 'TC-105')
link_type: Link type ('Relates', 'Tests', 'Implements', etc.)
"""
self.jira.create_issue_link(
type=link_type,
inwardIssue=source_issue,
outwardIssue=target_issue,
comment={
'body': f'Automated trace link created by AI traceability system'
}
)
def get_traceability_matrix(self, project_key: str) -> List[Dict]:
"""
Generate traceability matrix for a project.
Args:
project_key: Jira project key (e.g., 'PROJ')
Returns:
List of dictionaries containing trace link data
"""
# Query all requirements
requirements = self.jira.search_issues(
f'project={project_key} AND type=Requirement',
maxResults=1000
)
matrix = []
for req in requirements:
# Get all linked issues
links = []
for link in req.fields.issuelinks:
if hasattr(link, 'outwardIssue'):
links.append({
'target': link.outwardIssue.key,
'type': link.type.outward
})
elif hasattr(link, 'inwardIssue'):
links.append({
'target': link.inwardIssue.key,
'type': link.type.inward
})
matrix.append({
'requirement': req.key,
'summary': req.fields.summary,
'links': links,
'link_count': len(links)
})
return matrix
Azure DevOps Integration Example (REST API):
import requests
from typing import List, Dict
class AzureDevOpsTraceability:
def __init__(self, organization: str, project: str, pat: str):
self.organization = organization
self.project = project
self.base_url = f'https://dev.azure.com/{organization}/{project}/_apis'
self.headers = {
'Authorization': f'Basic {pat}',
'Content-Type': 'application/json-patch+json'
}
def create_work_item_link(
self,
source_id: int,
target_id: int,
link_type: str = 'System.LinkTypes.Related'
):
"""
Create a trace link between two work items.
Args:
source_id: Source work item ID
target_id: Target work item ID
link_type: Link type URL (e.g., 'System.LinkTypes.TestedBy')
"""
url = f'{self.base_url}/wit/workitems/{source_id}?api-version=7.0'
patch_document = [
{
'op': 'add',
'path': '/relations/-',
'value': {
'rel': link_type,
'url': f'{self.base_url}/wit/workitems/{target_id}',
'attributes': {
'comment': 'Automated trace link'
}
}
}
]
response = requests.patch(url, json=patch_document, headers=self.headers)
return response.json()
def query_traceability(self, wiql_query: str) -> List[Dict]:
"""
Execute WIQL query to retrieve traceability data.
Args:
wiql_query: Work Item Query Language query
Returns:
List of work items matching the query
"""
url = f'{self.base_url}/wit/wiql?api-version=7.0'
response = requests.post(
url,
json={'query': wiql_query},
headers=self.headers
)
return response.json()
# Example WIQL query for traceability coverage
wiql_coverage_query = """
SELECT [System.Id], [System.Title], [System.State]
FROM WorkItemLinks
WHERE [Source].[System.WorkItemType] = 'Requirement'
AND [System.Links.LinkType] = 'System.LinkTypes.TestedBy'
AND [Target].[System.WorkItemType] = 'Test Case'
MODE (MustContain)
"""
Open-Source Solutions
| Tool | Description | Integration Method | License |
|---|---|---|---|
| Capra | Eclipse-based traceability tool for requirements/code | API, command-line | EPL 1.0 |
| Gazelle | Traceability for markdown-based requirements | Python API, CLI | MIT |
| OpenFastTrace | Plain-text requirements traceability | Java API, CLI | GPL 3.0 |
| ReqIF | Requirements interchange format | Python/Java parsers | Open standard |
Gazelle Integration Example:
import json
from gazelle import TraceabilityAnalyzer
# Define requirements in Markdown
requirements_md = """
# Software Requirements
## REQ-042: CAN Message Parsing
The system shall parse CAN messages with ID 0x123 to extract vehicle speed.
## REQ-043: Speed Validation
The system shall validate that vehicle speed is within 0-250 km/h.
"""
# Define test cases in Markdown
tests_md = """
# Test Cases
## TC-105: CAN Parsing Test
**Covers**: REQ-042
Verify CAN message 0x123 parsing extracts correct speed value.
## TC-106: Speed Range Test
**Covers**: REQ-043
Verify speed values above 250 km/h are rejected.
"""
# Analyze traceability
analyzer = TraceabilityAnalyzer()
analyzer.parse_requirements(requirements_md)
analyzer.parse_tests(tests_md)
coverage_report = analyzer.generate_coverage_report()
print(json.dumps(coverage_report, indent=2))
ASPICE Alignment
ASPICE Bidirectional Traceability Requirements
Automated traceability directly supports multiple ASPICE processes:
SUP.8 Configuration Management (Base Practice 7):
- Requirement: "Establish and maintain bidirectional traceability between configuration items."
- AI Support: Automated trace link creation, suspect link detection, coverage reporting.
- Evidence: Traceability matrix, trace link database, coverage reports.
SYS.3 System Architectural Design (Base Practice 7):
- Requirement: "Ensure bidirectional traceability between system requirements and system architectural design elements."
- AI Support: ML-based suggestions between SRS and SDD artifacts.
- Evidence: Requirements-to-architecture traceability matrix.
SWE.1 Software Requirements Analysis (Base Practice 6):
- Requirement: "Establish bidirectional traceability between system requirements and software requirements."
- AI Support: Automated parent-child requirement linking.
- Evidence: System-to-software requirements trace matrix.
SWE.3 Software Detailed Design and Unit Construction (Base Practice 7-8):
- Requirement: "Establish bidirectional traceability between software requirements and software units."
- AI Support: Commit message parsing, code annotation extraction.
- Evidence: Requirements-to-code traceability matrix.
SWE.4/5/6 Software Integration/Qualification/System Tests (Base Practice 7):
- Requirement: "Establish bidirectional traceability between test cases and requirements."
- AI Support: Test-to-requirement semantic matching, test metadata parsing.
- Evidence: Test-to-requirement traceability matrix, coverage reports.
Traceability Matrix Structure
Requirements-to-Test Traceability Matrix (Markdown Example):
# Software Requirements Traceability Matrix
**Project**: Vehicle Speed ECU
**Version**: 2.1.0
**Date**: 2026-01-26
**ASIL Level**: ASIL-B
| Req ID | Requirement Summary | Arch Element | Code Module | Unit Test | Integration Test | System Test | Coverage |
|--------|-------------------|--------------|-------------|-----------|-----------------|-------------|----------|
| REQ-042 | CAN message parsing | `CAN_Parser` | `can_parser.c:120-145` | `TC-U-001` | `TC-I-012` | `TC-S-042` | 100% |
| REQ-043 | Speed validation | `Speed_Validator` | `validators.c:78-92` | `TC-U-002` | `TC-I-013` | `TC-S-043` | 100% |
| REQ-044 | Diagnostic error handling | `Diag_Handler` | `diagnostics.c:200-230` | `TC-U-003` | `TC-I-014` | `TC-S-044` | 67% ⚠️ |
| REQ-045 | Watchdog monitoring | `WDT_Monitor` | `watchdog.c:45-60` | `TC-U-004` | — ❌ | `TC-S-045` | 50% ⚠️ |
**Legend**:
- ✅ 100%: Full coverage (requirement → architecture → code → tests)
- ⚠️ 50-99%: Partial coverage (missing integration or unit tests)
- ❌ <50%: Insufficient coverage (critical gaps in trace chain)
**Orphan Requirements** (No Trace Links): None
**Suspect Links** (Potentially Outdated):
- REQ-044 → `diagnostics.c`: Code modified in commit `a1b2c3d` without requirement update review
Evidence Requirements for ASPICE Assessments
To satisfy ASPICE assessors, automated traceability systems must produce:
-
Traceability Matrix (SUP.8 Work Product 13-04):
- Bidirectional links between all lifecycle artifacts
- Coverage percentages per requirement
- Orphan and suspect link identification
-
Trace Link Database (SUP.8 Work Product 13-19):
- Persistent storage of all trace links
- Audit trail (who created/modified, when, why)
- Versioning aligned with configuration baselines
-
Coverage Reports (SWE.6 Work Product 13-22):
- Requirements coverage by tests
- Code coverage by unit tests
- Gaps analysis with risk assessment
-
Change Impact Analysis (SUP.10 Work Product 08-52):
- Automated impact propagation via trace links
- Affected artifacts list when requirements change
- Re-verification triggers
Assessor Questions to Anticipate:
| Question | Required Evidence | AI System Response |
|---|---|---|
| "How do you ensure traceability is maintained during development?" | Process description, tool configuration | "Automated extraction from commits/PRs, validated in CI/CD, reported weekly." |
| "Can you show bidirectional traces for this requirement?" | Traceability matrix, database query | "Query trace DB for REQ-ID, display upstream/downstream links." |
| "How do you detect outdated trace links?" | Suspect link algorithm, validation logs | "Compare artifact timestamps, flag links where source changed but target didn't." |
| "What is your requirements coverage percentage?" | Coverage report | "Generate current report: 94% SWE.1, 87% SWE.3, 92% SWE.6." |
Practical Examples
Example 1: Traceability Matrix in Markdown
This example demonstrates a production-ready traceability matrix for an ASIL-B automotive component:
# Traceability Matrix: Brake Pressure Monitoring System
**Component**: Brake ECU (Electronic Control Unit)
**ASIL**: ASIL-B (ISO 26262)
**Version**: 3.2.1
**Baseline**: BL-2026-01-15
## System Requirements → Software Requirements
| System Req | Software Req | Allocation Rationale | Verification Method |
|------------|--------------|---------------------|-------------------|
| SYS-001: Monitor brake pressure 0-200 bar | SWE-001, SWE-002 | SWE-001: Sensor interface, SWE-002: Range validation | Integration test |
| SYS-002: Detect sensor faults within 100ms | SWE-003, SWE-004 | SWE-003: Fault detection logic, SWE-004: Timing constraints | System test |
| SYS-003: Trigger warning at >180 bar | SWE-005 | Direct implementation in warning controller | System test |
## Software Requirements → Architecture → Code
| Software Req | Architecture Element | Code Module | Commit SHA | Status |
|--------------|---------------------|-------------|------------|--------|
| SWE-001 | `SensorInterface` component | `sensor_adc.c` lines 45-78 | `e4f5a6b` | ✅ Implemented |
| SWE-002 | `RangeValidator` component | `validators.c` lines 120-145 | `e4f5a6b` | ✅ Implemented |
| SWE-003 | `FaultDetector` component | `fault_detect.c` lines 200-250 | `a1b2c3d` | ⚠️ Suspect (code modified) |
| SWE-004 | `TimingController` component | `timing.c` lines 30-55 | `f7e8d9c` | ✅ Implemented |
| SWE-005 | `WarningController` component | — | — | ❌ Not implemented |
## Software Requirements → Test Cases
| Software Req | Unit Tests | Integration Tests | System Tests | Coverage |
|--------------|-----------|------------------|--------------|----------|
| SWE-001 | `test_sensor_adc.c::test_read_pressure` | `test_sensor_integration.py::test_adc_to_pressure` | `SYS_TC_001` | 100% |
| SWE-002 | `test_validators.c::test_range_check` | `test_validation_integration.py::test_out_of_range` | `SYS_TC_002` | 100% |
| SWE-003 | `test_fault_detect.c::test_sensor_fault` | `test_fault_integration.py::test_fault_response` | `SYS_TC_003` | 75% ⚠️ |
| SWE-004 | `test_timing.c::test_100ms_deadline` | `test_timing_integration.py::test_fault_timing` | `SYS_TC_003` | 100% |
| SWE-005 | — | — | — | 0% ❌ |
## Coverage Summary
| Lifecycle Phase | Total Artifacts | Traced Artifacts | Coverage % | Status |
|----------------|----------------|-----------------|-----------|--------|
| System → Software Req | 3 | 3 | 100% | ✅ Pass |
| Software Req → Architecture | 5 | 5 | 100% | ✅ Pass |
| Software Req → Code | 5 | 4 | 80% | ⚠️ Needs attention |
| Software Req → Tests | 5 | 4 | 80% | ⚠️ Needs attention |
## Issues Requiring Action
1. **SWE-003**: Code modified in commit `a1b2c3d` without updating requirement or test. **Action**: Review and re-validate.
2. **SWE-005**: Not implemented. **Action**: Implement warning controller module by sprint end.
3. **SWE-003 Test Coverage**: Only 75% coverage. **Action**: Add test case for sensor short-circuit fault scenario.
**Approval**:
- Prepared by: AI Traceability System v2.1
- Reviewed by: [Engineering Lead Name]
- Approved by: [Quality Manager Name]
- Date: 2026-01-26
Example 2: Python Script for Trace Link Extraction
This script extracts trace links from Git commit history and generates a JSON output suitable for database import:
#!/usr/bin/env python3
"""
extract_traces.py - Extract traceability links from Git commits
Usage:
python extract_traces.py --commits HEAD~10..HEAD --output traces.json
"""
import argparse
import json
import re
import subprocess
from datetime import datetime
from typing import List, Dict
# Requirement ID patterns (extend as needed)
REQUIREMENT_PATTERNS = {
'jira': r'\b([A-Z]+-\d+)\b',
'doors': r'\bREQ-(\d{4,5})\b',
'iso26262': r'\b(FSR|TSR|HSR|SWE|SYS)-(\d{3,5})\b',
}
def get_commit_history(commit_range: str) -> List[Dict[str, str]]:
"""
Retrieve commit history from Git.
Args:
commit_range: Git commit range (e.g., 'HEAD~10..HEAD', 'main..feature-branch')
Returns:
List of commit dictionaries with SHA, author, date, message
"""
cmd = [
'git', 'log', commit_range,
'--pretty=format:%H%n%an%n%ae%n%ai%n%s%n%b%n---END---'
]
result = subprocess.run(cmd, capture_output=True, text=True, check=True)
commits = []
raw_commits = result.stdout.split('---END---\n')
for raw in raw_commits:
if not raw.strip():
continue
lines = raw.strip().split('\n')
if len(lines) < 5:
continue
commits.append({
'sha': lines[0],
'author': lines[1],
'email': lines[2],
'date': lines[3],
'subject': lines[4],
'body': '\n'.join(lines[5:]) if len(lines) > 5 else ''
})
return commits
def extract_requirement_ids(text: str) -> List[Dict[str, str]]:
"""
Extract requirement IDs from text using defined patterns.
Args:
text: Commit message or code comment
Returns:
List of dictionaries with 'type' and 'id' keys
"""
requirements = []
for req_type, pattern in REQUIREMENT_PATTERNS.items():
matches = re.finditer(pattern, text, re.IGNORECASE)
for match in matches:
if req_type == 'iso26262':
req_id = f"{match.group(1)}-{match.group(2)}"
else:
req_id = match.group(1)
requirements.append({
'type': req_type,
'id': req_id
})
return requirements
def extract_traces(commits: List[Dict[str, str]]) -> List[Dict]:
"""
Extract traceability links from commit history.
Args:
commits: List of commit dictionaries
Returns:
List of trace link dictionaries
"""
traces = []
for commit in commits:
full_message = f"{commit['subject']}\n{commit['body']}"
requirements = extract_requirement_ids(full_message)
if requirements:
traces.append({
'commit_sha': commit['sha'],
'commit_date': commit['date'],
'author': commit['author'],
'requirements': requirements,
'message_subject': commit['subject']
})
return traces
def generate_trace_report(traces: List[Dict]) -> Dict:
"""
Generate summary statistics for trace extraction.
Args:
traces: List of trace link dictionaries
Returns:
Dictionary with statistics
"""
total_commits = len(traces)
total_requirements = sum(len(t['requirements']) for t in traces)
requirement_counts = {}
for trace in traces:
for req in trace['requirements']:
req_id = req['id']
requirement_counts[req_id] = requirement_counts.get(req_id, 0) + 1
return {
'extraction_date': datetime.now().isoformat(),
'total_commits_with_traces': total_commits,
'total_requirement_references': total_requirements,
'unique_requirements': len(requirement_counts),
'most_referenced_requirements': sorted(
requirement_counts.items(),
key=lambda x: x[1],
reverse=True
)[:10]
}
def main():
parser = argparse.ArgumentParser(
description='Extract traceability links from Git commit history'
)
parser.add_argument(
'--commits',
required=True,
help='Git commit range (e.g., HEAD~10..HEAD)'
)
parser.add_argument(
'--output',
required=True,
help='Output JSON file path'
)
args = parser.parse_args()
# Extract commits
print(f"Extracting commits from range: {args.commits}")
commits = get_commit_history(args.commits)
print(f"Found {len(commits)} commits")
# Extract traces
print("Extracting traceability links...")
traces = extract_traces(commits)
print(f"Found {len(traces)} commits with requirement references")
# Generate report
report = generate_trace_report(traces)
# Write output
output = {
'metadata': report,
'traces': traces
}
with open(args.output, 'w') as f:
json.dump(output, f, indent=2)
print(f"\nTrace extraction complete!")
print(f"Total commits with traces: {report['total_commits_with_traces']}")
print(f"Total requirement references: {report['total_requirement_references']}")
print(f"Unique requirements: {report['unique_requirements']}")
print(f"\nOutput written to: {args.output}")
if __name__ == '__main__':
main()
Usage Example:
# Extract traces from last 50 commits
python scripts/extract_traces.py --commits HEAD~50..HEAD --output traces.json
# Extract traces from feature branch
python scripts/extract_traces.py --commits main..feature/brake-monitoring --output traces.json
# Output (traces.json):
{
"metadata": {
"extraction_date": "2026-01-26T14:30:00",
"total_commits_with_traces": 23,
"total_requirement_references": 45,
"unique_requirements": 12,
"most_referenced_requirements": [
["SWE-001", 8],
["REQ-0042", 6],
["FSR-0001", 5]
]
},
"traces": [
{
"commit_sha": "e4f5a6b7c8d9",
"commit_date": "2026-01-25 16:45:00",
"author": "Jane Developer",
"requirements": [
{"type": "iso26262", "id": "SWE-001"},
{"type": "iso26262", "id": "SWE-002"}
],
"message_subject": "Implement sensor interface (SWE-001, SWE-002)"
}
]
}
Example 3: n8n Workflow for Automated Trace Updates
This workflow monitors Jira for new requirements and GitHub for new commits, then automatically creates bidirectional trace links:
# n8n Workflow Export (YAML format)
name: Automated Traceability Sync
version: 1
active: true
nodes:
- name: Schedule Trigger
type: n8n-nodes-base.scheduleTrigger
parameters:
rule:
interval:
- hours: 6 # Run every 6 hours
position: [250, 300]
- name: Query Jira Requirements
type: n8n-nodes-base.jira
parameters:
resource: issue
operation: getAll
jql: 'project = BRAKE AND type = Requirement AND updated >= -6h'
fields:
- key
- summary
- description
- updated
position: [450, 300]
- name: Query GitHub Commits
type: n8n-nodes-base.httpRequest
parameters:
url: 'https://api.github.com/repos/org/brake-ecu/commits'
method: GET
queryParameters:
since: '={{ $now.minus({ hours: 6 }).toISO() }}'
headerParameters:
Authorization: 'token {{ $env.GITHUB_TOKEN }}'
position: [450, 500]
- name: Extract Requirement IDs from Commits
type: n8n-nodes-base.code
parameters:
jsCode: |
const commits = $input.all();
const reqPattern = /\b(SWE|FSR|TSR|REQ)-(\d{3,5})\b/g;
const results = [];
for (const commit of commits) {
const message = commit.json.commit.message;
const matches = message.match(reqPattern) || [];
if (matches.length > 0) {
results.push({
commitSHA: commit.json.sha,
commitMessage: message,
commitAuthor: commit.json.commit.author.name,
commitDate: commit.json.commit.author.date,
requirements: [...new Set(matches)] // Deduplicate
});
}
}
return results;
position: [650, 500]
- name: Calculate Semantic Similarity
type: n8n-nodes-base.httpRequest
parameters:
url: 'https://api.openai.com/v1/embeddings'
method: POST
headerParameters:
Authorization: 'Bearer {{ $env.OPENAI_API_KEY }}'
Content-Type: 'application/json'
bodyParameters:
model: 'text-embedding-3-small'
input:
- '={{ $json.jira_summary }}'
- '={{ $json.commit_message }}'
position: [850, 400]
- name: Compute Cosine Similarity
type: n8n-nodes-base.code
parameters:
jsCode: |
function cosineSimilarity(vecA, vecB) {
const dotProduct = vecA.reduce((sum, a, i) => sum + a * vecB[i], 0);
const magA = Math.sqrt(vecA.reduce((sum, a) => sum + a * a, 0));
const magB = Math.sqrt(vecB.reduce((sum, b) => sum + b * b, 0));
return dotProduct / (magA * magB);
}
const embeddings = $json.data;
const similarity = cosineSimilarity(embeddings[0].embedding, embeddings[1].embedding);
return {
...$ json,
similarity: similarity,
confidence: similarity >= 0.85 ? 'high' : (similarity >= 0.70 ? 'medium' : 'low')
};
position: [1050, 400]
- name: Filter High Confidence
type: n8n-nodes-base.if
parameters:
conditions:
string:
- value1: '={{ $json.confidence }}'
operation: equals
value2: 'high'
position: [1250, 300]
- name: Auto-Create Jira Link
type: n8n-nodes-base.jira
parameters:
resource: issue
operation: update
issueKey: '={{ $json.requirement_key }}'
updateFields:
weblinks:
- url: 'https://github.com/org/brake-ecu/commit/{{ $json.commitSHA }}'
title: 'Implementation Commit'
position: [1450, 200]
- name: Update GitHub Commit Status
type: n8n-nodes-base.httpRequest
parameters:
url: 'https://api.github.com/repos/org/brake-ecu/statuses/{{ $json.commitSHA }}'
method: POST
headerParameters:
Authorization: 'token {{ $env.GITHUB_TOKEN }}'
bodyParameters:
state: 'success'
context: 'traceability/auto-link'
description: 'Linked to {{ $json.requirement_key }}'
position: [1450, 300]
- name: Filter Medium Confidence
type: n8n-nodes-base.if
parameters:
conditions:
string:
- value1: '={{ $json.confidence }}'
operation: equals
value2: 'medium'
position: [1250, 500]
- name: Send Slack Review Request
type: n8n-nodes-base.slack
parameters:
resource: message
operation: post
channel: '#traceability-review'
text: |
🔍 *Trace Link Review Needed*
*Requirement*: {{ $json.requirement_key }} - {{ $json.jira_summary }}
*Commit*: `{{ $json.commitSHA.slice(0, 7) }}` by {{ $json.commitAuthor }}
*Similarity*: {{ ($json.similarity * 100).toFixed(1) }}%
Should these be linked?
<https://jira.company.com/browse/{{ $json.requirement_key }}|View Requirement>
<https://github.com/org/brake-ecu/commit/{{ $json.commitSHA }}|View Commit>
position: [1450, 500]
- name: Log to Trace Database
type: n8n-nodes-base.postgres
parameters:
operation: insert
table: trace_links
columns:
- requirement_id
- commit_sha
- similarity_score
- confidence_level
- created_at
- created_by
values:
requirement_id: '={{ $json.requirement_key }}'
commit_sha: '={{ $json.commitSHA }}'
similarity_score: '={{ $json.similarity }}'
confidence_level: '={{ $json.confidence }}'
created_at: '={{ $now.toISO() }}'
created_by: 'n8n-automation'
position: [1650, 400]
connections:
Schedule Trigger:
main:
- - node: Query Jira Requirements
type: main
index: 0
- node: Query GitHub Commits
type: main
index: 0
Query GitHub Commits:
main:
- - node: Extract Requirement IDs from Commits
Extract Requirement IDs from Commits:
main:
- - node: Calculate Semantic Similarity
Calculate Semantic Similarity:
main:
- - node: Compute Cosine Similarity
Compute Cosine Similarity:
main:
- - node: Filter High Confidence
- node: Filter Medium Confidence
Filter High Confidence:
true:
- - node: Auto-Create Jira Link
- node: Update GitHub Commit Status
- node: Log to Trace Database
Filter Medium Confidence:
true:
- - node: Send Slack Review Request
- node: Log to Trace Database
Summary
Automated traceability capabilities:
- AI Trace Suggestion: ML models recommend trace links based on textual similarity (0.85+ confidence threshold for auto-approval)
- Auto-Linking: Parse commit messages and code comments for requirement references using regex patterns
- Suspect Detection: Identify potentially broken links after changes by comparing artifact timestamps
- Coverage Analysis: Automated gap identification in traceability matrix with orphan requirement detection
- Sync Automation: Keep requirements tools (Jira, Azure DevOps, DOORS) synchronized with code repositories via REST APIs and webhooks
Best Practices:
- Use consistent requirement ID patterns in commits (e.g.,
REQ-0001,SWE-042,PROJ-123) - Implement automated validation in CI/CD pipelines (extract traces on every push, fail builds on coverage drops)
- Review AI suggestions before accepting (low-confidence links require human validation)
- Monitor traceability coverage metrics (target: ≥95% for ASPICE CL2+, 100% for safety-critical requirements)
- Maintain bidirectional links for full V-Model coverage (upstream and downstream traces)
- Log all trace link creation/modification with audit trail (who, when, why, confidence score)
- Integrate with existing toolchains (Jira, Azure DevOps, DOORS, Polarion) rather than building custom solutions
- Use semantic embeddings for cross-artifact trace suggestions (requirements ↔ tests, requirements ↔ architecture)
- Validate suspect links after requirement or code changes (automated change impact analysis)
- Generate traceability evidence suitable for ASPICE/ISO 26262 assessments (matrices, coverage reports, audit logs)
Embedded Systems Consideration: In resource-constrained embedded systems, traceability automation must account for hardware-software co-design. Trace links should extend to hardware requirements (HWE.1-5 in ASPICE), FPGA modules, and hardware test specifications. Timing constraints, memory allocation, and interrupt handlers require explicit traceability to safety requirements (e.g., ASIL-B watchdog monitoring → SWE-045 → watchdog.c:45-60 → TC-U-004 → TC-S-045).
Liability Note: Automated traceability systems reduce but do not eliminate human accountability. ASPICE and safety standards require human approval of critical trace links, particularly for safety requirements (ASIL-B and above in ISO 26262, SIL-2+ in IEC 61508). AI-suggested links must include confidence scores, and low-confidence suggestions must undergo human review. Audit logs must demonstrate that automated trace creation was validated by qualified personnel. In the event of a safety incident, traceability evidence will be scrutinized—automated systems must provide reproducible, explainable link creation rationale.