[Sprint 2] Close: Domain Restructure / CQRS/MediatR#58
Conversation
- Merge decision inbox file into .squad/decisions.md with: - CI workflow security review (PR #5) - Template cleanup security review (PR #6) - Copyright header decision (PR #7) - Delete gandalf-pr5-pr6-merged.md from decisions/inbox/ - Add orchestration log with full PR merge details - Add session log summarizing board clear status PRs #5 (CI workflow), #6 (template cleanup), #7 (copyright headers) all merged to main by Gandalf. All 74 tests passing, 91.64% coverage. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- squad-pr-auto-label.yml: auto-labels new PRs with squad triage labels and routes dependabot PRs to Boromir - squad-label-enforce.yml: enforces mutual exclusivity on go:, release:, type:, and priority: label namespaces - codeql-analysis.yml: weekly + push/PR security scanning, adapted from IssueTrackerApp (removed Auth0/MongoDB secrets, added CI=true env var, updated to .NET 10 preview setup, uses codeql-action v3) Working as Boromir (DevOps) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Working as **Boromir** (DevOps) ## Summary Adds three missing GitHub Actions workflows to complete Phase 1-2 of the CI/CD roadmap. --- ### Workflows Added #### `squad-pr-auto-label.yml` Automatically labels new PRs when they're opened, reopened, or synchronized: - Routes **dependabot / renovate / github-actions bot** PRs directly to `squad:boromir` + `squad` with an explanatory comment - Labels all other PRs with `squad` (triage queue) and prompts the lead to assign a member #### `squad-label-enforce.yml` Enforces **mutual exclusivity** on managed label namespaces whenever a label is applied to an issue: - `go:` — only one triage verdict at a time; auto-applies `release:backlog` on `go:yes`, strips release labels on `go:no` - `release:` — only one release target at a time - `type:` — only one issue type at a time - `priority:` — only one priority at a time - Posts a comment whenever a label is replaced so the change is visible in the thread #### `codeql-analysis.yml` Security scanning via GitHub CodeQL: - Triggers on push to `main`/`dev` (`.cs`/`.csproj` changes), all PRs, weekly schedule (Fridays 00:31 UTC), and `workflow_dispatch` - Uses `codeql-action@v3`, `actions/checkout@v4`, `actions/setup-dotnet@v4` with .NET 10 preview - `CI: true` env var set to skip any interactive build steps during autobuild - Adapted from IssueTrackerApp: removed Auth0/MongoDB env vars, removed workflow_dispatch inputs block --- ### What's Next - **Phase 3** — Parallel test matrix (unit / integration / architecture tests in separate jobs) - **Phase 4** — Dev branch workflows (feature branch CI, preview deployments) --- > No issue to close — tracks internal CI/CD hardening plan.
Closes #45 Adds MediatR 14.1.0 and FluentValidation 12.0.0 to Domain; FluentValidation.AspNetCore + DI extensions to Web. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Closes #46 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Closes #39 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Closes #40 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…nt 2] Closes #56 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
SummarySummary
CoverageAppHost - 0%
Domain - 87.2%
ServiceDefaults - 0%
Web - 68.7%
|
Sprint branches are merge targets (squad PRs land here before dev).
They follow sprint/{N}-{slug} naming — add explicit allow-through that
skips the remaining feature gates (build, tests) for these branches.
Merge hierarchy: squad/* → sprint/* → dev → main (release only)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Note
Copilot was unable to run its full agentic suite in this review.
Sprint 2 closeout merging CQRS/MediatR + FluentValidation integration, Domain/Web restructuring, and supporting automation/documentation updates.
Changes:
- Added MediatR handlers/requests and FluentValidation validators + MediatR pipeline
ValidationBehavior. - Added unit tests covering validator rules and
ValidationBehavior. - Added/updated GitHub workflows and squad process docs for automation and enforcement.
Reviewed changes
Copilot reviewed 35 out of 35 changed files in this pull request and generated 7 comments.
Show a summary per file
| File | Description |
|---|---|
| tests/Unit.Tests/Features/BlogPosts/Commands/EditBlogPostCommandValidatorTests.cs | Adds validator unit tests for Edit command rules |
| tests/Unit.Tests/Features/BlogPosts/Commands/DeleteBlogPostCommandValidatorTests.cs | Adds validator unit tests for Delete command rules |
| tests/Unit.Tests/Features/BlogPosts/Commands/CreateBlogPostCommandValidatorTests.cs | Adds validator unit tests for Create command rules |
| tests/Unit.Tests/Behaviors/ValidationBehaviorTests.cs | Adds unit tests for MediatR validation pipeline behavior |
| src/Web/Web.csproj | Adds FluentValidation ASP.NET Core + DI packages |
| src/Web/Program.cs | Registers MediatR, validators, and validation pipeline behavior |
| src/Web/Features/BlogPosts/Edit/EditBlogPostCommandValidator.cs | Adds FluentValidation validator for Edit command (Web) |
| src/Web/Features/BlogPosts/Delete/DeleteBlogPostCommandValidator.cs | Adds FluentValidation validator for Delete command (Web) |
| src/Web/Features/BlogPosts/Create/CreateBlogPostCommandValidator.cs | Adds FluentValidation validator for Create command (Web) |
| src/Domain/Features/BlogPosts/Queries/GetBlogPostById/GetBlogPostByIdQueryHandler.cs | Adds Domain query handler for fetching a post by id |
| src/Domain/Features/BlogPosts/Queries/GetBlogPostById/GetBlogPostByIdQuery.cs | Adds Domain query request for fetching a post by id |
| src/Domain/Features/BlogPosts/Queries/GetAllBlogPosts/GetAllBlogPostsQueryHandler.cs | Adds Domain query handler for fetching all posts |
| src/Domain/Features/BlogPosts/Queries/GetAllBlogPosts/GetAllBlogPostsQuery.cs | Adds Domain query request for fetching all posts |
| src/Domain/Features/BlogPosts/Commands/UpdateBlogPost/UpdateBlogPostCommandValidator.cs | Adds Domain validator for update command |
| src/Domain/Features/BlogPosts/Commands/UpdateBlogPost/UpdateBlogPostCommandHandler.cs | Adds Domain handler for update command |
| src/Domain/Features/BlogPosts/Commands/UpdateBlogPost/UpdateBlogPostCommand.cs | Adds Domain update command request |
| src/Domain/Features/BlogPosts/Commands/DeleteBlogPost/DeleteBlogPostCommandValidator.cs | Adds Domain validator for delete command |
| src/Domain/Features/BlogPosts/Commands/DeleteBlogPost/DeleteBlogPostCommandHandler.cs | Adds Domain handler for delete command |
| src/Domain/Features/BlogPosts/Commands/DeleteBlogPost/DeleteBlogPostCommand.cs | Adds Domain delete command request |
| src/Domain/Features/BlogPosts/Commands/CreateBlogPost/CreateBlogPostCommandValidator.cs | Adds Domain validator for create command |
| src/Domain/Features/BlogPosts/Commands/CreateBlogPost/CreateBlogPostCommandHandler.cs | Adds Domain handler for create command |
| src/Domain/Features/BlogPosts/Commands/CreateBlogPost/CreateBlogPostCommand.cs | Adds Domain create command request |
| src/Domain/Domain.csproj | Adds FluentValidation + MediatR package references to Domain |
| src/Domain/Behaviors/ValidationBehavior.cs | Adds MediatR validation pipeline behavior using FluentValidation |
| global.json | Changes pinned .NET SDK version and roll-forward behavior |
| .squad/templates/issue-lifecycle.md | Documents mandatory sprint-stamped issue format |
| .squad/routing.md | Updates routing guardrails for sprint-stamped issues |
| .squad/playbooks/sprint-planning.md | Updates sprint planning playbook w/ sprint-stamping and automation notes |
| .squad/decisions.md | Adds decision record entries for prior CI/template cleanup work |
| .squad/agents/gandalf/history.md | Adds security review notes/history entry |
| .github/workflows/squad-pr-auto-label.yml | Adds PR auto-label workflow for squad triage |
| .github/workflows/squad-label-enforce.yml | Adds issue-label namespace mutual exclusivity enforcement |
| .github/workflows/project-board-automation.yml | Adds PR-driven project board status automation |
| .github/workflows/codeql-analysis.yml | Adds CodeQL workflow for C# |
| // MediatR — scans Web and Domain assemblies for all handlers | ||
| builder.Services.AddMediatR(cfg => | ||
| cfg.RegisterServicesFromAssembly(typeof(Program).Assembly)); | ||
| { | ||
| cfg.RegisterServicesFromAssembly(typeof(Program).Assembly); | ||
| cfg.RegisterServicesFromAssembly(typeof(BlogPost).Assembly); // Domain | ||
| }); | ||
|
|
||
| // FluentValidation — scans Domain assembly for all validators | ||
| builder.Services.AddValidatorsFromAssembly(typeof(BlogPost).Assembly); | ||
|
|
||
| // Register ValidationBehavior pipeline | ||
| builder.Services.AddTransient(typeof(IPipelineBehavior<,>), typeof(ValidationBehavior<,>)); |
| <PackageReference Include="Aspire.StackExchange.Redis.DistributedCaching" Version="13.2.2" /> | ||
| <PackageReference Include="Auth0.AspNetCore.Authentication" Version="1.7.0" /> | ||
| <PackageReference Include="Auth0.ManagementApi" Version="8.1.0" /> | ||
| <PackageReference Include="FluentValidation.AspNetCore" Version="11.3.0" /> | ||
| <PackageReference Include="FluentValidation.DependencyInjectionExtensions" Version="12.0.0" /> | ||
| <PackageReference Include="MediatR" Version="14.1.0" /> | ||
| <PackageReference Include="Microsoft.Bcl.AsyncInterfaces" Version="9.0.6" /> |
| if (!validators.Any()) | ||
| return await next(cancellationToken); | ||
|
|
||
| var context = new ValidationContext<TRequest>(request); | ||
| var failures = validators | ||
| .Select(v => v.Validate(context)) | ||
| .SelectMany(r => r.Errors) | ||
| .Where(f => f is not null) | ||
| .ToList(); |
| private static object CreateFailResult(Type resultType, string errorMessage) | ||
| { | ||
| if (resultType == typeof(Result)) | ||
| return Result.Fail(errorMessage, ResultErrorCode.Validation); | ||
|
|
||
| // Result<T> — get generic arg and call Result.Fail<T>(...) | ||
| var valueType = resultType.GetGenericArguments()[0]; | ||
| var method = typeof(Result) | ||
| .GetMethods() | ||
| .First(m => m.Name == "Fail" && m.IsGenericMethodDefinition && m.GetParameters().Length == 2); | ||
| return method.MakeGenericMethod(valueType).Invoke(null, [errorMessage, ResultErrorCode.Validation])!; | ||
| } |
| { | ||
| "sdk": { | ||
| "version": "10.0.202", | ||
| "rollForward": "latestMinor", | ||
| "version": "10.0.100", | ||
| "rollForward": "latestPatch", | ||
| "allowPrerelease": false | ||
| } | ||
| } |
| paths: | ||
| - "**.cs" | ||
| - "**.csproj" |
|
|
||
| steps: | ||
| - name: Move linked issues on project board | ||
| uses: actions/github-script@v9 |
Boromir — DevOps Review 🛡️Reviewed the DevOps-owned files in this Sprint 2 closeout PR. The new workflows are well-structured overall, but there is one blocking regression and two minor consistency issues that should be fixed before merging to 🔴 BLOCKING —
|
| Workflow | Version |
|---|---|
project-board-automation.yml |
actions/github-script@v9 |
squad-label-enforce.yml |
actions/github-script@v7 |
squad-pr-auto-label.yml |
actions/github-script@v7 |
Standardize all three to actions/github-script@v9.
✅ Approved items
- pre-push hook — Sprint branch Gate 0 fix is correct.
sprint/{N}-{slug}branches now bypass feature gates as intended. - project-board-automation.yml — Logic is sound.
DONE_OPTION_IDstring-quoting is correct (prevents YAML from interpreting the all-numeric ID as an integer). - squad-pr-auto-label.yml —
pull_request_targetis appropriate here since no external code is checked out. - squad-label-enforce.yml — Mutual-exclusivity enforcement logic is correct for all four namespaces.
Fix the global.json regression (blocking), then the two consistency items, and this is good to merge.
— Boromir 🛡️
Boromir — Follow-up ✅
Minor note: The two 🟡 items from my previous review ( This PR is unblocked from my side. Ready to merge to — Boromir 🛡️ |
- global.json: rollForward latestPatch → latestMinor Restores original value; latestPatch is too restrictive for developers on SDK 10.0.3xx+ - codeql-analysis.yml: dotnet-quality preview → ga Aligns with allowPrerelease: false in global.json - squad-label-enforce.yml: github-script@v7 → @v9 - squad-pr-auto-label.yml: github-script@v7 → @v9 Matches project-board-automation.yml which already uses @v9 Closes #64 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
|
🤖 Boromir — Follow-up ready The three non-blocking items from my review have been fixed in PR #65:
PR #65 targets |
- global.json: rollForward latestPatch → latestMinor Restores original value; latestPatch is too restrictive for developers on SDK 10.0.3xx+ - codeql-analysis.yml: dotnet-quality preview → ga Aligns with allowPrerelease: false in global.json - squad-label-enforce.yml: github-script@v7 → @v9 - squad-pr-auto-label.yml: github-script@v7 → @v9 Matches project-board-automation.yml which already uses @v9 Closes #64 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
🔍 CI Diagnosis — Coverage Gate (not test failures)All 100 unit tests pass. The "Unit Tests" job fails on the coverage threshold, not test logic.
Threshold: 89% line coverage · Actual: 83.68% ❌ Root cause: Domain (CQRS handlers/queries added in Sprint 2) has low line coverage (56.39%), dragging the total below the gate. Routing: Creating a Sprint 3 issue to add missing Domain unit tests. This unblocks Sprint 2 close once coverage is raised on the branch. |
- routing.md: Add Guardrails #9 (Gimli parallel), #10 (no-verify prohibition), #11 (rubber duck for new patterns); strengthen Rule #6 to name Gimli+Frodo+Pippin - ceremonies.md: Add Feature Work Kickoff ceremony; harden Retrospective with coverage-gate trigger and closure requirement - pre-push-process.md: Add hard block on git push --no-verify at top of file with SDK mismatch fix instructions - pr-merge-process.md: Step 3 now explicitly checks coverage gate (not just tests passing); adds 'Tests authored' gate for Gimli coverage - gimli/charter.md: Fix Critical Rule #1 paths from IssueTracker to MyBlog (tests/Unit.Tests, tests/Architecture.Tests); add coverage gate (89%); add Rule #9 enforcing parallel spawn Closes #68 (retrospective action items) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Add unit tests for all 5 Domain-layer CQRS handler classes: - CreateBlogPostCommandHandlerTests (2 tests: success, repo throws) - UpdateBlogPostCommandHandlerTests (3 tests: success, not found, repo throws) - DeleteBlogPostCommandHandlerTests (2 tests: success, repo throws) - GetAllBlogPostsQueryHandlerTests (3 tests: with posts, empty, repo throws) - GetBlogPostByIdQueryHandlerTests (3 tests: found, not found, repo throws) Domain coverage was 56.39% (13 tests / 0 Domain handler tests). These 13 new tests cover all handler branches, targeting ≥89% total line coverage. Resolves #68 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Merges governance enforcement updates from PR #67 into sprint branch. Squad documentation conflicts resolved by keeping the more comprehensive HEAD version (sprint enforcement) and incorporating net-new content from dev. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
|
Sprint 2 Closeout
Merges
sprint/2-cqrs-mediatr→devDelivered
Sprint 2 issues closed: 45, 46, 39, 40, 56
Closes #45
Closes #46
Closes #39
Closes #40
Closes #56
Co-authored-by: Copilot 223556219+Copilot@users.noreply.github.com