Repository navigation
Description
Finding
src/utils/pullRequestOwners.ts is at 100 % lines/branches under both suites (npm run test:coverage and npm run test:coverage:e2e on main @ 88241f4, local runs), but a hand mutation probe shows four behaviours no test observes. Each mutant was applied to src/, then run against (a) npx vitest run __tests__/utils/pullRequestOwners.test.ts __tests__/utils/ownersAuth.test.ts __tests__/plugins and (b) npm run pack + npx vitest run __tests__/bundle (502 tests). All four pass both:
| Line | Mutant | Why it survives |
|---|---|---|
| 97 | draft: pull.draft === true → pull.draft !== false |
The test titled defaults author, draft, reviewers, assignees and labels when the pull omits them serves prHandlers(...) with no overrides, and the shared pullBody (__tests__/utils/ownersData.ts:29-40) already sets draft: false and labels: []. Nothing is omitted, so the draft/labels half of the title is vacuous. |
| 72 | [...new Set(changed.flatMap(...))] → [...changed.flatMap(...)] |
No fixture has a path that is both a previous_filename and a filename (rename a→b plus a new a), so the dedupe is never exercised. |
| 44 | memo key ${owner}/${repo}#${pullNumber} → ${pullNumber} |
Every call uses one MockContext; keys the memo by pull number only varies the number. |
| 109 | tip-cache key ${owner}/${repo}@${branch} → ${branch} |
Same: is memoized per branch only ever reads one repository. |
open: pull.state === 'open' → !== 'closed' also survives, but GitHub's state is only open/closed, so that mutant is equivalent and is not counted.
Evidence
- Unit:
npm run test:coverageon 88241f4 —src/utils/pullRequestOwners.ts100 % lines / 100 % branches; the four mutants above each leaveTests 394 passed (394)on the selector in (a). - E2E:
npm run test:coverage:e2eon 88241f4 — same file 100 % / 100 %; each mutant repacked intodist/index.jsleavesTests 502 passed (502)on__tests__/bundle. - Both suites cover every line and branch, so this is an assertion-strength finding, not a coverage gap; priority follows "surviving under both suites".
Recommendation
One PR against __tests__/utils/pullRequestOwners.test.ts:
- make the defaults test actually omit
user,draft,state,requested_reviewers,assignees,labels(passundefinedoverrides so JSON drops the keys) and assertdraft: false,open: false,labels: [] - a positive
draft: true, state: 'open'→{ draft: true, open: true }andstate: 'closed'→open: falsecase - a rename whose
previous_filenameanother entry reuses → the path appears once infilesandperFile.sizeis 2 - a second
MockContextfor another repository: same pull number is fetched again, and the same branch name is read again
The memo keys cannot be pinned from dist/index.js (one repository per process), so this stays a unit-suite fix; the e2e routeOwners helper only serves string filenames, so the rename case stays unit-side too.
Priority
- Impact: medium —
loadPullRequestOwnersfeeds approve, approveReview, blunderbuss and owners-label; a wrongdraftfold would let/approveact on drafts, and a duplicated path would double-count coverage in approve's per-file loop - Effort: low
Filed by quality agent (hold-gated mode)
🐝 Hive Agent: quality | Instance: hosted-available-lke648397-260827-5q9t | SHA: 88241f4
— hive: agent=quality backend=copilot model=claude-fable-5.1 copilot=1.0.88
Activity
github-actions commentedon Oct 20, 2026
Please add a kind label with
/kind feature,/kind failing-testor/kind cleanup.