Skip to content

Per-edit diagnostics as a project setting, and the answer names the language server they come from - #2025

Open
MarioRial22 wants to merge 11 commits into
oraios:mainfrom
rialestate:contrib/edit-diagnostics-setting
Open

MarioRial22 wants to merge 11 commits into
oraios:mainfrom
rialestate:contrib/edit-diagnostics-setting

Conversation

@MarioRial22

Copy link
Copy Markdown

EditingToolWithDiagnostics.ENABLE_DIAGNOSTICS is a hard-coded False with no way for a project to opt in, while the machinery behind it is complete and tested. This adds edit_diagnostics to project.yml (default false, so nothing changes for anyone): a project whose workflow wants the verdict after every edit turns it on; the global flag keeps its meaning (on regardless of the project). The answer also names, per edited file, the language server the diagnostics come from (diagnostics_from): a project that grades with a second type checker at its gate should not read one server's "no errors" as the gate's.

Test (test/serena/test_serena_agent.py): with the flag off and the setting off, an edit reports nothing; with the setting on, the same edit reports the new diagnostic and diagnostics_from names the server. The project template documents the key.

Checklist

  • This PR follows the guidelines in CONTRIBUTING.md regarding the scope of PRs.
  • For changes that add features or fix problems, I have added an entry to CHANGELOG.md, which concisely describes the change.

…anguage server they come from

`EditingToolWithDiagnostics.ENABLE_DIAGNOSTICS` is a hard-coded False with
no way for a project to opt in, while the machinery behind it is complete
and tested. A new `edit_diagnostics` key in project.yml (default off, so
nothing changes for anyone) turns it on for the projects whose workflow
wants the verdict after every edit; the global flag keeps its meaning.

The answer also says, per edited file, which language server produced
the diagnostics (`diagnostics_from`): a project that grades with a
second type checker at its gate should not read one server's "no
errors" as the gate's.

@AmirF194 AmirF194 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.

I ran ProjectConfig.load() against this PR's head (87f874b9) in a clean container to check whether edit_diagnostics: true in project.yml actually reaches the loaded config.

ProjectConfig._from_dict (src/serena/config/serena_config.py:638-661) builds the returned instance with an explicit keyword for every other field (read_only=data["read_only"], etc.) but never reads data["edit_diagnostics"]. Since the dataclass field defaults to False, any value set in project.yml is silently dropped and the loaded ProjectConfig always comes back with edit_diagnostics=False, regardless of what the file says.

$ python3 /repro.py
edit_diagnostics on loaded ProjectConfig: False
Traceback (most recent call last):
  ...
AssertionError: BUG: project.yml's edit_diagnostics: true was not honored by ProjectConfig.load

(repro: write a project.yml with edit_diagnostics: true under a temp project root, call ProjectConfig.load(project_root, serena_config), assert .edit_diagnostics is True.)

The new test in this PR doesn't catch it because it sets project_config.edit_diagnostics = True directly on the Python object rather than loading it from project.yml, so it never exercises _from_dict.

Fix: add edit_diagnostics=data["edit_diagnostics"], to the cls(...) call in _from_dict, next to read_only=data["read_only"],.

…field explicitly and left this one at its default
@AmirF194

Copy link
Copy Markdown
Contributor

Confirmed: c76bdf7 adds edit_diagnostics to the _from_dict call and covers it with a test that loads project.yml directly. Thanks for the fix.

@CLAassistant

CLAassistant commented Sep 14, 2026 •

Copy link
Copy Markdown

CLA assistant check
All committers have signed the CLA.

@MarioRial22

Copy link
Copy Markdown
Author

Right — _from_dict builds the instance with an explicit keyword per field and I had not added this one, and the test mutated the loaded config instead of loading it, which is why it stayed green. Fixed in c76bdf7 (edit_diagnostics=data["edit_diagnostics"]), and test_edit_diagnostics_is_read_from_project_yml now round-trips through ProjectConfig.load from a project.yml with the key set to true; it fails on the previous commit.

…xtracted DiagnosticsContext

Upstream did half of this branch's work in the meantime: DiagnosticsContext
left EditingToolWithDiagnostics for serena/lsp/lsp_diagnostics.py and gained
an `enable` parameter, with the tool base passing `enable=ENABLE_DIAGNOSTICS`
through a `diagnostics_context()` factory. So the contribution is smaller
than it was and sits in the new seams:

- `diagnostics_context()` passes `ENABLE_DIAGNOSTICS or
  _is_edit_diagnostics_configured()`, so a project's `edit_diagnostics: true`
  turns the feature on without touching the global flag, whose meaning and
  default are unchanged.
- `DiagnosticsContext.DIAGNOSTICS_SOURCE_KEY` names, per edited file, the
  language server the reported diagnostics come from, and `DiagnosticsDiff`
  records the id of whichever server answered.

The loader fix (`_from_dict` reading `edit_diagnostics`) and the project
template's documentation of the key merged unchanged. The test follows the
constants to their new home.
The diagnostics source map read `language_server.ls_id.value`, which is
an attribute of the LanguageServerId enum and not part of the
LanguageServerIdLike protocol: an externally registered language server
(ExternalLanguageServerId) has no `value`, so the label crashed for
exactly the adapters the protocol exists to support.

`get_key()` is the protocol's accessor and returns `self.value` for enum
members, so the label is unchanged for the bundled servers.

`ty check src/serena src/solidlsp` reported this as
unresolved-attribute; it now passes.

@opcode81 opcode81 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Please see my comments.

@MischaPanch, do you think it is a good idea to expose the feature in this way (opt in)?

Comment thread src/serena/config/serena_config.py Outdated
ls_workspace_folders: list[str] = field(default_factory=lambda: ["."])
ls_additional_workspace_folders: list[str] = field(default_factory=list)
read_only: bool = False
edit_diagnostics: bool = False

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This would need to be called ls_edit_diagnostics to make clear that applies to language server applications (the LSP backend) only.

Comment on lines +124 to +129
# whether editing tools report the diagnostics (warnings and errors) an edit newly introduced in the edited
# files, as the language server sees them. The answer names the language server the diagnostics come from
# (`diagnostics_from`), since one server's verdict is not every checker's.
# Off by default: intermediate edits often introduce diagnostics on purpose (a signature changed here, its
# callers in the next edit), and reporting them at every step is noise for such workflows.
edit_diagnostics: false

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

The docstring would have to make clear that this feature currently affects the traditional tools agent interface only; the REPL interface does not provide diagnostics.

…ate its scope

* Name the setting `ls_edit_diagnostics`, like the other settings that apply to the LSP backend
  only (`ls_workspace_folders`, `ls_additional_workspace_folders`)
* State in the template that it currently affects the `tools` agent interface only; the REPL
  interface does not report per-edit diagnostics
* Document the setting in the template alone, as every other project setting is
* `DiagnosticsContext` gated on the language backend object, which is always truthy, instead of
  on `is_lsp()`, the check `is_using_language_server()` made before the backends were reified
* With `ls_edit_diagnostics` set under the JetBrains backend, every editing tool failed before its
  edit: the context asked for a language server manager the project does not have
@opcode81 opcode81 added the internal discussion This issue/PR should is flagged for discussion among maintainers. label Oct 6, 2026

This branch has not been deployed

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

Labels

internal discussion This issue/PR should is flagged for discussion among maintainers.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants