feat(analyzers): enable incremental latest-All enforcement

Centralize SDK and threading analyzers, baseline the .NET 10 All rule inventory at suggestion severity, and promote S3981 repo-wide. Fix the always-true worker count predicate and cover the idle/active branches.

Fixes #15

Co-Authored-By: Codex <codex@openai.com>
This commit is contained in:
2026-07-16 21:52:27 +02:00
co-authored by Codex
parent 9938d9a6cd
commit 8f90cea5cc
14 changed files with 399 additions and 37 deletions
+9 -5
View File
@@ -106,13 +106,17 @@ ij_json_wrap_long_lines = false
dotnet_diagnostic.ca1848.severity = none dotnet_diagnostic.ca1848.severity = none
# --- Static-analysis pack adoption (ersatztv#15) --- # --- Static-analysis pack adoption (ersatztv#15) ---
# Roslynator / SonarAnalyzer / Meziantou / AsyncFixer are referenced centrally # Threading analyzers and Roslynator / SonarAnalyzer / Meziantou / AsyncFixer are enabled centrally.
# (Directory.Build.targets). Default every analyzer diagnostic to `suggestion` so the new # Default their diagnostics to `suggestion`; the SDK's exact per-rule suggestion baseline lives in
# packs don't fail the TreatWarningsAsErrors build; high-value rules get promoted to # eng/analyzers/sdk-all-suggestion.globalconfig because AnalysisLevel=latest-All otherwise injects
# warning/error one at a time (see ersatztv#15 / docs/contributing.md). Explicit per-rule # exact warning severities that outrank this bulk setting. High-value rules are promoted one at a
# severities (e.g. ca1848 above) still take precedence over this bulk default. # time. Explicit per-rule severities (e.g. ca1848 above) take precedence over both baselines.
dotnet_analyzer_diagnostic.severity = suggestion dotnet_analyzer_diagnostic.severity = suggestion
# A collection count can never be negative. Treat comparisons that therefore collapse to a
# constant as errors; the first promotion caught a busy/idle branch that was permanently busy.
dotnet_diagnostic.S3981.severity = warning
# Blazor components: analyzers run on .razor/.cshtml @code too, and TWAE would otherwise # Blazor components: analyzers run on .razor/.cshtml @code too, and TWAE would otherwise
# turn their default-severity findings into build errors — keep them at suggestion as well. # turn their default-severity findings into build errors — keep them at suggestion as well.
[*.razor] [*.razor]
+13 -2
View File
@@ -3,6 +3,12 @@
<InformationalVersion>develop</InformationalVersion> <InformationalVersion>develop</InformationalVersion>
<IncludeSourceRevisionInInformationalVersion>false</IncludeSourceRevisionInInformationalVersion> <IncludeSourceRevisionInInformationalVersion>false</IncludeSourceRevisionInInformationalVersion>
<AllowMissingPrunePackageData>true</AllowMissingPrunePackageData> <AllowMissingPrunePackageData>true</AllowMissingPrunePackageData>
<!-- Analyzer posture (ersatztv#15): enable the complete SDK rule set and the
threading analyzer in every project. The checked-in globalconfig keeps the
SDK baseline at suggestion; individually promoted rules become CI-blocking. -->
<EnableNETAnalyzers>true</EnableNETAnalyzers>
<AnalysisLevel>latest-All</AnalysisLevel>
<EnableThreadingAnalyzers>true</EnableThreadingAnalyzers>
<!-- NuGet audit (on by default in .NET 10) reports vulnerable transitive <!-- NuGet audit (on by default in .NET 10) reports vulnerable transitive
packages as NU1901-1904 warnings. Several projects set packages as NU1901-1904 warnings. Several projects set
TreatWarningsAsErrors=true, which would otherwise fail `dotnet restore` TreatWarningsAsErrors=true, which would otherwise fail `dotnet restore`
@@ -10,8 +16,13 @@
advisories to warnings (still printed in build logs); NU1904 (critical) advisories to warnings (still printed in build logs); NU1904 (critical)
stays an error so criticals still block. Track fixes separately. stays an error so criticals still block. Track fixes separately.
WarningsAsErrors promotes NU1904 in EVERY project (even those without WarningsAsErrors promotes NU1904 in EVERY project (even those without
TreatWarningsAsErrors), so "criticals block" actually holds repo-wide. --> TreatWarningsAsErrors), so "criticals block" actually holds repo-wide.
S3981 is the first explicitly promoted analyzer rule (ersatztv#15). -->
<WarningsNotAsErrors>$(WarningsNotAsErrors);NU1901;NU1902;NU1903</WarningsNotAsErrors> <WarningsNotAsErrors>$(WarningsNotAsErrors);NU1901;NU1902;NU1903</WarningsNotAsErrors>
<WarningsAsErrors>$(WarningsAsErrors);NU1904</WarningsAsErrors> <WarningsAsErrors>$(WarningsAsErrors);NU1904;S3981</WarningsAsErrors>
</PropertyGroup> </PropertyGroup>
<ItemGroup>
<EditorConfigFiles Include="$(MSBuildThisFileDirectory)eng/analyzers/sdk-all-suggestion.globalconfig" />
</ItemGroup>
</Project> </Project>
-4
View File
@@ -1,8 +1,4 @@
<Project> <Project>
<PropertyGroup>
<EnableThreadingAnalyzers Condition="'$(EnableThreadingAnalyzers)' == ''">false</EnableThreadingAnalyzers>
</PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference <PackageReference
Include="Microsoft.VisualStudio.Threading.Analyzers" Include="Microsoft.VisualStudio.Threading.Analyzers"
@@ -4,7 +4,6 @@
<TargetFramework>net10.0</TargetFramework> <TargetFramework>net10.0</TargetFramework>
<NoWarn>VSTHRD200,CA1873</NoWarn> <NoWarn>VSTHRD200,CA1873</NoWarn>
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>
<AnalysisLevel>latest-Recommended</AnalysisLevel>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors> <TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<Configurations>Debug;Release;Debug No Sync</Configurations> <Configurations>Debug;Release;Debug No Sync</Configurations>
</PropertyGroup> </PropertyGroup>
@@ -27,7 +27,7 @@ public class ReleaseMemoryHandler : IRequestHandler<ReleaseMemory>
return Task.CompletedTask; return Task.CompletedTask;
} }
bool hasActiveWorkers = _ffmpegSegmenterService.Workers.Count >= 0 || FFmpegProcess.ProcessCount > 0; bool hasActiveWorkers = _ffmpegSegmenterService.Workers.Count > 0 || FFmpegProcess.ProcessCount > 0;
if (request.ForceAggressive || !hasActiveWorkers) if (request.ForceAggressive || !hasActiveWorkers)
{ {
_logger.LogDebug("Starting aggressive garbage collection"); _logger.LogDebug("Starting aggressive garbage collection");
-1
View File
@@ -4,7 +4,6 @@
<TargetFramework>net10.0</TargetFramework> <TargetFramework>net10.0</TargetFramework>
<NoWarn>VSTHRD200,CA1873</NoWarn> <NoWarn>VSTHRD200,CA1873</NoWarn>
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>
<AnalysisLevel>latest-Recommended</AnalysisLevel>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors> <TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<Nullable>disable</Nullable> <Nullable>disable</Nullable>
</PropertyGroup> </PropertyGroup>
-1
View File
@@ -4,7 +4,6 @@
<TargetFramework>net10.0</TargetFramework> <TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<AnalysisLevel>latest-Recommended</AnalysisLevel>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors> <TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks> <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<NoWarn>VSTHRD200,CA1873</NoWarn> <NoWarn>VSTHRD200,CA1873</NoWarn>
@@ -5,7 +5,6 @@
<GenerateRuntimeConfigurationFiles>true</GenerateRuntimeConfigurationFiles> <GenerateRuntimeConfigurationFiles>true</GenerateRuntimeConfigurationFiles>
<NoWarn>VSTHRD200,CA1873</NoWarn> <NoWarn>VSTHRD200,CA1873</NoWarn>
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>
<AnalysisLevel>latest-Recommended</AnalysisLevel>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors> <TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<DockerDefaultTargetOS>Linux</DockerDefaultTargetOS> <DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks> <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
-1
View File
@@ -8,7 +8,6 @@
<Configurations>Debug;Release;Debug No Sync</Configurations> <Configurations>Debug;Release;Debug No Sync</Configurations>
<Platforms>AnyCPU</Platforms> <Platforms>AnyCPU</Platforms>
<UserSecretsId>729e6271-c307-43c8-8e36-1b36c39f6de2</UserSecretsId> <UserSecretsId>729e6271-c307-43c8-8e36-1b36c39f6de2</UserSecretsId>
<AnalysisLevel>latest-Recommended</AnalysisLevel>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors> <TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<NoWarn>VSTHRD200,CA1873</NoWarn> <NoWarn>VSTHRD200,CA1873</NoWarn>
</PropertyGroup> </PropertyGroup>
@@ -0,0 +1,49 @@
using ErsatzTV.Application.Maintenance;
using ErsatzTV.Core.FFmpeg;
using ErsatzTV.Core.Interfaces.FFmpeg;
using Microsoft.Extensions.Logging;
using NSubstitute;
using NUnit.Framework;
using Shouldly;
namespace ErsatzTV.Tests.Application.Maintenance;
[TestFixture]
[NonParallelizable]
public class ReleaseMemoryHandlerTests
{
[Test]
public async Task Should_Use_Aggressive_Collection_When_No_Workers_Are_Active()
{
FFmpegProcess.ProcessCount.ShouldBe(0);
IFFmpegSegmenterService segmenterService = Substitute.For<IFFmpegSegmenterService>();
segmenterService.Workers.Returns([]);
ILogger<ReleaseMemoryHandler> logger = Substitute.For<ILogger<ReleaseMemoryHandler>>();
var handler = new ReleaseMemoryHandler(segmenterService, logger);
await handler.Handle(new ReleaseMemory(false), CancellationToken.None);
ShouldHaveLogged(logger, "Starting aggressive garbage collection");
}
[Test]
public async Task Should_Use_Regular_Collection_When_A_Worker_Is_Active()
{
FFmpegProcess.ProcessCount.ShouldBe(0);
IFFmpegSegmenterService segmenterService = Substitute.For<IFFmpegSegmenterService>();
segmenterService.Workers.Returns([Substitute.For<IHlsSessionWorker>()]);
ILogger<ReleaseMemoryHandler> logger = Substitute.For<ILogger<ReleaseMemoryHandler>>();
var handler = new ReleaseMemoryHandler(segmenterService, logger);
await handler.Handle(new ReleaseMemory(false), CancellationToken.None);
ShouldHaveLogged(logger, "Starting garbage collection");
}
private static void ShouldHaveLogged(ILogger<ReleaseMemoryHandler> logger, string expectedMessage) =>
logger.ReceivedCalls()
.Any(call => call.GetArguments().ElementAtOrDefault(2)?.ToString() == expectedMessage)
.ShouldBeTrue();
}
-1
View File
@@ -11,7 +11,6 @@
<Configurations>Debug;Release;Debug No Sync</Configurations> <Configurations>Debug;Release;Debug No Sync</Configurations>
<Platforms>AnyCPU</Platforms> <Platforms>AnyCPU</Platforms>
<UserSecretsId>bf31217d-f4ec-4520-8cc3-138059044ede</UserSecretsId> <UserSecretsId>bf31217d-f4ec-4520-8cc3-138059044ede</UserSecretsId>
<AnalysisLevel>latest-Recommended</AnalysisLevel>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors> <TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<RequiresAspNetWebAssets>true</RequiresAspNetWebAssets> <RequiresAspNetWebAssets>true</RequiresAspNetWebAssets>
<NeutralLanguage>en-US</NeutralLanguage> <NeutralLanguage>en-US</NeutralLanguage>
+29 -16
View File
@@ -299,27 +299,40 @@ running product from outside our C#/review stack.
## Static analysis & formatting ## Static analysis & formatting
**Analyzer packs** — `Directory.Build.targets` references **Roslynator**, **SonarAnalyzer.CSharp**, **Analyzers** — `Directory.Build.props` enables the SDK analyzers at `latest-All` and turns on
**Meziantou.Analyzer**, and **AsyncFixer** for every project (versions central via CPM; guarded on `Microsoft.VisualStudio.Threading.Analyzers` for every project. `Directory.Build.targets` also references
`ManagePackageVersionsCentrally` so the gitignored `.mcp` tool isn't pulled in). They are introduced **Roslynator**, **SonarAnalyzer.CSharp**, **Meziantou.Analyzer**, and **AsyncFixer** repo-wide (versions
**incrementally** (ersatztv#15): `.editorconfig` sets `dotnet_analyzer_diagnostic.severity = suggestion` central via CPM; guarded on `ManagePackageVersionsCentrally` so the gitignored `.mcp` tool isn't pulled in).
so the packs surface findings without failing the `TreatWarningsAsErrors` (TWAE) build. **Promotion is They are introduced **incrementally** (ersatztv#15). `eng/analyzers/sdk-all-suggestion.globalconfig`
the enforcement** — raising a rule to `warning` makes it a CI-blocking error via the existing TWAE enumerates the .NET 10 SDK `All` inventory at `suggestion`; this exact-ID baseline is necessary because
build, so no separate lint step is needed. the SDK's generated `latest-All` severities outrank `.editorconfig` bulk settings. `.editorconfig` keeps
the threading and curated-pack baselines at `suggestion`. Diagnostics remain visible to IDEs and
`dotnet format analyzers`, but do not create a wall of failures (a direct `latest-All` trial activated
455 existing errors in the TWAE projects).
**Promotion is the enforcement** — set an reviewed rule to `warning` in `.editorconfig` and append its ID
to the central `WarningsAsErrors` list in `Directory.Build.props`. The explicit list makes the rule block
in every project, including test projects that do not otherwise use TWAE. On a major SDK upgrade,
regenerate the checked-in SDK baseline from `analysislevel_<major>_all.globalconfig`, preserve SDK `none`
entries, and review newly introduced rules before accepting the snapshot.
Promoted rules are recorded here so the blocking subset stays intentional and reviewable:
- **Sonar `S3981` — `warning` + `WarningsAsErrors`** (ersatztv#15): rejects collection-count comparisons that are constant
regardless of collection size. Its first finding exposed `Workers.Count >= 0`, which permanently
classified scheduled memory releases as busy and skipped the intended aggressive idle collection.
- **StyleCop.Analyzers is intentionally excluded**: its latest stable (1.1.118) crashes (`AD0001`) on - **StyleCop.Analyzers is intentionally excluded**: its latest stable (1.1.118) crashes (`AD0001`) on
C# `record` declarations, and its rules overlap the existing `.editorconfig`/Roslynator. Revisit via C# `record` declarations, and its rules overlap the existing `.editorconfig`/Roslynator. Revisit via
the record-compatible `1.2.0-beta` only if specifically wanted. the record-compatible `1.2.0-beta` only if specifically wanted.
- **Blazor `.razor` caveat**: editorconfig severity overrides don't reach analyzer diagnostics in Razor - **The former Blazor `.razor` caveat is retired**: Blazor removal deleted the Razor sources and their
`@code` (source-generator limitation — `dotnet format` can't fix them either), so the currently-firing temporary Sonar `NoWarn` list. The `.razor`/`.cshtml` suggestion scopes remain in `.editorconfig` only
SonarAnalyzer rules are temporarily `NoWarn`-ed in `ErsatzTV.csproj` and burned down rule-by-rule in as a defensive default if server-rendered view code is ever reintroduced.
**ersatztv#25**. The same rules run at `suggestion` on `.cs`.
**Formatting** — the tree isn't yet `dotnet format`-clean (mixed UTF-8 BOM + whitespace inherited from **Formatting** — the inherited tree still contains legacy UTF-8 BOM/whitespace debt, so the standing
upstream: ~1,500 BOM files + ~480 whitespace). A one-time normalization lands as its **own dedicated policy is **format as you touch**, not a mass rewrite (ersatztv#311). The Husky pre-commit hook runs
PR** (kept out of the analyzer work to stay reviewable); afterwards `dotnet format whitespace `dotnet format --verify-no-changes` for staged C# files, and the blocking `format` CI job repeats that
--verify-no-changes` (+ `style`) joins the `test` job so drift can't return. `.gitattributes` already check for C# files changed by the PR. Untouched legacy files remain outside the gate; `.gitattributes`
pins line endings. pins line endings. A one-time full-tree normalization remains a separate, unmade decision.
## Migration integrity (EF Core, both providers) ## Migration integrity (EF Core, both providers)
+6 -3
View File
@@ -111,9 +111,12 @@ talks exclusively to the REST API. Every former Blazor route now 302-redirects t
- **`TreatWarningsAsErrors=true`** in the app projects — a warning fails the build. `NoWarn` carries a - **`TreatWarningsAsErrors=true`** in the app projects — a warning fails the build. `NoWarn` carries a
small, documented exemption list (e.g. `VSTHRD200`, `CA1873`); NuGet-audit `NU1901-1903` are demoted small, documented exemption list (e.g. `VSTHRD200`, `CA1873`); NuGet-audit `NU1901-1903` are demoted
to warnings in `Directory.Build.props` while `NU1904` (critical) blocks. to warnings in `Directory.Build.props` while `NU1904` (critical) blocks.
- **Static-analysis packs** (Roslynator, SonarAnalyzer, Meziantou, AsyncFixer) run at `suggestion` and - **Static analysis is centralized**: `Directory.Build.props` enables the SDK analyzers at
are promoted to `warning`/`error` rule-by-rule; promotion is the enforcement (the TWAE build). New `latest-All` plus the threading analyzer for every project; `Directory.Build.targets` adds Roslynator,
rules start at suggestion — never flip a wall of rules to error at once. (ersatztv#15) SonarAnalyzer, Meziantou, and AsyncFixer. The checked-in SDK globalconfig and `.editorconfig` keep the
broad baseline at `suggestion`. Promote one reviewed rule at a time by setting it to `warning` and
adding its ID to the central `WarningsAsErrors` list; never flip a wall of rules to error at once.
Refresh the SDK globalconfig deliberately when moving to a new .NET SDK major. (ersatztv#15)
## 8. Testing ## 8. Testing
@@ -0,0 +1,292 @@
# .NET 10 SDK analyzer baseline for ersatztv#15.
#
# AnalysisLevel=latest-All enables the complete SDK rule inventory, whose generated
# per-rule severities otherwise override .editorconfig's bulk suggestion setting.
# This higher-priority snapshot keeps every current .NET 10 rule visible but non-blocking.
# Preserve SDK 'none' entries for rules introduced after .NET 10. On an SDK major upgrade,
# regenerate this list from analysislevel_<major>_all.globalconfig and review new rules.
# A per-rule severity in the repository .editorconfig overrides this baseline.
is_global = true
global_level = -50
dotnet_diagnostic.CA1000.severity = suggestion
dotnet_diagnostic.CA1001.severity = suggestion
dotnet_diagnostic.CA1002.severity = suggestion
dotnet_diagnostic.CA1003.severity = suggestion
dotnet_diagnostic.CA1008.severity = suggestion
dotnet_diagnostic.CA1010.severity = suggestion
dotnet_diagnostic.CA1012.severity = suggestion
dotnet_diagnostic.CA1016.severity = suggestion
dotnet_diagnostic.CA1018.severity = suggestion
dotnet_diagnostic.CA1019.severity = suggestion
dotnet_diagnostic.CA1024.severity = suggestion
dotnet_diagnostic.CA1027.severity = suggestion
dotnet_diagnostic.CA1028.severity = suggestion
dotnet_diagnostic.CA1030.severity = suggestion
dotnet_diagnostic.CA1031.severity = suggestion
dotnet_diagnostic.CA1032.severity = suggestion
dotnet_diagnostic.CA1033.severity = suggestion
dotnet_diagnostic.CA1034.severity = suggestion
dotnet_diagnostic.CA1036.severity = suggestion
dotnet_diagnostic.CA1040.severity = suggestion
dotnet_diagnostic.CA1041.severity = suggestion
dotnet_diagnostic.CA1043.severity = suggestion
dotnet_diagnostic.CA1044.severity = suggestion
dotnet_diagnostic.CA1046.severity = suggestion
dotnet_diagnostic.CA1047.severity = suggestion
dotnet_diagnostic.CA1050.severity = suggestion
dotnet_diagnostic.CA1051.severity = suggestion
dotnet_diagnostic.CA1052.severity = suggestion
dotnet_diagnostic.CA1054.severity = suggestion
dotnet_diagnostic.CA1055.severity = suggestion
dotnet_diagnostic.CA1056.severity = suggestion
dotnet_diagnostic.CA1058.severity = suggestion
dotnet_diagnostic.CA1061.severity = suggestion
dotnet_diagnostic.CA1062.severity = suggestion
dotnet_diagnostic.CA1063.severity = suggestion
dotnet_diagnostic.CA1064.severity = suggestion
dotnet_diagnostic.CA1065.severity = suggestion
dotnet_diagnostic.CA1066.severity = suggestion
dotnet_diagnostic.CA1067.severity = suggestion
dotnet_diagnostic.CA1068.severity = suggestion
dotnet_diagnostic.CA1069.severity = suggestion
dotnet_diagnostic.CA1070.severity = suggestion
dotnet_diagnostic.CA1200.severity = suggestion
dotnet_diagnostic.CA1303.severity = suggestion
dotnet_diagnostic.CA1304.severity = suggestion
dotnet_diagnostic.CA1305.severity = suggestion
dotnet_diagnostic.CA1307.severity = suggestion
dotnet_diagnostic.CA1308.severity = suggestion
dotnet_diagnostic.CA1309.severity = suggestion
dotnet_diagnostic.CA1310.severity = suggestion
dotnet_diagnostic.CA1311.severity = suggestion
dotnet_diagnostic.CA1401.severity = suggestion
dotnet_diagnostic.CA1419.severity = suggestion
dotnet_diagnostic.CA1421.severity = suggestion
dotnet_diagnostic.CA1507.severity = suggestion
dotnet_diagnostic.CA1508.severity = suggestion
dotnet_diagnostic.CA1510.severity = suggestion
dotnet_diagnostic.CA1511.severity = suggestion
dotnet_diagnostic.CA1512.severity = suggestion
dotnet_diagnostic.CA1513.severity = suggestion
dotnet_diagnostic.CA1514.severity = suggestion
dotnet_diagnostic.CA1515.severity = suggestion
dotnet_diagnostic.CA1516.severity = none
dotnet_diagnostic.CA1700.severity = suggestion
dotnet_diagnostic.CA1707.severity = suggestion
dotnet_diagnostic.CA1708.severity = suggestion
dotnet_diagnostic.CA1710.severity = suggestion
dotnet_diagnostic.CA1711.severity = suggestion
dotnet_diagnostic.CA1712.severity = suggestion
dotnet_diagnostic.CA1713.severity = suggestion
dotnet_diagnostic.CA1715.severity = suggestion
dotnet_diagnostic.CA1716.severity = suggestion
dotnet_diagnostic.CA1720.severity = suggestion
dotnet_diagnostic.CA1721.severity = suggestion
dotnet_diagnostic.CA1724.severity = suggestion
dotnet_diagnostic.CA1725.severity = suggestion
dotnet_diagnostic.CA1727.severity = suggestion
dotnet_diagnostic.CA1802.severity = suggestion
dotnet_diagnostic.CA1805.severity = suggestion
dotnet_diagnostic.CA1806.severity = suggestion
dotnet_diagnostic.CA1810.severity = suggestion
dotnet_diagnostic.CA1812.severity = suggestion
dotnet_diagnostic.CA1813.severity = suggestion
dotnet_diagnostic.CA1814.severity = suggestion
dotnet_diagnostic.CA1815.severity = suggestion
dotnet_diagnostic.CA1816.severity = suggestion
dotnet_diagnostic.CA1819.severity = suggestion
dotnet_diagnostic.CA1820.severity = suggestion
dotnet_diagnostic.CA1821.severity = suggestion
dotnet_diagnostic.CA1822.severity = suggestion
dotnet_diagnostic.CA1823.severity = suggestion
dotnet_diagnostic.CA1824.severity = suggestion
dotnet_diagnostic.CA1825.severity = suggestion
dotnet_diagnostic.CA1826.severity = suggestion
dotnet_diagnostic.CA1827.severity = suggestion
dotnet_diagnostic.CA1828.severity = suggestion
dotnet_diagnostic.CA1829.severity = suggestion
dotnet_diagnostic.CA1830.severity = suggestion
dotnet_diagnostic.CA1832.severity = suggestion
dotnet_diagnostic.CA1833.severity = suggestion
dotnet_diagnostic.CA1834.severity = suggestion
dotnet_diagnostic.CA1835.severity = suggestion
dotnet_diagnostic.CA1836.severity = suggestion
dotnet_diagnostic.CA1837.severity = suggestion
dotnet_diagnostic.CA1838.severity = suggestion
dotnet_diagnostic.CA1839.severity = suggestion
dotnet_diagnostic.CA1840.severity = suggestion
dotnet_diagnostic.CA1841.severity = suggestion
dotnet_diagnostic.CA1842.severity = suggestion
dotnet_diagnostic.CA1843.severity = suggestion
dotnet_diagnostic.CA1844.severity = suggestion
dotnet_diagnostic.CA1845.severity = suggestion
dotnet_diagnostic.CA1846.severity = suggestion
dotnet_diagnostic.CA1847.severity = suggestion
dotnet_diagnostic.CA1848.severity = suggestion
dotnet_diagnostic.CA1849.severity = suggestion
dotnet_diagnostic.CA1850.severity = suggestion
dotnet_diagnostic.CA1851.severity = suggestion
dotnet_diagnostic.CA1852.severity = suggestion
dotnet_diagnostic.CA1853.severity = suggestion
dotnet_diagnostic.CA1854.severity = suggestion
dotnet_diagnostic.CA1855.severity = suggestion
dotnet_diagnostic.CA1856.severity = suggestion
dotnet_diagnostic.CA1858.severity = suggestion
dotnet_diagnostic.CA1859.severity = suggestion
dotnet_diagnostic.CA1860.severity = suggestion
dotnet_diagnostic.CA1861.severity = suggestion
dotnet_diagnostic.CA1862.severity = suggestion
dotnet_diagnostic.CA1863.severity = suggestion
dotnet_diagnostic.CA1864.severity = suggestion
dotnet_diagnostic.CA1865.severity = suggestion
dotnet_diagnostic.CA1866.severity = suggestion
dotnet_diagnostic.CA1867.severity = suggestion
dotnet_diagnostic.CA1868.severity = suggestion
dotnet_diagnostic.CA1869.severity = suggestion
dotnet_diagnostic.CA1870.severity = suggestion
dotnet_diagnostic.CA1871.severity = suggestion
dotnet_diagnostic.CA1872.severity = suggestion
dotnet_diagnostic.CA1873.severity = suggestion
dotnet_diagnostic.CA1874.severity = suggestion
dotnet_diagnostic.CA1875.severity = suggestion
dotnet_diagnostic.CA2000.severity = suggestion
dotnet_diagnostic.CA2002.severity = suggestion
dotnet_diagnostic.CA2007.severity = suggestion
dotnet_diagnostic.CA2008.severity = suggestion
dotnet_diagnostic.CA2009.severity = suggestion
dotnet_diagnostic.CA2011.severity = suggestion
dotnet_diagnostic.CA2012.severity = suggestion
dotnet_diagnostic.CA2016.severity = suggestion
dotnet_diagnostic.CA2019.severity = suggestion
dotnet_diagnostic.CA2020.severity = suggestion
dotnet_diagnostic.CA2025.severity = suggestion
dotnet_diagnostic.CA2100.severity = suggestion
dotnet_diagnostic.CA2101.severity = suggestion
dotnet_diagnostic.CA2119.severity = suggestion
dotnet_diagnostic.CA2153.severity = suggestion
dotnet_diagnostic.CA2201.severity = suggestion
dotnet_diagnostic.CA2207.severity = suggestion
dotnet_diagnostic.CA2208.severity = suggestion
dotnet_diagnostic.CA2211.severity = suggestion
dotnet_diagnostic.CA2213.severity = suggestion
dotnet_diagnostic.CA2214.severity = suggestion
dotnet_diagnostic.CA2215.severity = suggestion
dotnet_diagnostic.CA2216.severity = suggestion
dotnet_diagnostic.CA2217.severity = suggestion
dotnet_diagnostic.CA2218.severity = suggestion
dotnet_diagnostic.CA2219.severity = suggestion
dotnet_diagnostic.CA2224.severity = suggestion
dotnet_diagnostic.CA2225.severity = suggestion
dotnet_diagnostic.CA2226.severity = suggestion
dotnet_diagnostic.CA2227.severity = suggestion
dotnet_diagnostic.CA2231.severity = suggestion
dotnet_diagnostic.CA2234.severity = suggestion
dotnet_diagnostic.CA2235.severity = suggestion
dotnet_diagnostic.CA2237.severity = suggestion
dotnet_diagnostic.CA2241.severity = suggestion
dotnet_diagnostic.CA2242.severity = suggestion
dotnet_diagnostic.CA2243.severity = suggestion
dotnet_diagnostic.CA2244.severity = suggestion
dotnet_diagnostic.CA2245.severity = suggestion
dotnet_diagnostic.CA2246.severity = suggestion
dotnet_diagnostic.CA2248.severity = suggestion
dotnet_diagnostic.CA2249.severity = suggestion
dotnet_diagnostic.CA2250.severity = suggestion
dotnet_diagnostic.CA2251.severity = suggestion
dotnet_diagnostic.CA2252.severity = suggestion
dotnet_diagnostic.CA2253.severity = suggestion
dotnet_diagnostic.CA2254.severity = suggestion
dotnet_diagnostic.CA2262.severity = suggestion
dotnet_diagnostic.CA2263.severity = suggestion
dotnet_diagnostic.CA2300.severity = suggestion
dotnet_diagnostic.CA2301.severity = suggestion
dotnet_diagnostic.CA2302.severity = suggestion
dotnet_diagnostic.CA2305.severity = suggestion
dotnet_diagnostic.CA2310.severity = suggestion
dotnet_diagnostic.CA2311.severity = suggestion
dotnet_diagnostic.CA2312.severity = suggestion
dotnet_diagnostic.CA2315.severity = suggestion
dotnet_diagnostic.CA2321.severity = suggestion
dotnet_diagnostic.CA2322.severity = suggestion
dotnet_diagnostic.CA2326.severity = suggestion
dotnet_diagnostic.CA2327.severity = suggestion
dotnet_diagnostic.CA2328.severity = suggestion
dotnet_diagnostic.CA2329.severity = suggestion
dotnet_diagnostic.CA2330.severity = suggestion
dotnet_diagnostic.CA2350.severity = suggestion
dotnet_diagnostic.CA2351.severity = suggestion
dotnet_diagnostic.CA2352.severity = suggestion
dotnet_diagnostic.CA2353.severity = suggestion
dotnet_diagnostic.CA2354.severity = suggestion
dotnet_diagnostic.CA2355.severity = suggestion
dotnet_diagnostic.CA2356.severity = suggestion
dotnet_diagnostic.CA2361.severity = suggestion
dotnet_diagnostic.CA2362.severity = suggestion
dotnet_diagnostic.CA3001.severity = suggestion
dotnet_diagnostic.CA3002.severity = suggestion
dotnet_diagnostic.CA3003.severity = suggestion
dotnet_diagnostic.CA3004.severity = suggestion
dotnet_diagnostic.CA3005.severity = suggestion
dotnet_diagnostic.CA3006.severity = suggestion
dotnet_diagnostic.CA3007.severity = suggestion
dotnet_diagnostic.CA3008.severity = suggestion
dotnet_diagnostic.CA3009.severity = suggestion
dotnet_diagnostic.CA3010.severity = suggestion
dotnet_diagnostic.CA3011.severity = suggestion
dotnet_diagnostic.CA3012.severity = suggestion
dotnet_diagnostic.CA3061.severity = suggestion
dotnet_diagnostic.CA3075.severity = suggestion
dotnet_diagnostic.CA3076.severity = suggestion
dotnet_diagnostic.CA3077.severity = suggestion
dotnet_diagnostic.CA3147.severity = suggestion
dotnet_diagnostic.CA5350.severity = suggestion
dotnet_diagnostic.CA5351.severity = suggestion
dotnet_diagnostic.CA5358.severity = suggestion
dotnet_diagnostic.CA5359.severity = suggestion
dotnet_diagnostic.CA5360.severity = suggestion
dotnet_diagnostic.CA5361.severity = suggestion
dotnet_diagnostic.CA5362.severity = suggestion
dotnet_diagnostic.CA5363.severity = suggestion
dotnet_diagnostic.CA5364.severity = suggestion
dotnet_diagnostic.CA5365.severity = suggestion
dotnet_diagnostic.CA5366.severity = suggestion
dotnet_diagnostic.CA5367.severity = suggestion
dotnet_diagnostic.CA5368.severity = suggestion
dotnet_diagnostic.CA5369.severity = suggestion
dotnet_diagnostic.CA5370.severity = suggestion
dotnet_diagnostic.CA5371.severity = suggestion
dotnet_diagnostic.CA5372.severity = suggestion
dotnet_diagnostic.CA5373.severity = suggestion
dotnet_diagnostic.CA5374.severity = suggestion
dotnet_diagnostic.CA5375.severity = suggestion
dotnet_diagnostic.CA5376.severity = suggestion
dotnet_diagnostic.CA5377.severity = suggestion
dotnet_diagnostic.CA5378.severity = suggestion
dotnet_diagnostic.CA5379.severity = suggestion
dotnet_diagnostic.CA5380.severity = suggestion
dotnet_diagnostic.CA5381.severity = suggestion
dotnet_diagnostic.CA5382.severity = suggestion
dotnet_diagnostic.CA5383.severity = suggestion
dotnet_diagnostic.CA5384.severity = suggestion
dotnet_diagnostic.CA5385.severity = suggestion
dotnet_diagnostic.CA5386.severity = suggestion
dotnet_diagnostic.CA5387.severity = suggestion
dotnet_diagnostic.CA5388.severity = suggestion
dotnet_diagnostic.CA5389.severity = suggestion
dotnet_diagnostic.CA5390.severity = suggestion
dotnet_diagnostic.CA5391.severity = suggestion
dotnet_diagnostic.CA5392.severity = suggestion
dotnet_diagnostic.CA5393.severity = suggestion
dotnet_diagnostic.CA5394.severity = suggestion
dotnet_diagnostic.CA5395.severity = suggestion
dotnet_diagnostic.CA5396.severity = suggestion
dotnet_diagnostic.CA5397.severity = suggestion
dotnet_diagnostic.CA5398.severity = suggestion
dotnet_diagnostic.CA5399.severity = suggestion
dotnet_diagnostic.CA5400.severity = suggestion
dotnet_diagnostic.CA5401.severity = suggestion
dotnet_diagnostic.CA5402.severity = suggestion
dotnet_diagnostic.CA5403.severity = suggestion
dotnet_diagnostic.CA5404.severity = suggestion
dotnet_diagnostic.CA5405.severity = suggestion