Build1 publisher3 min readPublished Updated
SolonCode has writes wait for the language server's verdict, up to a default 2,000 ms (configurable, first write may exceed it)
The agent never reached for the optional lsp tool that carried diagnostics, so SolonCode moved error feedback onto write and edit, with a document version check so an old diagnosis cannot be read as a verdict on the new edit.
The Engineer · Build desk
What happened
- In the current design, write, edit and apply_patch synchronize the file, wait for diagnostics, and append them to the tool output after a successful change.
- The wait path tracks the expected document version, debounces notification bursts for 150 ms, and treats a version mismatch as stale rather than as a verdict on the newest edit.
- Before injection, the reporter keeps only ERROR severity, caps display at 20 errors per file, and summarizes the remainder as a count.
Compiled by The EngineerSomething wrong?How this is made
Why it matters
- cost The -Dlsp.diagnosticsWait knob is a session-wide dial, so buying certainty for the slow cold-start write charges the same extra milliseconds to every warm write that follows it.
- constraint Error text now enters context on every write whether the model wanted it or not, which makes the per-file display cap a spending limit and forces wide refactors to be repaired across several turns.
- precedent The stated rule reaches past LSP: if feedback is required to judge a mutation, shipping it as a tool the model may call is a design defect, which argues the same way for test runners and validators.
- exposure The model and the Web UI now consume the same diagnostic through different renderings, so a bug in the presentation filter can leave the agent and the human disagreeing about whether a file is broken.
An optional tool loses to a mandatory one on decision cost, not on capability. The first shape put nine navigation calls and diagnostics behind a single `lsp` entry point [1], which made error feedback one branch in ten [18]. To use it, the model had to remember after every edit which of those branches would tell it whether the edit compiled. According to the repository implementation note, it did not remember: diagnostics were never called [2]. In schema terms, a tool the model skips every time is just documentation.
The mutation path now does the remembering. `write`, `edit` and `apply_patch` sync the file, wait for diagnostics, then append them to the tool output [3]. The wait is where the engineering is. `syncFile` and `waitForDiagnostics` track the write time and the expected document version, and a notification whose version does not match is marked stale rather than treated as evidence about the latest edit [6]. That is the part worth copying. Language servers publish asynchronously, so an agent that accepts whatever notification arrives next will sometimes spend a turn repairing an error it has already repaired.
The price is set by a debounce window and a wait budget. A 150 ms debounce collects bursts of notifications [7], and the default wait budget is 2,000 ms [8]. Ten writes that each exhaust that budget is twenty seconds of blocked agent [19]. The note says the first write for a language can exceed two seconds during process startup and initial parsing, while later writes normally find a warm server [9]. That is why `read` warms the server asynchronously without delaying or altering the read result [4]: exploration pays the cold-start bill before the first edit needs it. Good sequencing, and free.
Whether 2,000 ms transfers to your stack is a separate question. The sample diagnostic in the note is javac reporting incompatible types at line 18, column 13 [14]. For the default to behave the same way for you, your server has to publish diagnostics for the synchronized document within roughly a debounce window, and it has to be warm by the time the agent starts writing. If indexing dominates, which is the normal case in a large workspace, the budget expires and the tool returns the most recent known result with the uncertainty made visible [16]. That failure mode is the better of the two available, but it remains a failure mode: the agent continues on a diagnosis it was told not to trust.
What reaches the model is edited, too. Positions come back as 1-based line and column, files as workspace-relative paths where possible, and the block carries an instruction to fix the errors [13]. Unfiltered, a server will push warnings, hints, generated-file paths and repeated secondary messages into the next turn [15]. Automatic feedback still has to fit a context budget.
In the write-up, the evidence for the redesign is that one observation about an uncalled tool [2], not a measured comparison. So the case rests on the mechanism. In my context that is enough, because the downside is bounded by a config line [10] and the old shape produced an agent that never checked its work.
What to watch
- A measured comparison of edit-retry counts before and after the redesign would show whether the 2,000 ms default is priced correctly.
- Whether the wait budget becomes per-language, since a JVM server's cold start and a Node server's are not the same bill.
- Whether the navigation-only lsp tool sees enough use to justify keeping nine operations in the schema.