You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
⚠️ Definition of Done: this issue must be completed in full, in a single PR. Do not split this
work across multiple PRs, and do not defer any Deliverable below to a follow-up issue. A PR that
satisfies only some of the Deliverables, stubs a required test, or leaves a checkbox
partially-done does NOT resolve this issue and will be closed.
Context
packages/loopover-engine/src/opportunity-metadata.ts computes the five ranker inputs
(potential, feasibility, laneFit, freshness, dupRisk) that decide which issue the miner works
on next. The file is inside vitest.config.ts's coverage.include and carries the dedicated engine
Codecov flag, yet 18 v8 ignore directives suppress branch counting across nearly all of its decision
logic:
computeMetadataPotential (lines 109-123) is wrapped entirely in a v8 ignore start/stop pair,
and each of its four branches additionally carries its own v8 ignore next. It is a pure function of { labels } returning a number.
computeMetadataFeasibility's non-finite-clock guard (line 130) and its whole title-length tier
block (lines 135-141) are suppressed.
titlesOverlap (lines 146-158) is suppressed, despite being deliberately re-exported for testing via opportunityMetadataInternals (lines 160-167).
computeMetadataDupRisk's five branches (lines 180-192) are each suppressed.
Six directives are bare — /* v8 ignore next */ with no rationale at all (lines 120, 204, 206,
215, 219, 236) — against a file where every other directive carries a -- reason explanation. The
repo convention is clearly to justify each one.
The rationales that do exist are self-refuting. Line 109 says "Metadata heuristics are exercised
end-to-end in test/unit/miner-opportunity-ranker.test.ts" and line 113 says "exercised in ranker
tests". If a line is genuinely exercised, v8 ignore on it is redundant — the coverage counter would
already show it hit. The directive only changes anything when the line is not hit. So each of these
is either dead weight or is concealing an untested branch, and today there is no way to tell which.
The concrete risk: these branches are the scoring rules. computeMetadataPotential's labels.includes("refactor") bonus (line 120, bare-suppressed), computeMetadataDupRisk's
same-repo-peer filter (lines 184-188, all suppressed), and titlesOverlap's shorter.length >= 12
threshold could each be inverted or deleted today without a single test failing and without the
coverage gate noticing.
Requirements
Every v8 ignore directive in packages/loopover-engine/src/opportunity-metadata.ts MUST be
deleted — all 18, including the start/stop pairs and the six bare ones. The single exception is
the opportunityMetadataInternals export block (lines 160-167), whose "Test-only export surface for
branch coverage" rationale is legitimate and may keep its start/stop pair.
No production logic in this file may change. The scoring formulas, thresholds, label lists, and
return values MUST be byte-for-byte identical after the change.
Direct unit tests MUST be added for each function whose suppressions are removed, exercising every
branch that was suppressed (enumerated in the Deliverables below). These must call the exported
functions (and opportunityMetadataInternals members) directly, not only through rankMetadataOpportunities.
The tests MUST live in packages/loopover-engine/test/opportunity-metadata.test.ts (a new file), so
the engine Codecov flag's own node:test suite covers them.
⚠️ Required pattern: follow the direct-unit-test style of packages/loopover-engine/test/opportunity-ranker.test.ts and packages/loopover-engine/test/opportunity-competition.test.ts — node:test + node:assert/strict,
importing from ../dist/index.js like every other suite in that directory. What does NOT satisfy
this issue: replacing a v8 ignore with a c8 ignore or an istanbul ignore; moving the
suppressions into vitest.config.ts's coverage.exclude or codecov.yml's ignore; deleting the
directives without adding tests (the patch gate would fail, but the branches would still be
untested); adding one end-to-end rankMetadataOpportunities test and calling the branches covered;
or changing any threshold, weight, or label list.
Deliverables
packages/loopover-engine/src/opportunity-metadata.ts contains exactly one v8 ignore pair (the opportunityMetadataInternals export block) and no other v8 ignore directive.
git diff shows no change to any numeric literal, label array, comparison operator, or return
expression in that file.
packages/loopover-engine/test/opportunity-metadata.test.ts exists and covers computeMetadataPotential for: a negative label present (returns 0), a positive label present, "bug" present, "refactor" present, "bug" + "refactor" together, and a neutral-labels-only
baseline of 0.45.
It covers computeMetadataFeasibility for: a non-finite nowMs (returns 0), a title of length >= 8, a title of length 4-7, and a title of length < 4.
It covers opportunityMetadataInternals.titlesOverlap for: an empty left, an empty right, exact
equality, a containment with shorter.length >= 12, a containment with shorter.length < 12,
and left-longer vs right-longer (both swap arms).
It covers computeMetadataDupRisk for: a blank title (returns 1), a self-peer skip, a
cross-repo peer skip, a same-repo overlapping peer, and a zero-overlap batch (returns 0).
It covers buildMetadataRankInput with highRiskDuplicateClusters and openPullRequests both
present and both absent (the two bare-suppressed ?? 0 arms at lines 204 and 206), and with updatedAt/createdAt both present and both absent (the bare-suppressed arm at line 215).
npm run test:coverage reports no uncovered line or branch in packages/loopover-engine/src/opportunity-metadata.ts outside the retained internals block.
All Deliverables above are required in a single PR. A PR that satisfies only some of them — for example
removing the directives and adding tests for computeMetadataPotential only, leaving computeMetadataDupRisk's five branches uncovered — does not resolve this issue.
Test Coverage Requirements
packages/loopover-engine/src/**/*.tsis inside coverage.include in vitest.config.ts and
carries its own engine Codecov flag, so the 99%+ branch-counted codecov/patch gate applies to every
line this PR touches — which, because the touched lines are precisely the ones the directives were
hiding, means the gate itself enforces the tests above. Both arms of every un-suppressed conditional
need a test; the enumerated cases in the Deliverables are the minimum set. Measure with npm run test:coverage (unsharded) before pushing, per the contributor guide.
Expected Outcome
The metadata ranker's scoring branches are genuinely branch-covered and any future change to a
threshold, weight, or filter is caught by a test, instead of being invisible behind 18 coverage
suppressions in a file the coverage gate is supposed to be grading.
Context
packages/loopover-engine/src/opportunity-metadata.tscomputes the five ranker inputs(
potential,feasibility,laneFit,freshness,dupRisk) that decide which issue the miner workson next. The file is inside
vitest.config.ts'scoverage.includeand carries the dedicatedengineCodecov flag, yet 18
v8 ignoredirectives suppress branch counting across nearly all of its decisionlogic:
computeMetadataPotential(lines 109-123) is wrapped entirely in av8 ignore start/stoppair,and each of its four branches additionally carries its own
v8 ignore next. It is a pure function of{ labels }returning a number.computeMetadataFeasibility's non-finite-clock guard (line 130) and its whole title-length tierblock (lines 135-141) are suppressed.
titlesOverlap(lines 146-158) is suppressed, despite being deliberately re-exported for testing viaopportunityMetadataInternals(lines 160-167).computeMetadataDupRisk's five branches (lines 180-192) are each suppressed./* v8 ignore next */with no rationale at all (lines 120, 204, 206,215, 219, 236) — against a file where every other directive carries a
-- reasonexplanation. Therepo convention is clearly to justify each one.
The rationales that do exist are self-refuting. Line 109 says "Metadata heuristics are exercised
end-to-end in test/unit/miner-opportunity-ranker.test.ts" and line 113 says "exercised in ranker
tests". If a line is genuinely exercised,
v8 ignoreon it is redundant — the coverage counter wouldalready show it hit. The directive only changes anything when the line is not hit. So each of these
is either dead weight or is concealing an untested branch, and today there is no way to tell which.
The concrete risk: these branches are the scoring rules.
computeMetadataPotential'slabels.includes("refactor")bonus (line 120, bare-suppressed),computeMetadataDupRisk'ssame-repo-peer filter (lines 184-188, all suppressed), and
titlesOverlap'sshorter.length >= 12threshold could each be inverted or deleted today without a single test failing and without the
coverage gate noticing.
Requirements
v8 ignoredirective inpackages/loopover-engine/src/opportunity-metadata.tsMUST bedeleted — all 18, including the
start/stoppairs and the six bare ones. The single exception isthe
opportunityMetadataInternalsexport block (lines 160-167), whose "Test-only export surface forbranch coverage" rationale is legitimate and may keep its
start/stoppair.return values MUST be byte-for-byte identical after the change.
branch that was suppressed (enumerated in the Deliverables below). These must call the exported
functions (and
opportunityMetadataInternalsmembers) directly, not only throughrankMetadataOpportunities.packages/loopover-engine/test/opportunity-metadata.test.ts(a new file), sothe
engineCodecov flag's own node:test suite covers them.Deliverables
packages/loopover-engine/src/opportunity-metadata.tscontains exactly onev8 ignorepair (theopportunityMetadataInternalsexport block) and no otherv8 ignoredirective.git diffshows no change to any numeric literal, label array, comparison operator, or returnexpression in that file.
packages/loopover-engine/test/opportunity-metadata.test.tsexists and coverscomputeMetadataPotentialfor: a negative label present (returns0), a positive label present,"bug"present,"refactor"present,"bug"+"refactor"together, and a neutral-labels-onlybaseline of
0.45.computeMetadataFeasibilityfor: a non-finitenowMs(returns0), a title of length>= 8, a title of length4-7, and a title of length< 4.opportunityMetadataInternals.titlesOverlapfor: an empty left, an empty right, exactequality, a containment with
shorter.length >= 12, a containment withshorter.length < 12,and left-longer vs right-longer (both swap arms).
computeMetadataDupRiskfor: a blank title (returns1), a self-peer skip, across-repo peer skip, a same-repo overlapping peer, and a zero-overlap batch (returns
0).buildMetadataRankInputwithhighRiskDuplicateClustersandopenPullRequestsbothpresent and both absent (the two bare-suppressed
?? 0arms at lines 204 and 206), and withupdatedAt/createdAtboth present and both absent (the bare-suppressed arm at line 215).npm run test:coveragereports no uncovered line or branch inpackages/loopover-engine/src/opportunity-metadata.tsoutside the retained internals block.All Deliverables above are required in a single PR. A PR that satisfies only some of them — for example
removing the directives and adding tests for
computeMetadataPotentialonly, leavingcomputeMetadataDupRisk's five branches uncovered — does not resolve this issue.Test Coverage Requirements
packages/loopover-engine/src/**/*.tsis insidecoverage.includeinvitest.config.tsandcarries its own
engineCodecov flag, so the 99%+ branch-countedcodecov/patchgate applies to everyline this PR touches — which, because the touched lines are precisely the ones the directives were
hiding, means the gate itself enforces the tests above. Both arms of every un-suppressed conditional
need a test; the enumerated cases in the Deliverables are the minimum set. Measure with
npm run test:coverage(unsharded) before pushing, per the contributor guide.Expected Outcome
The metadata ranker's scoring branches are genuinely branch-covered and any future change to a
threshold, weight, or filter is caught by a test, instead of being invisible behind 18 coverage
suppressions in a file the coverage gate is supposed to be grading.
Links & Resources
packages/loopover-engine/src/opportunity-metadata.ts(whole file)packages/loopover-engine/test/opportunity-ranker.test.ts,packages/loopover-engine/test/opportunity-competition.test.ts(the suite style to mirror)vitest.config.tscoverage.include;codecov.ymlflags.engine