Skip to content

fix(#1802): give language-service diagnostics the emit path's import scope - #1805

Merged
rbuergi merged 1 commit into
mainfrom
fix/1802-lsp-uses-emit-path
Aug 17, 2026
Merged

rbuergi merged 1 commit into
mainfrom
fix/1802-lsp-uses-emit-path

Conversation

@rbuergi

@rbuergi rbuergi commented Aug 17, 2026

Copy link
Copy Markdown
Contributor

Closes #1802.

The bug

Same node, same minute, two platform tools disagreeing:

tool verdict on @SocialMedia/PostsHub
get_diagnostics Ok — "Compile SUCCEEDED at 20:07:44Z. The NodeType assembly was built without errors and is loaded."
lsp_diagnostics_for_node 12 Errors — CS0308 ×4, CS0246 IMeshService ×2, CS1061 ×6

The LSP was wrong. Two agents spent a session about to "fix" source that compiles and ships.

Root cause

  • Emit (real): NodeCompileShaping.CombineSources joins ALL sources into ONE CodeConfiguration.Code; DynamicMeshNodeAttributeGenerator prepends a 22-namespace preamble and hoists every file's usings. One unit ⇒ everything in scope.
  • Language service: keeps one tree per file so a diagnostic carries the MeshNode path the user edits. A C# using is file-scoped, so the skeleton's preamble covered nothing, and every source relying on it reported phantom CS0246/CS0308.

The fix

Render the same scope as global using — the language feature for precisely this — and hand it to all three consumers that assemble per-file trees:

  • SpeculativeCompilation (recomputed from the substituted sources, so a using typed in Monaco counts)
  • CompileDiagnostics.DiagnoseInputs ← the one behind lsp_diagnostics_for_node
  • MeshNodeLanguageService.BuildOrReuseWorkspace (hover/completions)

Per-file trees are preserved, so positions still point at the file being edited. Generated-tree diagnostics are filtered, as the skeleton's already were.

Why not CombineSources + GenerateAttributeSource (the first-proposed route)

That collapses every source into one document and destroys the per-file positions the language service exists to provide — every diagnostic, hover and completion would report a location in a synthetic combined file. Preserving them would need an offset-mapping layer, which is itself a second implementation of the compile.

The actual intent — don't let the diagnostic path drift from the compile — is met structurally instead:

  • both renderings read one declaration, DynamicMeshNodeAttributeGenerator.StandardUsings (the emit path's inline list is now a loop over it, so adding a namespace updates both);
  • sibling usings are hoisted through the same ExtractUsingStatements the emit path hoists with.

Verification — the tests are a real gate

Two tests pin both halves: a source using preamble-only types (IMeshService, IMessageHub, generic GetService<T>) with no using of its own, and a source using a type imported only by a sibling.

Proven to fail without the fix — with the global usings suppressed both go red with the exact production signature:

CS0246 The type or namespace name 'IMeshService' could not be found
CS0246 The type or namespace name 'IMessageHub' could not be found
CS0103 The name 'CultureInfo' does not exist in the current context
  • Negative control: 2 failed / 0 passed
  • With the fix: 2 passed; full MeshNodeLanguageServiceTest 24/24
  • dotnet build -c Release -warnaserror clean; WhatsNewEntryIntegrityTest passes

Why this mattered

AGENTS.md mandates LspDiagnosticsForNode as the pre-prod sweep. With the known false PASS (#1592) it was untrustworthy in both directions — a sweep could report phantom failures and miss real ones.

🤖 Generated with Claude Code

…scope

`lsp_diagnostics_for_node` reported 12 errors on `SocialMedia/PostsHub` while
`get_diagnostics` said the assembly "was built without errors and is loaded" —
same node, same minute. The LSP was wrong, and two agents spent a session
fixing source that was never broken.

The emit path concatenates every source INTO the generated skeleton
(`NodeCompileShaping.CombineSources` → `DynamicMeshNodeAttributeGenerator`), so
the skeleton's 22-namespace preamble and every file's hoisted `using`s cover the
whole compilation. The language-service paths keep ONE TREE PER FILE so a
diagnostic carries the MeshNode path the user edits — and a C# `using` is
FILE-SCOPED, so the preamble reached none of those trees. Every source relying
on it reported phantom CS0246/CS0308.

Fix: render the same scope as `global using` — the language feature for exactly
this — and give it to all three consumers that assemble per-file trees
(`SpeculativeCompilation`, `CompileDiagnostics.DiagnoseInputs`,
`MeshNodeLanguageService.BuildOrReuseWorkspace`). Per-file trees are kept, so
positions still point at the file being edited.

Not routed through `CombineSources` + `GenerateAttributeSource` as first
proposed: that collapses every source into one document and destroys the
per-file positions the language service exists to provide. The anti-drift intent
is met instead by making both renderings read ONE declaration —
`DynamicMeshNodeAttributeGenerator.StandardUsings` — and by hoisting sibling
`using`s through the SAME `ExtractUsingStatements` the emit path hoists with.

Tests pin both halves (preamble types, and a type imported only by a sibling).
Verified as a real gate: with the global usings suppressed both FAIL with the
exact production signature — CS0246 `IMeshService`, CS0246 `IMessageHub`,
CS0103 `CultureInfo` — and pass with the fix. Full class 24/24, Release
-warnaserror clean.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Copilot AI lite review requested due to automatic review settings August 17, 2026 20:53

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR fixes a mismatch between the dynamic NodeType emit compilation path and the language-service/LSP diagnostic path by ensuring per-file Roslyn trees receive the same effective import scope that the real compiler gets via source concatenation. That removes false error reports (notably CS0246/CS0308) from lsp_diagnostics_for_node and related editor features while preserving per-file diagnostic locations.

Changes:

  • Introduces a generated global using document (derived from the canonical “standard usings” list plus the union of authored usings) and includes it in all per-file compilation/workspace builders.
  • Centralizes the “standard usings” list in DynamicMeshNodeAttributeGenerator.StandardUsings and makes the emit path read from that single declaration to prevent drift.
  • Adds regression tests covering (1) reliance on the generated preamble and (2) reliance on a sibling file’s using.

Reviewed changes

Copilot reviewed 8 out of 8 changed files in this pull request and generated no comments.

Show a summary per file
File Description
test/MeshWeaver.Hosting.Monolith.Test/MeshNodeLanguageServiceTest.cs Adds regression tests proving diagnostics align with the emit path for preamble-only and sibling-using scenarios.
src/MeshWeaver.Graph/Configuration/MeshNodeLanguageService.cs Adds a global-usings document to the Roslyn workspace and filters generated-tree diagnostics accordingly.
src/MeshWeaver.Graph/Configuration/MeshNodeCompilationService.cs Populates CompilationInputs.GlobalUsingsSource using the shared generator so downstream LSP/diagnostics consumers get the correct scope.
src/MeshWeaver.Compiler/SpeculativeCompilation.cs Recomputes global-usings scope from the effective (substituted) sources so Monaco edits immediately affect diagnostics.
src/MeshWeaver.Compiler/DynamicMeshNodeAttributeGenerator.cs Introduces StandardUsings as the single source of truth and adds GenerateGlobalUsingsSource for the language-service path.
src/MeshWeaver.Compiler/CompileDiagnostics.cs Extends per-file diagnostic shaping (DiagnoseInputs) to include the global-usings tree and filters its diagnostics from user-facing output.
src/MeshWeaver.Compiler/CompilationInputs.cs Adds GlobalUsingsSource to the shared compilation/workspace input contract with a correctness-focused doc comment.
src/MeshWeaver.Documentation/Data/WhatsNew/2026-08-17-the-editor-stops-reporting-errors-that-are-not-there.md Adds a WhatsNew entry documenting the user-visible fix and its impact on editor diagnostics.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

@github-actions

Copy link
Copy Markdown
Contributor

Test Results (shard 0)

972 tests  ±0   971 ✅ ±0   10m 48s ⏱️ - 1m 24s
 10 suites ±0     1 💤 ±0 
 10 files   ±0     0 ❌ ±0 

Results for commit a1148bd. ± Comparison against base commit 7e0f2eb.

@github-actions

Copy link
Copy Markdown
Contributor

Test Results (shard 5)

1 371 tests   1 370 ✅  5m 55s ⏱️
   11 suites      1 💤
   11 files        0 ❌

Results for commit a1148bd.

@github-actions

Copy link
Copy Markdown
Contributor

Test Results (shard 2)

2 462 tests   2 458 ✅  7m 15s ⏱️
   11 suites      4 💤
   11 files        0 ❌

Results for commit a1148bd.

@github-actions

Copy link
Copy Markdown
Contributor

Test Results (shard 1)

2 247 tests   2 144 ✅  8m 23s ⏱️
   11 suites    103 💤
   11 files        0 ❌

Results for commit a1148bd.

@github-actions

Copy link
Copy Markdown
Contributor

Test Results (shard 4)

1 802 tests  ±0   1 801 ✅ ±0   8m 5s ⏱️ + 1m 9s
   11 suites ±0       1 💤 ±0 
   11 files   ±0       0 ❌ ±0 

Results for commit a1148bd. ± Comparison against base commit 7e0f2eb.

@github-actions

github-actions Bot commented Aug 17, 2026 •

Copy link
Copy Markdown
Contributor

Test Results (shard 3)

   11 files  ±0     11 suites  ±0   4m 56s ⏱️ -49s
2 107 tests ±0  1 911 ✅ ±0  196 💤 ±0  0 ❌ ±0 
2 522 runs  +1  2 326 ✅ +1  196 💤 ±0  0 ❌ ±0 

Results for commit a1148bd. ± Comparison against base commit 7e0f2eb.

♻️ This comment has been updated with latest results.

@github-actions

github-actions Bot commented Aug 17, 2026 •

Copy link
Copy Markdown
Contributor

Test Results

    65 files  +   12      65 suites  +12   45m 24s ⏱️ + 5m 40s
10 961 tests +1 432  10 655 ✅ +1 431  306 💤 +1  0 ❌ ±0 
11 376 runs  +1 433  11 070 ✅ +1 432  306 💤 +1  0 ❌ ±0 

Results for commit a1148bd. ± Comparison against base commit 7e0f2eb.

♻️ This comment has been updated with latest results.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

LspDiagnosticsForNode reports FALSE errors: the speculative path compiles one tree per file, so the generated using-preamble never applies

2 participants