qa
Requirements traceability for safety-critical Rust software. Define requirements as code, link them to tests with an attribute macro, and auto-generate a traceability matrix.
Quick Start
# Cargo.toml
[]
= "0.1"
use *;
// Define a requirement
requirement!
// Link a test to it
// Generate the matrix
Defining Requirements
Single requirement
requirement!
Batch definition
requirements!
Requirement fields
description(required, must be first): human-readable text- type (required, after
:): aRequirementTypevariant - All other key-value pairs become freeform metadata
RequirementType
Built-in variants: Functional, NonFunctional, Performance, Safety, Security, Interface.
Extend with Custom:
const REGULATORY: RequirementType = Custom;
requirement!
Accessing metadata
let source = REQ_VOID_TRACKING.get; // Some("NRC Reg Guide 1.190 §4.2")
let missing = REQ_VOID_TRACKING.get; // None
Tracing Tests
use traces;
// Multiple requirements per test
Composability
#[traces] emits the test function unchanged and appends registration as a separate item. It composes with any attribute macro regardless of ordering:
Generating the Matrix
let matrix = collect;
Analysis
matrix.requirements // all registered requirements
matrix.traces // all registered traces
matrix.traces_for // tests for a specific requirement
matrix.untraced // requirements with no tests
matrix.orphan_traces // traces referencing nonexistent requirement IDs
matrix.coverage // fraction of requirements with ≥1 test (0.0..=1.0)
matrix.assert_complete // panics if any requirement is untraced
Output
// Terminal table (via tabled)
matrix.print;
// Markdown file
matrix.write.unwrap;
// JSON file (requires `json` feature)
matrix.write.unwrap;
Organizing Requirements
Place requirements at the top of the files they govern:
// src/transport.rs
requirements!
// ... implementation code ...
Requirements register globally via linkme distributed slices regardless of which file or crate they're defined in. No central manifest to maintain.
Filtering and Grouping
Operate on freeform metadata for custom views:
// Only safety requirements
let safety = matrix.filter_by;
safety.print;
// Group by source document
let by_source = matrix.group_by;
for in &by_source
no_std Support
The core types, macros, and linkme slices work without std. Disable default features:
[]
= { = "0.1", = false }
This gives you Requirement, RequirementType, TestTrace, requirement!, requirements!, and #[traces] on bare-metal targets. Matrix and all rendering require std.
Typical workflow: define requirements in your no_std library crate, then collect and render the matrix from a host-side test binary that enables std.
Feature Flags
| Feature | Default | Description |
|---|---|---|
std |
yes | Matrix, terminal tables, file output |
json |
no | JSON rendering via serde (implies std) |
Workspace
| Crate | Description |
|---|---|
qa |
Core library — types, macros, matrix generation |
qa-macros |
Proc-macro crate — #[traces] attribute |
Development
no_std verification
Releasing
Releases are triggered manually from GitLab CI. Go to CI/CD → Pipelines → Run pipeline, set the BUMP variable to patch, minor, or major, then run the release job. This bumps versions across the workspace, publishes to crates.io, and pushes a version commit + tag.
License
MIT