---
name: dotnet-cop
description: >
  Pre-merge code review for .NET 10 pull requests. Ground truth: Minimal API + IModule
  (reflection-based isolation) + hexagonal per module (Domain/Application/Infrastructure).
  Persistence is chosen per bounded context — EF Core CRUD and event-sourced Marten stores
  are both first-class, with no global default. Optional additive: DDD / CQRS per module.
  Diffs current branch against a target branch, applies .NET-specific checklists (Minimal
  API endpoints, modular isolation, ports & adapters, schema-per-module + RLS, C# strictness,
  xUnit v3 only), runs dotnet build + dotnet format --verify-no-changes, and emits a
  tiered report (verbose for juniors, terse for seniors). Auto-loads project AGENTS.md
  rules. Use when user runs /cop-review, says "pre-merge review", or invokes dotnet-cop.
---

# dotnet-cop

Pre-merge review. Compares HEAD vs `origin/<target>`. Minimal-API-first, SoT-aware. Project-aware (reads `AGENTS.md`). Tooling-aware (runs dotnet build + dotnet format --verify-no-changes).

## When to Activate

- Selected by `code-reviewer` for .NET guidance during `/cop-review`
- User runs `/cop-review <target>` on a .NET repo
- dotnet-cop specialist is explicitly invoked

## Inputs

| Arg | Required | Default | Meaning |
|---|---|---|---|
| `<target>` | yes | — | Target branch (e.g. `main`, `develop`, `release/x`) |
| `--level` | no | auto | `junior` (verbose teaching) or `senior` (terse). Auto = senior. |
| `--scope` | no | all | Comma list: `minimal-api,isolation,ports-adapters,ef-core,csharp,result,ddd` + optional `cqrs,event-sourcing`. `ddd` auto-enables when the diff touches domain files; pass `ddd` to force it on. |
| `--no-tools` | no | false | Skip dotnet build + format check (static review only) |

## Hard Rules

1. **Read-only.** Never patch code. Output report only.
2. **Diff window:** `git merge-base HEAD origin/<target>`..`HEAD`. Never review changes already on target.
3. **Confidence ≥ 80%.** Skip uncertain findings. Use `❓ q:` instead of speculative `🔴 bug:`.
4. **Project rules win.** `AGENTS.md` overrides this skill. Re-read on every run; do not cache between sessions.
5. **dotnet-clean-architecture ground truth:** load [[dotnet-clean-architecture]] SKILL.md before flagging architecture code. Do not invent APIs or patterns.
6. **No fluff.** No "great work", no restating what the diff already shows.

## Pipeline

```
1. Parse args -> target, level, scope
2. git fetch <remote> <target>          (silent; --quiet)
3. base = git merge-base HEAD <remote>/<target>
4. changed = git diff --name-status base..HEAD
5. Load <repo>/AGENTS.md (if exists) -> project rules
6. For each changed file:
     - Skim full file (not just hunk) for context
     - Apply relevant sub-checklists by path/role:
          *Module.cs / *Extensions.cs        -> modular-isolation.md
          Infrastructure/Events/*.cs / *DbContext.cs -> cross-module-communication.md
         *Endpoint.cs (Minimal API)         -> minimal-api.md
         **/Ports/Incoming/*.cs              -> ports-adapters.md
         **/Ports/Outgoing/*.cs              -> ports-adapters.md
         Infrastructure/Adapter/*.cs        -> ports-adapters.md
         *DbContext.cs / Migrations/**      -> ef-core.md
         *.cs (any)                         -> csharp-strict.md
     - Apply skill `comment-judge` (REVIEW mode) to every added/changed comment
     - If ddd is in scope OR the diff touches domain files (paths under **/*.Domain/** or **/Domain/**): load [[dotnet-ddd]] (review-checklist.md); defer deep CQRS/ES to optional-cqrs.md / optional-event-sourcing.md. ddd is auto-enabled for domain diffs; --scope=ddd forces it on when no domain file is detected.
     - If --scope includes cqrs && module signals use: optional-cqrs.md
     - If --scope includes event-sourcing && module signals use: optional-event-sourcing.md
7. If !--no-tools:
     - dotnet build --nologo -clp:ErrorsOnly (the solution if one exists, else the relevant project(s) — fail fast)
     - dotnet format --verify-no-changes (capture exit code)
8. Aggregate findings -> render via output-format.md
```

## Severity

| Tag | Meaning | Action |
|---|---|---|
| 🔴 bug | broken behavior, runtime crash, data loss | BLOCK merge |
| 🟠 sec | security risk (unvalidated input, leaked secret, tenant-data leak) | BLOCK merge |
| 🟡 risk | works today, fragile tomorrow (N+1, missing filter, scope violation) | Fix before merge |
| 🟢 arch | violates mandatory architecture rule (SoT) or AGENTS.md-escalated opt-in rule | Fix before merge |
| 🔵 nit | style, naming, micro-optim | Optional |
| ❓ q | genuine question | Author decides |

Promote to BLOCK if AGENTS.md flags the category as mandatory.

## Sub-pages (read on demand)

- [[dotnet-cop-minimal-api]] — endpoint mapping, route groups, ProblemDetails, FluentValidation at boundary, no business logic in handlers.
- [[dotnet-cop-modular-isolation]] — module boundaries, no direct cross-module type references (hard blocker), communication via ports/events, reflection-based module discovery, per-module language autonomy.
- [[dotnet-cop-cross-module-communication]] — Cross-module communication (modular monolith): Wolverine-only inter-module reads, per-module projection DbContexts, forbidden cross-domain read ports in SharedKernel, `Model/` convention. Illustrated with the Sales module.
- [[dotnet-cop-ports-adapters]] — hexagonal: Domain/Application define ports, Infrastructure implements adapters; dependency direction; no EF entities leaking into Domain/Application.
- [[dotnet-cop-ef-core]] — DbContext per context/projection (hard blocker on shared DbContext), schema-per-module isolation, FORCE RLS mandatory on all context-schema tables, query splitting, N+1 prevention.
- [[dotnet-cop-result]] — business errors returned as `Result`/`Result<T>`, never thrown; `Error` defined in Domain; no HTTP coupling in Domain/Application.
- [[dotnet-ddd]] (ddd scope — auto-enabled when the diff touches domain files) — DDD tactical patterns (entities, value objects, aggregates, repositories) and strategic design for domain-layer code. Deep CQRS/ES enforcement defers to [[dotnet-cop-optional-cqrs]] and [[dotnet-cop-optional-event-sourcing]].
- [[dotnet-cop-optional-cqrs]] (opt-in) — commands/queries, handlers, CQRS pattern. Only when module signals use.
- [[dotnet-cop-optional-event-sourcing]] (opt-in) — event-sourced aggregates, immutable events, append-only event store. Only when module signals use.
- [[dotnet-cop-output-format]] — junior vs senior render templates.
- [[dotnet-cop-enforcement]] — BLOCK vs WARN severity checklist (load always). SoT rules listed first; opt-in rules clearly marked.

## AGENTS.md Loading

Always:

```bash
test -f AGENTS.md && cat AGENTS.md
test -f .agent/AGENTS.md && cat .agent/AGENTS.md
```

Parse rule blocks. Where this skill and AGENTS.md disagree, AGENTS.md wins. Cite the AGENTS.md line in the finding: `(AGENTS.md §<section>)`.

## Output Contract

Single markdown document, sections in fixed order:

1. **Summary** — target, base SHA, head SHA, files changed, finding counts by severity.
2. **Blockers** (🔴 / 🟠 / 🟢-when-AGENTS-mandates) — sorted by severity, then file path.
3. **Should-fix** (🟡) — same sort.
4. **Optional** (🔵 / ❓) — collapsible.
5. **Tooling** — dotnet build summary, dotnet format summary.
6. **Verdict** — `APPROVE` / `APPROVE-WITH-CHANGES` / `BLOCK`.

See [[dotnet-cop-output-format]] for full templates.

## Boundaries

- Does not write code fixes. Suggestions only.
- Does not run integration or unit tests by default (delegate to the `tdd` workflow / `tdd-guide`).
- Does not approve PRs in GitHub/Azure. Author posts the report manually.
- Does not auto-fix formatting. Reports format violations only.
- If no diff (HEAD == base), exit early with "no changes to review".
