Skip to content

Cobertura post-processing double-counts <line> nodes, inflating lines-valid and every coverage rate #441

Description

@drmoisan

Discovered during research for issue #432 (epic #136, child F1).

Summary

scripts/vscode/Invoke-MSTestWithCoverage.ps1 and scripts/vscode/Invoke-MSTestWithCoverage.Helpers.ps1 compute coverage summaries using the XPath descendant axis .//lines/line. In the Cobertura documents actually produced by the pipeline, each <class> carries its <line> nodes twice: once nested under each <method> and once again as a class-level rollup. The descendant axis matches both sets, so every line is counted twice.

Evidence

  • Get-CoberturaCoverageSummary (scripts/vscode/Invoke-MSTestWithCoverage.Helpers.ps1:98) selects .//lines/line.
  • Merge-CoberturaClassesByFilename (scripts/vscode/Invoke-MSTestWithCoverage.Helpers.ps1:167) recomputes the merged line-rate through the same path, additionally double-weighting the primary class.
  • In the committed sample docs/features/active/2026-08-06-quickfiler-high-confidence-queue-init-stall-424/evidence/qa-gates/coverage-final.cobertura.xml, the header attribute lines-valid="110849" equals exactly the raw count of <line number= elements in the file, confirming the double count rather than the distinct-line count.

Full analysis: docs/features/active/2026-08-07-quickfiler-coverage-ledger-432/research/2026-08-07T22-15-quickfiler-coverage-ledger-research.md sections 4.2 and 4.5.

Impact

Reported repository-wide and per-assembly line-coverage figures are computed over an inflated denominator. The reported rate is not necessarily wrong in the same direction for every assembly, because the duplication is not uniform across classes. Every existing coverage gate and every committed coverage evidence baseline consumes this figure.

Why this is not fixed in #432

Issue #432 (the QuickFiler per-file coverage ledger and harness) deliberately does not change this behavior. Correcting the denominator would perturb every existing gate threshold and invalidate every committed coverage baseline in the repository at once, which is a separate, repo-wide change requiring its own baseline re-capture. The #432 harness avoids the defect locally by recomputing per-file rates directly from deduplicated <line> nodes and never reading the <class> line-rate attribute.

Suggested remediation

  1. Replace the .//lines/line descendant axis with a selection that reads each line exactly once, deduplicating by line number with max(hits).
  2. Re-capture the repository-wide coverage baseline against the corrected denominator.
  3. Reconcile existing gate thresholds and committed evidence artifacts against the corrected figures in the same change.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions