Repository navigation
Cobertura post-processing double-counts <line> nodes, inflating lines-valid and every coverage rate #441
Description
Activity
Confirmed, plus a second independent defect in the same two functions (from issue #454 preparation research)
Preparation research for issue #454 (epic #136, child F11) independently re-verified this issue and
found a second, distinct defect that a fix for the descendant axis alone would not correct. It is
filed separately as #478.This issue's citations all hold
Get-CoberturaCoverageSummaryselects.//lines/lineat
scripts/vscode/Invoke-MSTestWithCoverage.Helpers.ps1:98— confirmed.Merge-CoberturaClassesByFilenameat:167— confirmed.- In
docs/features/active/2026-08-06-quickfiler-high-confidence-queue-init-stall-424/evidence/qa-gates/coverage-final.cobertura.xml,
lines-valid="110849"equals the raw count of<line number=elements exactly, confirming the
double count rather than a distinct-line count.
The second defect (#478)
Merge-CoberturaClassesByFilenameunions the class-level<lines>of all<class>elements sharing
afilenamecorrectly (the union at:217-268takes max hits per line number), but it never merges
the corresponding<methods>subtrees of the non-primary group members. It then recomputes
line-rateover.//lines/line, which matches the correct union plus only the primary class's
method-level lines.The emitted per-file
line-rateis therefore a blend of two different denominators. Worked example
from the committed report,QfcHomeController.Iteration.cs:- True per-file figure from the class-level union alone: 45/56 = 80.36%
- Emitted attribute: 0.8625, which is exactly 69/80 — the blended numerator and denominator
Independent confirmation of the correct recipe:
#424's own delta evidence
(docs/features/active/2026-08-06-quickfiler-high-confidence-queue-init-stall-424/evidence/qa-gates/coverage-delta.2026-08-07T00-48.md:10,41)
arrived at the class-level-only computation.Why the two should be fixed together
Both live in the same two functions and both feed the same output attribute. Correcting the
descendant axis without also merging the<methods>subtrees would leave the attribute wrong in a
different way rather than fixing it. Whoever schedules this should take #441 and #478 as one change,
including the baseline re-capture step this issue already lists.A related trap for the re-capture step
#424's committed baseline artifact is raw (no<sources>element,line-rate=0.7019) while its
final artifact is post-processed (0.856453). Epic #136 imported the raw 70.19% figure as its
authoritative repository-wide baseline. Any re-capture must compare like with like, or it will
appear to show a large coverage jump that is purely an artifact of comparing a raw report against a
post-processed one.Full analysis:
docs/features/active/2026-08-07-quickfiler-collection-controller-coverage-454/research/coverage-harness-contract.md
sections A, B, and D.- added 13 commits that reference this issue
on Aug 8, 2026 6 remaining items
- added 12 commits that reference this issue
on Aug 11, 2026
Discovered during research for issue #432 (epic #136, child F1).
Summary
scripts/vscode/Invoke-MSTestWithCoverage.ps1andscripts/vscode/Invoke-MSTestWithCoverage.Helpers.ps1compute 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 mergedline-ratethrough the same path, additionally double-weighting the primary class.docs/features/active/2026-08-06-quickfiler-high-confidence-queue-init-stall-424/evidence/qa-gates/coverage-final.cobertura.xml, the header attributelines-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.mdsections 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-rateattribute.Suggested remediation
.//lines/linedescendant axis with a selection that reads each line exactly once, deduplicating by line number withmax(hits).