Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 10 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,22 +63,28 @@ named review-sets:
needs-review:
- "**/*.cs"
- "**/*.yaml"
- "!**/obj/**" # exclude build output
- "!src/Generated/**" # exclude auto-generated files
- "!**/obj/**" # exclude build output
- "!src/Generated/**" # exclude auto-generated files

# Configuration for the review evidence source
evidence-source:
type: url # 'none', 'url', or 'fileshare'
type: url # 'none', 'url', or 'fileshare'
location: https://reviews.example.com/evidence/index.json

# Optional reference files included in all reviews
context:
- "docs/design/introduction.md"

reviews:
- id: Core-Logic
title: Review of core business logic
paths:
- "src/Core/**/*.cs"
- "src/Core/**/*.yaml"
- "!src/Core/Generated/**"
context: # optional: reference docs a reviewer must read
context:
- "docs/design/core.md"

- id: Security-Layer
title: Review of authentication and authorization
paths:
Expand Down
4 changes: 2 additions & 2 deletions docs/design/review-mark/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,8 +76,8 @@ enumeration and owns SHA-256 fingerprinting, document generation, and elaboratio
4. `PublishReviewReport()` accepts `ReviewIndex` as a parameter and calls `GetEvidence()`
for each review-set to determine Current, Stale, Missing, or Failed status.
5. `ElaborateReviewSet()` generates a Markdown document that includes an optional Context
subsection listing resolved context files labeled `[global]` (from `GlobalContext`) or
`[local]` (from `ReviewSet.Context`); the subsection is omitted when no context files
subsection listing resolved context files as plain paths (global context files first,
followed by per-review-set context files); the subsection is omitted when no context files
resolve. `ReviewSet.Context` holds per-review-set context glob patterns; these patterns
identify reference material shown during elaboration and do not provide review coverage.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,8 +98,9 @@ and a boolean indicating whether any review-set is non-current.
Looks up the review-set with the given `id`, resolves its file list and fingerprint, and
returns a Markdown document with a heading at `markdownDepth`, a metadata table (ID, Title,
Fingerprint), an optional Context subsection, and a Files subheading. The Context subsection
lists all resolved context files labeled `[global]` (from `GlobalContext`) or `[local]` (from
`review.Context`), and is omitted when no context files resolve. Throws `ArgumentException`
lists all resolved context files as plain paths (global context files from `GlobalContext`
first, followed by per-review-set files from `review.Context`), and is omitted when no
context files resolve. Throws `ArgumentException`
for unknown IDs; throws `ArgumentOutOfRangeException` when `markdownDepth > 5`.

**Coverage note:** Context entries are reference material only. A file listed in `context:` is
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -232,8 +232,8 @@ sections:
- id: ReviewMark-Config-ContextInElaboration
title: >-
ElaborateReviewSet shall include a Context subsection listing all resolved context
files labeled [global] (from the top-level list) or [local] (from the
per-review-set list), omitting the subsection when no context files exist.
files as plain paths (global context first, then per-review-set context),
omitting the subsection when no context files exist.
justification: |
Reviewers need to know which reference files to consult.
tests:
Expand Down
4 changes: 2 additions & 2 deletions docs/user_guide/introduction.md
Original file line number Diff line number Diff line change
Expand Up @@ -524,8 +524,8 @@ The command prints a Markdown document to the console:

## Context

- `[global] docs/design/introduction.md`
- `[local] docs/design/core.md`
- `docs/design/introduction.md`
- `docs/design/core.md`

## Files

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -121,14 +121,14 @@ by `ReviewSet_GetFingerprint_ContextNotIncluded`.
**ReviewMarkConfiguration_ElaborateReviewSet_GlobalContext_AppearsInOutput**:
`ElaborateReviewSet` is called on a configuration with a global `context:` list; the context
files exist on disk. Expected outcome: the output Markdown contains a `Context` subsection and
each context file is listed with the `[global]` label. Requirement coverage:
each context file is listed as a plain path. Requirement coverage:
`ReviewMark-Config-ContextInElaboration`. This scenario is tested by
`ReviewMarkConfiguration_ElaborateReviewSet_GlobalContext_AppearsInOutput`.

**ReviewMarkConfiguration_ElaborateReviewSet_LocalContext_AppearsInOutput**:
`ElaborateReviewSet` is called on a configuration with a per-review-set `context:` list; the
context files exist on disk. Expected outcome: the output Markdown contains a `Context`
subsection and each context file is listed with the `[local]` label. Requirement coverage:
subsection and each context file is listed as a plain path. Requirement coverage:
`ReviewMark-Config-ContextInElaboration`. This scenario is tested by
`ReviewMarkConfiguration_ElaborateReviewSet_LocalContext_AppearsInOutput`.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -363,7 +363,7 @@
/// "Core-Logic" and "core-logic" are distinct IDs. Evidence-source type uses OrdinalIgnoreCase
/// because types like "fileshare" and "FILESHARE" are semantically identical.
/// </remarks>
internal static void ValidateReviews(

Check warning on line 366 in src/DemaConsulting.ReviewMark/Configuration/ReviewMarkConfiguration.cs

View workflow job for this annotation

GitHub Actions / Build / Build macos-latest

Refactor this method to reduce its Cognitive Complexity from 21 to the 15 allowed.

Check warning on line 366 in src/DemaConsulting.ReviewMark/Configuration/ReviewMarkConfiguration.cs

View workflow job for this annotation

GitHub Actions / Build / Build macos-latest

Refactor this method to reduce its Cognitive Complexity from 21 to the 15 allowed.

Check warning on line 366 in src/DemaConsulting.ReviewMark/Configuration/ReviewMarkConfiguration.cs

View workflow job for this annotation

GitHub Actions / Build / Build macos-latest

Refactor this method to reduce its Cognitive Complexity from 21 to the 15 allowed.

Check warning on line 366 in src/DemaConsulting.ReviewMark/Configuration/ReviewMarkConfiguration.cs

View workflow job for this annotation

GitHub Actions / Build / Build macos-latest

Refactor this method to reduce its Cognitive Complexity from 21 to the 15 allowed.

Check warning on line 366 in src/DemaConsulting.ReviewMark/Configuration/ReviewMarkConfiguration.cs

View workflow job for this annotation

GitHub Actions / Build / Build macos-latest

Refactor this method to reduce its Cognitive Complexity from 21 to the 15 allowed.

Check warning on line 366 in src/DemaConsulting.ReviewMark/Configuration/ReviewMarkConfiguration.cs

View workflow job for this annotation

GitHub Actions / Build / Build macos-latest

Refactor this method to reduce its Cognitive Complexity from 21 to the 15 allowed.

Check warning on line 366 in src/DemaConsulting.ReviewMark/Configuration/ReviewMarkConfiguration.cs

View workflow job for this annotation

GitHub Actions / Build / Build windows-latest

Refactor this method to reduce its Cognitive Complexity from 21 to the 15 allowed.

Check warning on line 366 in src/DemaConsulting.ReviewMark/Configuration/ReviewMarkConfiguration.cs

View workflow job for this annotation

GitHub Actions / Build / Build windows-latest

Refactor this method to reduce its Cognitive Complexity from 21 to the 15 allowed.

Check warning on line 366 in src/DemaConsulting.ReviewMark/Configuration/ReviewMarkConfiguration.cs

View workflow job for this annotation

GitHub Actions / Build / Build windows-latest

Refactor this method to reduce its Cognitive Complexity from 21 to the 15 allowed.

Check warning on line 366 in src/DemaConsulting.ReviewMark/Configuration/ReviewMarkConfiguration.cs

View workflow job for this annotation

GitHub Actions / Build / Build windows-latest

Refactor this method to reduce its Cognitive Complexity from 21 to the 15 allowed.

Check warning on line 366 in src/DemaConsulting.ReviewMark/Configuration/ReviewMarkConfiguration.cs

View workflow job for this annotation

GitHub Actions / Build / Build windows-latest

Refactor this method to reduce its Cognitive Complexity from 21 to the 15 allowed.

Check warning on line 366 in src/DemaConsulting.ReviewMark/Configuration/ReviewMarkConfiguration.cs

View workflow job for this annotation

GitHub Actions / Build / Build windows-latest

Refactor this method to reduce its Cognitive Complexity from 21 to the 15 allowed.

Check warning on line 366 in src/DemaConsulting.ReviewMark/Configuration/ReviewMarkConfiguration.cs

View workflow job for this annotation

GitHub Actions / Build / Build ubuntu-latest

Refactor this method to reduce its Cognitive Complexity from 21 to the 15 allowed.

Check warning on line 366 in src/DemaConsulting.ReviewMark/Configuration/ReviewMarkConfiguration.cs

View workflow job for this annotation

GitHub Actions / Build / Build ubuntu-latest

Refactor this method to reduce its Cognitive Complexity from 21 to the 15 allowed.

Check warning on line 366 in src/DemaConsulting.ReviewMark/Configuration/ReviewMarkConfiguration.cs

View workflow job for this annotation

GitHub Actions / Build / Build ubuntu-latest

Refactor this method to reduce its Cognitive Complexity from 21 to the 15 allowed.

Check warning on line 366 in src/DemaConsulting.ReviewMark/Configuration/ReviewMarkConfiguration.cs

View workflow job for this annotation

GitHub Actions / Build / Build ubuntu-latest

Refactor this method to reduce its Cognitive Complexity from 21 to the 15 allowed.

Check warning on line 366 in src/DemaConsulting.ReviewMark/Configuration/ReviewMarkConfiguration.cs

View workflow job for this annotation

GitHub Actions / Build / Build ubuntu-latest

Refactor this method to reduce its Cognitive Complexity from 21 to the 15 allowed.

Check warning on line 366 in src/DemaConsulting.ReviewMark/Configuration/ReviewMarkConfiguration.cs

View workflow job for this annotation

GitHub Actions / Build / Build ubuntu-latest

Refactor this method to reduce its Cognitive Complexity from 21 to the 15 allowed.
string filePath,
IReadOnlyList<ReviewSetYaml> reviews,
ICollection<LintIssue> issues)
Expand Down Expand Up @@ -1102,11 +1102,9 @@
sb.AppendLine($"| Fingerprint | `{fingerprint}` |");
sb.AppendLine();

// Resolve global and local context files, labeling each with its scope
var globalContextFiles = GlobMatcher.GetMatchingFiles(directory, GlobalContext)
.Select(f => $"[global] {f}");
var localContextFiles = GlobMatcher.GetMatchingFiles(directory, review.Context)
.Select(f => $"[local] {f}");
// Resolve global and local context files; global files appear first
var globalContextFiles = GlobMatcher.GetMatchingFiles(directory, GlobalContext);
var localContextFiles = GlobMatcher.GetMatchingFiles(directory, review.Context);
var allContext = globalContextFiles.Concat(localContextFiles).ToList();
Comment thread
Copilot marked this conversation as resolved.
Outdated

// Emit the context subsection only when at least one context file resolves
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1166,7 +1166,7 @@ public void ReviewSet_GetFingerprint_ContextNotIncluded()
}

/// <summary>
/// Test that ElaborateReviewSet includes a Context subsection with [global] labels
/// Test that ElaborateReviewSet includes a Context subsection with plain file paths
/// when global context files resolve.
/// </summary>
[Fact]
Expand Down Expand Up @@ -1196,14 +1196,15 @@ public void ReviewMarkConfiguration_ElaborateReviewSet_GlobalContext_AppearsInOu
// Act
var result = config.ElaborateReviewSet("Core-Logic", _testDirectory);

// Assert — context subsection is present and the file is labeled [global]
// Assert — context subsection is present, file is a plain-path list item, no scope labels
Assert.Contains("## Context", result.Markdown);
Assert.Contains("[global]", result.Markdown);
Assert.Contains("docs/design.md", result.Markdown);
Assert.Contains("- `docs/design.md`", result.Markdown);
Assert.DoesNotContain("[global]", result.Markdown);
Assert.DoesNotContain("[local]", result.Markdown);
}

/// <summary>
/// Test that ElaborateReviewSet includes a Context subsection with [local] labels
/// Test that ElaborateReviewSet includes a Context subsection with plain file paths
/// when per-review-set context files resolve.
/// </summary>
[Fact]
Expand Down Expand Up @@ -1233,10 +1234,54 @@ public void ReviewMarkConfiguration_ElaborateReviewSet_LocalContext_AppearsInOut
// Act
var result = config.ElaborateReviewSet("Core-Logic", _testDirectory);

// Assert — context subsection is present and the file is labeled [local]
// Assert — context subsection is present, file is a plain-path list item, no scope labels
Assert.Contains("## Context", result.Markdown);
Assert.Contains("[local]", result.Markdown);
Assert.Contains("docs/design.md", result.Markdown);
Assert.Contains("- `docs/design.md`", result.Markdown);
Assert.DoesNotContain("[global]", result.Markdown);
Assert.DoesNotContain("[local]", result.Markdown);
}

/// <summary>
/// Test that ElaborateReviewSet lists global context files before per-review-set context files.
/// </summary>
[Fact]
public void ReviewMarkConfiguration_ElaborateReviewSet_GlobalContextBeforeLocalContext()
{
// Arrange — create a global context file and a local context file
var srcDir = PathHelpers.SafePathCombine(_testDirectory, "src");
var docsDir = PathHelpers.SafePathCombine(_testDirectory, "docs");
var specDir = PathHelpers.SafePathCombine(_testDirectory, "spec");
Directory.CreateDirectory(srcDir);
Directory.CreateDirectory(docsDir);
Directory.CreateDirectory(specDir);
File.WriteAllText(PathHelpers.SafePathCombine(srcDir, "A.cs"), "class A {}");
File.WriteAllText(PathHelpers.SafePathCombine(docsDir, "global.md"), "# Global");
File.WriteAllText(PathHelpers.SafePathCombine(specDir, "local.md"), "# Local");

var yaml = """
context:
- "docs/**/*.md"
evidence-source:
type: none
reviews:
- id: Core-Logic
title: Review of core business logic
paths:
- "src/**/*.cs"
context:
- "spec/**/*.md"
""";
var config = ReviewMarkConfiguration.Parse(yaml);

// Act
var result = config.ElaborateReviewSet("Core-Logic", _testDirectory);

// Assert — both files appear as plain-path list items, global before local
var globalIndex = result.Markdown.IndexOf("- `docs/global.md`", StringComparison.Ordinal);
var localIndex = result.Markdown.IndexOf("- `spec/local.md`", StringComparison.Ordinal);
Assert.True(globalIndex >= 0, "Global context file not found in output");
Assert.True(localIndex >= 0, "Local context file not found in output");
Assert.True(globalIndex < localIndex, "Global context file should appear before local context file");
}

/// <summary>
Expand Down