|
| 1 | +--- |
| 2 | +applyTo: "crates/mcpls-core/src/bridge/**,crates/mcpls-core/src/lsp/**,crates/mcpls-core/src/lib.rs" |
| 3 | +--- |
| 4 | + |
| 5 | +## Bridge and LSP layer review checklist |
| 6 | + |
| 7 | +### Document state (`bridge/state.rs`) |
| 8 | + |
| 9 | +- `ensure_open` stats the file on every call and compares `(mtime, size)` against the |
| 10 | + cached `SyncSignature`. On mismatch it must send `didClose` then `didOpen` with a |
| 11 | + bumped version before returning. Verify this resync path is exercised by a test. |
| 12 | +- Stat must happen on the same `File` handle as the subsequent read, or be re-done after |
| 13 | + the read, to avoid TOCTOU: an atomic `rename(2)` between stat and `read_to_string` on |
| 14 | + a coarse-mtime filesystem (ext4: 1 s, FAT32: 2 s) leaves the cached signature stale |
| 15 | + permanently. |
| 16 | +- Version counter must reset to 1 on overflow, not saturate. `saturating_add(1)` at |
| 17 | + `i32::MAX` sends the same version on every subsequent resync; rust-analyzer silently |
| 18 | + discards non-monotone `didOpen` notifications. |
| 19 | + |
| 20 | +### Diagnostics pipeline (`bridge/translator.rs`, `bridge/notifications.rs`) |
| 21 | + |
| 22 | +- `DiagnosticsMode::Cached` returns an empty `Vec` for both "no errors" and "server |
| 23 | + has not yet analysed this file". AI clients cannot distinguish these. Flag if callers |
| 24 | + treat empty as "clean". |
| 25 | +- `merge_diagnostics` dedup key is `(range, severity, code)` when `code` is present, |
| 26 | + falling back to a path-qualifier-stripped message otherwise. Doc comments that say |
| 27 | + `(range, message, code)` are wrong — flag them. |
| 28 | +- `pull_diagnostics` has a 30 s timeout. In `Hybrid` mode it runs before the cache read. |
| 29 | + The cache read is a synchronous hashmap lookup; it should not be blocked behind the |
| 30 | + pull. Prefer `tokio::join!` for the two sources. |
| 31 | + |
| 32 | +### Notification pump (`lib.rs`) |
| 33 | + |
| 34 | +- `notification_pump` must hold only a `NotificationCache` lock, never the full |
| 35 | + `Translator` lock. Holding `Mutex<Translator>` across an LSP round-trip in a request |
| 36 | + handler while the pump waits for the same lock causes head-of-line deadlock when the |
| 37 | + notification channel fills. |
| 38 | + |
| 39 | +### File watcher (`lsp/file_watcher.rs`) |
| 40 | + |
| 41 | +- `GlobPattern::String` patterns without a leading `/` or `**/` must be anchored with |
| 42 | + `**/` before passing to `globset`. Bare `*.rs` does not match `/repo/src/lib.rs`. |
| 43 | +- `SyncSender::send` blocks when the channel is full. Use `try_send` with a warn log |
| 44 | + when the documented intent is drop-on-full. |
| 45 | +- `NEVER_FORWARD_COMPONENTS` filtering should happen before the channel send, not after, |
| 46 | + to avoid burning channel capacity on `target/` churn during `cargo build`. |
| 47 | +- `register()` overwrites duplicate registration IDs silently. LSP spec treats |
| 48 | + re-registration as an error; at minimum log a warning. |
| 49 | + |
| 50 | +### LSP client (`lsp/client.rs`, `lsp/transport.rs`) |
| 51 | + |
| 52 | +- Server-to-client requests (`method` + `id`) must receive a JSON-RPC response. |
| 53 | + Unhandled methods should return error code `-32601` (Method Not Found), not be dropped. |
| 54 | +- `id`-only messages (no `method`, no `result`, no `error`) are protocol errors and must |
| 55 | + not be treated as successful `null` responses. |
0 commit comments