Repository navigation
refactor: route every LPP provider client through one connect path - #1014
Conversation
The LPP connect sequence — resolve the provider, spawn it, initialize at the preferred protocol version, and on protocol-version-mismatch shut down, respawn, and retry at the highest mutually supported version — was written twice and had drifted: - provider lookup: the driver session resolved through `resolve()` while the language service fell back to `installed()`; - the driver's retry honored a per-target protocol floor (LPP §19.2), the language service's had none; - the same provider refusal produced `provider-refusal-<code>` in the driver and the raw refusal code in the LSP; - fix context, rename, and convert connected with plain `initialize` and no negotiation at all. `wright_driver::connect::connect_provider` is now the single connect path: it owns `opy` resolution (every client resolves; the owner decision removes the LSP `installed()` fallback), the floored highest-mutual-version retry, and hands every caller the same typed failure so the shared `provider-refusal-<code>` classification applies on every surface. The driver session load, `run_provider_flow` (fix context and rename), `opy_lookup`, `convert_opy`, and `LanguageService`'s OPY provider all connect through it. The LSP's parallel negotiation copy is deleted. Tests: the existing driver-side version-mismatch retry test keeps covering the CLI path; a new language-service test spawns a provider that rejects the preferred version, verifies the retry at the highest mutual version, and asserts an `lpp/check` refusal surfaces as `provider-refusal-<code>` — the driver contract — instead of the raw refusal code. The LSP and language-service boundary tests now pin provider resolution offline (`WRIGHT_OPY_PROVIDER_BASE_URL` pointing at an unreachable host; a nonexistent explicit executable) so the resolve-only contract stays deterministic without network access. Fixes #1004
…vider refusals Address review findings on #1014: - `lookup`'s connect `Err` arm reclassified an `lpp/initialize` LPP refusal into an `unavailable` capability gap, dropping the refusal code. LPP answers that are not negotiation gaps now carry through the shared `provider-refusal-<code>` classification; only resolution, spawn, process, and version-negotiation failures stay `unavailable`. - `LanguageService::session()` fabricated a `Refusal` `ProviderError` from a `CompilerSession::new` diagnostic, publishing `provider-refusal-invalid-selection` for a Wright-side failure. The latched connect failure is now a classified `(code, message)` pair, so a construction diagnostic keeps its own code on `.opy` diagnostics and rename while provider errors still classify through `provider_failure_code`. - `docs/language-services.md` still claimed the provider session never downloads at `initialize`; it now documents the `resolve()` path (explicit executable, installed store, or bootstrap download).
|
All three r1 findings addressed in
Gates: Ready for follow-up review. |
|
Review findings addressed in
Verification: The PR is ready for follow-up review. |
Teakowa
left a comment
There was a problem hiding this comment.
LGTM after independent review.
Keep the shared LPP connect path from this branch: the language service still connects through `CompilerSession::connect_provider` (no `installed()` fallback, `provider-refusal-<code>` classification via the shared `provider_failure_code`). Take main's typed `DiagnosticSeverity` findings (#1015): `SourceDiagnostic.severity` stays typed, the dead `lpp_severity`/`provider_failure_code` free functions both drop, and the `Severity`/`DiagnosticSeverity` imports merge. `pub mod connect` / `ConnectFloor` exports coexist with main's `pub mod store` promotion.
|
Merge conflicts with Resolution, keeping both intents:
Verification after the merge (all green):
Ready for a conflict-resolution re-review. |
Teakowa
left a comment
There was a problem hiding this comment.
LGTM after independent review.
Resolve the #1014 shared-connect-path merge: the `opy_lookup` `connect_provider` `Err` arm keeps main's capability-gap match and the `provider_failure_code` refusal code, and additionally carries the typed `provider_failure_class` so `invalid-*`/protocol/transport failures report their real exit class (#1003). `lib.rs` keeps both the new `connect` exports and the `ExitClass` re-export.
What changed
wright_driver::connect::connect_provideris now the single LPP connect path every Wright provider client uses. It owns:opyid's configuredresolve(); the LSPinstalled()fallback is removed per the owner decision (every client resolves);protocol-version-mismatch, shut down, respawn, and retry once at the highest mutually supported version at or above theConnectFloor(entry targets ≥ 1.1, directory targets ≥ 1.3 per LPP client: capability subsets rejected, repeated provider diagnostics dropped, UTF-16 columns, client name #638);ProviderErrorso callers map them through the sharedprovider-refusal-<code>classification.Callers migrated to the shared path:
CompilerSession::load_from_source_provider(the driver's spawn + 1.4-preferred initialize + floored retry, now viaconnect_provider);CompilerSession::run_provider_flow— fix context (provider_fix_validation) andProviderRename/language-service rename — which previously called plaininitializewith no negotiation;opy_lookup(preferred 1.5,ConnectFloor::Entry);convert_opy(preferred 1.0);LanguageService's OPY provider (connect_opy_providerdeleted; the service now reuses its lazyCompilerSession'sconnect_provider).The LSP's parallel
connect_opy_provider/mutual_protocol_versioncopy is deleted, and the language service's refusal mapping now uses the driver'sprovider_failure_code— a refusal reportsprovider-refusal-<code>on both the CLI and language-service surfaces instead of the raw refusal code.CompilerSession::language_providerremains as the spawn-only seam for hosts that initialize the provider themselves (its doc points atconnect_provider), andToolService::language_providerkeeps delegating to it.Verified
cargo fmt --all -- --check— cleancargo clippy --workspace --all-targets --all-features -- -D warnings— cleancargo test --workspace --all-targets --all-features— all binaries green (e.g.wright-clicli.rs 124/124,wright-driver22 test binaries,wright-language14+6,wright-lsp25/25)cargo check -p wright-wasm --target wasm32-unknown-unknown— clean (the connect path stays native-only per ADR-0037)an_opy_provider_negotiates_and_classifies_refusals_like_the_driver) spawns a provider that rejects the preferred protocol version, verifies the §19.2 retry at the highest mutual version, and asserts anlpp/checkrefusal surfaces asprovider-refusal-check.tooLarge— matching the driver-side retry test (a_version_mismatch_retries_at_the_highest_mutual_version).WRIGHT_OPY_PROVIDER_BASE_URLunreachable / nonexistent explicit executable) so the resolve-only contract is deterministic.Not verified
opy-rsprovider binary was exercised end-to-end on this machine; the negotiation is covered by the Python fake-provider tests on both paths.ui/gates (npm ci && npm run check && npm test && npm run build && npm run check:size) — there is noui/directory in this repository, so those checks do not apply.Fixes #1004