Skip to main content

Links and Relations

Links turn standalone artifacts into a navigable knowledge graph. Each link records direction, relation type, confidence, and provenance so downstream tooling can reason about coverage, dependencies, and impact.

{
"id": "link:L-001",
"from": "req:REQ-001",
"to": "test:TC-001",
"relation": "verified_by",
"confidence": 0.95,
"status": "approved",
"created_at": "2024-01-20T10:00:00Z",
"created_by": "jane.smith@example.com",
"rationale": "Test directly validates requirement acceptance criteria"
}

Core Relations

Verification

{ "from": "req:REQ-ACC-001", "to": "test:TC-ACC-001", "relation": "verified_by", "confidence": 1.0 }
{ "from": "test:TC-ACC-001", "to": "req:REQ-ACC-001", "relation": "validates" }

Implementation

{ "from": "design:DES-ACC-001", "to": "req:REQ-ACC-001", "relation": "implements", "confidence": 0.9 }
{ "from": "design:DES-ACC-001", "to": "comp:COMP-ACC-001", "relation": "realized_by" }

Hierarchy

{ "from": "req:SW-REQ-001", "to": "req:SYS-REQ-001", "relation": "derived_from", "rationale": "Software requirement refined from system requirement" }
{ "from": "req:SYS-REQ-001", "to": "req:SW-REQ-001", "relation": "decomposes" }

Domain Relations

Safety

{
"from": "haz:HAZ-001",
"to": "req:SR-001",
"relation": "mitigated_by",
"confidence": 0.85,
"fields": {
"mitigation_type": "prevention",
"effectiveness": "high"
}
}
{ "from": "sg:SG-001", "to": "haz:HAZ-001", "relation": "addresses" }

Dependencies and conflicts

{
"from": "comp:MODULE-A",
"to": "comp:MODULE-B",
"relation": "depends_on",
"fields": {
"dependency_type": "compile-time",
"version_constraint": ">=2.0.0"
}
}
{
"from": "req:REQ-100",
"to": "req:REQ-200",
"relation": "conflicts_with",
"rationale": "Mutually exclusive timing requirements"
}

Change management

{
"from": "cr:CR-2024-001",
"to": "req:REQ-001",
"relation": "modifies",
"fields": {
"impact": "major",
"change_type": "functional"
}
}
{ "from": "req:REQ-001-v2", "to": "req:REQ-001-v1", "relation": "supersedes", "created_at": "2024-02-01T10:00:00Z" }

Confidence Scoring

ScoreMeaningExample
1.0Direct, verifiedTest written specifically for requirement
0.9–0.99High confidenceClear implementation link
0.7–0.89ModeratePartial coverage or indirect verification
0.5–0.69LowAssumed or unverified relationship
< 0.5Very lowNeeds review
function calculateConfidence(link) {
let confidence = 1.0;
if (link.fields?.relationship_type === "indirect") confidence -= 0.2;
if (link.fields?.coverage === "partial") confidence -= 0.1;
if (link.fields?.verification === "manual") confidence -= 0.15;
return Math.max(0.5, confidence);
}

Traceability Patterns

graph LR
CR[Customer Req] --> SR[System Req]
SR --> SwR[Software Req]
SwR --> DD[Detailed Design]
DD --> Code[Implementation]
Code --> UT[Unit Test]
UT --> IT[Integration Test]
IT --> ST[System Test]
ST --> AT[Acceptance Test]
AT --> CR
const vModelLinks = [
{ from: "req:CUST-001", to: "req:SYS-001", relation: "refined_to" },
{ from: "req:SYS-001", to: "req:SW-001", relation: "refined_to" },
{ from: "req:SW-001", to: "design:DD-001", relation: "implemented_by" },
{ from: "design:DD-001", to: "code:MOD-001", relation: "realized_by" },
{ from: "code:MOD-001", to: "test:UT-001", relation: "verified_by" },
{ from: "test:UT-001", to: "test:IT-001", relation: "integrated_in" },
{ from: "test:IT-001", to: "test:ST-001", relation: "validated_in" },
{ from: "test:ST-001", to: "test:AT-001", relation: "accepted_in" },
{ from: "test:AT-001", to: "req:CUST-001", relation: "validates" }
];

const safetyCase = [
{ from: "haz:HAZ-001", to: "sg:SG-001", relation: "addressed_by" },
{ from: "sg:SG-001", to: "req:FSR-001", relation: "refined_to" },
{ from: "req:FSR-001", to: "req:TSR-001", relation: "refined_to" },
{ from: "req:TSR-001", to: "design:SAFETY-MON", relation: "implemented_by" },
{ from: "design:SAFETY-MON", to: "test:FIT-001", relation: "verified_by" },
{ from: "test:FIT-001", to: "result:PASS-001", relation: "produces" }
];
function forwardTrace(artifactId, links) {
const affected = new Set();
const queue = [artifactId];
while (queue.length) {
const current = queue.shift();
links
.filter(l => l.from === current)
.map(l => l.to)
.forEach(id => {
if (!affected.has(id)) {
affected.add(id);
queue.push(id);
}
});
}
return Array.from(affected);
}
function backwardTrace(testId, links) {
const sources = new Set();
const queue = [testId];
while (queue.length) {
const current = queue.shift();
links
.filter(l => l.to === current)
.map(l => l.from)
.forEach(id => {
if (!sources.has(id)) {
sources.add(id);
queue.push(id);
}
});
}
return Array.from(sources);
}
function calculateCoverage(artifacts, links) {
const requirements = artifacts.filter(a => a.kind === "requirement");
const tested = requirements.filter(req =>
links.some(l =>
l.from === req.id && l.relation === "verified_by" && l.confidence >= 0.7
)
);
return {
total: requirements.length,
covered: tested.length,
percentage: (tested.length / requirements.length) * 100,
gaps: requirements.filter(r => !tested.includes(r))
};
}
const validationRules = {
noSelfLinks: link => link.from !== link.to,
validRelation: (link, artifacts) => {
const from = artifacts.find(a => a.id === link.from);
const to = artifacts.find(a => a.id === link.to);
if (from.kind === "requirement" && link.relation === "verified_by") {
return to.kind === "test";
}
return true;
},
noCycles: links => !hasCycles(links),
validConfidence: link => link.confidence >= 0 && link.confidence <= 1
};

function findOrphans(artifacts, links) {
const linked = new Set();
links.forEach(link => {
linked.add(link.from);
linked.add(link.to);
});
return artifacts.filter(a => !linked.has(a.id));
}

Best Practices

  • Use relations that reflect intent:
{ "from": "test:TC-001", "to": "req:REQ-001", "relation": "validates" }
  • Capture rationale and conditions:
{
"from": "req:REQ-001",
"to": "test:TC-001",
"relation": "verified_by",
"rationale": "TC-001 directly tests all acceptance criteria of REQ-001",
"coverage": "full",
"test_conditions": ["nominal", "boundary", "error"]
}
  • Track inverse links or version constraints when needed:
{
"from": "req:REQ-001",
"to": "test:TC-001",
"relation": "verified_by",
"version_constraints": { "from_version": "2.0.0", "to_version": "1.5.0" }
}

Visualization

graph TD
REQ1[REQ-001: Safe Distance] --> TEST1[TC-001: Distance Test]
REQ1 --> TEST2[TC-002: Emergency Test]
REQ1 --> DESIGN1[DES-001: Sensor Fusion]
DESIGN1 --> COMP1[Radar Module]
DESIGN1 --> COMP2[Camera Module]
HAZ1[HAZ-001: Collision] --> REQ1
HAZ1 --> SG1[SG-001: Prevent Collision]
SG1 --> REQ1
REQ-001REQ-002REQ-003
TC-001
TC-002
TC-003
TC-004

Impact Analysis

function impactAnalysis(changedArtifact, links, artifacts) {
const impact = {
direct: [],
indirect: [],
tests_affected: [],
components_affected: [],
risk_level: "low"
};

impact.direct = links
.filter(l => l.from === changedArtifact || l.to === changedArtifact)
.map(l => (l.from === changedArtifact ? l.to : l.from));

impact.direct.forEach(id => {
const artifact = artifacts.find(a => a.id === id);
if (artifact.kind === "test") impact.tests_affected.push(id);
if (artifact.kind === "component") impact.components_affected.push(id);
});

if (impact.components_affected.length > 5) impact.risk_level = "high";
else if (impact.tests_affected.length > 10) impact.risk_level = "medium";

return impact;
}

Next Steps