traceability Skill
Generate and validate the requirements-to-evidence traceability matrix for projects that
have adopted the regulated-industry track. The skill is the read-mostly counterpart to
doc-index: where doc-index builds the catalogue, traceability stitches the catalogue
into the audit-facing matrix.
Usage
/traceability # Generate matrix and report broken links (warnings only)
/traceability --ci # Validate-only mode for CI; exits non-zero on broken links
/traceability --check-only # Validate the existing matrix without regenerating it
/traceability --verbose # Print per-row resolution detail
No positional arguments. Operates on the current project directory.
Arguments
| Flag | Behavior |
|---|---|
--ci |
Generate matrix, then validate. Exit non-zero if any broken link is reported. Intended for the validate job in GitHub Actions. |
--check-only |
Skip generation; validate the existing docs/.index/traceability.yaml against the current docs/.index/ and compliance/ state. Use to detect drift without rewriting the artifact. |
--verbose |
Print one line per matrix row showing how each cell was resolved (which manifest entry, which graph cascade, which compliance clause). |
--ci and --check-only are mutually exclusive. If both are supplied, --ci wins and a
warning is printed.
Inputs
| Path | Required | Purpose |
|---|---|---|
docs/.index/graph.yaml |
Yes (gate) | Source of cascade chains and req_chains. Skill is a no-op when this file is absent. |
docs/.index/manifest.yaml |
Yes | Document registry with doc_ids, sections, and tags. |
docs/.index/bundles.yaml |
Yes | Feature bundles used to detect orphan code paths. |
docs/.index/router.yaml |
Yes | ID routes for resolving requirement_id and other entity references. |
compliance/ |
Optional | Per-standard rule files (e.g. iec-62304.md, iso-13485.md). When present, each clause referenced in the matrix is verified to exist. |
Outputs
| Path | Format | Audience |
|---|---|---|
docs/.index/traceability.yaml |
YAML | Machine-readable matrix consumed by hooks, CI, and other skills. |
docs/.index/traceability.md |
Markdown | Human-readable matrix reviewable in PR diffs. |
Both files are regenerated atomically: the skill writes to a sibling *.tmp file and renames
on success. A failed generation never produces a half-written artifact.
Opt-in Gate
The skill is purely additive and must not break repos that have not adopted the regulated track.
if [[ ! -f docs/.index/graph.yaml ]]; then
echo "traceability: docs/.index/graph.yaml absent — skill is a no-op for this repo"
exit 0
fi
This check runs before any other phase. The exit code is 0 so CI invocations on
non-regulated repos do not fail.
Instructions
Phase 0: Validate Environment
- Confirm
docs/.index/graph.yamlexists; if not, print the no-op message and exit 0. - Confirm the remaining three index files (
manifest.yaml,bundles.yaml,router.yaml) are present. Missing any of these is a hard failure — the matrix cannot be built. - Detect optional
compliance/directory at the repo root. Record whether it exists; theclause_refsvalidation in Phase 3 depends on this. - If
--check-onlyis set, skip Phase 1 and 2. Read the existingdocs/.index/traceability.yamldirectly and proceed to Phase 3.
Phase 1: Resolve Entities
Build in-memory lookup tables from the index files. Reference: reference/matrix-schema.md
defines the row shape these tables feed.
- Requirements: from
router.yamlid_routes.SRS, walk each section insection_mapand emit one entry perSRS-{CAT}-{NNN}identifier discovered. Record source file and line range for each. - Design items: from
router.yamlid_routes.SI(andIFif present). Each becomes a candidatedesign_idfor matching requirements. - Code paths: from
bundles.yaml, collect everyfiles[].filevalue plus anycode_pathsfield present at the bundle level. The skill does not crawl source-code directories directly — it relies on the bundle catalogue to bound the search. - Tests: from
router.yamlid_routes.TC. EachTC-{CAT}-{NNN}is a candidatetest_id. Section line ranges identify the source SVP document. - Risk records: from
router.yamlid_routes.Hand anyid_routes.HUS. Hazards becomerisk_ids; HUS scenarios are recorded as additional risk evidence. - Clauses: if
compliance/exists, scancompliance/*.mdfor clause anchors. The accepted format is> **Clause**: <STANDARD>-<NUMBER>or a heading## Clause <STANDARD>-<NUMBER>. Record each clause as{standard, number, file, line}.
Phase 2: Stitch the Matrix
For each requirement_id discovered in Phase 1, build one matrix row by following the
cascade graph:
- Start with the row keyed by
requirement_id. - Design link: read
graph.yamlreq_chains.<requirement_category>.design_itemsand record the matchingSI-ids. If the row'srequirement_idisSRS-CALC-001, the relevant chain isreq_chains.SRS-CALC(or whatever keydoc-indexproduced). - Code paths: collect every bundle
files[].filewhose bundle includes the design id from step 2, or whose bundle name matches the requirement category. - Tests: read
req_chains.<category>.testsand record matchingTC-ids. - Risk: read
req_chains.<category>.hazardsand record matchingH-ids. - Clause refs: any clauses in
compliance/whose body cites the requirement id (viarequirement_id:frontmatter or inline> SRS-<CAT>-<NNN>reference) are added. - Status: derive from cell completeness. See
reference/matrix-schema.mdfor the full status table.
Phase 3: Validate
Reference: reference/validation-rules.md defines the broken-link taxonomy and exit codes.
Validation runs whether or not the matrix was just regenerated. Each finding is one of:
| Finding | Trigger |
|---|---|
requirement_without_test |
Row has test_ids: [] and status is not deferred. |
code_without_trace |
A file appears in bundles.yaml but no matrix row references it. |
dangling_clause_ref |
A clause_refs entry names a clause not present in compliance/. |
dangling_design_ref |
A design_id that does not appear in router.yaml id_routes.SI. |
dangling_risk_ref |
A risk_ids entry not present in router.yaml id_routes.H. |
dangling_test_ref |
A test_ids entry not present in router.yaml id_routes.TC. |
orphan_requirement |
A requirement_id discovered in Phase 1 has no row in the matrix. |
Findings are written to the report regardless of mode. The exit-code policy is:
- Default mode: warnings only, exit 0 even when findings exist.
--ciand--check-only: any finding causes a non-zero exit (seereference/validation-rules.mdfor the exit-code map).
Phase 4: Write Artifacts
Skip when --check-only is set.
- Write
docs/.index/traceability.yaml.tmpwith the row schema fromreference/matrix-schema.md. - Write
docs/.index/traceability.md.tmpfrom the same row data, formatted as a Markdown table grouped by requirement category. - On success, rename both
*.tmpfiles to their final names. On any error, delete the*.tmpfiles and exit non-zero.
Phase 5: Report
Emit a summary block on stdout:
## Traceability Matrix Generated
| Metric | Value |
|--------|-------|
| Requirements | N |
| Rows complete | N |
| Rows incomplete | N |
| Findings | N (M errors / K warnings) |
| traceability.yaml | X bytes |
| traceability.md | Y bytes |
Append a per-finding table when --verbose is set or when running under --ci.
Output
The skill produces the two artifacts above plus the on-stdout summary. No other files are
modified — in particular, the skill never edits manifest.yaml, bundles.yaml, graph.yaml,
or router.yaml. Those remain doc-index's responsibility.
Error Handling
| Condition | Action |
|---|---|
docs/.index/graph.yaml absent |
No-op exit 0 (opt-in gate, see Phase 0). |
docs/.index/{manifest,bundles,router}.yaml absent |
Exit non-zero with the missing file name. |
| YAML parse error in any input | Exit non-zero with file path and line number. |
| Write step fails (permission, disk) | Delete any *.tmp files, report the path, exit non-zero. |
Validation finding in --ci or --check-only mode |
Print the finding table, exit non-zero (see exit-code map in reference/validation-rules.md). |
| Validation finding in default mode | Print the finding table, exit 0. |
compliance/ referenced but absent |
Skip clause validation; print one informational line; do not fail. |
Policies
Command-Specific Rules
| Item | Rule |
|---|---|
| Inputs | Only docs/.index/*.yaml and compliance/*.md are read. The skill never crawls source-code directories directly. |
| Outputs | Only docs/.index/traceability.yaml and docs/.index/traceability.md. No other files are touched. |
| Opt-in | Absent docs/.index/graph.yaml is a no-op exit 0, never a failure. |
| Atomicity | Writes go to *.tmp first, then rename on success. Failure deletes the temp files. |
| Existing skills | This skill is purely additive; existing skill behavior is unchanged. |
How Other Components Use the Matrix
| Consumer | Use |
|---|---|
traceability-guard PreToolUse hook (sibling issue #590) |
Reads traceability.yaml to detect when a PR touches a code_paths entry without updating its row. |
compliance/<standard>.md rules (sibling issue #591) |
Reference clauses validated by this skill's dangling_clause_ref finding. |
pr-work skill (future P2) |
Auto-injects impacted matrix rows into the PR body. |
| External auditor | Reads traceability.md directly from the repo at any tagged release. |
References
- Schema for
traceability.yaml:reference/matrix-schema.md - Validation rules and exit codes:
reference/validation-rules.md - Catalogue producer:
global/skills/_internal/doc-index/SKILL.md - Parent epic:
kcenon/claude-config#588
Side Effects and Loop-Safety
This skill is loop_safe: true. It is a single-pass (max_iterations: 1) read-mostly operation: it consumes docs/.index/{manifest,bundles,graph,router}.yaml and writes only docs/.index/traceability.{yaml,md}, never mutating source documents. Re-running is idempotent — it regenerates the same two artifacts from current inputs, so wrapping it in a /loop is safe (and a no-op when graph.yaml is absent). The max_iterations: 1 / halt_conditions metadata expresses single-pass exit semantics, not a polling loop.