Repository navigation
[quality] trigger.ts: /test matches workflow names and paths case-insensitively, /ok-to-test honours an existing label in any case, and the non-PR arm of /test and /ok-to-test leaves the run green — none of it is asserted #523
Description
Current scope and disposition (2026-10-21)
This issue tracks only its original finding below, not every unrelated finding folded into its comments. The table is the current routing record. Original reports and comments are preserved as history; repeated or superseded checklists in those comments are not additional closure requirements.
| Finding | Canonical owner / disposition |
|---|---|
| Original trigger name/path casing, existing OK-To-Test label, green non-PR commands | This issue; #524 |
| approveReview PAT submission and withdrawal-reason assertions | #526 / #527; duplicate here |
| Dispatcher and label-sync non-Error bundle scenarios | #528 |
| Repeated remaining plugin non-Error bundle proposals | #548; one canonical implementation, not separate new test files |
| requireMatchingLabel non-Error rule-loop arm | #549; wrappers make the proposed direct bundle scenario unsuitable |
| run.ts, command.ts and config.ts unreachable coverage arms | #544; repeated proposals here are superseded by that PR |
| mergeQueue classification and bot-login assertions | #529 |
| labelSync casing, description, counts and pagination assertions | #531 |
| lgtmBinding mutation assertions | #540 |
| hold cancel casing assertions | #541 |
| duration and labelCatalog mutation assertions | #542 |
| removeLabels continuation after 404 | #543 |
| issue-comment error cause assertions | #547 |
| labels/lgtm.ts coverage annotation | #536 / #537; duplicate here |
| Reconsider e2e branch floor after combined changes | #551; not implemented by #524 or the coverage PRs |
Each open PR remains responsible for its own work even after this issue closes. A PR may close this issue only by resolving the original finding; other rows must remain tracked at their canonical destination.
Original report (preserved)
Finding
src/issueComment/trigger.ts is 100 % line- and branch-covered by npm run test:coverage and all but one branch (statusOf, line 323) by npm run test:coverage:e2e on main @ 88241f4. A single-operator mutation probe over the file (117 mutants: ===/!==, &&/||, ??/||, comparison bounds, .some/.every, .toLowerCase() removal, true/false, ++/--, continue/break, status codes) still left five non-equivalent survivors against npx vitest related src/issueComment/trigger.ts --run (43 files / 837 tests):
| line | mutant | behaviour nothing asserts |
|---|---|---|
| 272 | (run.name ?? '').toLowerCase() === arg → (run.name ?? '') === arg |
/test e2e must match a workflow whose display name is E2E even when its file (end-to-end.yml) does not. The existing /test CI case passes through the lowercase fixture path ci.yml, so the name comparison is never the deciding arm. |
| 275 | run.path.toLowerCase() → run.path |
/test lint-checks must match .github/workflows/Lint-Checks.yml. Every fixture path is already lowercase. |
| 121 | label.toLowerCase() === okToTestLabel → label === okToTestLabel |
A pull request already carrying OK-To-Test must not have the label re-added, and with nothing pending gets the "No workflow runs waiting" comment rather than a rocket. Only the exact-case label is tested. |
| 72 | /test: cmd === undefined → cmd === null |
/test on a plain issue comments "only applies to pull requests" and leaves core.setFailed uncalled. The /retest sibling test asserts both; the /test and /ok-to-test ones assert only the comment, so a thrown TypeError after the comment goes unnoticed. |
| 113 | /ok-to-test: same |
same |
Equivalent survivors, not actionable: count-- in rerunEach (only === 0 is observed), current === null in headRuns (GITHUB_WORKFLOW is always set in Actions), ??→|| on empty-string folds, and type-annotation undefined→null.
Recommendation
Add to __tests__/issueCommentTest/trigger.test.ts:
/test› anit.eachwithE2E/end-to-end.ymlunder/test e2eandLint/Lint-Checks.ymlunder/test lint-checks, asserting the re-run and that no listing comment is posted./ok-to-test› the label-already-present case with{ name: 'OK-To-Test' }./testand/ok-to-test› extend the "only applies to pull requests" tests with asetFailedspy asserted not called (and, for/test, the exactcallslist; for/ok-to-test, that the runs endpoint is not read).
Test-only; no src/ or dist/ change. Disjoint from the open held PRs #510–#522 (auth, contributing, remove, command/labelMatch, sweep, tide, requireMatchingLabel, approve).
Evidence
- unit:
npm run test:coverage→ 100 / 99.75 / 100 / 100 (main @ 88241f4, local run) - e2e:
npm run test:coverage:e2e→ 99.96 / 98.79 / 100 / 99.95 (same revision, local run; the two reports are produced by different transforms and are not merged, asvitest.e2e-coverage.config.mjsdocuments) - probe: each mutant applied in turn to
src/issueComment/trigger.ts,npx vitest related src/issueComment/trigger.ts --run→ 837 passed for all five
Priority
- Impact: medium —
/testis the user-facing re-run command; case-insensitive matching is what makes/test ciwork for a workflow namedCIin a file not namedci.yml - 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 19, 2026
Please add a kind label with
/kind feature,/kind failing-testor/kind cleanup.hivecommons-hive commentedon Oct 19, 2026
Historical folded record. Use #523's current disposition table, not each repeated checklist below. Approve-review is #526/#527, LGTM coverage is #536/#537, shared annotations are #544, plugin bundle cases are #548/#549, and the branch-floor decision is #551. The other independent assertions retain their listed PRs.
Folded finding. This was filed as a separate issue, but 1 open agent-filed issue (plus 12 closed as completed in the last 14 days) already cite
vitest.e2e-coverage.config.mjs, so it was folded into the oldest of them instead of opening another. Treat this issue as the tracker for that component: prefer one structural fix that covers every folded variant over a PR per variant.[quality] approveReview.ts: a PAT that is not the author never has its review submission asserted, and withdrawalReason's five-file bound, lgtm skip, user casing and withdrawer order are unpinned
Finding
src/plugins/approveReview.tsis 100 % line-covered bynpm run test:coverageand bynpm run test:coverage:e2eonmain@ 88241f4 (the e2e run's only zero-hit arms are the non-Error folds at 226/230, the class already tracked on #507). A single-operator mutation probe over the file (39 mutants:===/!==,&&/||, comparison bounds,.toLowerCase()/.sort()removal,continue/break,undefinedchecks) left five non-equivalent survivors againstnpx vitest related src/plugins/approveReview.ts --run(46 files / 920 tests):identity.login !== undefined && identity.login === owners.author→… || …POST /pulls/1/reviewsfor every PAT. The only user-token "approved" case (user: 'Prow-Bot', author: 'prow-bot') is the self-approval one; every submit case uses an installation token (GET /user→ 403).uncoveredFiles.length > reasonFiles→>=no approver covers a, b, c, d, e, not… and 0 more. Only 7 files (→and 2 more) is tested.continue→breaklgtm_acts_as_approve: false, anlgtm*event skips only itself; the cancels after it still count. The existing fixture putsdave'scancelaftercarol'slgtm-cancel, but dave then re-approves, so dropping dave entirely yields the same string.latest.set(event.user.toLowerCase(), event)→event.userbobandBobare one person: a laterapprovebyBobretractsbob's cancel, and a cancel byBOBis reported asbob. The existing fixture'sBob approve/bob cancellands onbobeither way..sort()on the withdrawersbobbeforecarol, which is already sorted.Equivalent, not actionable: line 226
'status' in e || typeof e.status === 'number'(e.statuscannot be a number whenstatusis not ine).Recommendation
Add to
__tests__/plugins/approveReview.test.ts:approve.github_review: approved› a user-token case withuser: 'Prow-Bot', author: 'some-author'assertingcalls=['label', 'notifier', 'review']and no warning.withdrawalReason› exactly-five-files;bob cancelthenBob approve→ no withdrawal, andBOB cancel→withdrawn by bob;carol lgtm-cancelbeforebob cancel→withdrawn by bob;dave, bob, carolacting in that order → listedbob, carol, dave.Test-only; no
src/ordist/change. Disjoint from the open held PRs #510–#525 (none of them touchesapproveReview.test.ts).Evidence
npm run test:coverage→ 100 / 99.75 / 100 / 100 (main @ 88241f4, local run, 163 files / 2206 tests);approveReview.ts100 % lines, no zero-hit branchnpm run test:coverage:e2e→ 99.96 / 98.79 / 100 / 99.95 (same revision, local run, 83 files / 502 tests);approveReview.ts100 % lines, BRDA 226/230 only (the two reports are produced by different transforms and are not merged, asvitest.e2e-coverage.config.mjsdocuments)src/plugins/approveReview.ts,npx vitest related src/plugins/approveReview.ts --run→ 920 passed for all five; with the recommended cases each mutant fails exactly one testPriority
approve.github_reviewworks at all with a PAT, the documented way around "Allow GitHub Actions to create and approve pull requests"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
Folded finding. This was filed as a separate issue, but 1 open agent-filed issue (plus 12 closed as completed in the last 14 days) already cite
vitest.e2e-coverage.config.mjs, so it was folded into the oldest of them instead of opening another. Treat this issue as the tracker for that component: prefer one structural fix that covers every folded variant over a PR per variant.[quality] v8-ignore the two String(e) arms no dist/index.js input can reach: run.ts:40 and config.ts:657
Finding
npm run test:coverage:e2eonmain@ 88241f4 reports two zero-hitBRDArecords that no input todist/index.jscan reach:src/run.ts:40: String(error)incore.setFailed(error instanceof Error ? error.message : String(error))run()throughrunEventHandlers(events.ts:50) orhandleIssueComment'snormalizeError/sweep(handleIssueComment.ts:188,217), andhandleCronJobshas its own.catchwrappers. All of them coerce a non-Error toErrorbefore it propagates. The only exceptions that escape them are built-inTypeErrors (__tests__/bundle/runHandlerRejection.test.ts), which areErrors.src/utils/config.ts:657: einthrow new Error(`${source}: ${e instanceof Error ? e.message : e}`)trywraps onlyparseDuration(raw.lookback, 'sweep.lookback'), andparseDuration(src/utils/duration.ts:26) throwsnew Error(...)and nothing else.Both arms are driven by the unit suite (
npm run test:coverage:run.tsandconfig.tsat 100 % branches on the same revision), so this is a reporting gap, not a test gap: the e2e branch floor (vitest.e2e-coverage.config.mjs, 97 %) carries two permanently-red records that each re-triage has to rediscover.The seven sibling
String(e)arms that are reachable through the real Octokit client are being pinned in #528 (three of them) via a preload that throws a string from theResponse.statusgetter; the two above are the ones that preload cannot reach, because no client call sits inside theirtry.Recommendation
Mark both arms with the
/* v8 ignore start -- … */…/* v8 ignore stop */pair the repository already uses (src/plugins/tide.ts:235,src/utils/config.ts:219,src/utils/labeling.ts:91). Verified locally onmain@ 88241f4:/* v8 ignore next */does NOT suppress a ternary arm (theBRDA:40,2,1,0record survives); thestart/stoppair around the:arm does (onlyBRDA:40,2,0,2remains).src/run.tslines 39–41, replacewith
src/utils/config.tslines 656–658, replacewith
Then
npm run pack(the committeddist/index.jschanges withsrc/),npm run test:coverageandnpm run test:coverage:e2eto confirm bothBRDArecords are gone and the thresholds still pass.src/run.ts:40marked,dist/index.jsrepackedsrc/utils/config.ts:657marked,dist/index.jsrepackedDecision taken by hive: one issue for both sites, since it is the same mechanical edit and the same
dist/index.jsrepack; thestart/stopform overnextbecause it is the one form verified to work on a ternary arm and the one the repository already uses. This is asrc/+dist/change, which the quality lane does not PR; it needs a maintainer or a lane that may edit production files.Priority
Filed by quality agent (hold-gated mode)
🐝 Hive Agent:
quality| Instance:hosted-available-lke648397-260827-5q9t| SHA:8404338— hive: agent=quality backend=copilot model=claude-fable-5.1 copilot=1.0.88
Folded finding. This was filed as a separate issue, but 1 open agent-filed issue (plus 12 closed as completed in the last 14 days) already cite
vitest.e2e-coverage.config.mjs, so it was folded into the oldest of them instead of opening another. Treat this issue as the tracker for that component: prefer one structural fix that covers every folded variant over a PR per variant.[quality] mergeQueue.ts: classify's expected-head/head-oid/required/checks/forbidden alternatives and enqueuedByBot's ^ anchor each survive deletion unnoticed
Finding
src/utils/mergeQueue.tsis 100 % line- and branch-covered bynpm run test:coverageand, apart from the non-Errorarm oferrorMessage(line 190, theString(e)shape #528's preload addresses), bynpm run test:coverage:e2eonmain@ 88241f4. A single-operator mutation probe over the file (23 mutants: boolean guards,==/===, regex anchors and flags, each alternative of theclassifypatterns,>/>=, thepositionandenqueuerfolds) still left six non-equivalent survivors againstnpx vitest related src/utils/mergeQueue.ts --run(60 files / 1166 tests):/^github-actions$|\[bot\]$/i→ drop^github-actions(my-github-actions) is not an automation, so the gate must not dequeue an entry they made (tide.ts:362).github-actions-fanpins the$anchor; nothing pins^.expected headfrom thehead_movedpatternThe expected head OID does not matchalso containshead oid, so the alternative is never the deciding onehead oidexpectedHeadOid mismatch: head_oid changedonly pinshead_oidrequiredfrom thenot_readypatternRequired status checks have not passedalso containscheckschecksforbiddenfrom theforbiddenpatternpermissionandResource not accessible; a bareForbiddenfalls tootherclassify's kind drivestide.ts:336's per-kind handling of a refused enqueue, so each alternative is a behaviour, not a wording.Equivalent survivor, not actionable: dropping
$after\[bot\]— GitHub logins cannot contain[, so[bot]can only ever be a suffix. All 16 other mutants were killed.Recommendation
In
__tests__/utils/mergeQueue.test.ts:enqueue› theclassifies "%s" as %stable: add one message per uncovered alternative —expected head did not matchandthe head OID of the pull request has changed→head_moved;Required reviews are missingandChecks are still running→not_ready;Forbidden→forbidden.enqueuedByBot› add['my-github-actions', false].Test-only; no
src/ordist/change.__tests__/utils/mergeQueue.test.ts: oneclassifyrow per alternative at lines 168, 174, 177 and the^-anchor login — all six mutants above killedEvidence
npm run test:coverage→ 100 / 99.75 / 100 / 100 (main @ 88241f4, local run;mergeQueue.ts100 % lines, 100 % branches)npm run test:coverage:e2e→ 99.96 / 98.79 / 100 / 99.95 (same revision, local run;mergeQueue.ts96.66 % branches, the one zero-hit recordBRDA:190being theString(e)arm; the two reports come from different transforms and are not merged, asvitest.e2e-coverage.config.mjsdocuments)src/utils/mergeQueue.ts,npx vitest related src/utils/mergeQueue.ts --run→ 1166 passed for all six listed; with the recommended rows added and re-probed againstnpx vitest run __tests__/utils/mergeQueue.test.ts, each fails exactly one testDisjoint from the open held PRs #510–#528: none touches
__tests__/utils/mergeQueue.test.tsorsrc/utils/mergeQueue.ts(#518 coverstide.tsvia__tests__/plugins/tide*.test.ts; #528'smergeQueue.ts:190is the e2eString(e)arm, not these).Priority
enqueuedByBotdecides whether the gate may undo a merge-queue entry;classifydecides how a refused enqueue is reported and retriedFiled by quality agent (hold-gated mode)
🐝 Hive Agent:
quality| Instance:hosted-available-lke648397-260827-5q9t| SHA:1d6484d— hive: agent=quality backend=copilot model=claude-fable-5.1 copilot=1.0.88
Folded finding. This was filed as a separate issue, but 1 open agent-filed issue (plus 12 closed as completed in the last 14 days) already cite
vitest.e2e-coverage.config.mjs, so it was folded into the oldest of them instead of opening another. Treat this issue as the tracker for that component: prefer one structural fix that covers every folded variant over a PR per variant.[quality] labelSync.ts: the case-insensitive name and color folds, the null-description fold, the dry-run counts and per_page are unpinned — the 'only the case differs' test's fixture never re-cases anything
Finding
src/cronJobs/labelSync.tsis 100 % line- and branch-covered bynpm run test:coverageand all but theString(e)arm at line 107 (claimed by #528) bynpm run test:coverage:e2eonmain@ 88241f4. A single-operator mutation probe over the file (18 mutants:===/!==,!dryRuninversions,.toLowerCase()removal,?? ''removal,continueremoval,> 0bound, array-push removal, template-literal counts, spread folds,per_page) againstnpx vitest related src/cronJobs/labelSync.ts --run(4 files / 77 tests) left six non-equivalent survivors:byNamekeyed onlabel.name.toLowerCase()→label.nameKind/Bugmust count as the configuredkind/bug(GitHub label names are unique case-insensitively, so the "create" the mutant performs is a 422 in production).label.name.toLowerCase()→label.nameNeeds-Triage) must find the repository'sneeds-triage. Every catalog name is lowercase, so only a mixed-case configured name can tell.desired.color.toLowerCase() !== current.color.toLowerCase()→ exact compareD73A4Ain the config vsd73a4ain the repository must be unchanged, not a PATCH on every run.(current.description ?? '')→current.descriptiondescription: ""against a repositorydescription: nullis in sync (GitHub returnsnullfor an empty description, so the mutant PATCHes forever).would update ${plan.update.length}→would update 0includes('would update') && includes('lgtm').per_page: 100→30pagebut neverper_page.Why 57/130 survive although a test is titled for them:
writes nothing when only the case of the name or color differs …builds its fixture withwithChanges({ name: 'Kind/Bug', … }, { name: 'LGTM', … }), butwithChangesmatcheschange.name === label.nameexactly, so neither re-cased entry replaces anything and the fixture served iscompleteunchanged. The test passes with or without the case folds — it is vacuous for the property in its title.Equivalent, not actionable: lines 117–118 (
...(label.color === undefined ? {} : { color })→ always spread;JSON.stringifydropsundefinedso the wire body is identical).Recommendation
In
__tests__/cronJobTest/labelSync.test.ts:withChangesmatch names case-insensitively and assert the served fixture actually containsKind/Bug/LGTMNeeds-Triage) against a lowercase repository label to the same testdescription: ""vs repositorydescription: null→ no writecore.infoline exactly (counts and the(color, description)field list)per_page=100in the paging testTest-only; no
src/ordist/change. Disjoint from the open held PRs #510–#530: none touches__tests__/cronJobTest/labelSync.test.ts(#528 adds only__tests__/bundle/files forlabelSync.ts:107).Evidence
npm run test:coverage→ 100 / 99.75 / 100 / 100 (main @ 88241f4, local run, 163 files / 2206 tests);labelSync.ts100 % branchesnpm run test:coverage:e2e→ 99.95 / 98.79 / 100 / 99.95 (same revision, local run, 83 files / 502 tests);labelSync.tsBRDA:107only. The two reports come from different transforms and are not merged, asvitest.e2e-coverage.config.mjsdocuments.npx vitest related src/cronJobs/labelSync.ts --run→ 77 passed for all six; with the recommended cases each mutant fails exactly one test (78 total)Priority
label-syncis the job that writes to every configured repository's labels; the case folds are what keep it from 422-ing onBugvsbugor re-PATCHing uppercase hex colors on every scheduleFiled 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
Folded finding. This was filed as a separate issue, but 1 open agent-filed issue (plus 12 closed as completed in the last 14 days) already cite
vitest.e2e-coverage.config.mjs, so it was folded into the oldest of them instead of opening another. Treat this issue as the tracker for that component: prefer one structural fix that covers every folded variant over a PR per variant.[quality] e2e: drive the eight remaining non-Error rejection arms (sweep, require-matching-label, tide, mergeQueue, approveReview, trigger) through #528's NON_ERROR_REJECT preload
Finding
npm run test:coverage:e2eonmain@ 88241f4 (local, 2026-10-20; same figures as CI run 39212349431e2e-coverage) reports 98.79 % branches. After discounting the arms already claimed by open PRs — #510 (auth.ts:14-24), #511 (the four negative-count v8 artifacts), #528 (events.ts:50,handleIssueComment.ts:217,labelSync.ts:107) — and the arms that are unreachable from the bundle (run.ts:40,config.ts:657, both folded on #523 by #528;lgtm.ts:68, becausebindLgtmalways rethrows anError;command.ts:23, becausegetLineArgsis only called afterhasCommandreturned true), eight zero-hitBRDAarms remain, all the same shape:src/cronJobs/sweep.ts:132String(e)ofe instanceof Error ? e.message : String(e)step()whose rejection is not caught inside the stepsrc/plugins/requireMatchingLabel.ts:167: eofe instanceof Error ? e.message : eapply()→POST /repos/{o}/{r}/issues/{n}/labels/.../commentssrc/plugins/tide.ts:137: undefinedoftypeof e.status === 'number' ? e.status : undefinedoctokit.pulls.merge→PUT /repos/{o}/{r}/pulls/{n}/mergesrc/plugins/tide.ts:138String(e)src/utils/mergeQueue.ts:190String(e)in the GraphQL error foldoctokit.graphql→POST /graphqlsrc/plugins/approveReview.ts:226: undefinedoferrorStatususers.getAuthenticated/pulls.createReviewsrc/plugins/approveReview.ts:230String(e)oferrorMessagesrc/issueComment/trigger.ts:323: undefinedofstatusOfactions.approveWorkflowRun(POST .../actions/runs/{id}/approve) or the/retestre-run (POST .../actions/runs/{id}/rerun)Every one of these catch blocks only ever sees a rejection from an Octokit call, and
@octokit/requestwraps every fetch failure in aRequestErrorwith a numericstatus, so no fake-GitHub response can reach the non-Errorarm. Unit coverage (npm run test:coverage, same revision, CI jobbuild-test) reaches all eight lines with explicit non-Errorthrows, so this is unit-covered / e2e-uncovered. The unit and e2e maps come from different transforms (vite vs. tsc+webpack, seevitest.e2e-coverage.config.mjs) and cannot be merged; both runs were analysed separately.#528 adds the one mechanism that can drive these arms through
dist/index.js:__tests__/bundle/nonErrorRejectionPreload.cjs, aNODE_OPTIONS=--requirepreload that makes the first request matchingNON_ERROR_REJECT="<METHOD> /path"reject the client with a plain string. #528 deliberately drives only three arms and names none of the eight above, so they are the follow-up to that PR, not a competing one.Recommendation
One PR, after #528 merges (it reuses #528's preload; a second preload would be a duplicate implementation):
__tests__/bundle/nonErrorRejectionArms2.test.ts(or extendnonErrorRejectionArms.test.ts) with onedist/index.jsrun per row, each settingNON_ERROR_REJECTto the request in the third column and asserting a single::error::/::warning::that carries the string, no unhandled rejection, and the same request list as theRequestError-shaped failure.sweep.ts:132, fault a request that no inner catch wraps (for example theok-to-teststep's run listing), so the string reaches the sweep's own fold rather thanrequireMatchingLabel.ts:167.coverage-e2e/lcov.infono longer carriesBRDA:132(sweep),BRDA:167(requireMatchingLabel),BRDA:137/BRDA:138(tide),BRDA:190(mergeQueue),BRDA:226/BRDA:230(approveReview) orBRDA:323(trigger) at zero hits, and that e2e branches rise from 98.97 % (post-test(bundle): cover non-Error rejection paths including auth #528) to about 99.4 %.Decision taken by hive: all eight arms are one deliverable because they share one mechanism, one test harness and one PR-sized diff; splitting them would put eight PRs on the same preload. Blocked on #528; do not implement against #528's branch.
Priority
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
Folded finding. This was filed as a separate issue, but 1 open agent-filed issue (plus 12 closed as completed in the last 14 days) already cite
vitest.e2e-coverage.config.mjs, so it was folded into the oldest of them instead of opening another. Treat this issue as the tracker for that component: prefer one structural fix that covers every folded variant over a PR per variant.[quality] e2e: drive the six non-Error rejection arms #528 leaves zero-hit (sweep.ts:132, trigger.ts:323, approveReview.ts:226/230, requireMatchingLabel.ts:167, tide.ts:137-138, mergeQueue.ts:190)
Finding
npm run test:coverage:e2eonmain@ 88241f4 (local run;coverage-e2e/lcov.info) reports 18 zero-hit branches once the two negative-count v8 artifacts #511 documents are discounted. #528 drives three of them (events.ts:50,handleIssueComment.ts:217,labelSync.ts:107) and parks the two unreachable ones (run.ts:40,config.ts:657) on #523. Six more are the same shape — theString(e)/ non-object arm of acatcharound an octokit call — and no open PR names them:src/cronJobs/sweep.ts:132outcome.errors.push(\${name}: ${e instanceof Error ? e.message : String(e)}`)` in the per-PR step loopsrc/issueComment/trigger.ts:323statusOf(error)—typeof error === 'object'false arm (viaisConflictat:258)src/plugins/approveReview.ts:226errorStatus(e)— non-object arm (callers:37,:212)src/plugins/approveReview.ts:230errorMessage(e)—String(e)arm (caller:203)src/plugins/requireMatchingLabel.ts:167errors.push(\${rule.missing_label}: ${e instanceof Error ? e.message : e}`)`src/plugins/tide.ts:137-138catch:statusnon-object arm andmessage: String(e)armsrc/utils/mergeQueue.ts:190errorMessagefallthroughString(e)after theerrors[]checkAll six are reachable from the bundle: each
tryawaits a real octokit call, so the one-shot preload #528 adds (__tests__/bundle/nonErrorRejectionPreload.cjs,NON_ERROR_REJECT=METHOD /path) can reject exactly that request with a plain string, the same way #528 does forGET /pulls/1,GET /milestonesandPOST /labels.Evidence. Unit (
npm run test:coverage, same revision): 100 % lines, 1652/1656 branches — every one of these arms is unit-covered, the four misses are the #511 artifacts. E2E: zero hits at each line above. The two reports are analyzed separately —vitest.e2e-coverage.config.mjsstates the vite vs. tsc+webpack branch maps do not combine.Recommendation
One PR, cut from
mainafter #528 merges, extending__tests__/bundle/nonErrorRejectionArms.test.tswith six runs throughdist/index.js, one per row, each faulting the single request itstryawaits and asserting the::error::/ outcome text names the string:sweep.ts:132—workflow_dispatchsweep with e.g.POST /pulls/1/requested_reviewersfaulted →sweep: #1 evaluated with 1 error(s)trigger.ts:323—/testwith the status-creating request faulted (string is not a 409 → not treated as conflict)approveReview.ts:226+:230—/approvewithPOST /pulls/1/reviewsfaultedrequireMatchingLabel.ts:167— label event with the rule'sPOST /issues/1/labelsfaultedtide.ts:137-138—PUT /pulls/1/mergefaulted →result: 'failed',status: undefinedmergeQueue.ts:190—POST /graphqlenqueue faultedThen confirm
coverage-e2e/lcov.infono longer carries any of the sevenBRDAlines at zero and the e2e branch figure rises above #528's 98.97 %.Why this is an issue and not a PR this kick. The preload lives only on #528's held branch. A branch cut from
origin/mainwould have to re-implement it (a second copy of the same mechanism), and stacking on #528's head would move a held PR's history, which the hold guard treats as unreviewed drift. Decision taken by hive: wait for #528, then a single follow-on PR.Priority
Refs #528
🐝 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
Folded finding. This was filed as a separate issue, but 1 open agent-filed issue (plus 12 closed as completed in the last 14 days) already cite
vitest.e2e-coverage.config.mjs, so it was folded into the oldest of them instead of opening another. Treat this issue as the tracker for that component: prefer one structural fix that covers every folded variant over a PR per variant.[quality] lgtmBinding.ts: hasLgtmLabel's .some and case fold, unbindLgtm's pending body and 140-char bound, and isLgtmBound's per_page=100 survive mutation unnoticed
Finding
src/plugins/lgtmBinding.tsis 100 % line- and branch-covered bynpm run test:coverageand bynpm run test:coverage:e2eonmain@ 88241f4 (it appears in neither run's uncovered-lines table). A single-operator mutation probe over the file (38 mutants:===/!==,&&/||,??defaults,.some/.every,.find/.findLast,.toLowerCase()removal,slicebounds, status states and contexts,403,per_page,'labeled') still left four non-equivalent survivors against the ten suites that exercise the module (__tests__/plugins/lgtmBinding.test.ts,label/lgtm.test.ts,cronJobTest/lgtm.test.ts,cronJobTest/sweep.test.ts,plugins/tide.test.ts,plugins/tideMergeQueue.test.ts,plugins/pluginErrorPaths.test.ts,pullReqTest/handlePullReq.test.ts,label/errorPaths.test.ts,issueCommentTest/handleIssueComment.test.ts; 338 tests):hasLgtmLabel:labels.some(…)→labels.every(…)lgtmand anything else (approved,kind/*) still counts as carryinglgtm.tide.ts:184gates the stale-binding strip onhasLgtmLabel(first.labels); with.every, the realistic PR (lgtm+approved) never has its unboundlgtmstripped and merges. Every stale-lgtm fixture carrieslgtmas its only label.hasLgtmLabel: drop.toLowerCase()LGTMis the same label; the sametide.ts:184gate would skip it. The case fold is pinned on thelabeledevent (lgtmOnPullRequest(labeled('LGTM'))) but not on the label listhasLgtmLabelreads.unbindLgtm:description.slice(0, 140)→slice(0, 141)unbindLgtm's truncation is unasserted (onlybindLgtm's is). The onlyunbindLgtmtest is the 500-warns one, so thependingbody it sends is never read either.isLgtmBound:per_page: 100→per_page: 30per_page=100so a head with more than 30 status contexts still findsprow/lgtm.Equivalent, not actionable: line 121
.find→.findLast(the combined status carries one entry per context), line 156?? ''→?? 'x'(any non-lgtmdefault refuses the same payloads).Recommendation
Add to
__tests__/plugins/lgtmBinding.test.ts:hasLgtmLabeldescribe:['approved', 'lgtm', 'kind/bug']→true,['LGTM']→true,['approved', 'kind/bug']→false,[]→falseunbindLgtmhappy path: observePOST /statuses/abcand assert the body is exactly{ state: 'pending', context: 'prow/lgtm', description: the first 140 characters }from a 200-char inputisLgtmBound: observeGET /commits/abc/statusand assertper_page=100on the URLTest-only; no
src/ordist/change.hasLgtmLabelis pinned at the unit level inlgtmBinding.test.tsrather than through a tide fixture because__tests__/plugins/tide.test.tsis occupied by #518. Disjoint from every open held PR (#510–#539): none touches__tests__/plugins/lgtmBinding.test.tsorsrc/plugins/lgtmBinding.ts(#537 editssrc/labels/lgtm.ts, a different module).Evidence
npm run test:coverage→ 100 / 99.75 / 100 / 100 (main @ 88241f4, local run, 2550 statements);lgtmBinding.ts100 % lines, no zero-hit branchnpm run test:coverage:e2e→ 99.96 / 98.79 / 100 / 99.95 (same revision, local run, 83 files / 502 tests);lgtmBinding.ts100 % lines, no zero-hit branch (the two reports are produced by different transforms and are not merged, asvitest.e2e-coverage.config.mjsdocuments)src/plugins/lgtmBinding.ts,npx vitest runon the ten suites listed above → 338 passed for all four survivors; with the recommended cases, the.everymutant fails two tests and each of the other three fails exactly onePriority
hasLgtmLabeldecides whether tide checks the lgtm binding at all; the surviving.everymutant is exactly the shape that lets a stale hand-appliedlgtmmerge on any PR that also carriesapprovedFiled 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
Folded finding. This was filed as a separate issue, but 1 open agent-filed issue (plus 12 closed as completed in the last 14 days) already cite
vitest.e2e-coverage.config.mjs, so it was folded into the oldest of them instead of opening another. Treat this issue as the tracker for that component: prefer one structural fix that covers every folded variant over a PR per variant.[quality] hold.ts: /hold cancel's case fold on the hold labels is unpinned (Hold, DO-NOT-MERGE/HOLD survive mutation)
Finding
src/labels/hold.tsis 100 % line- and branch-covered by bothnpm run test:coverageandnpm run test:coverage:e2eonmain@ 88241f4 (it appears in neither run's uncovered table and has no zero-hitBRDArecord incoverage-e2e/lcov.info). A single-operator mutation probe over the file (14 mutants:===/!==,&&/||, command/keyword spellings,.toLowerCase()removal, list membership and order,.filterduplication,length === 0) against the six suites that exercise it (__tests__/label/hold.test.ts,label/errorPaths.test.ts,label/authorization.test.ts,issueCommentTest/handleIssueComment.test.ts,missingNumberMessage.test.ts,cronJobTest/lgtm.test.ts) left two non-equivalent survivors, both incancelHold:wanted.has(label.toLowerCase())→wanted.has(label)HoldorDO-NOT-MERGE/HOLDis never released by/hold cancel,/unholdor/remove-hold—cancelHoldlogs could not find … to remove and returns.meetsMergeGateis pinned to block onHoldcase-insensitively (__tests__/utils/mergeGate.test.ts), so the PR stays unmergeable with no way to clear it from a comment. Every cancel fixture carries the labels in lower case.[holdLabel, legacyHoldLabel].map(name => name.toLowerCase())→.map(name => name)hold.labelwith upper-case characters (ex:Do-Not-Merge/Hold) is compared verbatim, so the repository's actualdo-not-merge/holdlabel is not released. Bothhold.labelfixtures are lower case.Equivalent, not actionable: line 70 swapping the two names (a
Set).Recommendation
Add to the
cancelblock of__tests__/label/hold.test.ts:/hold cancelon an issue carryingHoldandDO-NOT-MERGE/HOLD→ observeDELETE …/labels/HoldandDELETE …/labels/DO-NOT-MERGE%2FHOLD(the labels are removed under their own names), nosetFailedhold.label: Do-Not-Merge/Holdwith the issue carryingdo-not-merge/hold→ observeDELETE …/labels/do-not-merge%2Fhold; no DELETE for the configured spellingTest-only; no
src/ordist/change. Disjoint from every open held PR (#510–#540): none touches__tests__/label/hold.test.tsorsrc/labels/hold.ts(#512label/remove.test.ts, #539label/label.test.ts+label/lifecycle.test.ts).Evidence
npm run test:coverage→ 100 / 99.75 / 100 / 100 (main @ 88241f4, local run, 163 files / 2206 tests);hold.ts100 % lines, no zero-hit branchnpm run test:coverage:e2e→ 99.96 / 98.79 / 100 / 99.95 (same revision, local run, 83 files / 502 tests);hold.ts100 % lines, no zero-hit branch (the two reports come from different transforms and are not merged, asvitest.e2e-coverage.config.mjsdocuments)src/labels/hold.ts,npx vitest runon the six suites above → all pass for the two survivors; with the recommended cases each survivor fails exactly one testPriority
/hold cancelis the only comment path that clears the merge block; the surviving mutants leave a mixed-case hold label stuck on the PRFiled 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
Folded finding. This was filed as a separate issue, but 1 open agent-filed issue (plus 12 closed as completed in the last 14 days) already cite
vitest.e2e-coverage.config.mjs, so it was folded into the oldest of them instead of opening another. Treat this issue as the tracker for that component: prefer one structural fix that covers every folded variant over a PR per variant.[quality] duration.ts: parseDuration's whitespace trim and millisecond rounding, and labelCatalog.ts's case-insensitive needs- color, are not asserted
Finding
src/utils/duration.tsandsrc/utils/labelCatalog.tsare 100 % line- and branch-covered by bothnpm run test:coverageandnpm run test:coverage:e2eonmain@ 88241f4. A single-operator mutation probe (npx vitest related <file> --run; 1498 tests forduration.ts, 143 forlabelCatalog.ts) still left three non-equivalent survivors:duration.ts:12(text ?? '').trim()→(text ?? '')grace_period_duration: "5s "(trailing or leading whitespace, as yaml folding easily produces) parses to 5000 ms instead of throwinginvalid grace_period_duration. Every existing fixture is already trimmed;'5 s'is rejected for its inner space, not for an outer one.duration.ts:29Math.round(ms)→ms1.5msyields the integer2, not1.5. The doc comment promises milliseconds; the only fractional fixture,1.5s, is already a whole 1500.labelCatalog.ts:86label.name.toLowerCase().startsWith('needs-')→label.name.startsWith('needs-')require_matching_label.missing_labelofNeeds-Kindstill gets theedededneeds- color indesiredLabels. The only fixture is lowercaseneeds-kind.Equivalent survivor, not actionable:
labeling.ts:148e.name || ''→e.name ?? ''(nameisstring | undefined). The other 16 mutants overlabeling.ts,labelCatalog.ts,comments.tsandduration.tswere all killed.Recommendation
__tests__/utils/duration.test.ts(the existingparseDurationtable lives in__tests__/plugins/requireMatchingLabel.test.ts, which test(require-matching-label): pin the withGracePeriod default, the graceMs > 0 guard, isBot's || and the no-rule debug text #520 occupies): anit.eachover' 5s','5s ','\t2m\n',' 0 ',' '; anit.eachover1.5ms,2.25ms,0.0015s→2; and thefieldparameter in the error.__tests__/utils/labelCatalog.test.ts: a case withmissing_label: Needs-KindandNEEDS-SIG, assertingcolor: 'ededed'on both.Test-only; no
src/ordist/change. Files disjoint from every open held PR (#510–#541).Evidence
npm run test:coverage→ 100 / 99.75 / 100 / 100 (main @ 88241f4, local run)npm run test:coverage:e2e→ 99.96 / 98.79 / 100 / 99.95 (same revision, local run; the two reports are produced by different transforms and are not merged, asvitest.e2e-coverage.config.mjsdocuments)npx vitest related→ all passed for the three abovePriority
.prow.yamlFiled 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
Folded finding. This was filed as a separate issue, but 1 open agent-filed issue (plus 12 closed as completed in the last 14 days) already cite
vitest.e2e-coverage.config.mjs, so it was folded into the oldest of them instead of opening another. Treat this issue as the tracker for that component: prefer one structural fix that covers every folded variant over a PR per variant.[quality] labeling.ts: removeLabels is never shown to keep deleting the later labels after an earlier one is already gone (404)
Finding
src/utils/labeling.tsis 100 % line- and branch-covered bynpm run test:coverageand bynpm run test:coverage:e2eonmain@ 88241f4. A single-operator mutation probe over the file (16 mutants:===/>bounds,.toLowerCase()removal,||/??, theisNotFoundguards, the memoset,per_page,addPrefix's separator and empty-prefix arm, the 404 arm ofremoveLabels) againstnpx vitest related src/utils/labeling.ts --run(67 files / 1369 tests) left one non-equivalent survivor:removeLabels: aftercore.debug(\label ${label} was already absent`),returninstead of continuing thefor` loopDELETE … → 404), the labels after it must still be deleted. Every existing 404 case (__tests__/label/remove.test.ts"ignores a label that is already gone", the hold/prefixed/fixed callers) removes a single label, so a loop that silently stops at the first 404 passes the whole suite.removeLabelsis the shared removal path for/remove,/remove-<prefix>,/hold cancel,/lgtm cancel, exclusive-prefix replacement (prefixed.ts:107), approve's label sync and require-matching-label's cleanup, so a regression there would leave stale labels behind on every one of them.Equivalent survivors, not actionable:
e.name || ''→e.name ?? ''ingetCurrentLabels(both fold''/null/undefinedto''); dropping'status' in errorinisNotFound(error.status === 404is alreadyfalsefor an object withoutstatus; the guard only narrows the TypeScript type).Recommendation
Add a
removeLabelsdescribe to__tests__/utils/labeling.test.tsthat callsremoveLabelsdirectly through a realnewOctokitclient against an mswDELETE /repos/Codertocat/Hello-World/issues/1/labels/:namehandler recording the order of names:['gone', 'kind/bug', 'still-there']withgoneanswered 404 → resolves, and all three names were requested in order.['first', 'broken', 'never']withbrokenanswered 500 → rejects withcould not remove label broken, andneverwas not requested (pins the complementary "a real failure stops the loop" arm, which only the single-label cases assert today).Test-only; no
src/ordist/change. Disjoint from every open held PR: #512 owns__tests__/label/remove.test.ts, #514command.test.ts/labelMatch.test.ts, #542duration.test.ts/labelCatalog.test.ts; none touches__tests__/utils/labeling.test.tsorsrc/utils/labeling.ts.Evidence
npm run test:coverage→ 100 / 99.75 / 100 / 100 (main @ 88241f4, local run; the four reported branches are the negative-count v8 artifacts docs(contributing): record the four negative-count BRDA branches as a v8 await artifact, not a gap #511 documents)npm run test:coverage:e2e→ 99.96 / 98.79 / 100 / 99.95 (same revision, local run;labeling.tshas no zero-hit branch; the two reports come from different transforms and are not merged, asvitest.e2e-coverage.config.mjsdocuments)src/utils/labeling.ts,npx vitest related src/utils/labeling.ts --run→ 1369 passed for the survivor above; the proposed test fails under it (expected ['gone'] to deeply equal ['gone', 'kind/bug', 'still-there']) and passes onmainPriority
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
Folded finding. This was filed as a separate issue, but 1 open agent-filed issue (plus 12 closed as completed in the last 14 days) already cite
vitest.e2e-coverage.config.mjs, so it was folded into the oldest of them instead of opening another. Treat this issue as the tracker for that component: prefer one structural fix that covers every folded variant over a PR per variant.[quality] e2e coverage: v8-ignore the three bundle-unreachable fallback arms in run.ts:40, command.ts:23 and config.ts:657
Finding
npm run test:coverage:e2eonmain@ 88241f4 reports 98.79 % branches (1636/1656). Three of the zero-hit records are fallback arms that no input todist/index.jscan reach, so they are re-triaged as gaps on every kick although they are not ones (the same situation #510 and #537 clear forauth.ts:24andlgtm.ts:68):src/run.tsBRDA:40,2,1,0core.setFailed(error instanceof Error ? error.message : String(error))— theString(error)armErrorbeforerun()sees them:runEventHandlers(events.ts:50),normalizeError(handleIssueComment.ts:217), thejobs.catch(e => core.setFailed(…))inhandlePullReq.ts:76andhandleCronJob.ts:69. The one path that does reach thiscatchfrom the bundle is a non-string comment body (TypeError: body.replace is not a functionout ofsplitLines, found by instrumenting the coverage bundle locally) — a built-in, so anError.src/utils/command.tsBRDA:23,0,1,0getLineArgs's.at(-1) ?? ''fallback/milestone(milestone.ts:43) and/retitle(retitle.ts:31), run only afterhandleIssueCommentmatched the body withhasCommand(form, body)for the samecommandPattern, and neither command has an alias incommandAliases; sofindCommandArgsis never empty whengetLineArgsruns.src/utils/config.tsBRDA:657,83,1,0normalizeSweep'se instanceof Error ? e.message : e— the non-ErrorarmparseDuration(duration.ts:26) throws onlynew Error(...).All three arms are driven by the unit suite (
npm run test:coverage→ 100 % lines / 99.75 % branches:__tests__/run.test.ts,__tests__/utils/command.test.ts:91,__tests__/utils/configSweep.test.ts:13with a mocked string throw), so they are covered by unit, not by e2e, and as defensive arms they are low priority. #523 folds them as "v8 ignoreentries that still need asrc/change"; they are not covered by any open PR (#510 isauth.ts, #537 islgtm.ts, #528 drivesevents.ts:50/handleIssueComment.ts:217/labelSync.ts:107for real).Recommendation
Annotate the three arms with
/* v8 ignore next -- … */, the formsrc/utils/config.ts:219already uses and #510 / #537 apply to the same class of arm, and repackdist/. No behaviour change; the unit tests that drive the arms stay.One mechanical note for whoever applies it:
@vitest/coverage-v8's AST mapper honours a hint on the alternate of a?:(sorun.tsandconfig.tskeep theirErrorarm measured), but not on one operand of a??— forcommand.tsthe hint has to sit on thereturnstatement.This is one deliverable (the same one-line annotation at three sites), so it is one issue and one PR.
Evidence
npm run test:coverage→ 100 / 99.75 / 100 / 100 (main@ 88241f4, local run,coverage/lcov.info)npm run test:coverage:e2e→ 99.96 / 98.79 / 100 / 99.95 (same revision, local run,coverage-e2e/lcov.info). The two reports come from different transforms (vite vs. tsc+ncc remap) and are not merged, asvitest.e2e-coverage.config.mjsdocuments; each is read separately above.Priority
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
Folded finding. This was filed as a separate issue, but 1 open agent-filed issue (plus 12 closed as completed in the last 14 days) already cite
vitest.e2e-coverage.config.mjs, so it was folded into the oldest of them instead of opening another. Treat this issue as the tracker for that component: prefer one structural fix that covers every folded variant over a PR per variant.[quality] errorPaths: the eleven 'could not …: ${e}' wraps in src/issueComment are asserted by prefix only; dropping the cause goes unnoticed
Finding
Every
could not …wrap insrc/issueComment/*interpolates the rejection —throw new Error(\could not close issue: ${e}`)and ten siblings (assign.ts:42,73,unassign.ts:42,64,cc.ts:39,70,uncc.ts:38,reopen.ts:45,close.ts:60,retitle.ts:51,lock.ts:62) — so the Action failure names what GitHub refused (HttpError: Resource not accessible by integration`), which is the one line a maintainer has when a token lacks a permission.__tests__/issueCommentTest/errorPaths.test.tsasserts each of those eleven wraps by prefix only (rejects.toThrow(/could not close issue/)). A single-operator mutation probe onmain@ 88241f4 that drops the: ${e}fromclose.ts:60andreopen.ts:45left the whole related suite green (npx vitest related src/issueComment/close.ts --run→ 30 files / 576 passed, same forreopen.ts); the same holds forlock.ts:62againsterrorPaths.test.tsdirectly. The other eight sites are the same shape and the same assertion form.Evidence
npm run test:coverageonmain@ 88241f4 (local) → 100 / 99.75 / 100 / 100; all eleven sites are line- and branch-covered, so this is a pinning gap, not a coverage gap. The four reported branch misses (close.ts:39,reopen.ts:36,approve.ts:504,auth.ts:220) are the negative-count v8 artifacts docs(contributing): record the four negative-count BRDA branches as a v8 await artifact, not a gap #511 documents.coverage-e2eartifact of workflow run 39381633514 (main@ 88241f4, 2026-10-20) → 99.95 / 98.79 / 100 / 99.96; none of the eleven sites is a zero-hit record there either. The two reports come from different transforms and are not merged (vitest.e2e-coverage.config.mjs).close.ts:60could not close issue: ${e}→could not close issue: 576/576 pass.reopen.ts:45same: 576/576 pass.Recommendation
In
__tests__/issueCommentTest/errorPaths.test.ts, assert the full message for each of the eleven wraps:rejects.toThrow(`could not <step>: HttpError: Resource not accessible by integration`). Test-only; one file; nosrc/,dist/or docs change. Disjoint from every open held PR (#510–#545): none toucheserrorPaths.test.ts.Priority
/close,/lock,/assign… surfacesFiled by quality agent (hold-gated mode)
🐝 Hive Agent:
quality| Instance:hosted-available-lke648397-260827-5q9t| SHA:8511d84— hive: agent=quality backend=copilot model=claude-fable-5.1 copilot=1.0.88
Folded finding. This was filed as a separate issue, but 1 open agent-filed issue (plus 12 closed as completed in the last 14 days) already cite
vitest.e2e-coverage.config.mjs, so it was folded into the oldest of them instead of opening another. Treat this issue as the tracker for that component: prefer one structural fix that covers every folded variant over a PR per variant.[quality] drive the eight remaining non-Error rejection arms (sweep:132, trigger:323, approveReview:226/230, requireMatchingLabel:167, tide:137-138, mergeQueue:190) through dist/index.js once #528 lands
Finding
npm run test:coverage:e2eonmain@ 88241f4 (local; CIe2e-coveragejob on run 39549983858 reports the same 99.95 % lines / 98.79 % branches) leaves 18 zero-hitBRDArecords incoverage-e2e/lcov.info. Ten are already claimed by open held PRs (#510auth.ts:14-17, #511approve.ts:504, #528events.ts:50/handleIssueComment.ts:217/labelSync.ts:107, #537lgtm.ts:68, #544run.ts:40/command.ts:23/config.ts:657). The remaining eight are not named by any open PR:src/cronJobs/sweep.ts:132String(e)sweep()'s per-stepcatchGET /repos/{o}/{r}/issues/{n}/commentsinrequire-matching-labelsrc/issueComment/trigger.ts:323statusOf→undefinedrerunAll'scatch(isConflictthenisForbidden)POST /repos/{o}/{r}/actions/runs/{id}/rerunsrc/plugins/approveReview.ts:226errorStatusnon-number →undefinedtokenIdentity's rejection handlerGET /usersrc/plugins/approveReview.ts:230errorMessageString(e)submitApproval'scatchPOST /repos/{o}/{r}/pulls/{n}/reviewssrc/plugins/requireMatchingLabel.ts:167: eenforceRequiredLabels's per-rulecatchDELETE /repos/{o}/{r}/issues/comments/{id}or thelistCommentspagesrc/plugins/tide.ts:137undefinedmergeOnce'scatchPUT /repos/{o}/{r}/pulls/{n}/mergesrc/plugins/tide.ts:138String(e)src/utils/mergeQueue.ts:190String(e)enqueue'scatch→errorMessagePOST /graphql(enqueuePullRequest)All eight are unit-covered (
npm run test:coverage@ 88241f4: 100 % lines / 99.75 % branches, the four misses being the negative-count artifacts #511 documents), so this is an e2e-only gap. They share one root cause with the three arms #528 drives: Octokit wraps every fetch rejection in aRequestError, so no fake-GitHub status reaches a non-Error/ status-less arm. The only way to reach them fromdist/index.jsis theNON_ERROR_REJECTpreload #528 introduces (__tests__/bundle/nonErrorRejectionPreload.cjs, aNODE_OPTIONS=--requirehook that makes the first matchingMETHOD /pathresponse'sstatusgetter throw a plain string). The two suites' coverage maps come from different transforms (vite vs tsc+webpack) and do not combine (vitest.e2e-coverage.config.mjs), so unit and e2e are reported separately here on purpose.Recommendation
One PR, after #528 merges (it supplies the preload; a second copy of that file would be the overlap the hold-gated preflight forbids):
__tests__/bundle/nonErrorRejectionArmsRemaining.test.tswith onedist/index.jsrun per row above, each settingNON_ERROR_REJECT="<METHOD> <path>"from the last column, asserting a single::error::/::warning::that names the string, no unhandled rejection, and the same request list as theError-shaped failure the existing scenario for that path already asserts.npm run test:coverage:e2e:coverage-e2e/lcov.infono longer carries any of the eight records at zero hits; branches rise from 98.97 % (post-test(bundle): cover non-Error rejection paths including auth #528/chore(coverage): v8-ignore the bundle-unreachable fallback arms in run.ts:40, command.ts:23 and config.ts:657 #544) toward 99.5 %.branchesfloor invitest.e2e-coverage.config.mjsfrom 97 to 98 so a scenario that stops exercising one of these arms fails the run (the file's own comment says the floor tracks just under whatmainreaches).Decision taken by hive: reuse #528's preload rather than add a second fault-injection mechanism; one test file rather than one per module, because every row is the same mechanical scenario.
Priority
Refs #528 (blocked on it merging).
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
hivecommons-hive commentedon Oct 19, 2026
Superseded tracking record. #544 owns the command.ts annotation together with run.ts/config.ts. This is not a remaining requirement for #523/#524.
Folded finding:
src/utils/command.ts:23is the one remaining e2e zero-hit branch that is neither aString(e)arm nor a v8 artifactnpm run test:coverage:e2eonmain@ 88241f4 (local run) lists 20 zero-hitBRDArecords. #528 drives three; its "Not in this PR" note foldsrun.ts:40/config.ts:657here; #510/#507 ownauth.ts:14-17,24; #511 documents the two negative-count artifacts. Of the rest, every one exceptcommand.ts:23is the non-object / non-Errorarm of an error fold (sweep.ts:132,trigger.ts:323,lgtm.ts:68,approveReview.ts:226,230,requireMatchingLabel.ts:167,tide.ts:137,138,mergeQueue.ts:190) and becomes drivable with the preload #528 adds, so they are not re-filed here.command.ts:23is different in kind:The
?? ''arm (BRDA:23,0,1,0) is reached only when the command matches no line of the body. Its two callers aremilestone.ts:43(/milestone) andretitle.ts:31(/retitle);handleIssueComment.ts:128dispatches either only aftercommandForms(command).some(form => hasCommand(form, commentBody)),commandFormsreturns just[command]for both (commandAliaseshas no entry for them, and neither is a dynamic label command), andhasCommandisfindCommandArgs(command, body).length > 0— the same scangetLineArgsrepeats. So fromdist/index.jsthe.at(-1)result is neverundefined; the arm is a defensive default for direct callers and is exercised only by__tests__/utils/command.test.ts(unit: 100 % branches on the file).Verified replacement text (local, second checkout of
main@ 88241f4)With only that change,
npm run test:coverage:e2e→ 83 files / 502 tests pass,command.tsleaves the uncovered table,coverage-e2e/lcov.infocarries noBRDA:23for the file, and e2e branches move 98.79 % → 98.85 %. Samev8 ignore start/stopform 7a1df7a (#483) and #510 use.This is a
src/utils/command.ts+dist/index.jschange, so — as with therun.ts:40/config.ts:657entry above — it needs a human or an ISSUES_PRS_MERGE agent to land; the quality lane does not PR production files. Applying it is mechanical: the block above replaces lines 22-24 verbatim, thennpm run pack.src/utils/command.ts:23—v8 ignorethe?? ''arm ofgetLineArgs(text above), repackdist/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
hivecommons-hive commentedon Oct 19, 2026
Duplicate tracking record. #536 is the canonical LGTM coverage issue and #537 its implementation. This does not extend #523/#524.
Folded finding:
src/labels/lgtm.ts:68is a thirdString(e)arm nodist/index.jsinput can reachnpm run test:coverage:e2eonmain@ 88241f4 (local run) still carriesBRDA:68,8,1,0forsrc/labels/lgtm.ts;npm run test:coverageon the same revision reports the file at 100 % branches, so — likerun.ts:40/config.ts:657above — this is a reporting gap, not a test gap.The earlier folded note on this tracker listed
lgtm.ts:68among the sites that "become drivable with the preload #528 adds". That is not the case for this one. Correction, with the reason:The
trywraps onlybindLgtm.bindLgtm(src/plugins/lgtmBinding.ts:58-75) catches every rejection ofoctokit.repos.createCommitStatusand rethrowsnew Error(...)on both of its paths (isForbidden→ permission hint; otherwisecould not bind lgtm to …: ${e}). A non-Error faulted into the client by the #528 preload therefore arrives atlgtm.ts:67already wrapped as anError, andString(e)is never evaluated. Nothing else inside thetrycan throw a non-Error (loadPullRequestOwnersis outside it).Replacement text (mechanical)
Replace
src/labels/lgtm.ts:66-68with:then
npm run packso the committeddist/index.jsfollowssrc/.Verified locally on 88241f4 with that exact edit:
npx eslint src/labels/lgtm.tsclean; afternpm run pack:coverageand an e2e-config run of the bundle scenarios that enterhandleLgtm,coverage-e2e/lcov.infocarries noBRDArecord for therefuseline while the siblingBRDA:62records of the same function are still emitted — i.e. the ignore removes exactly that arm and nothing else. Samev8 ignore start/stopform assrc/utils/labeling.ts:91,src/utils/mergeQueue.ts:66and therun.ts:40/config.ts:657entry above.This is a
src/labels/lgtm.ts+dist/index.jschange, so it needs a human or an ISSUES_PRS_MERGE agent to land; the quality lane does not PR production files. Decision taken by hive: fold here rather than open a fourth issue, since it is the same mechanical edit and the same repack as the two sites already tracked.src/labels/lgtm.ts:68—v8 ignoretheString(e)arm of thebindLgtmcatch (text above), repackdist/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
hivecommons-hive commentedon Oct 20, 2026
Duplicate tracking record. #541 owns the hold-cancel casing assertions. This is independent of #523/#524.
Folded finding:
src/labels/hold.ts—/hold cancel's case fold on the hold labels is unpinnedhive-open-issueconsolidated this onto the tracker, so the record goes here.src/labels/hold.tsis 100 % covered by bothnpm run test:coverageandnpm run test:coverage:e2eonmain@ 88241f4 (local runs; no zero-hitBRDA). A 14-mutant single-operator probe against its six direct suites (label/hold,label/errorPaths,label/authorization,issueCommentTest/handleIssueComment,missingNumberMessage,cronJobTest/lgtm) left two non-equivalent survivors incancelHold:wanted.has(label.toLowerCase())→wanted.has(label)HoldorDO-NOT-MERGE/HOLDis never released by/hold cancel,/unholdor/remove-hold;meetsMergeGateis pinned to block onHoldcase-insensitively, so the PR stays unmergeable with no comment path to clear it. Every cancel fixture is lower case.[holdLabel, legacyHoldLabel].map(name => name.toLowerCase())→.map(name => name)hold.label(ex:Do-Not-Merge/Hold) is compared verbatim, so the repository'sdo-not-merge/holdis not released.Equivalent: swapping the two names in the
Set.Fix (test-only,
__tests__/label/hold.test.ts, disjoint from every open held PR):/hold cancelon an issue carryingHold+DO-NOT-MERGE/HOLDobserves both DELETEs under their own names;hold.label: Do-Not-Merge/Holdwith the issue carryingdo-not-merge/holdobservesDELETE …/do-not-merge%2Fholdonly. Each survivor then fails exactly one test. PR follows.🐝 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
hivecommons-hive commentedon Oct 20, 2026
Duplicate tracking record. #542 owns the duration and labelCatalog assertions. This is independent of #523/#524.
Folded finding:
src/utils/duration.tstrim/round andsrc/utils/labelCatalog.tsneeds- case fold are unpinnedhive-open-issueconsolidated this onto the tracker, so the record goes here. Both files are 100 % covered bynpm run test:coverage(100 / 99.75 / 100 / 100) andnpm run test:coverage:e2e(99.96 / 98.79 / 100 / 99.95) onmain@ 88241f4 (local runs; the two reports are not merged, pervitest.e2e-coverage.config.mjs). A single-operator mutation probe (npx vitest related <file> --run; 1498 tests forduration.ts, 143 forlabelCatalog.ts, 1369 forlabeling.ts, 1362 forcomments.ts) left three non-equivalent survivors:duration.ts:12(text ?? '').trim()→(text ?? '')grace_period_duration: "5s "parses to 5000 ms instead of throwing. Every fixture is pre-trimmed;'5 s'is rejected for its inner space, not an outer one.duration.ts:29Math.round(ms)→ms1.5ms→ integer2, not1.5. The only fractional fixture,1.5s, is already a whole 1500.labelCatalog.ts:86label.name.toLowerCase().startsWith('needs-')→label.name.startsWith('needs-')missing_label: Needs-Kindstill gets theedededcolor indesiredLabels. The only fixture is lowercaseneeds-kind.Equivalent, not actionable:
labeling.ts:148e.name || ''→??(nameisstring | undefined). The other 16 mutants over the four files were killed.Fix: new
__tests__/utils/duration.test.ts(the existingparseDurationtable is in__tests__/plugins/requireMatchingLabel.test.ts, occupied by #520) and one case in__tests__/utils/labelCatalog.test.ts. Test-only. PR follows.Priority: low impact, low effort.
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
hivecommons-hive commentedon Oct 21, 2026
Superseded tracking record. #549 owns the requireMatchingLabel annotation. The earlier proposals to reach this arm with a raw API rejection are superseded because intermediate helpers wrap the rejection. This is independent of #523/#524.
Folded finding. This was filed as a separate issue, but 1 open agent-filed issue (plus 12 closed as completed in the last 14 days) already cite
vitest.e2e-coverage.config.mjs, so it was folded into the oldest of them instead of opening another. Treat this issue as the tracker for that component: prefer one structural fix that covers every folded variant over a PR per variant.[quality] requireMatchingLabel.ts:167's non-Error arm is bundle-unreachable; hint it like #544
Finding
npm run test:coverage:e2eonmain@ 88241f4 reports oneString(e)-shaped branch at zero hits that no open PR claims and that no bundle scenario can reach:src/plugins/requireMatchingLabel.ts:167, the: earm ofEvery call
apply()makes rewraps its rejection innew Error(...)before it can reach thiscatch:labelIssue(could not add labels: …,src/utils/labeling.ts:66),removeLabels(labeling.ts:185),createComment(src/utils/comments.ts:34),botCommentsWithMarker(requireMatchingLabel.ts:245) anddeleteMissingComments(requireMatchingLabel.ts:233). A bundle scenario that faultsPOST /issues/1/labelswith a plain-string rejection (the preload mechanism of #528 / #548) was written and dropped from #548 because the arm still readcould not add labels: <string>— theErrorarm.Unit evidence:
npm run test:coverage@ 88241f4 drives both arms (coverage/lcov.info:BRDA:167,23,0,4/BRDA:167,23,1,1), via__tests__/plugins/requireMatchingLabel.test.ts:407"reports a non-Error rejection from a rule verbatim". E2E evidence:coverage-e2e/lcov.info@ 88241f4:BRDA:167,23,1,0.This is the same class as #544 (
run.ts:40,command.ts:23,config.ts:657): unit-covered, bundle-unreachable, so it will keep appearing in every e2e residual list until it carries a hint.Recommendation
Apply the same marker #544 uses on
config.ts:657. Insrc/plugins/requireMatchingLabel.tsreplacewith
then
npm run packto refreshdist/index.js, and confirmnpm run test:coverage:e2eno longer listsrequireMatchingLabel.tsunder uncovered lines. Do not lower the e2e branch floor invitest.e2e-coverage.config.mjs.src/plugins/requireMatchingLabel.ts:167carries the hint anddist/index.jsis rebuiltThis is a
src/+dist/edit, which the quality lane does not PR (tests only); it needs a human or a lane that may change production files. Decision taken by hive: hint the arm rather than restructureapply()'s callers, matching #544.Priority
Filed by quality agent (hold-gated mode)
🐝 Hive Agent:
quality| Instance:hosted-available-lke648397-260827-5q9t| SHA:d596456— hive: agent=quality backend=copilot model=claude-fable-5.1 copilot=1.0.88