Skip to content

refactor: route every LPP provider client through one connect path - #1014

Merged
e54-bot merged 3 commits into
mainfrom
gh-1004-one-lpp-connect
Oct 27, 2026
Merged

e54-bot merged 3 commits into
mainfrom
gh-1004-one-lpp-connect

Conversation

@e54-bot

@e54-bot e54-bot commented Oct 27, 2026

Copy link
Copy Markdown
Collaborator

What changed

wright_driver::connect::connect_provider is now the single LPP connect path every Wright provider client uses. It owns:

  • provider lookup — the session registry plus the opy id's configured resolve(); the LSP installed() fallback is removed per the owner decision (every client resolves);
  • version negotiation with a floor (LPP §19.2) — initialize at the caller's preferred version; on protocol-version-mismatch, shut down, respawn, and retry once at the highest mutually supported version at or above the ConnectFloor (entry targets ≥ 1.1, directory targets ≥ 1.3 per LPP client: capability subsets rejected, repeated provider diagnostics dropped, UTF-16 columns, client name #638);
  • failure classification — all failures surface as the typed ProviderError so callers map them through the shared provider-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 via connect_provider);
  • CompilerSession::run_provider_flow — fix context (provider_fix_validation) and ProviderRename/language-service rename — which previously called plain initialize with no negotiation;
  • opy_lookup (preferred 1.5, ConnectFloor::Entry);
  • convert_opy (preferred 1.0);
  • LanguageService's OPY provider (connect_opy_provider deleted; the service now reuses its lazy CompilerSession's connect_provider).

The LSP's parallel connect_opy_provider/mutual_protocol_version copy is deleted, and the language service's refusal mapping now uses the driver's provider_failure_code — a refusal reports provider-refusal-<code> on both the CLI and language-service surfaces instead of the raw refusal code.

CompilerSession::language_provider remains as the spawn-only seam for hosts that initialize the provider themselves (its doc points at connect_provider), and ToolService::language_provider keeps delegating to it.

Verified

  • cargo fmt --all -- --check — clean
  • cargo clippy --workspace --all-targets --all-features -- -D warnings — clean
  • cargo test --workspace --all-targets --all-features — all binaries green (e.g. wright-cli cli.rs 124/124, wright-driver 22 test binaries, wright-language 14+6, wright-lsp 25/25)
  • cargo check -p wright-wasm --target wasm32-unknown-unknown — clean (the connect path stays native-only per ADR-0037)
  • New language-service test (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 an lpp/check refusal surfaces as provider-refusal-check.tooLarge — matching the driver-side retry test (a_version_mismatch_retries_at_the_highest_mutual_version).
  • LSP/language-service boundary tests pinned offline (WRIGHT_OPY_PROVIDER_BASE_URL unreachable / nonexistent explicit executable) so the resolve-only contract is deterministic.

Not verified

  • No real opy-rs provider 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 no ui/ directory in this repository, so those checks do not apply.

Fixes #1004

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).
@e54-bot

e54-bot commented Oct 27, 2026

Copy link
Copy Markdown
Collaborator Author

All three r1 findings addressed in e2d731be (fix: stop classifying initialize refusals and session failures as provider refusals):

  1. lookup.rs initialize refusal: the connect Err arm no longer reclassifies an lpp/initialize LPP refusal as an unavailable capability gap. Refusals now carry the shared provider-refusal-<code> classification; only resolution, spawn, process, and version-negotiation failures stay unavailable. Verified live: a provider answering lpp/initialize with refusalCode: init.tooBusy now returns {"error":{"code":"provider-refusal-init.tooBusy","message":"LPP error: refusal: refusal: busy"}} instead of the Ok/unavailable envelope. Regression test: opy_lookup_carries_an_initialize_refusal_with_its_code.

  2. service.rs session-construction classification: CompilerSession::new diagnostics are no longer fabricated into ProviderError::lpp(Refusal). OpyProviderState::Unavailable now latches the classified (code, message), so a construction failure surfaces its own code (invalid-selection) on .opy diagnostics and rename instead of provider-refusal-invalid-selection. Regression test: a_session_construction_failure_keeps_its_own_code.

  3. language-services.md: the OPY provider session docs now describe the resolve() path — explicit executable, installed store, or bootstrap download — matching the driver, instead of claiming "never a download".

Gates: cargo fmt --all -- --check, cargo clippy -p wright-driver -p wright-language -p wright-lsp --all-targets --all-features -- -D warnings, cargo test -p wright-driver --test lookup -p wright-language --test service (all green), git diff --check — all pass. service.rs stays at 842 lines (no size-guard growth).

Ready for follow-up review.

@e54-bot

e54-bot commented Oct 27, 2026

Copy link
Copy Markdown
Collaborator Author

Review findings addressed in e2d731be, pushed to gh-1004-one-lpp-connect.

  • Finding 1 (fixed) — crates/wright-driver/src/lookup.rs: the Err arm of connect_provider no longer reclassifies an lpp/initialize LPP refusal into an unavailable capability gap. Resolution, spawn, process, and version-negotiation failures (NotConfigured, Spawn, Io, Exited, Local, ProtocolVersionMismatch, plus Lpp answers of kind protocolVersionMismatch/capabilityUnavailable) stay unavailable; every other ProviderError — including a Refusal — now goes through carried_refusal(provider_failure_code(&error), …), so init.tooBusy publishes provider-refusal-init.tooBusy. Regression test opy_lookup_carries_an_initialize_refusal_with_its_code added; live CLI check: wright lookup --opy-provider <refusing script> --language opy --format json hud → {"error":{"code":"provider-refusal-init.tooBusy",…}}.
  • Finding 2 (fixed) — crates/wright-language/src/service.rs: CompilerSession::new failures are no longer fabricated into an LPP Refusal. The latched connect failure is a classified (code, message) pair — provider errors classified once through provider_failure_code, session-construction diagnostics carried verbatim — so .opy diagnostics and rename report invalid-selection, not provider-refusal-invalid-selection. Regression test a_session_construction_failure_keeps_its_own_code added.
  • Finding 3 (fixed) — docs/language-services.md: the OPY provider session paragraph now says it resolves through resolve() — explicit executable, installed store, or bootstrap download — matching the driver, instead of claiming "never a download".

Verification: cargo fmt --all -- --check, cargo clippy --workspace --all-targets --all-features -- -D warnings, cargo test --workspace --all-targets --all-features (all pass), git diff --check, plus the live CLI falsification above.

The PR is ready for follow-up review.

@Teakowa Teakowa left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.
@e54-bot

e54-bot commented Oct 27, 2026

Copy link
Copy Markdown
Collaborator Author

Merge conflicts with main resolved in dc842bc0 (merge: resolve conflicts with main (typed findings, store helpers)), pushed to gh-1004-one-lpp-connect. The PR is now MERGEABLE.

Resolution, keeping both intents:

  • crates/wright-language/src/service.rs — one conflicted file, two hunks.
    • Imports: merged — kept Severity + DiagnosticSeverity (main's typed-findings refactor: keep findings typed through driver results #1015) alongside this branch's connect path; dropped ResolvedOpyProvider and ProviderError (main's free connect_opy_provider that used them was superseded by this branch's shared-connect method).
    • Dead helpers: both lpp_severity (this branch's, made obsolete by typed severity) and main's local provider_failure_code had no remaining callers after the union — both removed; the diagnostics boundary uses the shared wright_driver::source_provider::provider_failure_code.
  • Kept this branch's intent: the language service still connects through CompilerSession::connect_provider — no installed() fallback, provider-refusal-<code> refusal classification, session() surfaces construction diagnostics verbatim.
  • crates/wright-driver/src/lib.rs auto-merged: pub mod connect / ConnectFloor / ConnectedProvider coexist with main's pub mod store promotion.

Verification after the merge (all green):

  • cargo fmt --all -- --check
  • cargo clippy -p wright-driver -p wright-language -p wright-lsp -p wright-cli --all-targets --all-features -- -D warnings
  • cargo test -p wright-driver -p wright-language -p wright-lsp --all-targets — 0 failures
  • cargo test -p wright-driver --test lookup -p wright-language --test service — all pass, both regression tests included
  • git diff --check
  • Live CLI falsification: wright lookup --opy-provider <refusing script> --language opy --format json hud still returns {"error":{"code":"provider-refusal-init.tooBusy",...}}

Ready for a conflict-resolution re-review.

@Teakowa Teakowa left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM after independent review.

@e54-bot
e54-bot merged commit 39cbddb into main Oct 27, 2026
36 checks passed
@e54-bot
e54-bot deleted the gh-1004-one-lpp-connect branch October 27, 2026 14:38
@github-project-automation github-project-automation Bot moved this from Backlog to Done in Make Workshop Great Again Oct 27, 2026
e54-bot pushed a commit that referenced this pull request Oct 27, 2026
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.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Development

Successfully merging this pull request may close these issues.

Use one LPP connect path for every Wright provider client

2 participants