From 5ea2381cadb003f7bcd5fbe5aec282736fdf708a Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 22 Sep 2026 04:28:00 +0000 Subject: [PATCH] chore: close the local SonarCloud calibration gap The local reproduction reported five S2699 and missed the sixth issue SonarCloud reports. That issue is S8969 ("Null-forgiving operators should not be redundant") on DocComment.cs:191, where the string.IsNullOrEmpty guard directly above already makes the `text!` redundant. Adding a severity line alone would not have surfaced it. S8969 ships disabled by default AND was absent from the pinned SonarAnalyzer.CSharp 10.18.0.131500, so the rule could not fire at all. 10.30.0.144632 is its first release, so the pin moves there and the severity line goes in. The local set now matches SonarCloud exactly, by file and line: 5x S2699 in CodeBlocker.Test plus S8969 on DocComment.cs:191. Records the calibration query against the public SonarCloud API so the comparison is repeatable, and notes that a rule which stays silent after being listed is a package-version problem rather than a severity one. Nothing imports these files automatically: a plain `dotnet build` still reports no Sonar diagnostics and `dotnet test` passes 171/171. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01FUReBqNhW1FferSYkYG9Gd --- .sonarlint/sonar-local.globalconfig | 26 +++++++++++++++++----- .sonarlint/sonar-local.props | 11 ++++++++-- CLAUDE.md | 34 ++++++++++++++++++++--------- 3 files changed, 53 insertions(+), 18 deletions(-) diff --git a/.sonarlint/sonar-local.globalconfig b/.sonarlint/sonar-local.globalconfig index b52b70b..2dc460a 100644 --- a/.sonarlint/sonar-local.globalconfig +++ b/.sonarlint/sonar-local.globalconfig @@ -8,8 +8,10 @@ is_global = true # disabled by default. Raise them so a local run sees what CI sees. # # S3267 and S2699 are here because CI reported them on PR #87 - S3267 as new issues on -# DocComment.Validate, S2699 against the older test files. The rest are carried over from the -# equivalent config in ktsu.Semantics, whose quality profile is the closest available reference. +# DocComment.Validate, S2699 against the older test files. S8969 is here because it is the +# remaining issue this repository's SonarCloud project reports (see below). The rest are carried +# over from the equivalent config in ktsu.Semantics, whose quality profile is the closest +# available reference. dotnet_diagnostic.S107.severity = warning dotnet_diagnostic.S1075.severity = warning dotnet_diagnostic.S1172.severity = warning @@ -22,13 +24,25 @@ dotnet_diagnostic.S3358.severity = warning dotnet_diagnostic.S3458.severity = warning dotnet_diagnostic.S3776.severity = warning dotnet_diagnostic.S6444.severity = warning +dotnet_diagnostic.S8969.severity = warning # Enabled by default in the analyzer package. Left enabled here: unlike ktsu.Semantics, this # repository has not been shown to have a profile that excludes it, so a false positive is # cheaper than a missed finding. # dotnet_diagnostic.S1481.severity = none -# KNOWN GAP: SonarCloud reported one new issue on PR #87 that this configuration does not -# reproduce. The rule behind it is either absent from the analyzer package or shipped disabled -# and not listed above. If you have dashboard access and can identify it, add it here - the -# calibration is only as good as the rules it names. +# Calibration. The list above is only as good as the rules it names, so check it against the +# dashboard rather than guessing. The project is public, so this needs no token: +# +# curl -s 'https://sonarcloud.io/api/issues/search?componentKeys=ktsu-dev_CodeBlocker&resolved=false&ps=100' +# +# Every rule that query returns should appear above, and a local run should report the same set. +# As of this writing both sides agree: 5x S2699 in CodeBlocker.Test, and S8969 on +# DocComment.cs:191. +# +# S8969 ("Null-forgiving operators should not be redundant") was the issue previously recorded +# here as an unidentified gap. It was not a missing severity line - the rule ships disabled AND +# was absent from the pinned analyzer package, so adding it alone would have changed nothing. +# It needed the package bump to 10.30.0.144632 as well. That is the failure mode to watch for: +# a rule CI reports that stays silent locally after being listed here is a package-version +# problem, not a severity problem. diff --git a/.sonarlint/sonar-local.props b/.sonarlint/sonar-local.props index 311f56c..4d39c51 100644 --- a/.sonarlint/sonar-local.props +++ b/.sonarlint/sonar-local.props @@ -19,13 +19,20 @@ restore to pick up the PackageReference below. sonar-local.globalconfig (next to this file) sets the rule severities so the local warning set - approximates CI's. + matches CI's. + + The analyzer version is pinned deliberately. A rule CI reports cannot be reproduced locally if + the pinned package predates it - that is a silent gap, not a visible failure, because a rule + the package does not carry simply never fires. 10.30.0.144632 is the first release carrying + S8969, which is why the pin sits here rather than on an older release. When calibrating against + a rule CI reports and this build does not, check that the package actually contains it before + assuming the severity line is wrong. Nothing in the repository imports this, so normal builds, the CI pipeline, and packaging are all unaffected. --> - + diff --git a/CLAUDE.md b/CLAUDE.md index 287dfe1..57061ee 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -42,16 +42,30 @@ The opt-in lives in `.sonarlint/sonar-local.props` (the analyzer package) and analyzer package ships disabled). Nothing imports these automatically, so normal builds, the CI pipeline, and packaging are unaffected. -On current `main` the run is clean apart from five `S2699` warnings (test methods that assert -nothing) in `CodeBlocker.Test`. It found and named `S4144` on `ScopeTests.cs` — two test methods with -identical bodies, one of which did not test what its name claimed — which is the kind of finding the -setup exists for. - -**Known gap:** SonarCloud reported one new issue on PR #87 that this configuration does not -reproduce, and sonarcloud.io is not reachable from the agent sandbox to identify it. The rule -behind it is either absent from the analyzer package or shipped disabled and not listed in the -globalconfig. If you have dashboard access, add it — the calibration is only as good as the rules -it names. +On current `main` the run reports six findings, and they are the same six SonarCloud reports: +five `S2699` (test methods that assert nothing) in `CodeBlocker.Test`, and one `S8969` on +`CodeBlocker/Templates/DocComment.cs:191` — a null-forgiving `text!` that the +`string.IsNullOrEmpty(text)` guard directly above already makes redundant. The setup also earlier +found and named `S4144` on `ScopeTests.cs` — two test methods with identical bodies, one of which +did not test what its name claimed — which is the kind of finding it exists for. + +### Recalibrating + +The local set is only as good as the rules `sonar-local.globalconfig` names, so check it against +the dashboard rather than guessing. The SonarCloud project is public, so this needs no token: + +```bash +curl -s 'https://sonarcloud.io/api/issues/search?componentKeys=ktsu-dev_CodeBlocker&resolved=false&ps=100' +``` + +Every rule it returns should be listed in the globalconfig, and a local run should report the same +file-and-line set. + +If a rule CI reports stays silent locally *after* you add its severity line, the problem is the +analyzer package version, not the severity. Rules ship in the package; one released after the +pinned version simply cannot fire. That is exactly what hid `S8969` — it is both disabled by +default and absent from the previously pinned `10.18.0.131500`, so it needed the bump to +`10.30.0.144632` (its first release) as well as the severity line. ## Project Structure