Nimblesite / Nimblesite/SharpLsp

F# sidecar coverage gate has zero headroom and under-reports inlined functions

Open
#205 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
TypeScript
Stars
132
Forks
5
Avg merge
6h 24m
Merged PRs (30d)
27

Description

What

The .NET / Sidecars coverage gate now passes, but the F# package clears it by a single line:

[sharplsp-sidecar-fsharp] coverage: 94.0034% (threshold: 95%, effective: 94% with 1pp tolerance)

That is 179 missed lines against 179 allowed. The next F# line added without a covering test turns the gate red.

Why it is fragile beyond the margin

Coverlet under-reports F#: it loses sequence points for small functions the compiler inlines, so lines that demonstrably execute are reported as never hit. Two confirmed examples, both of which run in every one of the 32 passing sidecar rename tests:

  • FSharpRenameToken.tokenMatchesName — its body is called on every rename via Option.filter, and reports 0 hits.
  • FSharpRenameIndexers.sameSymbolIsEffectivelySameAs; a probe proved it executes (isIndexerSymbol returns true only if it does), and it reports 0 hits.

So an unknown share of the 179 "missed" lines is unreachable by any test. The gate is currently balanced on that artifact rather than on real coverage.

How it got here

FSharpRenameAliases.fs, FSharpRenameIndexers.fs and FSharpRenameToken.fs are new on the cleanup branch — roughly 560 lines of rename machinery whose only tests ran through the VS Code extension host, which the .NET coverage gate does not measure. The F# package fell to 88.77% against an unchanged 95% threshold. It was masked because _check_cov checks C# first and exits on the first failure, so neither the F# nor the Common package was evaluated while C# was red.

Coverage was restored to 94.00% by adding sidecar tests (not by lowering the threshold). This issue is about the remaining fragility.

Suggested fix

One of:

  1. Exclude or correct the inlined-function attribution so the number reflects reality, then set the threshold from the corrected baseline.
  2. Set sharplsp-sidecar-fsharp in .config/coverage/thresholds.json to a deliberate value with the artifact documented, instead of leaving it one line from red.

Also worth changing: _check_cov should evaluate all three packages and report every failure, rather than exiting on the first. A masked gate is how this went unnoticed.

Related smaller items

  • src/sidecars/SharpLsp.Sidecar.FSharp/FSharpRename.fs is 516 LOC, over the 500-line limit in CLAUDE.md. Extracting the foreign-rename/transient-projection block is the natural seam but it depends on six private helpers.
  • FSharpRenameSemanticTests.fs / FSharpCodeActionSemanticTests.fs and HeadlessOverrideGenerationTests.cs / MergeDeclarationAssignmentTests.cs each duplicate a temp-project + code-action harness. A shared harness was started and withdrawn during a concurrent edit; it should be extracted once nothing is in flight.

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with .config/coverage/thresholds.json and _check_cov, then inspect FSharpRenameToken.fs and FSharpRenameIndexers.fs alongside the 32 sidecar rename tests. Compare the reported coverage with the confirmed inlined-function cases and determine how all three packages are evaluated. Done means the F# baseline and attribution are deliberate and documented, and every package failure is reported.

Written by the indexing model from the issue text.

Assessment

Tech stack
csharp, fsharp
Domain
build-system, ci-cd, testing-qa
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
45/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.