feat(analyzers): enable incremental latest-All enforcement #375

Merged
timothy merged 2 commits from feat/15-analyzer-promotion into main 2026-07-16 22:19:07 +02:00
Owner

Summary

  • centralize SDK analyzers at latest-All and enable threading analyzers for every centrally managed project
  • keep the complete .NET 10 SDK rule inventory visible at suggestion severity via a checked-in 281-rule globalconfig baseline
  • promote Sonar S3981 to a repo-wide CI blocker
  • fix the always-true worker-count predicate and add idle/active-worker regression tests
  • preserve the gitignored non-CPM MCP tool and copy the analyzer baseline into Docker restore/publish layers
  • update static-analysis and formatting documentation

Root cause

ReleaseMemoryHandler tested Workers.Count >= 0. A collection count cannot be negative, so every non-forced scheduled release was classified as busy and the intended aggressive idle-GC branch was unreachable.

The analyzer rollout also exposed an SDK precedence detail: latest-All injects exact per-ID severities, which outrank a bulk .editorconfig suggestion. The checked-in SDK baseline uses exact IDs at a higher global-config level, so All-only rules remain enabled and visible without turning the inherited backlog into hundreds of errors. Per-rule repository promotions still override it.

Verification

  • TZ=UTC dotnet restore ErsatzTV.sln -v minimal
  • TZ=UTC dotnet build ErsatzTV.sln --no-restore -v minimal (passes; 20 pre-existing compiler nullability warnings on a full rebuild)
  • TZ=UTC dotnet test ErsatzTV.sln --no-build -v quiet --logger "console;verbosity=quiet" (3,688 passed, 1 skipped)
  • changed-file dotnet format --verify-no-changes
  • evaluated test-project properties: SDK analyzers enabled, AnalysisLevel=latest-All, threading analyzers enabled, checked-in globalconfig loaded
  • negative control: temporarily restoring Count >= 0 fails the build only on S3981
  • gitignored non-CPM MCP restore: reproduced NU1015 before the guard and passes after it
  • pre-push API generation, lint, typecheck, and production web build

Deferred / limitations

  • full-tree formatting normalization remains a separate decision; format-as-you-touch stays enforced
  • a coverage floor remains deferred until CI summaries establish a stable baseline
  • the SDK globalconfig must be deliberately regenerated and reviewed on a future .NET SDK major upgrade
  • active-process and forced-override memory-handler branches were unchanged and remain outside this focused regression test
  • Docker is unavailable on the development workstation; the Dockerfile now copies the exact missing build input, but no local image build is claimed

Fixes #15

## Summary - centralize SDK analyzers at `latest-All` and enable threading analyzers for every centrally managed project - keep the complete .NET 10 SDK rule inventory visible at suggestion severity via a checked-in 281-rule globalconfig baseline - promote Sonar `S3981` to a repo-wide CI blocker - fix the always-true worker-count predicate and add idle/active-worker regression tests - preserve the gitignored non-CPM MCP tool and copy the analyzer baseline into Docker restore/publish layers - update static-analysis and formatting documentation ## Root cause `ReleaseMemoryHandler` tested `Workers.Count >= 0`. A collection count cannot be negative, so every non-forced scheduled release was classified as busy and the intended aggressive idle-GC branch was unreachable. The analyzer rollout also exposed an SDK precedence detail: `latest-All` injects exact per-ID severities, which outrank a bulk `.editorconfig` suggestion. The checked-in SDK baseline uses exact IDs at a higher global-config level, so All-only rules remain enabled and visible without turning the inherited backlog into hundreds of errors. Per-rule repository promotions still override it. ## Verification - `TZ=UTC dotnet restore ErsatzTV.sln -v minimal` - `TZ=UTC dotnet build ErsatzTV.sln --no-restore -v minimal` (passes; 20 pre-existing compiler nullability warnings on a full rebuild) - `TZ=UTC dotnet test ErsatzTV.sln --no-build -v quiet --logger "console;verbosity=quiet"` (3,688 passed, 1 skipped) - changed-file `dotnet format --verify-no-changes` - evaluated test-project properties: SDK analyzers enabled, `AnalysisLevel=latest-All`, threading analyzers enabled, checked-in globalconfig loaded - negative control: temporarily restoring `Count >= 0` fails the build only on `S3981` - gitignored non-CPM MCP restore: reproduced `NU1015` before the guard and passes after it - pre-push API generation, lint, typecheck, and production web build ## Deferred / limitations - full-tree formatting normalization remains a separate decision; format-as-you-touch stays enforced - a coverage floor remains deferred until CI summaries establish a stable baseline - the SDK globalconfig must be deliberately regenerated and reviewed on a future .NET SDK major upgrade - active-process and forced-override memory-handler branches were unchanged and remain outside this focused regression test - Docker is unavailable on the development workstation; the Dockerfile now copies the exact missing build input, but no local image build is claimed Fixes #15
Author
Owner

Reviewer response for blocked verdict on d3008b4c:

  • Docker globalconfig input — fixed in 2b8b16a5: the build stage now copies eng/analyzers/sdk-all-suggestion.globalconfig before restore/publish, matching the unconditional path in Directory.Build.props.
  • Non-CPM .mcp restore — fixed: the threading analyzer PackageReference now shares the ManagePackageVersionsCentrally=true guard used by the curated packs. The exact local MCP restore changed from NU1015 failure to exit 0; docs now state the centrally managed-project boundary.
  • Decision-matrix coverage — deferred as non-blocking: this regression changes only the empty-vs-nonempty worker-count decision and covers both sides. Active FFmpeg-process and forced-override behavior were not changed; expanding those branches can be a separate focused test increment.

Post-fix verification: full restore/build pass, 3,644 tests pass (1 intentional skip), MCP restore passes, pre-push API/lint/typecheck/web build passes. Docker is unavailable on this workstation, so no local image build is claimed; the Dockerfile now supplies the exact previously missing build input.

Requesting a fresh adversarial review of current head 2b8b16a5.

Reviewer response for blocked verdict on `d3008b4c`: - **Docker globalconfig input — fixed** in `2b8b16a5`: the build stage now copies `eng/analyzers/sdk-all-suggestion.globalconfig` before restore/publish, matching the unconditional path in `Directory.Build.props`. - **Non-CPM .mcp restore — fixed**: the threading analyzer PackageReference now shares the `ManagePackageVersionsCentrally=true` guard used by the curated packs. The exact local MCP restore changed from `NU1015` failure to exit 0; docs now state the centrally managed-project boundary. - **Decision-matrix coverage — deferred as non-blocking**: this regression changes only the empty-vs-nonempty worker-count decision and covers both sides. Active FFmpeg-process and forced-override behavior were not changed; expanding those branches can be a separate focused test increment. Post-fix verification: full restore/build pass, 3,644 tests pass (1 intentional skip), MCP restore passes, pre-push API/lint/typecheck/web build passes. Docker is unavailable on this workstation, so no local image build is claimed; the Dockerfile now supplies the exact previously missing build input. Requesting a fresh adversarial review of current head `2b8b16a5`.
Author
Owner

Fresh adversarial re-review completed against the current head.

  • The CPM guard preserves analyzer packages for centrally managed projects while excluding the non-CPM .mcp tool.
  • The generated analyzer globalconfig is copied before Docker restore/publish and is not excluded by .dockerignore.
  • The SDK analyzer snapshot still exactly matches .NET SDK 10.0.301, including CA1516 = none.
  • The remaining active-process/forced-override test gap is low-severity, non-blocking coverage debt; those branches were unchanged.

CI remains a separate merge gate.

Review-verdict: MERGEABLE @ 2b8b16a5884441988aafe3aa0624c8a2fbe9d21f

Fresh adversarial re-review completed against the current head. - The CPM guard preserves analyzer packages for centrally managed projects while excluding the non-CPM `.mcp` tool. - The generated analyzer globalconfig is copied before Docker restore/publish and is not excluded by `.dockerignore`. - The SDK analyzer snapshot still exactly matches .NET SDK 10.0.301, including `CA1516 = none`. - The remaining active-process/forced-override test gap is low-severity, non-blocking coverage debt; those branches were unchanged. CI remains a separate merge gate. Review-verdict: MERGEABLE @ 2b8b16a5884441988aafe3aa0624c8a2fbe9d21f
timothy closed this pull request 2026-07-16 21:25:36 +02:00
timothy reopened this pull request 2026-07-16 21:25:36 +02:00
timothy force-pushed feat/15-analyzer-promotion from 2b8b16a588 to 4ddc229375 2026-07-16 21:44:35 +02:00 Compare
Author
Owner

Fresh adversarial re-review completed after the required rebase onto main (dd273fbb).

  • The rebased base-to-head patch is byte-for-byte identical to the previously reviewed patch.
  • The CPM guard still excludes the non-CPM .mcp tool while loading analyzers for centrally managed projects.
  • Docker still copies the generated analyzer globalconfig before restore/publish, and .dockerignore permits it.
  • Evaluated properties remain latest-All with SDK and threading analyzers enabled.
  • The 281-rule baseline still exactly matches .NET SDK 10.0.301, including CA1516 = none.
  • The active-process/forced-override test gap remains low-severity, non-blocking coverage debt.

CI remains a separate merge gate.

Review-verdict: MERGEABLE @ 4ddc22937563e320cc767db9b8a9a7f81c168b96

Fresh adversarial re-review completed after the required rebase onto `main` (`dd273fbb`). - The rebased base-to-head patch is byte-for-byte identical to the previously reviewed patch. - The CPM guard still excludes the non-CPM `.mcp` tool while loading analyzers for centrally managed projects. - Docker still copies the generated analyzer globalconfig before restore/publish, and `.dockerignore` permits it. - Evaluated properties remain `latest-All` with SDK and threading analyzers enabled. - The 281-rule baseline still exactly matches .NET SDK 10.0.301, including `CA1516 = none`. - The active-process/forced-override test gap remains low-severity, non-blocking coverage debt. CI remains a separate merge gate. Review-verdict: MERGEABLE @ 4ddc22937563e320cc767db9b8a9a7f81c168b96
timothy force-pushed feat/15-analyzer-promotion from 4ddc229375 to 10ae885b47 2026-07-16 21:55:37 +02:00 Compare
Author
Owner

Final adversarial re-review completed after rebasing onto merged PR #374.

  • The analyzer feature patch is byte-for-byte identical to the previously reviewed patch.
  • PR #374 changed no analyzer/MSBuild/Docker configuration and introduced no S3981 conflict or threading suppression.
  • Current evaluation still loads all analyzer packages for CPM projects and excludes the non-CPM .mcp project.
  • Docker/globalconfig and SDK-inventory checks remain valid.
  • The post-rebase full build and 3,688-pass test run confirm the newly merged IPTV code compiles cleanly under the promoted analyzer posture.

CI remains a separate merge gate.

Review-verdict: MERGEABLE @ 10ae885b47

Final adversarial re-review completed after rebasing onto merged PR #374. - The analyzer feature patch is byte-for-byte identical to the previously reviewed patch. - PR #374 changed no analyzer/MSBuild/Docker configuration and introduced no `S3981` conflict or threading suppression. - Current evaluation still loads all analyzer packages for CPM projects and excludes the non-CPM `.mcp` project. - Docker/globalconfig and SDK-inventory checks remain valid. - The post-rebase full build and 3,688-pass test run confirm the newly merged IPTV code compiles cleanly under the promoted analyzer posture. CI remains a separate merge gate. Review-verdict: MERGEABLE @ 10ae885b4750495458a921958273af8746e5f265
timothy merged commit dbd4bb43f7 into main 2026-07-16 22:19:07 +02:00
timothy deleted branch feat/15-analyzer-promotion 2026-07-16 22:19:07 +02:00
Sign in to join this conversation.