fix(bridge): signal degraded positions and evict documents on the LRU cap - #502
Merged
Merged
Conversation
bug-ops
added a commit
that referenced
this pull request
Sep 21, 2026
… cap Position-encoding conversion now sets a positions_degraded flag on every DTO whose fields come from position conversion whenever a column could not be converted (disk-read budget exhausted, unresolvable server path, oversized file, invalid UTF-8, or a line past EOF), instead of silently passing the raw column through and leaving the only signal in a log line. DocumentTracker now evicts the least-recently-used unlocked document (sending textDocument/didClose to the LSP server) when open() would exceed workspace.max_documents, instead of permanently refusing every new document for the rest of the process lifetime once the cap is reached. Eviction skips documents with an in-flight operation or unsaved local edits, falling back to the existing DocumentLimitExceeded error only when no evictable candidate remains. Closes #497 Closes #495
bug-ops
force-pushed
the
fix/497-bridge-encoding-eviction
branch
from
September 21, 2026 14:26
8df64fb to
1cf3854
Compare
bug-ops
enabled auto-merge (squash)
September 21, 2026 14:27
test_e2e_max_documents_config_enforced still asserted the pre-#495 reject-once-the-cap-is-reached behavior, so it failed deterministically in CI once DocumentTracker started evicting the least-recently-used document instead. This test lives under tests/e2e/, a separate binary not covered by --lib --bins, which is why local verification missed it. Now asserts every open beyond the configured limit still succeeds (crossing the boundary twice) and that a document opened before the first crossing remains re-openable once evicted.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Two independent fixes in the bridge subsystem, both surfaced by continuous-improvement cycle 035 against v0.5.0 (commit bfe82b0).
positions_degradedflag on every DTO whose fields come from position conversion (hover, definition, references, locations, rename, format, code actions, document/workspace symbols, call hierarchy, inlay hints, diagnostics) whenever a column could not be converted for encoding — disk-read budget exhausted, unresolvable server path, oversized file, invalid UTF-8, or a line past EOF. Previously the only signal was atracing::warn!in mcpls's own log; a caller had no way to tell that the tail of a result set might carry silently wrong columns.DocumentTrackernow evicts the least-recently-used unlocked document (sendingtextDocument/didCloseto the LSP server) whenopen()would exceedworkspace.max_documents, instead of permanently refusing every new document for the rest of the process lifetime once the cap is reached. Eviction skips documents with an in-flight operation (tracked viapath_locks) or unsaved local edits (disk().is_some()gate), falling back to the existingDocumentLimitExceedederror only when no evictable candidate remains.Details
positions_degraded(#497) — the flag is set directly at the "passing server column through unconverted" decision point into_lsp/to_mcp(not derived from the disk-read-budget bookkeeping, which only covers one of several causes), so it fires on the first degraded lookup in a response, not just after the budget is fully exhausted.Translator::merge_diagnosticsORs the flag across the pull and cached diagnostics contexts. All affected MCP tool descriptions and DTO doc comments were updated to describe the flag;tool_surface.jsonwas regenerated accordingly.Document eviction (#495) —
DocumentTrackerhas noLspClientaccess, so evictions are queued asEvictedDocument { path, uri, synced_servers }and drained byTranslator::notify_evicted_documents, which sendstextDocument/didCloseafter everyensure_opencall (including on that call's own error path, so a queued eviction from a prior lookup is never lost).DocumentState::last_accessedtracks LRU order, bumped on everyensure_open/updateagainst a tracked document.A narrow, non-default-config race is documented but deliberately not structurally closed:
PathLockGuardcoversensure_open/update, not the LSP round-trip that follows, so atmax_documents: 1-2with concurrent calls, two in-flight documents could in principle evict each other. This is gated behind a config far below the default (100), and closing it structurally would require widening lock scope across every MCP handler — out of scope for this PR. A follow-up issue will track it.Test plan
cargo +nightly fmt --all -- --checkcargo clippy --all-targets --all-features --workspace -- -D warningscargo nextest run --workspace --all-features --lib --bins(1016 passed, 1 skipped)RUSTFLAGS="-D warnings" RUSTDOCFLAGS="--deny rustdoc::broken_intra_doc_links" cargo doc --no-deps --workspacepositions_degradedflips true end-to-end through a full mocked handler call and through themerge_diagnosticsOR-merge;DocumentTrackerLRU-vs-insertion-order distinction, lock-skip fallback toDocumentLimitExceeded, unsaved-edit eviction guard, and wire-leveltextDocument/didCloseon evictionCloses #497
Closes #495