What happened?
.editorconfig severity overrides are read once, when the sidecar first loads the solution, and never again. Editing .editorconfig in a running session has no effect on published diagnostics until the language server is restarted.
Concretely: test-fixtures/workspace/.editorconfig sets
[*.{cs,vb}]
dotnet_diagnostic.CS0219.severity = error
and Refactor.cs has an unused local. dotnet build agrees and emits error CS0219. The live session keeps showing it as a warning.
This directly violates [DIAG-LSP-REFRESH], which already lists .editorconfig file change inside the solutionas a required refresh trigger, and the project's "100% reactive" hard rule inCLAUDE.md`.
Root cause
Nothing in the stack observes .editorconfig:
- No file watcher covers it. The only two globs in the extension are
src/editors/vscode/src/extension.ts:646 — const SOLUTION_FILE_GLOB = '**/*.{sln,slnx}';
src/editors/vscode/src/project-deps-store.ts:18 — const WATCH_GLOB = '**/{*.csproj,*.fsproj,Directory.Packages.props}';
- The Rust host registers no
workspace/didChangeWatchedFiles handler at all — grep -rn "DidChangeWatchedFiles" src/sharplsp/src/ returns nothing.
- The sidecar never mutates its analyzer config.
WithAnalyzerConfigDocumentText / AnalyzerConfigDocument appear nowhere in C# sidecar production code. WorkspaceManager.GetDiagnosticsAsync (src/sidecars/SharpLsp.Sidecar.CSharp/Workspace/WorkspaceManager.cs:227) reads through MapDiagnostics → model.GetDiagnostics() (.../WorkspaceManager.Helpers.cs:23) against the long-lived MSBuildWorkspace solution, whose AnalyzerConfigDocument text is a snapshot from load time.
So the severity is baked into the compilation at load and stays there.
Evidence
Roslyn itself is not at fault — it honours the file correctly on the exact code path the sidecar uses. Standalone probe against TestFixtures.csproj with the same package versions (Microsoft.CodeAnalysis 5.3.0, Microsoft.Build.Locator 1.11.2):
AnalyzerConfigDocuments: 3
ACD: C:\Code\SharpLsp\.editorconfig
ACD: ...\test-fixtures\workspace\.editorconfig
ACD: ...\obj\Debug\net10.0\TestFixtures.GeneratedMSBuildEditorConfig.editorconfig
--- model.GetDiagnostics() (what MapDiagnostics uses) ---
CS0219 severity=Error defaultSeverity=Warning isWarnAsError=True
SyntaxTreeOptionsProvider: Microsoft.CodeAnalysis.ProjectState+ProjectSyntaxTreeOptionsProvider
And the staleness itself, reproduced against a long-lived MSBuildWorkspace — the sidecar's exact lifetime model:
1. editorconfig says error -> live server reports: Error
2. editorconfig now says none -> live server STILL reports: Error
3. after restart (fresh load) -> reports: <absent>
AnalyzerConfigDocument text held by the live workspace after the edit:
root = true | | [*.cs] | dotnet_diagnostic.CS0219.severity = error |
Step 2 is the bug: the file on disk said none, the workspace still served Error, and the AnalyzerConfigDocument still held the pre-edit text.
dotnet build on the fixture, for comparison:
Refactor.cs(7,20): error CS0219: The variable 'unused' is assigned but its value is never used
1 Warning(s)
1 Error(s)
Steps to reproduce
- Open
src/editors/vscode/test-fixtures/workspace and let the server load TestFixtures.sln.
- Open
Refactor.cs — CS0219 is reported at its default severity, Warning.
- Add
dotnet_diagnostic.CS0219.severity = error under [*.{cs,vb}] in that folder's .editorconfig and save.
- Edit and save
Refactor.cs to force a re-pull.
- Observed:
CS0219 is still a Warning.
Expected: it becomes an Error, matching dotnet build.
- Restart the language server — it now reports Error, confirming the value is only ever read at load.
Scope
The same staleness class applies to every build-input file the workspace snapshots but nothing watches: .editorconfig, Directory.Build.props / .targets, global.json, and .globalconfig. A fix should cover the family, not just .editorconfig.
The F# sidecar should be checked separately — FCS does not consume dotnet_diagnostic.*.severity the way Roslyn does, so the parity story for F# needs its own answer rather than being assumed fixed by the C# change.
Suggested fix
- Watch
**/.editorconfig (and the siblings above) in the extension, or — better, since it is editor-agnostic — register workspace/didChangeWatchedFiles from the Rust host so every editor gets it.
- On change, have the sidecar apply
Solution.WithAnalyzerConfigDocumentText(...) for a known document, or reload the project when the file is new/deleted.
- Emit the
diagnostics/refresh IPC notification so the host sends workspace/diagnostic/refresh, per [DIAG-LSP-REFRESH].
- Cover it with a coarse e2e test: load the fixture, assert
CS0219 is a Warning, rewrite .editorconfig to error, assert it becomes an Error without a restart.
Note on the pasted marker
The Problems entry that surfaced this carries "owner": "msCompile", "source": "cpp" — that is VS Code's built-in $msCompile task problem matcher, i.e. a marker left by a dotnet build task, not a SharpLsp diagnostic (SharpLsp tags its own sharplsp-csharp / sharplsp-fsharp, src/sharplsp/src/diagnostics.rs:537). That particular row is a stale build marker. The SharpLsp defect above is separate and independently reproduced.
Component
C# sidecar (Roslyn) — with a required piece in the Rust LSP host and/or VS Code extension.
Language
C# (F# needs a separate assessment, see Scope)
SharpLsp version
0.1.0
Editor & OS
VS Code, Windows 11 (26200), .NET SDK 10.0.303
What happened?
.editorconfigseverity overrides are read once, when the sidecar first loads the solution, and never again. Editing.editorconfigin a running session has no effect on published diagnostics until the language server is restarted.Concretely:
test-fixtures/workspace/.editorconfigsetsand
Refactor.cshas an unused local.dotnet buildagrees and emitserror CS0219. The live session keeps showing it as a warning.This directly violates
[DIAG-LSP-REFRESH], which already lists.editorconfigfile change inside the solutionas a required refresh trigger, and the project's "100% reactive" hard rule inCLAUDE.md`.Root cause
Nothing in the stack observes
.editorconfig:src/editors/vscode/src/extension.ts:646—const SOLUTION_FILE_GLOB = '**/*.{sln,slnx}';src/editors/vscode/src/project-deps-store.ts:18—const WATCH_GLOB = '**/{*.csproj,*.fsproj,Directory.Packages.props}';workspace/didChangeWatchedFileshandler at all —grep -rn "DidChangeWatchedFiles" src/sharplsp/src/returns nothing.WithAnalyzerConfigDocumentText/AnalyzerConfigDocumentappear nowhere in C# sidecar production code.WorkspaceManager.GetDiagnosticsAsync(src/sidecars/SharpLsp.Sidecar.CSharp/Workspace/WorkspaceManager.cs:227) reads throughMapDiagnostics→model.GetDiagnostics()(.../WorkspaceManager.Helpers.cs:23) against the long-livedMSBuildWorkspacesolution, whoseAnalyzerConfigDocumenttext is a snapshot from load time.So the severity is baked into the compilation at load and stays there.
Evidence
Roslyn itself is not at fault — it honours the file correctly on the exact code path the sidecar uses. Standalone probe against
TestFixtures.csprojwith the same package versions (Microsoft.CodeAnalysis5.3.0,Microsoft.Build.Locator1.11.2):And the staleness itself, reproduced against a long-lived
MSBuildWorkspace— the sidecar's exact lifetime model:Step 2 is the bug: the file on disk said
none, the workspace still servedError, and theAnalyzerConfigDocumentstill held the pre-edit text.dotnet buildon the fixture, for comparison:Steps to reproduce
src/editors/vscode/test-fixtures/workspaceand let the server loadTestFixtures.sln.Refactor.cs—CS0219is reported at its default severity, Warning.dotnet_diagnostic.CS0219.severity = errorunder[*.{cs,vb}]in that folder's.editorconfigand save.Refactor.csto force a re-pull.CS0219is still a Warning.Expected: it becomes an Error, matching
dotnet build.Scope
The same staleness class applies to every build-input file the workspace snapshots but nothing watches:
.editorconfig,Directory.Build.props/.targets,global.json, and.globalconfig. A fix should cover the family, not just.editorconfig.The F# sidecar should be checked separately — FCS does not consume
dotnet_diagnostic.*.severitythe way Roslyn does, so the parity story for F# needs its own answer rather than being assumed fixed by the C# change.Suggested fix
**/.editorconfig(and the siblings above) in the extension, or — better, since it is editor-agnostic — registerworkspace/didChangeWatchedFilesfrom the Rust host so every editor gets it.Solution.WithAnalyzerConfigDocumentText(...)for a known document, or reload the project when the file is new/deleted.diagnostics/refreshIPC notification so the host sendsworkspace/diagnostic/refresh, per[DIAG-LSP-REFRESH].CS0219is a Warning, rewrite.editorconfigtoerror, assert it becomes an Error without a restart.Note on the pasted marker
The Problems entry that surfaced this carries
"owner": "msCompile","source": "cpp"— that is VS Code's built-in$msCompiletask problem matcher, i.e. a marker left by adotnet buildtask, not a SharpLsp diagnostic (SharpLsp tags its ownsharplsp-csharp/sharplsp-fsharp,src/sharplsp/src/diagnostics.rs:537). That particular row is a stale build marker. The SharpLsp defect above is separate and independently reproduced.Component
C# sidecar (Roslyn) — with a required piece in the Rust LSP host and/or VS Code extension.
Language
C# (F# needs a separate assessment, see Scope)
SharpLsp version
0.1.0
Editor & OS
VS Code, Windows 11 (26200), .NET SDK 10.0.303