Repository navigation
[quality] the e2e coverage attributedPaths set carries a converter.functions arm that can never contribute a path #1304
Description
Finding
convertScript in tests/tools/e2e-coverage-report.mjs:685-692 builds the set
that decides which of a bundle's original sources a script's coverage may be
written to:
const attributedPaths = new Set([
...Object.entries(converter.branches ?? {})
.filter(([, ranges]) => ranges.length > 0)
.map(([path]) => path),
...Object.entries(converter.functions ?? {})
.filter(([, ranges]) => ranges.length > 0)
.map(([path]) => path),
]);Three of the regions in that expression can never be evaluated, and they are
three of the ten regions that hold the harness below 100%.
The converter.functions arm contributes nothing, ever. v8-to-istanbul
writes this.functions[path] only under a truthy block.functionName —
node_modules/v8-to-istanbul/lib/v8-to-istanbul.js:167 (if (block.functionName && i === 0)) and :178 (} else if (block.functionName) {). Every block this
converter is given comes from normalizeRanges
(tests/tools/e2e-coverage-report.mjs:344-352), which rebuilds a script's whole
V8 record as exactly one block with functionName: ''. So converter.functions
is permanently {}, and .map(([path]) => path) on line 691 is unreachable.
Neither ?? {} can fire. this.branches = {} and this.functions = {} are
set in the converter's constructor (lib/v8-to-istanbul.js:36-37) and are never
reassigned, so the nullish guards on lines 686 and 689 are unreachable too.
Confirmed against the installed converter rather than argued from its source:
driving it with a boundary-split anonymous block populates branches for both
of a two-source map's sources and leaves functions as {}; the same block
named populates functions for one source only — the one its first range
lands in. So even if the arm were reachable it would be a strictly weaker
signal than the branches arm beside it.
This is not cosmetic. collectE2ECoverage:786-791 drops any src/ path missing
from attributedPaths whenever the bundle maps to more than one source, with no
diagnostic. Dead code sitting in that expression reads as a second, independent
attribution signal backing up the first. There is no second signal: if
branches ever stopped naming a source, the file would silently leave the
report and the e2e gate would pass on a smaller denominator.
Evidence and provenance
- Repository revision
4184f33(main), clean clone,npm ci, node v26.10.0,
TZ=UTC. - Unit:
npm run test:unit:coverage→ 2321 tests, 0 failures; harness files
99.32% regions (1471/1481), withtests/tools/e2e-coverage-report.mjsat
97.98% and lines244 627 686 689 691 782 793 1017 1096named as its
uncovered regions. Lines 686, 689 and 691 are the three regions above.
Resolved to exact region text by re-running the suite under
NODE_V8_COVERAGEand reading the zero-count ranges directly:?? {},
?? {},([path]) => path. - End-to-end: not applicable, and no e2e claim is made here. This file is
the harness that produces the e2e report;src filesalready measures
100.00% lines / 100.00% regions under the unit suite at this revision.
Not overlapping #1303, which is on splitRangeAtBoundaries and its line-627
[range] fallback in the same file.
Recommendation
One deliverable, one edit, in tests/tools/e2e-coverage-report.mjs: reduce the
set to the arm that actually decides attribution, and record why the other two
guards are gone, so this does not get "restored" as defensiveness later. Exact
replacement for lines 685-692:
// `converter.branches` is the whole attribution signal, and the two things
// this does not also read are not an oversight:
//
// * `converter.functions` is permanently `{}` here. v8-to-istanbul writes
// `this.functions[path]` only under `if (block.functionName ...)`
// (lib/v8-to-istanbul.js:167,178), and `normalizeRanges` above rewrites
// every script's record into exactly one block with `functionName: ''`.
// A `functions` arm would therefore contribute no path that `branches`
// has not already contributed.
// * neither needs a `?? {}` guard: both are initialised to `{}` in the
// converter's constructor (lib/v8-to-istanbul.js:36-37) and are never
// reassigned.
//
// tests/e2e-coverage-attribution.test.mjs pins both facts against the
// installed converter, so a release that started naming blocks or stopped
// initialising the maps fails there rather than silently dropping a source
// from a multi-source bundle.
const attributedPaths = new Set(
Object.entries(converter.branches)
.filter(([, ranges]) => ranges.length > 0)
.map(([path]) => path),
);Removing a guard is only safe while the premise under it holds, and nothing in
this repository holds v8-to-istanbul to it — it is a pinned dependency that
Dependabot bumps. So the same deliverable adds
tests/e2e-coverage-attribution.test.mjs, stating the premises against the
installed converter plus the end-to-end consequence:
branchesandfunctionsare{}afterload()and object-valued after
applyCoverage, so neither needs a nullish guard;- an anonymous block attributes both sources through
branchesand none
throughfunctions; - a named block does populate
functions, for its first range's source only
— non-vacuity for the test above, and the reason the arm would be the weaker
one even ifnormalizeRangesever named a block; - a two-source bundle keeps both sources in
report.sources, including one
whose coverage is a single uninterrupted covered range.
Priority
- Impact: medium — removes three permanently-uncovered harness regions and
replaces an unreachable second attribution arm with a test that fails if the
real one ever stops working. - Effort: low — one expression, one new test file, no production code.
🐝 Hive Agent: quality | Instance: hosted-available-lke648397-260827-5n31 | SHA: 4184f33
— hive: agent=quality backend=copilot model=claude-opus-5 copilot=1.0.88
Activity
test(e2e-coverage): pin reporter nullish premises and delete the dead…
test(e2e-coverage): pin reporter nullish premises and delete the dead…
test: pin the harness per-file ceiling prose to the residual note it …