Serena MCP is mandatory for code (read-only here). First call
mcp__serena__initial_instructionsto load the Serena tool manual, then use Serena for ALL code reading / searching / navigation — prefer symbol navigation (get_symbols_overview/find_symbol/find_referencing_symbols) over whole-file reads.
.NET performance review (read-only scan)
A static, read-only anti-pattern scanner for the {{ProductName}} .NET API — it reports, it does not edit. Pairs
with the architect-backend review and microbenchmarking (to confirm a fix with evidence). Aligns with our
coding-standards.md and async-discipline rules.
Inputs: the source to scan (required); hot-path context + target framework (.NET 10); depth =
critical-only / standard (default) / comprehensive.
Workflow
- Signal detection → topics. Scan for signals and select topics:
async/await/Task/ValueTask→ async;Span</stackalloc/ArrayPool/Substring/.Replace/.ToLower/+=in loops → memory & strings;Regex/[GeneratedRegex]→ regex;Dictionary</List</.ToList()/LINQ → collections;JsonSerializer/HttpClient/Stream→ I/O & serialization. - Scan & confirm with grep (emit a checklist with exact hit counts; 0 hits is a valid finding):
grep -n '\.Substring('·grep -En '\.(StartsWith|EndsWith|Contains)\s*\('(missingStringComparison) ·grep -n '\.ToLower()\|\.ToUpper()'(useStringComparison.OrdinalIgnoreCase) ·grep -n 'new HttpClient('(check forIHttpClientFactoryfirst) ·grep -n 'RegexOptions.Compiled'vsgrep -n 'GeneratedRegex'(prefer source-gen for literal patterns) ·grep -n 'static readonly Dictionary<'(FrozenDictionary candidate only if never mutated).- Verify-the-inverse: for absence patterns report the ratio (e.g. "3 of 7 use
StringComparison").
- Classify: 🔴 Critical (deadlock/crash/security/>10×), 🟡 Moderate (2–10× / hot-path best practice), ℹ️ Info. Hot-path code elevates severity; 11–50 instances bump Info→Moderate, 50+ = systematic. Report counts.
- Report compactly per finding:
#### ID. Title (N instances)/ Impact / Files asFile.cs:L42/ Fix / optional Caveat — grouped by severity, ending in a summary table. Close with the non-determinism caveat (an LLM scan is a lead, not proof — confirm hot-path wins withmicrobenchmarking).
Correctness rules (don't over-flag)
Memory<T>notSpan<T>in async methods (aligns with our async discipline).- LINQ only on hot paths (since .NET 7
Min/Max/Sum/Averageare vectorized — no blanket ban). ConfigureAwait(false)only in library code (e.g.{{ProjectName}}.Shared), not in the API/handlers.ValueTaskonly for frequently-synchronous hot paths;[GeneratedRegex]only for compile-time-literal patterns.- Never recommend
unsafe/CollectionsMarshal.AsSpanwithout benchmarked evidence.
Our deviation from the upstream scanner
The Microsoft version flags unsealed classes as a structural perf finding. We do not — our standard
deliberately drops "seal your classes" (CA1852/MA0053 → suggestion) because the domain model uses
intentional inheritance. Skip the unsealed-class finding (or scope it strictly to internal non-domain hot
types), and never propose sealing domain entities/aggregates.