Skip to content
14 changes: 14 additions & 0 deletions .reviewmark.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
needs-review:
- "**/*.cs" # All C# source and test files
- "docs/reqstream/**/*.yaml" # Requirements files
- "docs/design/**/*.md" # Design documents
- "!**/obj/**" # Exclude build output
- "!**/bin/**" # Exclude build output

Expand All @@ -28,27 +29,31 @@ reviews:
title: Review of ReqStream Context Unit
paths:
- "docs/reqstream/unit-context.yaml"
- "docs/design/context.md"
- "src/**/Context.cs"
- "test/**/ContextTests.cs"

- id: ReqStream-Program
title: Review of ReqStream Program Unit
paths:
- "docs/reqstream/unit-program.yaml"
- "docs/design/program.md"
- "src/**/Program.cs"
- "test/**/ProgramTests.cs"

- id: ReqStream-Validation
title: Review of ReqStream Validation Unit
paths:
- "docs/reqstream/unit-validation.yaml"
- "docs/design/validation.md"
- "src/**/Validation.cs"
- "test/**/ValidationTests.cs"

- id: ReqStream-Requirements
title: Review of ReqStream Requirements Unit
paths:
- "docs/reqstream/unit-requirements.yaml"
- "docs/design/requirements.md"
- "src/**/Requirement.cs"
- "src/**/Requirements.cs"
- "src/**/Section.cs"
Expand All @@ -59,11 +64,20 @@ reviews:
title: Review of ReqStream TraceMatrix Unit
paths:
- "docs/reqstream/unit-trace-matrix.yaml"
- "docs/design/tracematrix.md"
- "src/**/TraceMatrix.cs"
- "test/**/TraceMatrixTests.cs"
- "test/**/TraceMatrixReadTests.cs"
- "test/**/TraceMatrixExportTests.cs"

- id: ReqStream-Linter
title: Review of ReqStream Linter Unit
paths:
- "docs/reqstream/unit-linter.yaml"
- "docs/design/linter.md"
- "src/**/Linter.cs"
- "test/**/LinterTests.cs"

# Platform and OTS dependency reviews
- id: Platform-Support
title: Review of Platform and Runtime Support Requirements
Expand Down
31 changes: 29 additions & 2 deletions ARCHITECTURE.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ concerns with distinct classes for each major responsibility.
| `Context` | `Context.cs` | Parses CLI arguments; owns all options and output |
| `Requirements` | `Requirements.cs` | Reads, merges, and validates YAML requirement files |
| `TraceMatrix` | `TraceMatrix.cs` | Maps test results to requirements; calculates coverage |
| `Linter` | `Linter.cs` | Lints requirement YAML files and reports all structural issues |

Two supporting value types live alongside `TraceMatrix`:

Expand All @@ -42,16 +43,20 @@ flowchart TD
ctx[Context<br/>options & output]
req[Requirements<br/>parsed tree]
tm[TraceMatrix<br/>coverage analysis]
lint[Linter<br/>YAML structural checks]
reports[Markdown Reports<br/>requirements · justifications · trace matrix]
exit[Exit Code<br/>0 = pass · 1 = fail]

yaml --> req
yaml --> lint
tests --> tm
args --> ctx
ctx --> req
ctx --> lint
req --> tm
tm --> reports
tm --> exit
lint --> exit
```

### Execution Flow at a Glance
Expand All @@ -60,7 +65,8 @@ flowchart TD
2. Banner → printed for all remaining steps (`--help`, `--validate`, normal run)
3. `--help` → print usage and exit
4. `--validate` → run self-validation tests and exit
5. Normal run → read requirements → generate reports → enforce coverage
5. `--lint` → lint requirements files and exit
6. Normal run → read requirements → generate reports → enforce coverage

Each step is described in detail in the [Program Execution Flow](#program-execution-flow) section.

Expand Down Expand Up @@ -151,6 +157,24 @@ Handles CLI argument parsing and owns all program-wide options and output.
- Manage console and log file output through `WriteLine` / `WriteError`
- Track error state and surface the appropriate process exit code

### Linter

**Location**: `Linter.cs`

Lints requirement YAML files and reports all structural issues found.

**Key Responsibilities**:

- Parse YAML files using YamlDotNet's representation model to retain position information
- Report unknown fields at document root, section, requirement, and mapping level
- Report missing required fields (`title` for sections; `id` and `title` for requirements; `id` for mappings)
- Report blank field values for `title`, `id`, and list entries (tests, tags)
- Detect and report duplicate requirement IDs across all files (including includes)
- Follow `includes:` directives recursively, deduplicating visited files
- Report **all** issues found rather than stopping at the first error
- Format errors as `{file}({line},{col}): error: {description}`
- Print a no-issues message when the files pass all checks

## Requirements Processing Flow

### 1. YAML File Parsing
Expand Down Expand Up @@ -311,7 +335,10 @@ enforcement results — this allows users to review the trace matrix even on a f
4. Self-Validation (--validate)
└─> Run self-validation tests and exit

5. Requirements Processing
5. Lint (--lint)
└─> Lint requirements files and exit

6. Requirements Processing
├─> Read and merge requirements files
├─> Export requirements report (if --report specified)
├─> Export justifications report (if --justifications specified)
Expand Down
8 changes: 6 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ create, validate, and manage requirement documents in a structured and maintaina
- 🧪 **Test Mapping** - Link requirements to test cases for traceability
- 📦 **File Includes** - Modularize requirements across multiple YAML files
- ✅ **Validation** - Built-in validation for requirement structure and references
- 🔍 **Linting** - Validate requirements YAML structure and report all issues in one pass
- 🏷️ **Tag Filtering** - Categorize and filter requirements using tags
- 📋 **Justifications** - Document the rationale behind each requirement
- 🔒 **Continuous Compliance** - Compliance evidence generated automatically on every CI run, following
Expand Down Expand Up @@ -97,6 +98,7 @@ Options:
--validate Run self-validation
--results <file> Write validation results to file (TRX or JUnit format)
--log <file> Write output to log file
--lint Lint requirements files for structural issues
--requirements <pattern> Requirements files glob pattern
--report <file> Export requirements to markdown file
--report-depth <depth> Markdown header depth for requirements report (default: 1)
Expand Down Expand Up @@ -129,9 +131,10 @@ Running self-validation produces a report containing the following information:
✓ ReqStream_ReportExport - Passed
✓ ReqStream_TagsFiltering - Passed
✓ ReqStream_EnforcementMode - Passed
✓ ReqStream_Lint - Passed

Total Tests: 5
Passed: 5
Total Tests: 6
Passed: 6
Failed: 0
```

Expand All @@ -142,6 +145,7 @@ Each test in the report proves:
- **`ReqStream_ReportExport`** - requirements report is correctly exported to a markdown file.
- **`ReqStream_TagsFiltering`** - requirements are correctly filtered by tags.
- **`ReqStream_EnforcementMode`** - enforcement mode correctly validates requirement test coverage.
- **`ReqStream_Lint`** - linter correctly validates requirements YAML file structure and reports all issues.

See the [User Guide][link-guide] for more details on the self-validation tests.

Expand Down
127 changes: 127 additions & 0 deletions docs/design/context.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
# Context Unit Design

## Overview

`Context` is the command-line argument parser and I/O owner for ReqStream. It is the single
authoritative source for all runtime options and is the only unit permitted to write to the console
or the log file. `Context` never touches YAML content, test result data, or domain objects; its
sole concerns are parsing arguments and surfacing results to the caller.

`Context` implements `IDisposable` so that the log-file `StreamWriter` is closed deterministically
when the enclosing `using` block in `Program.Main` exits.

## Private State

| Field | Type | Purpose |
| ----- | ---- | ------- |
| `_logWriter` | `StreamWriter?` | Open writer for the optional log file; `null` when no log file was requested |
| `_hasErrors` | `bool` | Accumulates error state; initially `false`; set to `true` by `WriteError` |

## Properties

| Property | Type | CLI flag | Notes |
| -------- | ---- | -------- | ----- |
| `Version` | `bool` | `--version` | Print version and exit |
| `Help` | `bool` | `--help` | Print usage and exit |
| `Silent` | `bool` | `--silent` | Suppress console output |
| `Validate` | `bool` | `--validate` | Run self-validation tests |
| `Lint` | `bool` | `--lint` | Lint requirements files |
| `ResultsFile` | `string?` | `--results` | Path for validation test-results output file |
| `Enforce` | `bool` | `--enforce` | Fail if requirements are not fully covered |
| `FilterTags` | `HashSet<string>?` | `--filter` | Comma-separated tag filter; `null` when not specified |
| `RequirementsFiles` | `List<string>` | `--requirements` | Expanded list of requirement file paths |
| `TestFiles` | `List<string>` | `--tests` | Expanded list of test-result file paths |
| `RequirementsReport` | `string?` | `--report` | Destination path for requirements report |
| `ReportDepth` | `int` | `--report-depth` | Heading depth for requirements report |
| `Matrix` | `string?` | `--matrix` | Destination path for trace matrix report |
| `MatrixDepth` | `int` | `--matrix-depth` | Heading depth for trace matrix report |
| `JustificationsFile` | `string?` | `--justifications` | Destination path for justifications report |
| `JustificationsDepth` | `int` | `--justifications-depth` | Heading depth for justifications report |
| `ExitCode` | `int` | — | Computed: `_hasErrors ? 1 : 0` |

## Methods

### `Create(args)`

`Create` is the static factory method that constructs and returns a fully initialized `Context`.
It implements a sequential switch-based parser over the `args` array.

**Parse loop**:

1. Iterate `args` with an index variable `i`.
2. Match `args[i]` against known flags using a `switch` statement.
3. For flags that consume the next element (e.g., `--requirements`), check `i + 1 >= args.Length`
before advancing; if the check fails an `ArgumentException` is thrown.
4. An unrecognized argument causes an `ArgumentException` listing the unknown argument.

**`--filter` handling**:

The value following `--filter` is split on `','`. Each non-empty token is added to `FilterTags`.
If `FilterTags` is `null` at the point the first `--filter` is encountered, the `HashSet` is
created before adding tokens. Multiple `--filter` arguments are accumulated into the same set.

**`--requirements` and `--tests` handling**:

Each value is passed to `ExpandGlobPattern`; the resulting paths are appended to
`RequirementsFiles` or `TestFiles` respectively.

**Log file**:

If `--log` was specified, `Create` opens the named file for writing and assigns the resulting
`StreamWriter` to `_logWriter` before returning.

### `ExpandGlobPattern(pattern)`

`ExpandGlobPattern` resolves a single pattern (which may contain `*` or `**` wildcards) to a list
of absolute file paths.

**Implementation**:

1. Construct a `Microsoft.Extensions.FileSystemGlobbing.Matcher`.
2. Add `pattern` as an include pattern.
3. Execute the matcher against `Directory.GetCurrentDirectory()`.
4. Return the matched absolute paths.

**Known limitation**: the `Matcher` library silently ignores patterns that are themselves absolute
paths. Callers that pass absolute paths directly will receive an empty result set. This is an
accepted limitation of the underlying library; users should use relative paths or glob wildcards.

### `WriteLine(message)`

`WriteLine` writes a message to the output channel.

1. If `Silent` is `false`, write to `Console.WriteLine`.
2. If `_logWriter` is not `null`, write to `_logWriter`.

### `WriteError(message)`

`WriteError` records an error and writes it to the error channel.

1. Set `_hasErrors = true`.
2. If `Silent` is `false`, set `Console.ForegroundColor` to red, write to `Console.Error`, then
restore the original foreground color.
3. If `_logWriter` is not `null`, write to `_logWriter`.

### `Dispose()`

`Dispose` flushes and closes `_logWriter` if it is not `null`, then sets it to `null`. This
ensures the log file is not truncated and file handles are not leaked even when the process exits
via an early return path.

## Interactions with Other Units

| Unit | Nature of interaction |
| ---- | --------------------- |
| `Program` | Creates `Context` via `Create`; calls `WriteLine` and `WriteError`; reads `ExitCode` |
| `Validation` | Calls `context.WriteLine`, `context.WriteError`, reads `ResultsFile`, `Silent` |
| `Linter` | Calls `context.WriteError` to report linting issues |
| `Requirements` | Receives `RequirementsFiles`; does not hold a reference to `Context` |
| `TraceMatrix` | Receives `TestFiles`; does not hold a reference to `Context` |

## References

- [ReqStream Architecture][arch]
- [ReqStream Repository][repo]

[arch]: ../../ARCHITECTURE.md
[repo]: https://github.com/demaconsulting/ReqStream
20 changes: 20 additions & 0 deletions docs/design/definition.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
---
resource-path:
- docs/design
- docs/template

input-files:
- docs/design/title.txt
- docs/design/introduction.md
- docs/design/program.md
- docs/design/context.md
- docs/design/validation.md
- docs/design/requirements.md
- docs/design/tracematrix.md
- docs/design/linter.md

template: template.html

table-of-contents: true

number-sections: true
49 changes: 49 additions & 0 deletions docs/design/introduction.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# Introduction

This document provides the detailed design for the ReqStream tool, a .NET command-line application
for managing software requirements in YAML format.

## Purpose

The purpose of this document is to describe the internal design of each software unit that comprises
ReqStream. It captures data models, algorithms, key methods, and inter-unit interactions at a level
of detail sufficient for formal code review, compliance verification, and future maintenance. The
document does not restate requirements; it explains how they are realized.

## Scope

This document covers the detailed design of the following software units:

- **Program** — entry point and execution orchestrator (`Program.cs`)
- **Context** — command-line argument parser and I/O owner (`Context.cs`)
- **Validation** — self-validation test runner (`Validation.cs`)
- **Requirements, Section, and Requirement** — YAML parsing, section merging, validation, and export
(`Requirements.cs`, `Section.cs`, `Requirement.cs`)
- **TraceMatrix** — test result loader and requirement-coverage analyzer (`TraceMatrix.cs`)
- **Linter** — structural linter for requirement YAML files (`Linter.cs`)

The following topics are out of scope:

- External library internals (YamlDotNet, DemaConsulting.TestResults)
- Build pipeline configuration
- Deployment and packaging

## Document Conventions

Throughout this document:

- Class names, method names, property names, and file names appear in `monospace` font.
- The word **shall** denotes a design constraint that the implementation must satisfy.
- Section headings within each unit chapter follow a consistent structure: overview, data model,
methods/algorithms, and interactions with other units.
- Text tables are used in preference to diagrams, which may not render in all PDF viewers.

## References

- [ReqStream Architecture][arch]
- [ReqStream User Guide][guide]
- [ReqStream Repository][repo]

[arch]: ../../ARCHITECTURE.md
[guide]: ../../README.md
[repo]: https://github.com/demaconsulting/ReqStream
Loading
Loading