Skip to content

Push per-file diagnostics for clients without pull diagnostics support - #4297

Closed
Christian Vuerings (christianvuerings) wants to merge 4 commits into
microsoft:mainfrom
christianvuerings:push-file-diagnostics
Closed

Push per-file diagnostics for clients without pull diagnostics support#4297
Christian Vuerings (christianvuerings) wants to merge 4 commits into
microsoft:mainfrom
christianvuerings:push-file-diagnostics

Conversation

@christianvuerings

Copy link
Copy Markdown

Problem

The LSP server only supports pull diagnostics (textDocument/diagnostic); push diagnostics are only used for config file errors. Clients that do not implement pull diagnostics get no file diagnostics at all. This affects eglot before Dec 2025, Nova, Claude Code, and other lighter LSP clients (see the discussion in #2362).

Change

When the client advertises textDocument.publishDiagnostics but not textDocument.diagnostic, the server now pushes per-file diagnostics for open files:

  • didOpen publishes initial diagnostics for the opened file
  • didChange schedules a debounced (500ms) snapshot update that requests open documents, so dirty programs are rebuilt eagerly, and republishes diagnostics for open files whose program updated
  • didClose clears diagnostics for the closed file
  • Triggers that would send workspace/diagnostic/refresh (watched file changes, config changes, ATA updates) schedule a snapshot update instead, since push-only clients cannot re-pull

Clients that support pull diagnostics are unaffected (verified: zero per-file pushes when textDocument.diagnostic is declared), and the existing disablePushDiagnostics initialization option also disables the new path. Diagnostics are converted with the existing DiagnosticToLSPPush path and include the document version.

Validation

  • New unit tests in internal/project/project_test.go (open/change/close/disabled)
  • go test ./internal/project/... ./internal/ls/... ./internal/lsp/... passes
  • Tested end to end over stdio against a large TypeScript monorepo (~50k files): diagnostics arrive ~1.2s after didOpen and ~500ms after each didChange, are cleared on didClose, and pull requests keep working alongside

Notes

I am aware of the pre-7.0 scope guidance in CONTRIBUTING.md; opening this as a draft since it is a behavior addition. Happy to hold it until after 7.0, or adjust the approach (for example gating behind an initialization option instead of capability detection) if you would consider it earlier.

Disclosure per CONTRIBUTING.md: this patch was authored with AI assistance (Claude Code). I have read and understand the change and will respond to review feedback myself.

Clients that do not advertise the textDocument.diagnostic capability
(e.g. eglot before Dec 2025, Nova, Claude Code) previously received no
file diagnostics at all, since the server only supports pull diagnostics
and only pushes project-level diagnostics to the tsconfig URI.

When the client advertises textDocument.publishDiagnostics but not
textDocument.diagnostic, push per-file diagnostics for open files:

- didOpen publishes initial diagnostics for the opened file
- didChange schedules a debounced snapshot update that rebuilds dirty
  programs and republishes diagnostics for affected open files
- didClose clears diagnostics for the closed file
- workspace/diagnostic/refresh triggers (watched files, config changes,
  ATA updates) schedule a snapshot update instead of a refresh request,
  since push-only clients cannot re-pull

Clients that support pull diagnostics see no behavior change, and the
existing disablePushDiagnostics initialization option also disables the
new path.
@christianvuerings
Christian Vuerings (christianvuerings) marked this pull request as ready for review June 12, 2026 21:31
Copilot AI review requested due to automatic review settings June 12, 2026 21:31

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

Note

Copilot was unable to run its full agentic suite in this review.

Adds per-file push diagnostics for open documents to support clients that don’t implement pull diagnostics, wiring this through session snapshot updates and the LSP server initialization.

Changes:

  • Introduces PushFileDiagnosticsEnabled and new update reasons to trigger snapshot updates for open-file diagnostic pushes.
  • Publishes/clears textDocument/publishDiagnostics for open/closed files after snapshot updates, and computes per-file diagnostics via ProvidePushDiagnostics.
  • Adds end-to-end tests validating publish behavior on open/change/close and version capability handling.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
internal/project/snapshot.go Logs new snapshot update reasons for improved observability.
internal/project/session.go Adds a push-only diagnostics path: schedule updates, request open resources, and publish per-file diagnostics post-snapshot.
internal/project/project_test.go Adds coverage for push diagnostics behavior across open/change/close and capability variants.
internal/lsp/server.go Enables per-file push diagnostics based on client pull/push capability detection.
internal/ls/diagnostics.go Adds ProvidePushDiagnostics to produce publishDiagnostics-formatted diagnostics.

Comment thread internal/lsp/server.go Outdated
Comment thread internal/project/session.go
Comment thread internal/project/session.go
Comment thread internal/project/session.go
- Do not gate push-file diagnostics on the textDocument.publishDiagnostics
  capability; it is a baseline notification and the capability only
  advertises extensions
- Gate the per-file push path on PushDiagnosticsEnabled as well, so the
  global option always wins
- Skip publishing empty diagnostics for files that never had any, and
  skip the clear on close for files with nothing published

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

Copilot reviewed 5 out of 5 changed files in this pull request and generated 2 comments.

Comment thread internal/project/session.go
Comment thread internal/project/session.go
* origin/main:
  Make LS checkers time out after being idle, segment based on use (take 2) (microsoft#3435)
  Fix external helper crash after module-status updates (microsoft#3994)
  Allow LSP server to use builtin watcher on Windows and macOS (microsoft#4288)
  Rebuilt CLI watcher around new `fswatch` package (microsoft#4026)
  Fix stack overflow crash in base constraint resolution (microsoft#4242)

# Conflicts:
#	internal/project/session.go
@christianvuerings

Copy link
Copy Markdown
Author

Jake Bailey (@jakebailey) could you take a look at this PR?

Claude code doesn't support pull diagnostics: anthropics/claude-code#40282 and TypeScript Go doesn't support push diagnostics.

@jakebailey

Copy link
Copy Markdown
Member

We haven't had time to test it; we'd have to disable pull diags and test in VS Code and make sure it works. Push diagnostics get tricky when dealing with LS restarts and other racy ish conditions.

@jakebailey Jake Bailey (jakebailey) added the Unmigrated PR This PR was open at the time of the repo move back to TypeScript label Aug 17, 2026
@RyanCavanaugh

Copy link
Copy Markdown
Member

Thank you for contributing to the TypeScript native port!

Development has moved from this repository back to the main microsoft/TypeScript repository. GitHub does not have PR transfer functionality, so we're closing this PR here.

If this change is still relevant, please reopen it as a new pull request in microsoft/TypeScript. We'd appreciate your help carrying the contribution over, and we apologize for the extra work.

See microsoft/typescript-go#4918 for more information about the move.

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

Labels

Unmigrated PR This PR was open at the time of the repo move back to TypeScript

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants