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
{{ message }}
Repository navigation
[quality] coverage-e2e names tide.ts:99 uncovered; the zero is the never-reached options.initial ?? await getPull fallback on line 98 #466
npm run test:coverage:e2e (main @ 7f01721, local run) reports src/plugins/tide.ts as 99.56% Stmts / 93.98% Branch, with line 99 (for (const delay of unknownRetryDelaysMs)) listed as uncovered. That line is not uncovered: in the same coverage-e2e/lcov.info the loop body executes (DA:100,65).
What the zero really is: the ?? await getPull(...) fallback on line 98
Both fetchMergeability call sites (evaluateMerge, tide.ts:198-201, and evaluateInQueue, tide.ts:307-310) pass initial: first, so the right-hand side never runs from dist/index.js:
V8/istanbul attributes that zero-count ?? range to the following line, which is why the report names 99. The unit run shows the same attribution (coverage/lcov.info: BRDA:98,0,1,7 and DA:99,7 while DA:100,135); it just is not visible there because the unit suite does call fetchMergeability without initial. Of the 52 for … of headers in src/, this is the only one the e2e report zeroes.
Only the unit tests exercise the fallback. It is the same shape as the arms #462 removed for #458 (retryIf default in this very function), and was not in that list.
Recommendation
Follow #462: make initial required in FetchMergeabilityOptions and drop the ?? await getPull(...) fallback (plus the unit cases that only reach it); rebuild dist/. After that, tide.ts no longer appears in the e2e "Uncovered Line #s" column for this reason, and the report stops pointing at a line that does run.
npm run test:coverage:e2e no longer lists tide.ts:99
This is a production-code change, so no PR accompanies this issue. The related e2e-only behaviour gap in the same function (the !retryIf(pr) short-circuit never reached end-to-end) is covered by #465.
Folded finding. This was filed as a separate issue, but 1 open agent-filed issue (plus 63 closed as completed in the last 14 days) already cite dist/index.js, 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] coverage-e2e: isOwnReview's user-token arm (approveReview.ts:63, login === identity.login) never reached from dist/index.js
Finding
npm run test:coverage:e2e (main @ 7f01721, local run) leaves one arm of isOwnReview in src/plugins/approveReview.ts unreached end-to-end:
coverage-e2e/lcov.info for SF:src/plugins/approveReview.ts: BRDA:63,5,0,9 BRDA:63,5,1,0 — the installation-token fallback (isBotUser) is taken 9×, the user-token comparison 0×. DA:35,1 shows GET /user succeeds in exactly one bundle run (approveReview.test.ts → "does not even try when the token is a user who opened the pull request"), and that run routes no reviews, so isOwnReview is never called with a marker review under an identified token. The unit suite does reach the arm (coverage/lcov.info: BRDA:63,5,1,4).
The docstring of syncApprovalReview promises "Reviews without the marker, or by anyone else, are never touched"; for a PAT/user token "anyone else" is decided by this login comparison, and nothing exercises that through dist/index.js: whether an existing marker review by the token's own login suppresses resubmission, whether a bot's marker review is (correctly) not treated as own once the token has a login, and whether /approve cancel dismisses only the login-matching review.
Unit evidence: npx vitest run --coverage on main@7f01721 — 100% lines, approveReview.ts 100% branch. E2E evidence: npm run test:coverage:e2e on the same revision — approveReview.ts 90.38% branch, arm above at 0. Both from a local run on the same checkout; lcov raw data read directly (not the table summary).
Recommendation
Add a bundle scenario file routing GET /user → 200 { login } with marker-bearing APPROVED reviews present, asserting:
own review (author = token login, different case) on the head sha → no POST /pulls/1/reviews, already carries the approval review debug
marker review by github-actions[bot] under the user token → not own; a fresh review is submitted
/approve cancel with both present → PUT …/reviews/<own>/dismissals only
Priority
Impact: medium (covered by unit tests, not end-to-end)
Folded finding. This was filed as a separate issue, but 1 open agent-filed issue (plus 63 closed as completed in the last 14 days) already cite dist/index.js, 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] coverage-e2e: approve.ignore_review_state is never set in any bundle scenario (approve.ts:380-381 arms at 0 from dist/index.js)
Finding
npm run test:coverage:e2e (main @ 7f01721, local run) shows that no bundle scenario ever sets approve.ignore_review_state: true. In coverage-e2e/lcov.info for SF:src/plugins/approve.ts:
The true arms of both ternaries are taken 0× end-to-end; grep -rn ignore_review_state __tests__/bundle finds nothing. The unit suite reaches them (coverage/lcov.info: BRDA:380,55,0,2, BRDA:381,57,0,3).
docs/configuration.md:343 and docs/commands.md:214-215 document the option: with it set, APPROVED reviews add nobody and CHANGES_REQUESTED reviews remove nobody, and docs/commands.md:298 promises that without github_review the reviews are not read at all. None of those three promises is exercised through dist/index.js.
Unit evidence: npx vitest run --coverage on main@7f01721 — 100% lines, approve.ts 100% branch. E2E evidence: npm run test:coverage:e2e on the same revision — approve.ts 93.25% branch, the two arms above at 0. Both from a local run on the same checkout; lcov raw data read directly.
Recommendation
Add a bundle scenario file with approve:\n ignore_review_state: true in prow.yaml, asserting through dist/index.js:
an APPROVED review by a listed approver → #1 is not approved, no approved label, and no GET /pulls/1/reviews at all
/approve followed by a CHANGES_REQUESTED review → #1 is approved by bob, approved added, no DELETE
with github_review: true as well (GET /user → 403) → reviews are read for the mirror, still count for nobody, no POST /pulls/1/reviews
Priority
Impact: medium (covered by unit tests, not end-to-end)
Two more findings folded here by the dist/index.js consolidation, both from npm run test:coverage:e2e on main@7f01721:
1. approve.ignore_review_state never set in any bundle scenario — src/plugins/approve.tsBRDA:380,55,0,0 / BRDA:381,57,0,0. The documented behaviour (docs/commands.md:214-215,298) is unit-tested only. A hold-gated PR adding __tests__/bundle/approveIgnoreReviewState.test.ts (3 scenarios) is open; see the linked PR.
2. effectiveKind's 'ignore' arms at approve.ts:228,230 are unreachable from dist/index.js — same shape as the arms #462 dropped for #458. With the setting on, line 381 already passes [] as the review list to approvalEvents, so no review-approved / review-changes event can ever exist when settings.ignore_review_state is true. computeApproval has one production caller (approve.ts:382). Even with the new scenario file both arms stay at BRDA:228,33,0,0 / BRDA:230,34,0,0. Production-code cleanup (drop the ternaries to plain 'add' / 'remove', repack dist/), so no PR from this lane:
effectiveKindreview-approved → 'add', review-changes → 'remove' unconditionally; the unit cases reaching only the 'ignore' arms removed; dist/ repacked
Folded finding. This was filed as a separate issue, but 1 open agent-filed issue (plus 63 closed as completed in the last 14 days) already cite dist/index.js, 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] coverage-e2e: approvalEvents' non-APPROVED/CHANGES_REQUESTED review arm (approve.ts:125) never reached from dist/index.js
Finding
npm run test:coverage:e2e (main @ 7f01721, local run) leaves the fall-through arm of approvalEvents' review-state switch in src/plugins/approve.ts unreached end-to-end:
if(review.state==='APPROVED'){// :122events.push({user: login,kind: 'review-approved', at })}elseif(review.state==='CHANGES_REQUESTED'){// :125events.push({user: login,kind: 'review-changes', at })}
coverage-e2e/lcov.info for SF:src/plugins/approve.ts: BRDA:125,15,0,1 BRDA:125,15,1,0 — CHANGES_REQUESTED is taken once, the else-arm (any other state: COMMENTED, DISMISSED, PENDING) never. The bundle suite does list COMMENTED/DISMISSED reviews (bundle.test.ts:718, approveMembershipArms.test.ts:83-84, approveReviewShortCircuits.test.ts:91, sweepArms.test.ts:142), but each is either the bot's review or has no submitted_at, so it is dropped by the guard on line 118 before the switch. The unit suite reaches the arm (coverage/lcov.info: BRDA:125,15,1,>0; approve.ts 100% lines, 98.87% branch there).
docs/automatic-merging.md:398 documents the contract: "GitHub reviews | APPROVED adds an approver, CHANGES_REQUESTED removes one". That a human's COMMENTED review adds nobody, and that a DISMISSED review (a dismissed approval or a dismissed changes-request) neither adds nor withdraws, is exercised only by unit tests.
Unit evidence: npx vitest run --coverage on main@7f01721 — 100% lines / 99.69% branch overall. E2E evidence: npm run test:coverage:e2e on the same revision — approve.ts 93.25% branch, arm above at 0. Both from a local run on the same checkout; lcov raw data read directly (not the table summary).
Recommendation
Add a bundle scenario file on a pull_request_review event with human reviews carrying submitted_at, asserting through dist/index.js:
a COMMENTED review by the covering approver → #1 is not approved; nobody approves sdk/x.go, no approved label, notifier NOT APPROVED
a DISMISSED review by the covering approver → same: a dismissed approval is no approval
/approve followed by COMMENTED and DISMISSED reviews → #1 is approved by bob, approved kept, no DELETE (contrast with the existing CHANGES_REQUESTED scenario in bundle.test.ts:1748)
Disjoint from #465 (tide.ts retryIf), #467 (approveReview.ts:63) and #468 (approve.ts:380-381, ignore_review_state, which passes [] to approvalEvents and so cannot reach this arm).
Priority
Impact: medium (covered by unit tests, not end-to-end)
Folded finding. This was filed as a separate issue, but 1 open agent-filed issue (plus 63 closed as completed in the last 14 days) already cite dist/index.js, 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] coverage-e2e: canonicalCommand's dynamic remove-form arm (handleIssueComment.ts:91, e.g. /remove-triage) never reached from dist/index.js
Finding
npm run test:coverage:e2e (main @ 7f01721, local run) leaves the dynamic arm of canonicalCommand in src/issueComment/handleIssueComment.ts unreached end-to-end:
constbase=name.replace(/^\/remove-/,'/')returnbase!==name&&isDynamicLabelCommand(base) ? base : name// :91
coverage-e2e/lcov.info for SF:src/issueComment/handleIssueComment.ts: BRDA:91,3,0,0 BRDA:91,4,1,0 — the base consequent is taken 0×, and isDynamicLabelCommand(base) is never even evaluated, so no bundle run ever lists a dynamic section's remove form (such as /remove-triage) in prow-commands. The only canonicalization scenario (commandCanonicalization.test.ts) uses /remove-help, which resolves through the alias table on line 84 before reaching line 90. The unit suite does reach the arm (coverage/lcov.info: BRDA:91,3,0,>0).
docs/commands.md:14-15 and :75 document the contract: listing an alias enables the whole family, any other lower-case slash-key is a label command backed by the matching config section, and its remove form is enabled together with its base. Through dist/index.js nothing checks that configuring only /remove-triage enables /triage, that /remove-triage and /triage listed together collapse to one run, or what a remove form with no matching section does.
Unit evidence: npx vitest run --coverage on main@7f01721 — 100% lines, handleIssueComment.ts 100% branch. E2E evidence: npm run test:coverage:e2e on the same revision — handleIssueComment.ts 94.54% branch, the two arms above at 0. Both from a local run on the same checkout; lcov raw data read directly (not the table summary).
Recommendation
Add a bundle scenario file with a labels: triage: values: [accepted] section in .github/prow.yaml, asserting through dist/index.js:
Folded finding. This was filed as a separate issue, but 1 open agent-filed issue (plus 63 closed as completed in the last 14 days) already cite dist/index.js, 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] coverage-e2e: merge-queue answers without an entry, enqueuer or error message (tide.ts:329-330,361; mergeQueue.ts:105,123,184) never driven from dist/index.js
Finding
npm run test:coverage:e2e (main @ 7f01721, local run, coverage-e2e/lcov.info read directly — re-run with the heads of held PRs #465/#467/#468/#469/#470 merged in, so none of these arms is already claimed) leaves the merge-queue answers the shared fixture never gives unreached from dist/index.js:
SF:src/utils/mergeQueue.ts
BRDA:105,3,0,0 # entry.enqueuer === null → no `enqueuer` on the queue state
BRDA:123,4,0,0 # enqueuePullRequest answered with mergeQueueEntry: null → { ok: true } without position
BRDA:184,12,1,0 # GraphQL `errors: []` → falls through to the client's own message
SF:src/plugins/tide.ts
BRDA:329,44,0,0 # `enqueued pr #n` logged without ` (position P)`
BRDA:330,45,0,0 # { result: 'enqueued' } without position
BRDA:361,52,1,0 # `was enqueued by an unknown actor; leaving it in the queue`
The cause is in the fixture, not the scenarios: __tests__/bundle/fakeGithub.tsmergeQueueRoute always answers the enqueue mutation with { state: 'QUEUED', position: 1 } and always wraps entry.enqueuer in { login }, so every bundle run sees a position and a named enqueuer. The unit suite reaches all six arms (coverage/lcov.info: BRDA:105,3,0,2, BRDA:123,4,0,3, BRDA:184,12,1,1, tide BRDA:329,44,0,>0).
docs/automatic-merging.md:240 documents enqueued pr #<n> (position P) and :268 the rule "only the bot's own entry (enqueuer is github-actions or ends with [bot])" is ever dequeued. What happens when GitHub answers without an entry or without an enqueuer — the position is omitted rather than printed as undefined, and an entry with no enqueuer is treated as not-ours and left alone — is exercised only by unit tests.
Unit evidence: npx vitest run --coverage on main@7f01721 — 100% lines / 99.69% branch, all six arms >0. E2E evidence: npm run test:coverage:e2e on the same revision plus the five held heads — mergeQueue.ts 86.66% branch, tide.ts 93.98% branch, the six arms above at 0. Both local runs on the same checkout.
Not claimed: mergeQueue.ts:188 arm 1 (a non-Error thrown by octokit.graphql) — @octokit/graphql only throws Error subclasses, so it is defensive and stays at 0.
Recommendation
Add a bundle scenario file routing POST /graphql by operation (as mergeQueueArms.test.ts already does for its HTTP-500 case), asserting through dist/index.js:
enqueue answered with mergeQueueEntry: null → exit 0, stdout enqueued pr #1 with no (position, no PUT …/merge
pull_requestunlabeled lgtm with isInMergeQueue: true and mergeQueueEntry.enqueuer: null → ::debug::pr #1 was enqueued by an unknown actor; leaving it in the queue, no dequeuePullRequest
enqueue answered with data: null, errors: [] → exit 1, could not enqueue pr #1: Request failed due to following response errors:
Disjoint from #465 (tideVerdictArms.test.ts, retryIf), #467, #468, #469 (approve*) and #470 (handleIssueComment.ts): none touch the GraphQL merge-queue path.
Priority
Impact: medium (covered by unit tests, not end-to-end)
Folded finding. This was filed as a separate issue, but 1 open agent-filed issue (plus 63 closed as completed in the last 14 days) already cite dist/index.js, 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] coverage-e2e: suggestApprovers' second greedy round (approve.ts:260) never reached from dist/index.js — the notifier never suggests two approvers end-to-end
Finding
npm run test:coverage:e2e (main @ 7f01721, local run, with the heads of held PRs #465/#467/#468/#469/#470/#471 merged in so none of their ground is counted) leaves the greedy set cover in suggestApprovers (src/plugins/approve.ts) one-round-only end-to-end.
coverage-e2e/lcov.info for SF:src/plugins/approve.ts:
In every round the chosen best covered every remaining file, so the remaining set always emptied after round one. No bundle scenario ever produces state.suggested with more than one login: every please assign assertion in __tests__/bundle/ names exactly one (**alice**, **bob**, **carol**), and nothing asserts the /assign @x @y form.
The notifier's contract (renderNotifier, approve.ts:296-300) is that a pull request spanning directories with disjoint approvers gets all of them listed — please assign **bob**, **carol** and /assign @bob @carol — with the most-covering approver first and ties broken alphabetically. That is unit-tested (__tests__/plugins/approve.test.ts:160 "suggests approvers greedily…") but never observed through dist/index.js.
Unit evidence: npx vitest run --coverage on main@7f01721 — approve.ts 100% lines / 100% branch. E2E evidence: npm run test:coverage:e2e on the same revision (+ held heads above) — arm above at 0. Both local runs on the same checkout; lcov raw data read directly (not the table summary, which ncc's column-less source map can misreport — #424).
Recommendation
Add a bundle scenario file __tests__/bundle/approveSuggestionArms.test.ts asserting through dist/index.js on a pull_request_review event:
root OWNERS with reviewers only, sdk/OWNERS: [bob], olm/OWNERS: [carol], files in both → please assign **bob**, **carol**, /assign @bob @carol, both OWNERS files bold in the details list
a/[x,y], b/[y,z], c/[z] (all no_parent_owners) → please assign **y**, **z**, /assign @y @z, x never suggested
Disjoint from #465 (tide.ts retryIf), #466 (tide.ts:98), #467 (approveReview.ts:63), #468 (approve.ts:380-381, ignore_review_state), #469 (approve.ts:125, review-state arm), #470 (handleIssueComment.ts:91) and #471 (merge-queue nulls): none touch suggestApprovers or assert a multi-login suggestion.
Priority
Impact: medium (covered by unit tests, not end-to-end)
Folded finding. This was filed as a separate issue, but 1 open agent-filed issue (plus 63 closed as completed in the last 14 days) already cite dist/index.js, 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] coverage-e2e: tide.labels is never configured in any bundle scenario (tide.ts:542 probe-skip arm at 0 from dist/index.js)
Finding
npm run test:coverage:e2e (main @ 7f01721, local run) shows that no bundle scenario ever configures a valid tide.labels list. In coverage-e2e/lcov.info for SF:src/plugins/tide.ts:
loadTide takes the "labels undefined → probe the base branch for OWNERS" arm 367× and the "labels configured → skip the probe" arm 0×. grep -rn 'labels:' __tests__/bundle under a tide: key finds only configSchemaArms.test.ts:57, which is the schema-error case ([lgtm, ""]) and throws before loadTide runs. Consequently meetsMergeGate's missing <pattern> reason is reached end-to-end only from the default [lgtm] / [lgtm, approved] lists, never from a configured pattern (wildcard, mixed case). The unit suite reaches the arm (coverage/lcov.info: BRDA:542,83,1,4; __tests__/plugins/tide.test.ts:840 routes tide:\n labels: [lgtm] with an OWNERS tree and asserts it is not read).
docs/automatic-merging.md:317-340 documents three promises for a configured list, none exercised through dist/index.js: every entry "must be present"; "A configured list replaces the default list, it does not extend it"; and the OWNERS tree listing is "skipped entirely when tide.labels is configured".
Unit evidence: npx vitest run --coverage on main@7f01721 — 100% lines / 99.69% branch, tide.ts 100% branch at line 542. E2E evidence: npm run test:coverage:e2e on the same revision — tide.ts 93.98% branch, arm above at 0. Both from a local run on the same checkout; lcov raw data read directly (not the table summary).
Disjoint from #465 (tide.ts retryIf short-circuit, tideVerdictArms.test.ts), #466 (tide.ts:98initial fallback, production change), #471 (merge-queue nulls, mergeQueueNullArms.test.ts) and the approve*/handleIssueComment clusters (#467–#470, #472): none configure tide.labels or assert on the OWNERS probe being skipped.
Recommendation
Add a bundle scenario file on a pull_requestlabeled event with tide:\n labels: […] in prow.yaml, asserting through dist/index.js:
labels: [lgtm, approved] on a PR carrying only lgtm → skipping pr #1: missing approved, no PUT, and no GET /git/trees/master?recursive=true
labels: [lgtm] on a base whose tree carries a root OWNERS → merged pr #1 and the tree is never read (the list replaces the [lgtm, approved] default)
labels: [LGTM, "size/*"] on a PR with lgtm + size/M → merges (case-insensitive, * spans /); [lgtm, "size/*"] on a PR with only lgtm → skipping pr #1: missing size/*
Priority
Impact: medium (covered by unit tests, not end-to-end)
Folded finding. This was filed as a separate issue, but 1 open agent-filed issue (plus 41 closed as completed in the last 14 days) already cite dist/index.js, 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] tide/sweep optional-field folds (tide.ts:258,426; sweep.ts:141) only run under the unit suite
Finding
Three nullish folds on optional GitHub REST fields are unit-covered but never executed by the bundle e2e suite (npm run test:coverage:e2e, __tests__/bundle driving dist/index.js):
src/plugins/tide.ts:258 — explainForkWorkflows: (compared.data.files ?? []) when a compare response omits files
src/plugins/tide.ts:426 — getPull: data.draft ?? false when a pull request response omits draft
src/cronJobs/sweep.ts:141 — approveIfTrusted: (pr.labels ?? []).some(...) when a listed pull request omits labels
Every existing bundle case serves those fields populated, so the production shape where GitHub leaves them out (both are optional in the REST schema) is only exercised against unit fixtures.
Evidence
Unit: npm run test:coverage on main @ 1062ce7 — all three branches taken (coverage/lcov.info has no BRDA:…,0 for these lines).
E2E: npm run test:coverage:e2e on main @ 1062ce7 — coverage-e2e/lcov.info: SF:src/plugins/tide.ts BRDA:258,27,1,0, BRDA:426,63,1,0; SF:src/cronJobs/sweep.ts BRDA:141,14,1,0. 78 files / 487 tests, Branches 97.96% (1633/1667).
Recommendation
Add one bundle test file (__tests__/bundle/tideOptionalFields.test.ts) driving each fold through dist/index.js: a pull_request labeled lgtm whose GET /pulls/1 has no draft; a schedule lgtm fork-403 whose compare has no files; a schedule sweep whose listing item has no labels.
Folded finding. This was filed as a separate issue, but 1 open agent-filed issue (plus 41 closed as completed in the last 14 days) already cite dist/index.js, 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] 17 non-Error rejection normalizer arms are unreachable from dist/index.js: drop them or accept as unit-only
Finding
After #497 and #498, every remaining branch the bundle e2e suite (npm run test:coverage:e2e, main @ 1062ce7, coverage-e2e/lcov.info) leaves untaken in the error-handling paths is the same shape: the else arm of e instanceof Error ? e.message : String(e) (or 'status' in e / typeof e === 'object') for a rejection that is not an Error:
Through dist/index.js every rejection these catch comes from Octokit (RequestError, an Error), js-yaml (YAMLException, an Error), or fetch (TypeError). No fake-GitHub response can make the runtime throw a string or a plain object, so no bundle test can take these arms; the unit suite reaches them only by throwing literals directly.
Evidence
Unit: npm run test:coverage main @ 1062ce7 — all arms taken.
E2E: npm run test:coverage:e2e main @ 1062ce7 — each of the above appears as BRDA:<line>,…,1,0 in coverage-e2e/lcov.info; src/utils/auth.ts additionally DA:24,0.
Decision needed
Same question #466's reopen comment settled for approve.ts/meow.ts, now for the normalizers. Either:
Folded finding. This was filed as a separate issue, but 1 open agent-filed issue (plus 5 closed as completed in the last 14 days) already cite coverage/lcov.info, 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] coverage-reporting: unit and e2e lcov carry negative BRDA counts for 4 implicit-else arms after a conditional await (ast-v8-to-istanbul#207); text report names 4 phantom uncovered lines
Finding
Both coverage artifacts on main @ 1062ce7 contain negative branch hit counts, which the lcov format does not allow (a BRDA count is a non-negative integer or -):
All six are the implicit else of an if whose condition is the result of a conditionalawait — the exact shape of the open upstream report AriPerkkio/ast-v8-to-istanbul#207 (filed 2026-10-14, reproduced with a raw node:inspector capture, no Vitest involved; we pull ast-v8-to-istanbul@1.0.6 via @vitest/coverage-v8@5.0.3):
The arms are not uncovered. The line after each if block — the first statement of the else path — has a positive DA count in both suites (unit DA:40,12, DA:37,9, DA:504,7, DA:221,94; e2e DA:40,2, DA:37,3, DA:504,29, DA:221,48), and the bundle suite asserts on those paths directly (__tests__/bundle/defaultBranchFallback.test.ts:50 → approve: the base branch has no OWNERS files; __tests__/bundle/triggerTestAndLgtmCancel.test.ts:199 → stranger is not a org member or collaborator). The unit suite has explicit cases for each (close.test.ts:55, reopen.test.ts:55, approveEvents.test.ts:237, auth.test.ts). Re-running vitest run --coverage __tests__/issueCommentTest/close.test.ts alone still yields BRDA:39,3,1,-2, so it is not a worker-merge effect.
coverage-summary.json → the ### Coverage step summary in test.yml reads 1662/1667 branches (99.7%); the true figure is 1666/1667. The e2e summary reads 1633/1667 (97.96%); true is 1635/1667.
The two coverage-* artifacts uploaded by test.yml are not spec-valid lcov, so a strict consumer (Codecov-style parsers, lcov --summary) may reject or misreport them.
Nothing fails today: thresholds are 93 / 95 branches.
No coverage-gap finding is attached to any of these four sites.
Recommendation
This is upstream tooling, not something a test or workflow change in this repository can correct, so no PR accompanies this issue.
Closing out the e2e-zero catalog on main @ 1062ce7 (npm run test:coverage:e2e, coverage-e2e/lcov.info read directly). After #497, #498 and the normalizer-arms decision above, exactly two zero-count arms were not yet named on this tracker:
1. src/utils/command.ts:23 — getLineArgs's ?? '' is unreachable from dist/index.js by construction.BRDA:23,0,0,26 BRDA:23,0,1,0 (unit: BRDA:23,0,1,3). Its only callers are milestone.ts:43 and retitle.ts:31, and the dispatcher (handleIssueComment.ts:128) runs either handler only after hasCommand(form, body) — which is findCommandArgs(...).length > 0, the same match getLineArgs performs — returned true. Neither /milestone nor /retitle has an alias in commandAliases, so the form that matched is the one getLineArgs is called with, and .at(-1) is always defined. Same shape as the approve.ts:415 arm #497 drops: production cleanup (findCommandArgs(command, body).at(-1) as string, or make getLineArgs take the already-matched args) plus the unit case that calls it with an absent command; no PR from this lane.
getLineArgs?? '' arm removed, dist/ repacked; BRDA:23 no longer listed under SF:src/utils/command.ts in coverage-e2e/lcov.info
2. src/issueComment/approve.ts:94 — String(context.payload.issue?.user?.login ?? '').BRDA:94,6,0,30 BRDA:94,6,1,0 (unit: BRDA:94,6,1,1). A ?? '' on issue.user.login, a field GitHub always sends — the class the d93ecb8 comment above already lists as not worth a scenario. Noted here only so the catalog is complete.
Separately, the four negativeBRDA entries in both lcov files (close.ts:39, reopen.ts:36, approve.ts:503, auth.ts:220) are a reporter artifact (ast-v8-to-istanbul#207), not gaps; filed as its own coverage-reporting issue.
Folded finding. This was filed as a separate issue, but 1 open agent-filed issue (plus 41 closed as completed in the last 14 days) already cite dist/index.js, 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] coverage-reporting: the e2e regression floor (99/95/98/99) now sits 49 branches and 10 functions under what main reaches
Finding
vitest.e2e-coverage.config.mjs gates npm run test:coverage:e2e at 99 / 95 / 98 / 99 (lines / branches / functions / statements). #484 set those "just under what main reaches" when main measured 99.54 / 96.25 / 98.79 / 99.56 (d93ecb8). Since then the bundle scenarios in #467–#496 landed and main now measures:
So a bundle scenario that stops driving up to 49 src/ branches or 10 functions through dist/index.js still passes the e2e run, which is exactly the regression the floor exists to catch. The functions floor in particular was set when six reset*() hooks were unreached; #483 marked those v8 ignore, and the figure has been 100 % since.
Evidence (both suites run locally at main@1062ce7, Node $(node --version)):
docs/contributing.md:50 documents the same 99 / 95 / 98 / 99 values and needs the same update.
Recommendation
Apply the repository's own rule (#202, #484, #500: a floor just under what main reaches):
vitest.e2e-coverage.config.mjscoverage.thresholds: branches: 95 → 97, functions: 98 → 99 (lines/statements stay 99); update the comment to record the figure it was set under
Folded finding. This was filed as a separate issue, but 1 open agent-filed issue (plus 41 closed as completed in the last 14 days) already cite dist/index.js, 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] newOctokit's api.github.com fallback (src/utils/octokit.ts) is never exercised by the dist/index.js e2e suite
Finding
newOctokit in src/utils/octokit.ts picks its base URL with process.env.GITHUB_API_URL || 'https://api.github.com'. The fallback is what makes the action work when a runner leaves GITHUB_API_URL unset or empty.
Evidence at 1062ce7 (origin/main):
Unit (npm run test:coverage, vitest v8): src/utils/octokit.ts 100% lines / 100% branches — __tests__/utils/octokit.test.ts covers unset, GHES and empty-string values.
End-to-end (npm run test:coverage:e2e, the __tests__/bundle suite against the source-mapped bundle, local run on the same revision): src/utils/octokit.ts 100% lines / 50% branches. Every bundle test passes apiUrl: gh.url through runBundle, which sets GITHUB_API_URL to the fake server, so the 'https://api.github.com' arm never runs through dist/index.js.
The two reports are produced by separate vitest configs over different artifacts (source vs. packed bundle) and are not merged; the gap is stated per source above.
Recommendation
Add a bundle test that runs a command with GITHUB_API_URL='' and a --require preload that rewrites the https://api.github.com origin to the fake GitHub (the same shape as __tests__/bundle/catApiPreload.cjs), asserting the requests land on the fake. Include a fail-closed case so the child can never reach the real API from the test.
__tests__/bundle/githubApiPreload.cjs + __tests__/bundle/githubApiUrlDefault.test.ts bring src/utils/octokit.ts to 100% branches in coverage-e2e
Priority
Impact: medium (unit-covered, e2e-uncovered; priority 2 under the coverage-gap rules)
Folded finding. This was filed as a separate issue, but 1 open agent-filed issue (plus 6 closed as completed in the last 14 days) already cite src/plugins/tide.ts, 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] the 15 e2e-uncovered branches on main not claimed by an open PR are all unreachable non-Error fallbacks (instanceof Error / status typeof / getLineArgs ?? '') across 13 files
Finding
npm run test:coverage:e2e on main @ 1062ce7 (local run, 78 files / 487 tests) reports 97.96 % branches (1633/1667). Of the 34 zero-hit branches in coverage-e2e/lcov.info, the ones not already claimed by an open PR (#497, #498, #504, #505, #508, #509) or issue (#507, auth.ts:24) are 15 branches across 13 files, and every one is the same shape: a defensive arm for a thrown value that is not an Error / has no numeric status.
errorMessage tail: e instanceof Error ? e.message : String(e)
String(e)
Why no bundle scenario can reach them:
Every throw in src/ is either throw new Error(…) (or a subclass) or a rethrow of a caught value (lgtm.ts:147, config.ts:326, auth.ts:339, issueComment/approve.ts:133, trigger.ts:311, meow.ts:94/99/104, config.ts:457/478 via malformedSection). parseDuration (duration.ts:26) throws new Error. There is no throw <primitive> and no Promise.reject(<primitive>).
getLineArgs is called only from milestone.ts:43 and retitle.ts:31, and handleIssueComment.ts:128 dispatches those handlers only after hasCommand(form, commentBody) matched, i.e. after findCommandArgs returned at least one entry — so .at(-1) is never undefined.
Unit coverage (npx vitest run --coverage, same revision, 157 files / 2116 tests) is 100 % lines / 99.7 % branches; each arm above is reached only by a unit case that injects a primitive rejection with vi.spyOn(…).mockRejectedValueOnce('…') or calls the helper directly — spies, not inputs the action can see. The five unit-side "uncovered" branches the text reporter lists (close.ts:39, reopen.ts:36, approve.ts:415/503, auth.ts:220) carry negative hit counts in coverage/lcov.info (BRDA:39,3,1,-3, BRDA:220,13,1,-51, …): that is v8-to-istanbul's implicit-else accounting on await-containing if bodies, and the false arms are exercised (close.test.ts:55, reopen.test.ts:175, auth.test.ts:361). They are not gaps.
This is the same disposition as #466 (dropped by #492) and #507: arms that only the unit suite reaches, keeping the e2e branch figure below 99 % for no reason a test can fix. It is one mechanical change at 13 sites, so it is one issue, not thirteen.
Recommendation
Add one helper and route the sites through it, so the single unreachable fallback is excluded once instead of fourteen times:
// src/utils/errors.ts/* v8 ignore start -- every throw in src/ and every Octokit rejection is an Error; the String() fallback is defensive */exportfunctionerrorMessage(e: unknown): string{returneinstanceofError ? e.message : String(e)}exportfunctionasError(e: unknown): Error{returneinstanceofError ? e : newError(String(e))}/* v8 ignore stop */
replace the inline instanceof Error ? … : String(e) / : e at run.ts:40, labelSync.ts:107, sweep.ts:132, lgtm.ts:68, requireMatchingLabel.ts:167, tide.ts:138, config.ts:657, mergeQueue.ts:190 with errorMessage(e); approveReview.ts:230's local errorMessage becomes a re-export or is deleted
replace handleIssueComment.ts:217normalizeError and events.ts:50 with asError(e)
errorStatus (approveReview.ts:226), statusOf (trigger.ts:323) and tide.ts:137: either narrow the parameter to RequestError-shaped ({ status: number }) since that is all callers ever pass, or move the three into the same helper file under the same ignore block
command.ts:23: getLineArgs can drop the ?? '' only if it stops being string-typed for absent commands; the smaller change is a /* v8 ignore next */ on the fold with a comment naming the hasCommand precondition in handleIssueComment.ts:128
repack dist/; remove the unit cases that only exist to inject primitive rejections (they test the helper now, in one place), keeping the one direct errorMessage('socket hang up') / asError('x') unit case for the helper itself
This is a production-code change (same category as #492 / #507), so no PR accompanies this issue from the quality lane. After it lands, with #497/#498/#504/#505/#508/#509 and #507, main's e2e branch figure reaches 100 % and the floor proposed in #502 can be revisited.
src/utils/errors.ts (or equivalent) added; the 13 sites above route through it
dist/ repacked
npm run test:coverage:e2e no longer lists any of the 13 files in Uncovered Line #s
Activity
github-actions commentedon Oct 13, 2026
Please add a kind label with
/kind failing-testor/kind cleanup.hivecommons-hive commentedon Oct 13, 2026
Folded finding. This was filed as a separate issue, but 1 open agent-filed issue (plus 63 closed as completed in the last 14 days) already cite
dist/index.js, 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] coverage-e2e: isOwnReview's user-token arm (approveReview.ts:63, login === identity.login) never reached from dist/index.js
Finding
npm run test:coverage:e2e(main @ 7f01721, local run) leaves one arm ofisOwnReviewinsrc/plugins/approveReview.tsunreached end-to-end:coverage-e2e/lcov.infoforSF:src/plugins/approveReview.ts:BRDA:63,5,0,9 BRDA:63,5,1,0— the installation-token fallback (isBotUser) is taken 9×, the user-token comparison 0×.DA:35,1showsGET /usersucceeds in exactly one bundle run (approveReview.test.ts→ "does not even try when the token is a user who opened the pull request"), and that run routes no reviews, soisOwnReviewis never called with a marker review under an identified token. The unit suite does reach the arm (coverage/lcov.info:BRDA:63,5,1,4).The docstring of
syncApprovalReviewpromises "Reviews without the marker, or by anyone else, are never touched"; for a PAT/user token "anyone else" is decided by this login comparison, and nothing exercises that throughdist/index.js: whether an existing marker review by the token's own login suppresses resubmission, whether a bot's marker review is (correctly) not treated as own once the token has a login, and whether/approve canceldismisses only the login-matching review.Unit evidence:
npx vitest run --coverageon main@7f01721 — 100% lines, approveReview.ts 100% branch. E2E evidence:npm run test:coverage:e2eon the same revision — approveReview.ts 90.38% branch, arm above at 0. Both from a local run on the same checkout; lcov raw data read directly (not the table summary).Recommendation
Add a bundle scenario file routing
GET /user→200 { login }with marker-bearingAPPROVEDreviews present, asserting:POST /pulls/1/reviews,already carries the approval reviewdebuggithub-actions[bot]under the user token → not own; a fresh review is submitted/approve cancelwith both present →PUT …/reviews/<own>/dismissalsonlyPriority
Filed by quality agent (hold-gated mode)
🐝 Hive Agent:
quality| Instance:hosted-available-lke648397-260827-5q9t| SHA:7f01721— hive: agent=quality backend=copilot model=claude-fable-5.1 copilot=1.0.88
hivecommons-hive commentedon Oct 13, 2026
Folded finding. This was filed as a separate issue, but 1 open agent-filed issue (plus 63 closed as completed in the last 14 days) already cite
dist/index.js, 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] coverage-e2e: approve.ignore_review_state is never set in any bundle scenario (approve.ts:380-381 arms at 0 from dist/index.js)
Finding
npm run test:coverage:e2e(main @ 7f01721, local run) shows that no bundle scenario ever setsapprove.ignore_review_state: true. Incoverage-e2e/lcov.infoforSF:src/plugins/approve.ts:The true arms of both ternaries are taken 0× end-to-end;
grep -rn ignore_review_state __tests__/bundlefinds nothing. The unit suite reaches them (coverage/lcov.info:BRDA:380,55,0,2,BRDA:381,57,0,3).docs/configuration.md:343anddocs/commands.md:214-215document the option: with it set,APPROVEDreviews add nobody andCHANGES_REQUESTEDreviews remove nobody, anddocs/commands.md:298promises that withoutgithub_reviewthe reviews are not read at all. None of those three promises is exercised throughdist/index.js.Unit evidence:
npx vitest run --coverageon main@7f01721 — 100% lines, approve.ts 100% branch. E2E evidence:npm run test:coverage:e2eon the same revision — approve.ts 93.25% branch, the two arms above at 0. Both from a local run on the same checkout; lcov raw data read directly.Recommendation
Add a bundle scenario file with
approve:\n ignore_review_state: trueinprow.yaml, asserting throughdist/index.js:APPROVEDreview by a listed approver →#1 is not approved, noapprovedlabel, and noGET /pulls/1/reviewsat all/approvefollowed by aCHANGES_REQUESTEDreview →#1 is approved by bob,approvedadded, noDELETEgithub_review: trueas well (GET /user→ 403) → reviews are read for the mirror, still count for nobody, noPOST /pulls/1/reviewsPriority
Filed by quality agent (hold-gated mode)
🐝 Hive Agent:
quality| Instance:hosted-available-lke648397-260827-5q9t| SHA:7f01721— hive: agent=quality backend=copilot model=claude-fable-5.1 copilot=1.0.88
hivecommons-hive commentedon Oct 13, 2026
Two more findings folded here by the
dist/index.jsconsolidation, both fromnpm run test:coverage:e2eon main@7f01721:1.
approve.ignore_review_statenever set in any bundle scenario —src/plugins/approve.tsBRDA:380,55,0,0/BRDA:381,57,0,0. The documented behaviour (docs/commands.md:214-215,298) is unit-tested only. A hold-gated PR adding__tests__/bundle/approveIgnoreReviewState.test.ts(3 scenarios) is open; see the linked PR.2.
effectiveKind's'ignore'arms atapprove.ts:228,230are unreachable fromdist/index.js— same shape as the arms #462 dropped for #458. With the setting on, line 381 already passes[]as the review list toapprovalEvents, so noreview-approved/review-changesevent can ever exist whensettings.ignore_review_stateis true.computeApprovalhas one production caller (approve.ts:382). Even with the new scenario file both arms stay atBRDA:228,33,0,0/BRDA:230,34,0,0. Production-code cleanup (drop the ternaries to plain'add'/'remove', repackdist/), so no PR from this lane:effectiveKindreview-approved→'add',review-changes→'remove'unconditionally; the unit cases reaching only the'ignore'arms removed;dist/repacked🐝 Hive Agent:
quality| Instance:hosted-available-lke648397-260827-5q9t| SHA:3c70ee9— hive: agent=quality backend=copilot model=claude-fable-5.1 copilot=1.0.88
hivecommons-hive commentedon Oct 13, 2026
Folded finding. This was filed as a separate issue, but 1 open agent-filed issue (plus 63 closed as completed in the last 14 days) already cite
dist/index.js, 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] coverage-e2e: approvalEvents' non-APPROVED/CHANGES_REQUESTED review arm (approve.ts:125) never reached from dist/index.js
Finding
npm run test:coverage:e2e(main @ 7f01721, local run) leaves the fall-through arm ofapprovalEvents' review-state switch insrc/plugins/approve.tsunreached end-to-end:coverage-e2e/lcov.infoforSF:src/plugins/approve.ts:BRDA:125,15,0,1 BRDA:125,15,1,0—CHANGES_REQUESTEDis taken once, the else-arm (any other state:COMMENTED,DISMISSED,PENDING) never. The bundle suite does listCOMMENTED/DISMISSEDreviews (bundle.test.ts:718,approveMembershipArms.test.ts:83-84,approveReviewShortCircuits.test.ts:91,sweepArms.test.ts:142), but each is either the bot's review or has nosubmitted_at, so it is dropped by the guard on line 118 before the switch. The unit suite reaches the arm (coverage/lcov.info:BRDA:125,15,1,>0; approve.ts 100% lines, 98.87% branch there).docs/automatic-merging.md:398documents the contract: "GitHub reviews |APPROVEDadds an approver,CHANGES_REQUESTEDremoves one". That a human'sCOMMENTEDreview adds nobody, and that aDISMISSEDreview (a dismissed approval or a dismissed changes-request) neither adds nor withdraws, is exercised only by unit tests.Unit evidence:
npx vitest run --coverageon main@7f01721 — 100% lines / 99.69% branch overall. E2E evidence:npm run test:coverage:e2eon the same revision — approve.ts 93.25% branch, arm above at 0. Both from a local run on the same checkout; lcov raw data read directly (not the table summary).Recommendation
Add a bundle scenario file on a
pull_request_reviewevent with human reviews carryingsubmitted_at, asserting throughdist/index.js:COMMENTEDreview by the covering approver →#1 is not approved; nobody approves sdk/x.go, noapprovedlabel, notifierNOT APPROVEDDISMISSEDreview by the covering approver → same: a dismissed approval is no approval/approvefollowed byCOMMENTEDandDISMISSEDreviews →#1 is approved by bob,approvedkept, noDELETE(contrast with the existingCHANGES_REQUESTEDscenario inbundle.test.ts:1748)Disjoint from #465 (
tide.tsretryIf), #467 (approveReview.ts:63) and #468 (approve.ts:380-381,ignore_review_state, which passes[]toapprovalEventsand so cannot reach this arm).Priority
Filed by quality agent (hold-gated mode)
🐝 Hive Agent:
quality| Instance:hosted-available-lke648397-260827-5q9t| SHA:f62ea2d— hive: agent=quality backend=copilot model=claude-fable-5.1 copilot=1.0.88
hivecommons-hive commentedon Oct 13, 2026
Folded finding. This was filed as a separate issue, but 1 open agent-filed issue (plus 63 closed as completed in the last 14 days) already cite
dist/index.js, 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] coverage-e2e: canonicalCommand's dynamic remove-form arm (handleIssueComment.ts:91, e.g. /remove-triage) never reached from dist/index.js
Finding
npm run test:coverage:e2e(main @ 7f01721, local run) leaves the dynamic arm ofcanonicalCommandinsrc/issueComment/handleIssueComment.tsunreached end-to-end:coverage-e2e/lcov.infoforSF:src/issueComment/handleIssueComment.ts:BRDA:91,3,0,0 BRDA:91,4,1,0— thebaseconsequent is taken 0×, andisDynamicLabelCommand(base)is never even evaluated, so no bundle run ever lists a dynamic section's remove form (such as/remove-triage) inprow-commands. The only canonicalization scenario (commandCanonicalization.test.ts) uses/remove-help, which resolves through the alias table on line 84 before reaching line 90. The unit suite does reach the arm (coverage/lcov.info:BRDA:91,3,0,>0).docs/commands.md:14-15and:75document the contract: listing an alias enables the whole family, any other lower-case slash-key is a label command backed by the matching config section, and its remove form is enabled together with its base. Throughdist/index.jsnothing checks that configuring only/remove-triageenables/triage, that/remove-triageand/triagelisted together collapse to one run, or what a remove form with no matching section does.Unit evidence:
npx vitest run --coverageon main@7f01721 — 100% lines, handleIssueComment.ts 100% branch. E2E evidence:npm run test:coverage:e2eon the same revision — handleIssueComment.ts 94.54% branch, the two arms above at 0. Both from a local run on the same checkout; lcov raw data read directly (not the table summary).Recommendation
Add a bundle scenario file with a
labels: triage: values: [accepted]section in.github/prow.yaml, asserting throughdist/index.js:prow-commands: /remove-triage+ comment/triage accepted→POST /issues/1/labels { labels: ['triage/accepted'] }prow-commands: /remove-triage+ comment/remove-triage accepted→DELETE /issues/1/labels/triage%2Faccepted, no POSTprow-commands: /remove-triage /triage→ duplicates collapse: exactly one label writeprow-commands: /remove-nosuchwith nonosuchsection → canonicalized to/nosuch, fails withnosuch: yaml malformed, expected 'nosuch' top level keyDisjoint from #465 (tide.ts retryIf), #466 (tide.ts:98), #467 (approveReview.ts:63), #468 (approve.ts:380-381) and #469 (approve.ts:125): none touch
handleIssueComment.ts.Priority
Filed by quality agent (hold-gated mode)
🐝 Hive Agent:
quality| Instance:hosted-available-lke648397-260827-5q9t| SHA:7f01721— hive: agent=quality backend=copilot model=claude-fable-5.1 copilot=1.0.88
hivecommons-hive commentedon Oct 13, 2026
Folded finding. This was filed as a separate issue, but 1 open agent-filed issue (plus 63 closed as completed in the last 14 days) already cite
dist/index.js, 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] coverage-e2e: merge-queue answers without an entry, enqueuer or error message (tide.ts:329-330,361; mergeQueue.ts:105,123,184) never driven from dist/index.js
Finding
npm run test:coverage:e2e(main @ 7f01721, local run,coverage-e2e/lcov.inforead directly — re-run with the heads of held PRs #465/#467/#468/#469/#470 merged in, so none of these arms is already claimed) leaves the merge-queue answers the shared fixture never gives unreached fromdist/index.js:The cause is in the fixture, not the scenarios:
__tests__/bundle/fakeGithub.tsmergeQueueRoutealways answers the enqueue mutation with{ state: 'QUEUED', position: 1 }and always wrapsentry.enqueuerin{ login }, so every bundle run sees a position and a named enqueuer. The unit suite reaches all six arms (coverage/lcov.info:BRDA:105,3,0,2,BRDA:123,4,0,3,BRDA:184,12,1,1, tideBRDA:329,44,0,>0).docs/automatic-merging.md:240documentsenqueued pr #<n> (position P)and:268the rule "only the bot's own entry (enqueuerisgithub-actionsor ends with[bot])" is ever dequeued. What happens when GitHub answers without an entry or without an enqueuer — the position is omitted rather than printed asundefined, and an entry with no enqueuer is treated as not-ours and left alone — is exercised only by unit tests.Unit evidence:
npx vitest run --coverageon main@7f01721 — 100% lines / 99.69% branch, all six arms >0. E2E evidence:npm run test:coverage:e2eon the same revision plus the five held heads —mergeQueue.ts86.66% branch,tide.ts93.98% branch, the six arms above at 0. Both local runs on the same checkout.Not claimed:
mergeQueue.ts:188arm 1 (a non-Errorthrown byoctokit.graphql) —@octokit/graphqlonly throwsErrorsubclasses, so it is defensive and stays at 0.Recommendation
Add a bundle scenario file routing
POST /graphqlby operation (asmergeQueueArms.test.tsalready does for its HTTP-500 case), asserting throughdist/index.js:mergeQueueEntry: null→ exit 0, stdoutenqueued pr #1with no(position, noPUT …/mergepull_requestunlabeledlgtm withisInMergeQueue: trueandmergeQueueEntry.enqueuer: null→::debug::pr #1 was enqueued by an unknown actor; leaving it in the queue, nodequeuePullRequestdata: null, errors: []→ exit 1,could not enqueue pr #1: Request failed due to following response errors:Disjoint from #465 (
tideVerdictArms.test.ts, retryIf), #467, #468, #469 (approve*) and #470 (handleIssueComment.ts): none touch the GraphQL merge-queue path.Priority
Filed by quality agent (hold-gated mode)
🐝 Hive Agent:
quality| Instance:hosted-available-lke648397-260827-5q9t| SHA:7f01721— hive: agent=quality backend=copilot model=claude-fable-5.1 copilot=1.0.88
hivecommons-hive commentedon Oct 13, 2026
Folded finding. This was filed as a separate issue, but 1 open agent-filed issue (plus 63 closed as completed in the last 14 days) already cite
dist/index.js, 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] coverage-e2e: suggestApprovers' second greedy round (approve.ts:260) never reached from dist/index.js — the notifier never suggests two approvers end-to-end
Finding
npm run test:coverage:e2e(main @ 7f01721, local run, with the heads of held PRs #465/#467/#468/#469/#470/#471 merged in so none of their ground is counted) leaves the greedy set cover insuggestApprovers(src/plugins/approve.ts) one-round-only end-to-end.coverage-e2e/lcov.infoforSF:src/plugins/approve.ts:In every round the chosen
bestcovered every remaining file, so theremainingset always emptied after round one. No bundle scenario ever producesstate.suggestedwith more than one login: everyplease assignassertion in__tests__/bundle/names exactly one (**alice**,**bob**,**carol**), and nothing asserts the/assign @x @yform.The notifier's contract (
renderNotifier, approve.ts:296-300) is that a pull request spanning directories with disjoint approvers gets all of them listed —please assign **bob**, **carol**and/assign @bob @carol— with the most-covering approver first and ties broken alphabetically. That is unit-tested (__tests__/plugins/approve.test.ts:160"suggests approvers greedily…") but never observed throughdist/index.js.Unit evidence:
npx vitest run --coverageon main@7f01721 — approve.ts 100% lines / 100% branch. E2E evidence:npm run test:coverage:e2eon the same revision (+ held heads above) — arm above at 0. Both local runs on the same checkout; lcov raw data read directly (not the table summary, which ncc's column-less source map can misreport — #424).Recommendation
Add a bundle scenario file
__tests__/bundle/approveSuggestionArms.test.tsasserting throughdist/index.json apull_request_reviewevent:OWNERSwith reviewers only,sdk/OWNERS: [bob],olm/OWNERS: [carol], files in both →please assign **bob**, **carol**,/assign @bob @carol, both OWNERS files bold in the details lista/[x,y],b/[y,z],c/[z](allno_parent_owners) →please assign **y**, **z**,/assign @y @z,xnever suggestedDisjoint from #465 (
tide.tsretryIf), #466 (tide.ts:98), #467 (approveReview.ts:63), #468 (approve.ts:380-381,ignore_review_state), #469 (approve.ts:125, review-state arm), #470 (handleIssueComment.ts:91) and #471 (merge-queue nulls): none touchsuggestApproversor assert a multi-login suggestion.Priority
Filed by quality agent (hold-gated mode)
🐝 Hive Agent:
quality| Instance:hosted-available-lke648397-260827-5q9t| SHA:06d4d6c— hive: agent=quality backend=copilot model=claude-fable-5.1 copilot=1.0.88
hivecommons-hive commentedon Oct 13, 2026
Folded finding. This was filed as a separate issue, but 1 open agent-filed issue (plus 63 closed as completed in the last 14 days) already cite
dist/index.js, 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] coverage-e2e: tide.labels is never configured in any bundle scenario (tide.ts:542 probe-skip arm at 0 from dist/index.js)
Finding
npm run test:coverage:e2e(main @ 7f01721, local run) shows that no bundle scenario ever configures a validtide.labelslist. Incoverage-e2e/lcov.infoforSF:src/plugins/tide.ts:loadTidetakes the "labels undefined → probe the base branch for OWNERS" arm 367× and the "labels configured → skip the probe" arm 0×.grep -rn 'labels:' __tests__/bundleunder atide:key finds onlyconfigSchemaArms.test.ts:57, which is the schema-error case ([lgtm, ""]) and throws beforeloadTideruns. ConsequentlymeetsMergeGate'smissing <pattern>reason is reached end-to-end only from the default[lgtm]/[lgtm, approved]lists, never from a configured pattern (wildcard, mixed case). The unit suite reaches the arm (coverage/lcov.info:BRDA:542,83,1,4;__tests__/plugins/tide.test.ts:840routestide:\n labels: [lgtm]with an OWNERS tree and asserts it is not read).docs/automatic-merging.md:317-340documents three promises for a configured list, none exercised throughdist/index.js: every entry "must be present"; "A configured list replaces the default list, it does not extend it"; and the OWNERS tree listing is "skipped entirely whentide.labelsis configured".Unit evidence:
npx vitest run --coverageon main@7f01721 — 100% lines / 99.69% branch, tide.ts 100% branch at line 542. E2E evidence:npm run test:coverage:e2eon the same revision — tide.ts 93.98% branch, arm above at 0. Both from a local run on the same checkout; lcov raw data read directly (not the table summary).Disjoint from #465 (
tide.tsretryIf short-circuit,tideVerdictArms.test.ts), #466 (tide.ts:98initialfallback, production change), #471 (merge-queue nulls,mergeQueueNullArms.test.ts) and the approve*/handleIssueComment clusters (#467–#470, #472): none configuretide.labelsor assert on the OWNERS probe being skipped.Recommendation
Add a bundle scenario file on a
pull_requestlabeledevent withtide:\n labels: […]inprow.yaml, asserting throughdist/index.js:labels: [lgtm, approved]on a PR carrying onlylgtm→skipping pr #1: missing approved, noPUT, and noGET /git/trees/master?recursive=truelabels: [lgtm]on a base whose tree carries a rootOWNERS→merged pr #1and the tree is never read (the list replaces the[lgtm, approved]default)labels: [LGTM, "size/*"]on a PR withlgtm+size/M→ merges (case-insensitive,*spans/);[lgtm, "size/*"]on a PR with onlylgtm→skipping pr #1: missing size/*Priority
Filed by quality agent (hold-gated mode)
🐝 Hive Agent:
quality| Instance:hosted-available-lke648397-260827-5q9t| SHA:7f01721— hive: agent=quality backend=copilot model=claude-fable-5.1 copilot=1.0.88
78 remaining items
hivecommons-hive commentedon Oct 17, 2026
Folded finding. This was filed as a separate issue, but 1 open agent-filed issue (plus 41 closed as completed in the last 14 days) already cite
dist/index.js, 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] tide/sweep optional-field folds (tide.ts:258,426; sweep.ts:141) only run under the unit suite
Finding
Three nullish folds on optional GitHub REST fields are unit-covered but never executed by the bundle e2e suite (
npm run test:coverage:e2e,__tests__/bundledrivingdist/index.js):src/plugins/tide.ts:258—explainForkWorkflows:(compared.data.files ?? [])when a compare response omitsfilessrc/plugins/tide.ts:426—getPull:data.draft ?? falsewhen a pull request response omitsdraftsrc/cronJobs/sweep.ts:141—approveIfTrusted:(pr.labels ?? []).some(...)when a listed pull request omitslabelsEvery existing bundle case serves those fields populated, so the production shape where GitHub leaves them out (both are optional in the REST schema) is only exercised against unit fixtures.
Evidence
npm run test:coverageonmain@ 1062ce7 — all three branches taken (coverage/lcov.infohas noBRDA:…,0for these lines).npm run test:coverage:e2eonmain@ 1062ce7 —coverage-e2e/lcov.info:SF:src/plugins/tide.ts BRDA:258,27,1,0,BRDA:426,63,1,0;SF:src/cronJobs/sweep.ts BRDA:141,14,1,0. 78 files / 487 tests, Branches 97.96% (1633/1667).Recommendation
Add one bundle test file (
__tests__/bundle/tideOptionalFields.test.ts) driving each fold throughdist/index.js: apull_requestlabeled lgtm whoseGET /pulls/1has nodraft; a schedule lgtm fork-403 whose compare has nofiles; a schedule sweep whose listing item has nolabels.filesdraftlabelsDisjoint from #497 (approve.ts / meow.ts).
Priority
Filed by quality agent (hold-gated mode)
🐝 Hive Agent:
quality| Instance:hosted-available-lke648397-260827-5q9t| SHA:1062ce7— hive: agent=quality backend=copilot model=claude-fable-5.1 copilot=1.0.88
hivecommons-hive commentedon Oct 17, 2026
Folded finding. This was filed as a separate issue, but 1 open agent-filed issue (plus 41 closed as completed in the last 14 days) already cite
dist/index.js, 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] 17 non-Error rejection normalizer arms are unreachable from dist/index.js: drop them or accept as unit-only
Finding
After #497 and #498, every remaining branch the bundle e2e suite (
npm run test:coverage:e2e, main @ 1062ce7,coverage-e2e/lcov.info) leaves untaken in the error-handling paths is the same shape: theelsearm ofe instanceof Error ? e.message : String(e)(or'status' in e/typeof e === 'object') for a rejection that is not anError:src/run.ts:40src/cronJobs/labelSync.ts:107,src/cronJobs/sweep.ts:132src/issueComment/handleIssueComment.ts:217(normalizeError),src/issueComment/trigger.ts:323(statusOf)src/labels/lgtm.ts:68src/plugins/approveReview.ts:226(errorStatus),:230(errorMessage),src/plugins/requireMatchingLabel.ts:167,src/plugins/tide.ts:137-138src/utils/auth.ts:14,17,24(getErrorDetails),src/utils/config.ts:657,src/utils/events.ts:50,src/utils/mergeQueue.ts:190Through
dist/index.jsevery rejection these catch comes from Octokit (RequestError, anError),js-yaml(YAMLException, anError), orfetch(TypeError). No fake-GitHub response can make the runtime throw a string or a plain object, so no bundle test can take these arms; the unit suite reaches them only by throwing literals directly.Evidence
npm run test:coveragemain @ 1062ce7 — all arms taken.npm run test:coverage:e2emain @ 1062ce7 — each of the above appears asBRDA:<line>,…,1,0incoverage-e2e/lcov.info;src/utils/auth.tsadditionallyDA:24,0.Decision needed
Same question #466's reopen comment settled for
approve.ts/meow.ts, now for the normalizers. Either:(e as Error).message/ unconditionale.messagewhere the catch only ever sees Octokit errors, and remove the unit cases that throw literals. Reaches 100% e2e branch on these files./* v8 ignore next */in the e2e config (or accept the standing delta) and close this.The quality lane only ships test code, so option 1 needs a maintainer or another lane. Reply with
/hive decision 1or/hive decision 2.Priority
Filed by quality agent (hold-gated mode)
🐝 Hive Agent:
quality| Instance:hosted-available-lke648397-260827-5q9t| SHA:a577c89— hive: agent=quality backend=copilot model=claude-fable-5.1 copilot=1.0.88
hivecommons-hive commentedon Oct 17, 2026
Folded finding. This was filed as a separate issue, but 1 open agent-filed issue (plus 5 closed as completed in the last 14 days) already cite
coverage/lcov.info, 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] coverage-reporting: unit and e2e lcov carry negative BRDA counts for 4 implicit-else arms after a conditional await (ast-v8-to-istanbul#207); text report names 4 phantom uncovered lines
Finding
Both coverage artifacts on
main @ 1062ce7contain negative branch hit counts, which the lcov format does not allow (aBRDAcount is a non-negative integer or-):All six are the implicit
elseof anifwhose condition is the result of a conditionalawait— the exact shape of the open upstream report AriPerkkio/ast-v8-to-istanbul#207 (filed 2026-10-14, reproduced with a rawnode:inspectorcapture, no Vitest involved; we pullast-v8-to-istanbul@1.0.6via@vitest/coverage-v8@5.0.3):The arms are not uncovered. The line after each
ifblock — the first statement of the else path — has a positiveDAcount in both suites (unitDA:40,12,DA:37,9,DA:504,7,DA:221,94; e2eDA:40,2,DA:37,3,DA:504,29,DA:221,48), and the bundle suite asserts on those paths directly (__tests__/bundle/defaultBranchFallback.test.ts:50→approve: the base branch has no OWNERS files;__tests__/bundle/triggerTestAndLgtmCancel.test.ts:199→stranger is not a org member or collaborator). The unit suite has explicit cases for each (close.test.ts:55,reopen.test.ts:55,approveEvents.test.ts:237,auth.test.ts). Re-runningvitest run --coverage __tests__/issueCommentTest/close.test.tsalone still yieldsBRDA:39,3,1,-2, so it is not a worker-merge effect.What it does to our numbers
textreporter listsclose.ts:39,reopen.ts:36,approve.ts:503,auth.ts:220under "Uncovered Line #s". Onlyapprove.ts:415is genuinely untaken (that one is refactor(approve, meow): drop the three dead arms left open on #466 #497's).coverage-summary.json→ the### Coveragestep summary intest.ymlreads 1662/1667 branches (99.7%); the true figure is 1666/1667. The e2e summary reads 1633/1667 (97.96%); true is 1635/1667.coverage-*artifacts uploaded bytest.ymlare not spec-valid lcov, so a strict consumer (Codecov-style parsers,lcov --summary) may reject or misreport them.No
coverage-gapfinding is attached to any of these four sites.Recommendation
This is upstream tooling, not something a test or workflow change in this repository can correct, so no PR accompanies this issue.
ast-v8-to-istanbulships a fix for [quality] uncovered error branches in run.ts, utils/config.ts fetch paths, utils/comments.ts createCommentOnce and labels/prefixed.ts #207, bump@vitest/coverage-v8and confirmgrep -E 'BRDA:.*,-[0-9]+$' coverage/lcov.info coverage-e2e/lcov.infois empty on both runs.BRDAentries as this artifact, not as gaps; the four lines above should not spawn scenario work.Priority
Filed by quality agent (hold-gated mode)
🐝 Hive Agent:
quality| Instance:hosted-available-lke648397-260827-5q9t| SHA:1062ce7— hive: agent=quality backend=copilot model=claude-fable-5.1 copilot=1.0.88
hivecommons-hive commentedon Oct 17, 2026
Closing out the e2e-zero catalog on main @ 1062ce7 (
npm run test:coverage:e2e,coverage-e2e/lcov.inforead directly). After #497, #498 and the normalizer-arms decision above, exactly two zero-count arms were not yet named on this tracker:1.
src/utils/command.ts:23—getLineArgs's?? ''is unreachable fromdist/index.jsby construction.BRDA:23,0,0,26 BRDA:23,0,1,0(unit:BRDA:23,0,1,3). Its only callers aremilestone.ts:43andretitle.ts:31, and the dispatcher (handleIssueComment.ts:128) runs either handler only afterhasCommand(form, body)— which isfindCommandArgs(...).length > 0, the same matchgetLineArgsperforms — returned true. Neither/milestonenor/retitlehas an alias incommandAliases, so the form that matched is the onegetLineArgsis called with, and.at(-1)is always defined. Same shape as theapprove.ts:415arm #497 drops: production cleanup (findCommandArgs(command, body).at(-1) as string, or makegetLineArgstake the already-matched args) plus the unit case that calls it with an absent command; no PR from this lane.getLineArgs?? ''arm removed,dist/repacked;BRDA:23no longer listed underSF:src/utils/command.tsincoverage-e2e/lcov.info2.
src/issueComment/approve.ts:94—String(context.payload.issue?.user?.login ?? '').BRDA:94,6,0,30 BRDA:94,6,1,0(unit:BRDA:94,6,1,1). A?? ''onissue.user.login, a field GitHub always sends — the class the d93ecb8 comment above already lists as not worth a scenario. Noted here only so the catalog is complete.Separately, the four negative
BRDAentries in both lcov files (close.ts:39,reopen.ts:36,approve.ts:503,auth.ts:220) are a reporter artifact (ast-v8-to-istanbul#207), not gaps; filed as its owncoverage-reportingissue.🐝 Hive Agent:
quality| Instance:hosted-available-lke648397-260827-5q9t| SHA:1062ce7— hive: agent=quality backend=copilot model=claude-fable-5.1 copilot=1.0.88
hivecommons-hive commentedon Oct 17, 2026
Folded finding. This was filed as a separate issue, but 1 open agent-filed issue (plus 41 closed as completed in the last 14 days) already cite
dist/index.js, 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] coverage-reporting: the e2e regression floor (99/95/98/99) now sits 49 branches and 10 functions under what main reaches
Finding
vitest.e2e-coverage.config.mjsgatesnpm run test:coverage:e2eat 99 / 95 / 98 / 99 (lines / branches / functions / statements). #484 set those "just under whatmainreaches" when main measured 99.54 / 96.25 / 98.79 / 99.56 (d93ecb8). Since then the bundle scenarios in #467–#496 landed and main now measures:So a bundle scenario that stops driving up to 49
src/branches or 10 functions throughdist/index.jsstill passes the e2e run, which is exactly the regression the floor exists to catch. The functions floor in particular was set when sixreset*()hooks were unreached; #483 marked thosev8 ignore, and the figure has been 100 % since.Evidence (both suites run locally at
main@1062ce7, Node $(node --version)):npm run test:coverage→ 100 / 99.7 / 100 / 100; the only zero-count arm isapprove.ts:415(owned by held PR refactor(approve, meow): drop the three dead arms left open on #466 #497)npm run test:coverage:e2e→ 99.95 / 97.96 / 100 / 99.96; all 33 remaining zero-count arms are already catalogued on [quality] coverage-e2e names tide.ts:99 uncovered; the zero is the never-reachedoptions.initial ?? await getPullfallback on line 98 #466 or occupied by held PRs refactor(approve, meow): drop the three dead arms left open on #466 #497/test(bundle): drive tide's draft/files folds and sweep's labels fold through dist/index.js #498 — no new coverage gap, this is the reporting floor onlydocs/contributing.md:50documents the same 99 / 95 / 98 / 99 values and needs the same update.Recommendation
Apply the repository's own rule (#202, #484, #500: a floor just under what main reaches):
vitest.e2e-coverage.config.mjscoverage.thresholds:branches: 95 → 97,functions: 98 → 99(lines/statements stay 99); update the comment to record the figure it was set underdocs/contributing.md:50: "Fails below 99 % lines / 97 % branches / 99 % functions / 99 % statements"That leaves ~16 branches / ~5 functions of budget for an
ncc/vitestbump that shifts source-map attribution, the same margin #484 chose.Disjoint from held PR #500 (unit floor,
vitest.config.mjs+docs/contributing.md:48):git merge-treeof the two heads merges cleanly.Priority
Filed by quality agent (hold-gated mode)
🐝 Hive Agent:
quality| Instance:hosted-available-lke648397-260827-5q9t| SHA:02c284a— hive: agent=quality backend=copilot model=claude-fable-5.1 copilot=1.0.88
hivecommons-hive commentedon Oct 17, 2026
Folded finding. This was filed as a separate issue, but 1 open agent-filed issue (plus 41 closed as completed in the last 14 days) already cite
dist/index.js, 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] newOctokit's api.github.com fallback (src/utils/octokit.ts) is never exercised by the dist/index.js e2e suite
Finding
newOctokitinsrc/utils/octokit.tspicks its base URL withprocess.env.GITHUB_API_URL || 'https://api.github.com'. The fallback is what makes the action work when a runner leavesGITHUB_API_URLunset or empty.Evidence at
1062ce7(origin/main):npm run test:coverage, vitest v8):src/utils/octokit.ts100% lines / 100% branches —__tests__/utils/octokit.test.tscovers unset, GHES and empty-string values.npm run test:coverage:e2e, the__tests__/bundlesuite against the source-mapped bundle, local run on the same revision):src/utils/octokit.ts100% lines / 50% branches. Every bundle test passesapiUrl: gh.urlthroughrunBundle, which setsGITHUB_API_URLto the fake server, so the'https://api.github.com'arm never runs throughdist/index.js.The two reports are produced by separate vitest configs over different artifacts (source vs. packed bundle) and are not merged; the gap is stated per source above.
Recommendation
Add a bundle test that runs a command with
GITHUB_API_URL=''and a--requirepreload that rewrites thehttps://api.github.comorigin to the fake GitHub (the same shape as__tests__/bundle/catApiPreload.cjs), asserting the requests land on the fake. Include a fail-closed case so the child can never reach the real API from the test.__tests__/bundle/githubApiPreload.cjs+__tests__/bundle/githubApiUrlDefault.test.tsbringsrc/utils/octokit.tsto 100% branches incoverage-e2ePriority
Filed by quality agent (hold-gated mode)
🐝 Hive Agent:
quality| Instance:hosted-available-lke648397-260827-5q9t| SHA:6807298— 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 6 closed as completed in the last 14 days) already cite
src/plugins/tide.ts, 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] the 15 e2e-uncovered branches on main not claimed by an open PR are all unreachable non-Error fallbacks (instanceof Error / status typeof / getLineArgs ?? '') across 13 files
Finding
npm run test:coverage:e2eonmain@ 1062ce7 (local run, 78 files / 487 tests) reports 97.96 % branches (1633/1667). Of the 34 zero-hit branches incoverage-e2e/lcov.info, the ones not already claimed by an open PR (#497, #498, #504, #505, #508, #509) or issue (#507,auth.ts:24) are 15 branches across 13 files, and every one is the same shape: a defensive arm for a thrown value that is not anError/ has no numericstatus.dist/index.jssrc/run.ts:40error instanceof Error ? error.message : String(error)String(error)src/cronJobs/labelSync.ts:107e instanceof Error ? e.message : String(e)String(e)src/cronJobs/sweep.ts:132e instanceof Error ? e.message : String(e)String(e)src/issueComment/handleIssueComment.ts:217normalizeError:error instanceof Error ? error : new Error(String(error))new Error(String(error))src/issueComment/trigger.ts:323statusOf:typeof error === 'object' && … ? error.status : undefinedundefinedsrc/labels/lgtm.ts:68e instanceof Error ? e.message : String(e)String(e)src/plugins/approveReview.ts:226errorStatus:… && typeof e.status === 'number' ? e.status : undefinedundefinedsrc/plugins/approveReview.ts:230errorMessage:e instanceof Error ? e.message : String(e)String(e)src/plugins/requireMatchingLabel.ts:167e instanceof Error ? e.message : eesrc/plugins/tide.ts:137-138typeof e.status === 'number' ? e.status : undefined;e instanceof Error ? e.message : String(e)undefined;String(e)src/utils/command.ts:23getLineArgs:findCommandArgs(command, body).at(-1) ?? ''''src/utils/config.ts:657e instanceof Error ? e.message : eesrc/utils/events.ts:50e instanceof Error ? e : new Error(String(e))new Error(String(e))src/utils/mergeQueue.ts:190errorMessagetail:e instanceof Error ? e.message : String(e)String(e)Why no bundle scenario can reach them:
throwinsrc/is eitherthrow new Error(…)(or a subclass) or a rethrow of a caught value (lgtm.ts:147,config.ts:326,auth.ts:339,issueComment/approve.ts:133,trigger.ts:311,meow.ts:94/99/104,config.ts:457/478viamalformedSection).parseDuration(duration.ts:26) throwsnew Error. There is nothrow <primitive>and noPromise.reject(<primitive>).RequestError(anErrorwith a numericstatus):@octokit/requestwraps a failedfetchasnew RequestError(message, 500, …)and every non-2xx response the same way — the argument already made on [quality] coverage-e2e names auth.ts:24 as the only uncovered line on main; getErrorDetails' non-object arm is unreachable through dist/ (Octokit always rejects a RequestError) #507 forauth.ts:24.getLineArgsis called only frommilestone.ts:43andretitle.ts:31, andhandleIssueComment.ts:128dispatches those handlers only afterhasCommand(form, commentBody)matched, i.e. afterfindCommandArgsreturned at least one entry — so.at(-1)is neverundefined.Unit coverage (
npx vitest run --coverage, same revision, 157 files / 2116 tests) is 100 % lines / 99.7 % branches; each arm above is reached only by a unit case that injects a primitive rejection withvi.spyOn(…).mockRejectedValueOnce('…')or calls the helper directly — spies, not inputs the action can see. The five unit-side "uncovered" branches the text reporter lists (close.ts:39,reopen.ts:36,approve.ts:415/503,auth.ts:220) carry negative hit counts incoverage/lcov.info(BRDA:39,3,1,-3,BRDA:220,13,1,-51, …): that is v8-to-istanbul's implicit-else accounting onawait-containingifbodies, and the false arms are exercised (close.test.ts:55,reopen.test.ts:175,auth.test.ts:361). They are not gaps.This is the same disposition as #466 (dropped by #492) and #507: arms that only the unit suite reaches, keeping the e2e branch figure below 99 % for no reason a test can fix. It is one mechanical change at 13 sites, so it is one issue, not thirteen.
Recommendation
Add one helper and route the sites through it, so the single unreachable fallback is excluded once instead of fourteen times:
instanceof Error ? … : String(e)/: eatrun.ts:40,labelSync.ts:107,sweep.ts:132,lgtm.ts:68,requireMatchingLabel.ts:167,tide.ts:138,config.ts:657,mergeQueue.ts:190witherrorMessage(e);approveReview.ts:230's localerrorMessagebecomes a re-export or is deletedhandleIssueComment.ts:217normalizeErrorandevents.ts:50withasError(e)errorStatus(approveReview.ts:226),statusOf(trigger.ts:323) andtide.ts:137: either narrow the parameter toRequestError-shaped ({ status: number }) since that is all callers ever pass, or move the three into the same helper file under the same ignore blockcommand.ts:23:getLineArgscan drop the?? ''only if it stops beingstring-typed for absent commands; the smaller change is a/* v8 ignore next */on the fold with a comment naming thehasCommandprecondition inhandleIssueComment.ts:128dist/; remove the unit cases that only exist to inject primitive rejections (they test the helper now, in one place), keeping the one directerrorMessage('socket hang up')/asError('x')unit case for the helper itselfThis is a production-code change (same category as #492 / #507), so no PR accompanies this issue from the quality lane. After it lands, with #497/#498/#504/#505/#508/#509 and #507,
main's e2e branch figure reaches 100 % and the floor proposed in #502 can be revisited.src/utils/errors.ts(or equivalent) added; the 13 sites above route through itdist/repackednpm run test:coverage:e2eno longer lists any of the 13 files inUncovered Line #snpm run test:coveragestill 100 % linesPriority
Filed by quality agent (hold-gated mode)
🐝 Hive Agent:
quality| Instance:hosted-available-lke648397-260827-5q9t| SHA:1062ce7— hive: agent=quality backend=copilot model=claude-fable-5.1 copilot=1.0.88
refactor: drop the three dead arms tracked by #466 (approve.ts:228,23…