Repository navigation
Feature: quickfiler-coverage-ledger #432
Description
- Work Mode: full-feature
Problem / Why
Epic #136 requires that every production .cs file compiled by QuickFiler/QuickFiler.csproj
reach at least 80% line coverage or sit on an explicitly ratified exemption ledger. Fifteen sibling
child features are blocked on three shared prerequisites that must be settled exactly once:
- The denominator is undefined. No authoritative per-file classification exists that says which
of the 121 compiled files aretestableand which areratified-exempt. Without it, a child
cannot state its own acceptance criteria, because it cannot tell whether a file such as
ItemViewer.Designer.csis inside its target set. - The existing
[ExcludeFromCodeCoverage]attributes are unratified. QuickFiler carries a
population of these attributes that has never been judged against the irreducible-remainder
standard. Per the epic manifest, an attribute sitting on a testable seam is a Blocking finding.
Until each one has a recorded disposition, children would independently and inconsistently decide
whether to remove or keep them, and would collide on shared configuration. - There is no per-file coverage measurement.
scripts/vscode/Invoke-MSTestWithCoverage.ps1
emits a Cobertura report, but nothing derives per-file line-coverage percentages from it. Fifteen
children each building their own reporting would produce fifteen inconsistent numbers and a
capstone (F16) that cannot close.
Aggregate assembly coverage does not satisfy issue #136, which measures success per production file.
Proposed Behavior
Deliver the wave-0 enabler for epic #136. No QuickFiler production behavior changes; no file under
QuickFiler/ is modified by this child.
-
Per-file classification ledger at
docs/features/epics/quickfiler-per-file-coverage/coverage-ledger.md, with one row for every
file listed as<Compile Include=...>inQuickFiler/QuickFiler.csproj. The compiled list is
derived from the csproj itself, not from a directory walk:QuickFiler/Legacy/**and
QuickFiler/Notes/**exist on disk but are not compiled and are out of scope. Each row records
file path, line count, owning child feature (per the epic manifest's "Feature File Assignments"),
classification (testableorratified-exempt), and, for every exempt row, a rationale tested
against the irreducible-remainder standard. -
Disposition of every existing
[ExcludeFromCodeCoverage]attribute in the compiled surface.
Each is treated as unratified until this ledger judges it, and receives eitherratifiedwith a
rationale, orremovenaming the owning child that must remove it and cover the file. -
Repeatable per-file coverage report harness: a PowerShell script that consumes the Cobertura
output already produced byscripts/vscode/Invoke-MSTestWithCoverage.ps1and emits per-file
line-coverage percentages for the QuickFiler assembly, flagging anytestablefile below 80% and
exiting non-zero when one is found. Pure parsing and threshold logic is separated from file and
process I/O so the logic is unit-testable without I/O.
Only three grounds justify a ratified-exempt classification:
- generated WinForms
*.Designer.csfiles and generatedProperties/files; - interface-only declarations with no executable behavior (the type-only/interface-only clause in
.claude/rules/general-unit-test.md); - irreducible WinForms/COM wiring where no interface seam, injectable delegate, or adapter can
isolate the logic, with the row stating specifically why.
Acceptance Criteria
- The ledger accounts for every compiled file in
QuickFiler.csprojwith no unassigned or
unclassified file. - Every
ratified-exemptrow carries a rationale meeting one of the three permitted grounds. - Every existing
[ExcludeFromCodeCoverage]attribute in the compiled surface has a recorded
disposition naming the owning child. - The harness produces a deterministic per-file line-coverage report for the QuickFiler assembly
from Cobertura input and exits non-zero when atestablefile is below 80%. - The harness's pure logic is unit-tested with Pester at the mirrored
tests/path, with no
temporary files. - The full PowerShell toolchain (PoshQC format, PSScriptAnalyzer, Pester) passes in final form.
Constraints & Risks
- No production C# change. No file under
QuickFiler/may be modified by this child. - No policy re-legislation.
.claude/rules/**,CLAUDE.md, and.github/instructions/**must
not be modified. The policy reconciliation between theCLAUDE.md§ UT2 COM/VSTO/WinForms
exemption and the.claude/rules/general-unit-test.mdCoverage Exclusion Policy is already
recorded in the epic manifest; this child implements it. - No change to repository-wide coverage thresholds.
- Manifest figures require ground-truthing. The epic manifest's counts and its
[X]markers are
authoring-time estimates. Preliminary inspection indicates the manifest's "33
[ExcludeFromCodeCoverage]" figure counts files containing the string - including comment-only
mentions and files that are not compiled - rather than attribute usages in the compiled surface.
The ledger must be built from verified counts and must record the reconciliation against the
manifest. - Cobertura schema must be confirmed, not assumed. Element and attribute names must be read from
the real output of the existing script rather than inferred. - PowerShell file-size limit.
Invoke-MSTestWithCoverage.Helpers.ps1is already 357 lines
against a 500-line cap, so the new logic belongs in its own file rather than appended there. - Blocking risk. Fifteen sibling children and the capstone are blocked until this child merges,
so an incomplete or non-deterministic ledger propagates to every downstream feature.
Test Conditions
- Pure per-file coverage computation from a Cobertura document with mixed hit and miss lines.
- Threshold evaluation: file above 80%, file exactly at 80%, file below 80%.
- Classification filtering: a
ratified-exemptfile below 80% must not trigger a failure. - Zero-executable-line file (interface-only) must not be reported as a 0% failure.
- Malformed or empty Cobertura input produces an explicit error, not a silent pass.
- Exit-code contract: non-zero when any
testablefile is below threshold; zero otherwise. - Determinism: identical input yields byte-identical report output and stable row ordering.
Source
From: docs/features/potential/2026-08-07-quickfiler-coverage-ledger.md
Activity
drmoisan commentedon Aug 8, 2026
Findings from child F11 (#454) preparation that bear on this child's harness and ledger
Preparation research for issue #454 (epic #136, child F11 —
QfcCollectionController, the epic'slargest single file) produced four measurement findings that are directly load-bearing for F1's
harness and ledger. Recording them here so F1 does not have to rediscover them.
Full analysis:
docs/features/active/2026-08-07-quickfiler-collection-controller-coverage-454/research/coverage-harness-contract.md1. Per-file attribution survives a partial split — verified empirically
Cobertura emits one
<class>element per(type, source file)pair. Checked againstdocs/features/active/2026-08-06-quickfiler-high-confidence-queue-init-stall-424/evidence/qa-gates/coverage-final.cobertura.xml:QfcItemController(10 partials) produces 10<class>elements with 10 distinctfilenamevalues,all sharing
name="QuickFiler.Controllers.QfcItemController"(
:22740, :23126, :23519, :24004, :24222, :24601, :25411, :25754, :26058, :26662).QfcHomeController(3 partials) produces 3 elements (:21643, :22314, :22612).<method>elements are split per file, not grouped. The instrumenter even splits a single methodacross files:
.ctorappears under bothQfcHomeController.cs(:21645) andQfcHomeController.Metrics.cs(:22316).This matters for F1 because several children (F2, F9, F11) create partials mid-wave. The ledger's
per-file rows remain meaningful after those splits.
2. A second harness defect, now filed as #478
Beyond #441's descendant-axis double count,
Merge-CoberturaClassesByFilenameunions theclass-level
<lines>correctly (Invoke-MSTestWithCoverage.Helpers.ps1:217-268) but never mergesthe non-primary group members'
<methods>subtrees, then recomputes the rate over.//lines/line.The emitted
line-rateblends the correct union with a primary-only method subtree.Worked example —
QfcHomeController.Iteration.cs: true per-file is 45/56 = 80.36%; the emittedattribute is 0.8625 = 69/80.
Consequence for F1: the harness must recompute per-file rates by unioning
./lines/line(class-level only, max hits per
@number) and must never read the<class>line-rateattribute.That is what epic.md's directive already says; #478 documents why. #441 and #478 should be fixed
together, since a fix for either alone leaves the attribute wrong.
3. Branch coverage is fully emitted
branch,condition-coverage, and<conditions>are present per line, andbranch-rateperclass/package/report. The 75% branch gate is enforceable today. One caveat for the ledger schema: a
file with no branching lines yields
0/0and must report N/A, never 0% — the same trap thethird
interface-only / not-measuredbucket exists to prevent on the line axis.4. A like-for-like trap in the epic's repository-wide baseline
#424's committed baseline artifact is raw (no<sources>element,line-rate=0.7019) while itsfinal artifact is post-processed (
0.856453). Epic #136's "Coverage-Target Reconciliation"section imported the raw 70.19% as the authoritative repository-wide baseline.
Since the epic's repository-wide criterion is "retain or improve", comparing a raw baseline against a
post-processed post-change figure would show a large apparent improvement that is purely an artifact
of the comparison. F1 should either re-state the baseline in post-processed terms or record
explicitly which form each child must compare against.
Related:
.github/workflows/ci.yml:134-140produces no Cobertura output at all, so therepository-wide figure has to be produced locally. CI also does not filter
.claude/worktreesfromits test-assembly enumeration, so a local run needs a stale-worktree pre-flight assertion to avoid
picking up agent-worktree builds.
docs(432): prepare quickfiler coverage ledger child feature
docs(432): absorb epic F1 ledger and harness directives
docs(432): absorb late epic manifest facts into the F1 plan
docs(epic): correct coverage baseline; F1 census; back-fill F1
docs(454): prepare epic child F11 quickfiler-collection-controller-co…
docs(quickfiler): prepare F13 breadcrumb drop-down and WebView2 cover…
docs(quickfiler): prepare F9 EFC form/item controller coverage (#452)
docs(quickfiler-itemviewer-coverage): prepare epic child F14 (#456)
docs(f12): clear atomic-executor preflight for #495 breadcrumb bridge…