Summary
lsp diagnostics returns OK with details.success: true for a file that has real diagnostics when the server never publishes for that document inside the wait budget. "No fresh publish observed" is indistinguishable from "clean" in the tool result, so an agent can be told a broken config file is fine.
Repro (custom tombi server, omp 18.8.9)
~/.omp/agent/lsp.json:
{
"servers": {
"tombi": {
"command": "tombi",
"args": ["lsp"],
"fileTypes": [".toml"],
"rootMarkers": ["wrangler.toml"],
"isLinter": true
}
}
}
wrangler.toml with two schema violations:
name = "lsp-probe"
main = "src/index.ts"
compatibility_date = 12345
unknown_field = true
- In a fresh session,
lsp diagnostics with file="wrangler.toml" returns OK (serverName: tombi, success: true).
- Repeating the identical call returns the real result:
2 error(s):
# wrangler.toml
3:22 [error] [Tombi] expected a value of type String, but found Integer (type-mismatch)
4:1 [error] [Tombi] "unknown_field" is not allowed (key-not-allowed)
The same happens on the write path: write returns diagnostics: { server: "tombi", messages: [], summary: "OK", errored: false }, and an immediate re-run of lsp diagnostics returns the two errors.
Control: the same first call in a cold session against typescript-language-server returns real errors, so this is not a general cold-start problem in the tool.
Mechanism (read from the shipped sources)
src/lsp/tool.ts (diagnostics action): const minVersion = client.diagnosticsVersion → await refreshFile(client, resolved, signal) → waitForDiagnostics(client, uri, { timeoutMs, minVersion, expectedDocumentVersion }).
src/lsp/diagnostics.ts → waitForDiagnostics(): when client.diagnostics.get(uri) stays empty until the deadline and the pull path is unavailable (supportsDocumentDiagnostics(client) is false — tombi answers textDocument/diagnostic but does not advertise diagnosticProvider), the function returns [].
tool.ts then maps the empty array to OK with success: true.
Server-side trigger used here: tombi publishes diagnostics only after its background schema/config load; a document opened before that load finishes never gets a publish (verified: didOpen sent immediately after initialized → no publishDiagnostics for 12s+; with a ~1s gap → publish arrives immediately). Once the client is warm, every later call is correct.
Suggested fix
- Track whether any publish (or successful pull) was observed for the URI during the wait. If none was, do not report clean — reuse the existing "some servers failed" warning shape, e.g.
OK + no diagnostics published for <file> within <N>s, or return success: false with an explicit unverified message.
- Consider probing
textDocument/diagnostic for servers that answer pull requests without advertising diagnosticProvider (tombi does), or treating an empty pull as unverified rather than clean.
Environment
omp 18.8.9 (macOS 25.3.0, arm64), tombi 1.8.1 (tombi lsp), typescript-language-server as control.
Summary
lsp diagnosticsreturnsOKwithdetails.success: truefor a file that has real diagnostics when the server never publishes for that document inside the wait budget. "No fresh publish observed" is indistinguishable from "clean" in the tool result, so an agent can be told a broken config file is fine.Repro (custom
tombiserver, omp 18.8.9)~/.omp/agent/lsp.json:{ "servers": { "tombi": { "command": "tombi", "args": ["lsp"], "fileTypes": [".toml"], "rootMarkers": ["wrangler.toml"], "isLinter": true } } }wrangler.tomlwith two schema violations:lsp diagnosticswithfile="wrangler.toml"returnsOK(serverName: tombi,success: true).The same happens on the write path:
writereturnsdiagnostics: { server: "tombi", messages: [], summary: "OK", errored: false }, and an immediate re-run oflsp diagnosticsreturns the two errors.Control: the same first call in a cold session against
typescript-language-serverreturns real errors, so this is not a general cold-start problem in the tool.Mechanism (read from the shipped sources)
src/lsp/tool.ts(diagnostics action):const minVersion = client.diagnosticsVersion→await refreshFile(client, resolved, signal)→waitForDiagnostics(client, uri, { timeoutMs, minVersion, expectedDocumentVersion }).src/lsp/diagnostics.ts→waitForDiagnostics(): whenclient.diagnostics.get(uri)stays empty until the deadline and the pull path is unavailable (supportsDocumentDiagnostics(client)is false — tombi answerstextDocument/diagnosticbut does not advertisediagnosticProvider), the function returns[].tool.tsthen maps the empty array toOKwithsuccess: true.Server-side trigger used here:
tombipublishes diagnostics only after its background schema/config load; a document opened before that load finishes never gets a publish (verified:didOpensent immediately afterinitialized→ nopublishDiagnosticsfor 12s+; with a ~1s gap → publish arrives immediately). Once the client is warm, every later call is correct.Suggested fix
OK+no diagnostics published for <file> within <N>s, or returnsuccess: falsewith an explicit unverified message.textDocument/diagnosticfor servers that answer pull requests without advertisingdiagnosticProvider(tombi does), or treating an empty pull as unverified rather than clean.Environment
omp 18.8.9 (macOS 25.3.0, arm64),
tombi 1.8.1(tombi lsp),typescript-language-serveras control.