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.

Traceability Layers

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.

Source Systems Integration

Architecture Principles:

  1. Separation of Concerns: Extraction, processing, validation, and storage are decoupled.
  2. Idempotency: Re-running extraction does not create duplicate trace links.
  3. Auditability: All trace link creation/modification events are logged with timestamp and user.
  4. 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.

Traceability Triggers

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:

  1. Embedding Generation: Convert requirement text and test case descriptions to vector embeddings.
  2. Similarity Calculation: Compute cosine similarity between requirement and test embeddings.
  3. Threshold-Based Filtering: Accept suggestions above confidence threshold.
  4. 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:

  1. Duplicate Detection: Prevent creating trace links that already exist.
  2. Orphan Detection: Identify requirements or test cases with zero trace links.
  3. Cycle Detection: Prevent circular dependencies (e.g., REQ-A → REQ-B → REQ-A).
  4. 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:

  1. Traceability Matrix (SUP.8 Work Product 13-04):

    • Bidirectional links between all lifecycle artifacts
    • Coverage percentages per requirement
    • Orphan and suspect link identification
  2. 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
  3. Coverage Reports (SWE.6 Work Product 13-22):

    • Requirements coverage by tests
    • Code coverage by unit tests
    • Gaps analysis with risk assessment
  4. 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:

  1. Use consistent requirement ID patterns in commits (e.g., REQ-0001, SWE-042, PROJ-123)
  2. Implement automated validation in CI/CD pipelines (extract traces on every push, fail builds on coverage drops)
  3. Review AI suggestions before accepting (low-confidence links require human validation)
  4. Monitor traceability coverage metrics (target: ≥95% for ASPICE CL2+, 100% for safety-critical requirements)
  5. Maintain bidirectional links for full V-Model coverage (upstream and downstream traces)
  6. Log all trace link creation/modification with audit trail (who, when, why, confidence score)
  7. Integrate with existing toolchains (Jira, Azure DevOps, DOORS, Polarion) rather than building custom solutions
  8. Use semantic embeddings for cross-artifact trace suggestions (requirements ↔ tests, requirements ↔ architecture)
  9. Validate suspect links after requirement or code changes (automated change impact analysis)
  10. 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.