Repository navigation
LSP: verify the standalone editing contract and publish editor recipes #1981
Description
Parent epic: #1390. Final closure follows #1391, #1392, #1393, #1394, #1398, #1975, #1976, #1977, #1978, #1979 and #1980. Reuse the delivered child harnesses and evidence; this issue adds the remaining package, client, CI and end-to-end checks.
Outcome
The documented standalone and coexistence workflows work through the shipped language-server tool and actual supported editors. A bounded automated protocol suite protects that contract in CI. Published evidence distinguishes supported behavior, deliberate refusal and measured costs.
The standalone recipe is --language-features full --diagnostics all. The coexistence recipe is --language-features interop-only --diagnostics sharpts-only, with another TypeScript service owning ordinary language features. Document the existing CLI defaults separately; do not change them as part of this verification issue.
1. Reuse and wire the protocol suites into CI
- Add one bounded aggregate command that builds the required projects once, then reuses
scripts/test-analysis-snapshots.mjs,scripts/test-semantic-hover.mjs,scripts/test-semantic-completion.mjs,scripts/test-semantic-signatures.mjs,scripts/test-member-references.mjsand the completed private-rename script. Preserve each script's named failures, source/version context, request/process deadlines and cleanup. Record the source commit, SDK/runtime/Node versions, commands and individual results in an evidence index. - Run the aggregate on Ubuntu and Windows in the repository's full CI route, using the pinned SDK and Node version. Upload diagnostics/logs/result manifests on failure. Keep the existing workflow policy checks and job time bounds. Tests must not depend on installed user editors, a globally installed SharpTS tool or public package feeds after their declared acquisition step.
- Include the pinned formatter compatibility command in an explicit development/integration CI step or job, with
npm cifrom its lockfile and its separate evidence-project build. It remains outside ordinary .NET build/test dependencies and adds no Node/formatter dependency to either packaged tool. - Assert initialized capabilities and any subsequent registrations in both modes. Full exposes only implemented navigation; hover/completion/signature/code-action interop remains available in both. Ordinary hover/completion/signature fallback is full-only. Neither mode advertises inlay hints, semantic tokens, folding or document/range/on-type formatting. Unregistered requests receive a normal protocol error and leave the server usable.
- Keep concrete client negotiation cases: omitted nested hover/completion/signature capabilities, Markdown/plaintext hover, signature string/UTF-16-offset labels and active-parameter support, and private rename with
workspace.workspaceEdit.documentChangestrue/false/missing. Clients without versioned-edit support retain existing lexical rename and receive no private edits. - Use the existing deterministic unit-test gates for stale captures and cancellation. Wire cancellation tests send actual
$/cancelRequest, accept a legitimate result that completed before cancellation, and require a surviving peer/fresh request. Do not turn an unavoidable transport race into a flaky assertion.
2. Verify the packaged executable and shipping extension
- Pack
SharpTS.LanguageServer, install that exact package into an isolated tool directory through a local-only feed/configuration, and launch its generatedsharpts-lspshim from a disposable workspace. Do not accidentally launch repository build DLLs or a global tool. Exercise initialize/initialized, one ordinary supported request in full, ordinary refusal plus retained CLR/decorator interop in interop-only, and shutdown/exit. Record the package version/hash and process command. - Keep extension compile/package checks and verify the VSIX contains the bundled language-server files. Run one isolated extension-host smoke with the shipping SharpTS extension, VS Code's built-in TypeScript service and the selected Prettier module. Confirm actual extension activation, ordinary TypeScript navigation owned by VS Code, retained SharpTS CLR interop, and two dirty format-on-save cycles with exactly one formatter owner.
- Preserve the shipping extension's default
interop-onlycontract. The existing formatter smoke's test-only hover bridge is useful formatter evidence but is not evidence of shipping-extension activation; label it accordingly.
3. Exercise the supported graph and live-editing contract
- Aggregate the child coverage into a concise supported/refused matrix, rather than duplicating every child assertion in a new suite. The source fixture includes two configured projects, project references, a closed reverse importer, a dirty dependency and exact target-document UTF-16/CRLF ranges.
- Across the appropriate child suites, require ordinary hover, lexical/member completion, complete and unfinished call/new signature help, source definitions, member references with
includeDeclarationboth ways, lexical rename and supported private rename. Apply representative completion/rename edits and obtain fresh parse/check or diagnostics results; private edits contain only captured, versioned document changes. - Cover open/change/close, dirty source/dependency versions, closed source and
.d.tsedits (including same length/timestamp), missing-import creation, configuration/project membership, workspace roots and CLR metadata generation changes. Complete member references refuse an incomplete configured graph; a proven local definition/private domain may survive an unrelated broken project as its child contract allows. - Verify ordinary parser/type errors appear under the standalone diagnostics preset. Test changing diagnostic mode through configuration in an initialized session, including explicit
diagnostics=allininterop-only; full checking for diagnostics must not enable ordinary semantic request providers or require dynamic feature registration. - Preserve refusal boundaries in the final matrix: structural/public/TypeScript-private/protected/parameter-property rename; nested or incompletely checked private domains; unsupported source-member lookup branches; synthetic holes; unknown or stale analysis. Private compound/logical/update originals currently rejected by the ordinary parser remain refusal tests, not promised new grammar.
- Malformed/incomplete buffers return a bounded unavailable/partial result where documented and never terminate the server. The recovery matrix distinguishes supported caret-local member/call gaps from lexical failures and arbitrary broken enclosing syntax. No recovered hole is a selected overload, declaration or rename target.
4. Test real editor recipes with explicit ownership
- Update
docs/language-server.md,docs/formatting.md,STATUS.mdand release notes around the final supported/refused matrix. Every sole-server launch example explicitly selectsfull --diagnostics all; every coexistence example selectsinterop-only --diagnostics sharpts-only. Explain initialization-bound feature mode and independently changeable diagnostic mode. - Record exact editor/server/formatter/TypeScript-server versions, source commit, operating system, launch/config files and result/log paths for the tested recipes. A recorded tested version is evidence for that version, not a permanent all-version certification promise.
- In actual Neovim and Helix sessions, exercise the full-alone recipe on
.ts/.tsx: dirty source/dependency updates; ordinary semantic hover; receiver completion and call signature help; source navigation; and formatting before/after a fresh language request. Exercise lexical rename and private rename where the client actually advertises versioned document changes; otherwise record the private operation as correctly unavailable for that client. - Run at least one actual Neovim/Helix two-server coexistence scenario, in addition to the shipping VS Code scenario above. Confirm the TypeScript server owns ordinary navigation and only Prettier owns formatting. Verify at least one actual SharpTS interop response and record hover/signature ownership under the documented client routing; do not imply that a single-provider client merges both servers' results. Existing Neovim/Helix formatter runs attached only SharpTS and do not establish this result.
- Document client routing limits honestly. For example, a client that chooses one server for hover/signature help may require an explicit server order; require the documented choice to behave as stated rather than inventing a position-aware provider router or promising merged hovers. Do not add a general UI automation platform or a new editor support project.
5. Publish reproducible end-to-end performance evidence
- Reuse the existing exact-baseline analysis/syntax/member/editor metadata benchmarks. For equivalent pre-existing definition/reference/diagnostic paths, retain the exact baseline revision, identical fixture/options and result fingerprints. New features with no baseline equivalent report absolute cost; they do not claim a percentage improvement over missing behavior.
- Add a bounded current-version interactive sequence on the small file and shared multi-project fixture: hover, receiver completion, signature help, definition, references and applicable rename preparation. Include fresh service/process startup separately from cache-cold queries in a warmed process, unchanged warm requests, changed open/dependency versions, and completion/signature cursor recovery.
- Measure unchanged same-caret reuse separately from changed-caret/version recovery. Report actual whole-component checker counts in the instrumented service runner; repeated unchanged requests perform no new checking. A different recovered caret may require a fresh affected-component parse/check and must be reported rather than described as incremental checking. Include one realistic default-library fixture and a CLR metadata refresh case alongside the existing
noLib/types:[]isolation fixture. - Include a bounded rapid-edit/caret burst that cancels obsolete requests and then sends a fresh request. Record admitted/in-flight build counts, cancellation settlement, retained cursor entries and fresh-request latency; prove admission/cleanup remains bounded without adding incremental compiler scope or a wall-clock pass/fail threshold.
- Report median/p90 latency, allocations, serialized response payload sizes, actual check counts, estimated retained cache bytes and a separately described managed retained-heap observation. Stdio latency/payload measurements and internal service counters may use separate runs of the same source fixture; do not claim unobserved server counters or add public protocol methods solely for benchmarking.
- Exercise bounded retention after multiple documents/carets and release completed requests/leases before measuring eviction/invalidation. State that the default eight-entry/64 MiB budget is an estimate for completed cached graphs, with an additional four checked-cursor-entry cap; active leases, in-flight work, runtime/CLR metadata and estimator error are not a strict process-memory limit.
- Repeat and investigate an observed >10% latency/allocation regression in an equivalent existing path, documenting variance, validation-cost changes and the disposition. Keep timing comparisons out of gating CI. CI may deterministically gate result fingerprints, check counts, cache bounds and cleanup; single noisy timing samples must not fail it.
Acceptance
- The bounded protocol/formatter integration commands pass on supported Ubuntu and Windows CI hosts and preserve failure artifacts.
- The isolated installed tool works in both modes; the shipping VS Code extension activates and preserves its coexistence contract.
- Version-stamped full-alone Neovim/Helix results and an actual two-server ownership result are recorded. Unsupported client routing/capabilities are documented without false feature claims.
- Child-supported graph/lifecycle/edit-safety cases are traceable from the final matrix to automated evidence; deliberate refusals remain refusals.
- Focused affected suites, required repository CI and the relevant parser/checker TypeScript/Test262 selections pass. Do not require unrelated exhaustive corpora for documentation-only changes or rerun already applicable checks without a source change or unresolved concern.
- Reproducible performance results and retained-memory limitations are published, with regression investigations recorded and no flaky timing gate.
Non-goals
TypeScript language-service parity; native formatting; inlay/semantic-token/folding providers; public or structural member rename; new private compound/update grammar; a compiler incrementalization project; a new debugger or UI automation platform; general TypeScript features in the default VS Code SharpTS client; or unmeasured performance claims.
Implemented and locally verified
Implementation commit: fa10d8b6a3ab0e367e363dd43da2ecbd953c9e41, following the eleven verified feature/integration commits. The baseline was rechecked and current main merged at a20b07d7 before final acceptance.
- Added a bounded eight-suite aggregate: six real-stdio feature scripts, pinned formatter compatibility and the exact locally packed/installed executable shim in both modes. The full CI route now requires the Ubuntu/Windows
editor-contractmatrix and retains evidence on success or failure. Node/SDK acquisition, local-only tool installation, hash checks, per-process deadlines and isolated cleanup are explicit. - Verified actual shipping VSIX activation with VS Code 1.134.0, built-in TypeScript extension 10.0.0/backend 6.0.3, Prettier extension 12.4.0/local module 3.9.9, six fresh CLR responses and two dirty saves. Its provider-free test extension neither launches the server nor supplies a language provider.
- Verified actual Neovim 0.12.5 full-alone editing and two-server TypeScript 6.0.3/adapter 6.0.1 coexistence (12 scenarios). Verified actual Helix 25.07.1 full-alone
.ts/.tsxediting, native completion/lexical/private edit application, dirty dependencies, signatures/navigation and fresh diagnostics around exact formatter saves. Neovim's default missing versioned-edit capability correctly refuses private rename; its explicit capability opt-in and Helix apply versioned private edits. - Published explicit presets, supported/refused coverage, client routing limits, recovery/cache bounds and unreleased notes. Large CLR references and existing checker limitations remain documented; no TypeScript-parity or new private grammar scope was added.
- Final Release core selection: 25,210 passed, three existing skips, zero failures (
artifacts/tests/1981-core-ci-final.trx). Final focused handlers/services: 157 passed; isolated checker-gate collection: 21 passed. The full-run gate starvation failure was investigated and fixed by isolating deliberately blocking xUnit tests; assertions and deadlines were retained. - Code-quality and workflow policy passed; NuGet release checks 10/10, GUI conformance 134/134, and the isolated exact packaged SDK consumer passed. Existing feature commits retain their focused tests and applicable TypeScript/Test262 selections. The duplicate contextual-token admission rule was extracted without changing behavior to satisfy the existing quality gate.
The final local aggregate was 8/8 at artifacts/editor-contract/20261007T215921-0682873b/index.json. All three actual-editor final runs exercised LS SHA-256 9dc0e3c3b4d401e833735179ee84185c460b9f2dcb2ae187f71f8e808627a40b and core SHA-256 a2ee2949aace31ab14706d2bf2352125ed94d9fed085cb76ec7b55d95909e45b. Compact verification index, per-editor reports and replay instructions are committed; raw local run artifacts are ignored, with CI artifacts retained separately.
The workflow report measures startup, seven-feature absolute cold/warm costs, source/dependency/caret churn, default libraries, CLR refresh, cancellation/admission cleanup, payloads, allocations and separately observed retained heap. Exact equivalent baseline fingerprints match. Multi-project existing-path warm time improved 86–87% with zero checks, while cold latency increased 26–37% and cold allocations 15%; fresh-process repeats and consumer/currentness measurements document this accepted safety/correctness tradeoff. Large custom CLR references remain expensive. Timing comparisons are not CI gates; estimated completed-cache bytes are not a process-memory cap.
Required remote verification passed on final head 666e197a37a3bf90871a511efc273da9ac985000: CI matrix and GUI packaging/native checks. Both Ubuntu and Windows editor-contract jobs passed. The first CI attempt exposed multiple Node PATH matches; follow-up commit ec51932b selects the first application while preserving the exact pinned-version check. A duplicate-PATH reproduction and all eight local suites passed before that repair was committed. The local compact index remains a timestamped pre-CI record; these run links provide final remote status.
The final test-only follow-up removes an observer-versus-worker scheduling race discovered by the Windows core run. Cancellation tests now call the real token/nested-parsing routines directly, bypass public entry checks, and require the exact cancellation token plus a cursor strictly inside the comment/tuple. The JSX case explicitly covers attribute-expression nesting after its opening-tag diagnostic preflight. Existing public-entry, request/gated cancellation and peer-survival tests remain. Production Core/LS source and the recorded editor/benchmark binaries are unchanged by this repair.
The final documentation-only follow-up 666e197a replaces three ignored local-artifact hyperlinks with committed compact verification reports. Both targets are tracked, parse successfully and record completed actual-client runs; git diff --check passed. No production, test or runner files changed in that follow-up. The final CI and GUI links below cover this exact documentation head as well.
PR and release status
Implementation and delivery verification are complete in PR #1982, final head 666e197a37a3bf90871a511efc273da9ac985000. The required CI matrix, including Ubuntu/Windows editor contracts and Gate, and the applicable GUI packaging/native checks passed on that head. Checklists record verified implementation on the PR branch. This ticket remains open until merge; this is not a released-version claim.
Activity
Resolve the first pinned Node application on hosted runners (#1981)
Make lexer and nested parser cancellation proofs deterministic (#1981)
Link editor documentation to committed verification reports (#1981)
Deliver verified standalone editor support (#1390) (#1982)