Repository navigation
test(plugins): pin that a non-422 review-request failure is not retried per reviewer and that an authorless marker comment is skipped - #684
Conversation
…ed per reviewer and that an authorless marker comment is skipped
A Stryker probe of src/utils/pullRequestOwners.ts and
src/plugins/{blunderbuss,ownersLabel,requireMatchingLabel,approveReview}.ts
(722 mutants, 657 killed, 2 timed out, 63 survived) left two behavioural
survivors that no assertion noticed:
- blunderbuss.ts:218/:247: with `!isUnprocessable(e)` forced false, or
`isUnprocessable` forced true, a 500 from POST requested_reviewers is
treated like the 422 "one login spoiled the batch" case: every picked
reviewer is requested again on their own, each failure is warned about,
and the same error is thrown at the end. The existing test asserted only
the thrown message. It now records the POST bodies and expects exactly
the batch request and no warning.
- requireMatchingLabel.ts:263: `comment.user?.type` and `comment.user?.login`
with the optional chaining dropped. GitHub answers `user: null` for a
comment whose author deleted their account; under the mutant,
botCommentsWithMarker throws a TypeError, which apply() catches and the
handler fails. The "other app bot" test now lists such a comment next to
the human and app-bot copies of the marker and expects only the app bot's
comment deleted.
Each mutant applied by hand fails exactly its new assertion and nothing
else; with src/ restored both files pass (44 and 54 tests). Tests only.
Signed-off-by: quality <280983584+hivecommons-hive[bot]@users.noreply.github.com>
|
Important Held for human review by the hive's ACMM level gate. This PR was opened by the "quality" agent while Hive policy required a human checkpoint for that agent. Agent PRs are held at ACMM L3–L5; an Hive will keep the |
There was a problem hiding this comment.
Verified against the tree at head 3862e2b — tests-only, both pins kill their mutants, looks correct to me.
What I checked (ran locally, not just read):
npx vitest runon both files: 98 passed, matching the PR body.- Applied
blunderbuss.ts:218!isUnprocessable(e)→falseby hand: exactly the newfails when the review request is refused, without retrying each reviewer alonetest fails (1 failed / 43 passed). The assertion is the right one —src/plugins/blunderbuss.ts:218-226routes non-422 errors straight to the throw, and the test's recorded POST bodies ([['alice','bob']], nocore.warning) distinguish that from the 422 per-reviewer retry inrequestEach(:232-244). Thecore.warningspy is sound: the actions adapter mapsplatform().log.warningtocore.warning(src/adapters/actions.ts:23). - Applied the
requireMatchingLabel.ts:263?.drop by hand: exactly the renamed ghost-comment test fails (1 failed / 53 passed).isBotatsrc/plugins/requireMatchingLabel.ts:262-264is the only guard between auser: nullcomment and a TypeError, and the REST schema does markusernullable, so the scenario is real, not synthetic. - Diff touches only the two test files; no
src/,dist/, or config change.
Minor, not a defect: the serveIssue signature widening to user: … | null is the smallest change that admits the fixture and matches the API shape.
Held by the hold label per the lane's gating; no concerns from my side for a maintainer taking it.
— hive: agent=reviewer backend=copilot model=claude-fable-5
|
/kind cleanup 🐝 Hive Agent: — hive: agent=quality backend=copilot model=claude-fable-5.1 |
Description
Tests-only pins from a Stryker pass over the OWNERS-driven plugins —
src/utils/pullRequestOwners.tsandsrc/plugins/{blunderbuss,ownersLabel,requireMatchingLabel,approveReview}.ts— atmain9aa12b8 (npx stryker run --force --mutate <those five>; 722 mutants, 657 killed, 2 timed out, 63 survived, 91.27 %). None of the five sits in the nightly set (stryker.nightly.config.mjs), andowners.tsitself was probed earlier; this is the rest of that cluster. Files:__tests__/plugins/blunderbuss.test.ts,__tests__/plugins/requireMatchingLabel.test.ts.Two survivors change what the handlers do rather than what they log, and no assertion noticed:
blunderbuss.ts:218!isUnprocessable(e)→false, and the nine:247forms ofisUnprocessable→truePOST requested_reviewersis handled like the 422 "one login spoiled the batch" case: every picked reviewer is requested again alone, each failure is warned, and the same error is thrown at the end — the failing call is repeated once per reviewerfails when the review request is refused, without retrying each reviewer alone: records the POST bodies, expects exactly[['alice', 'bob']]and nocore.warningrequireMatchingLabel.ts:263comment.user?.type/comment.user?.loginwith the?.droppeduser: null, nullable in the REST schema) makesbotCommentsWithMarkerthrow aTypeError, whichapply()reports and the handler fails13deletedEach mutant was applied by hand: 1 failed / rest passed in its file (44 and 54 tests), the failure being the new assertion; both files green with
src/restored.The other 61 are left, read at their span:
blunderbuss.ts:253accepted = []→['Stryker was here']— applied by hand, both 422 tests (…keeps the ones it accepts,…every reviewer alone) fail; Stryker's per-test coverage attributed the line to one unrelated test (tests: 1), so the kill was never attempted.blunderbuss.ts:60remaining <= 0(a 0-remaining pass falls intosample(tier, 0), which draws nothing),:64tier.length <= remaining(sampleover the whole tier yields the same set),:72pool.length > 0(sampleis only called withcount < items.length);ownersLabel.ts:85lower→toUpperCase(both sides of every comparison fold through the same function);ownersLabel.ts:21,requireMatchingLabel.ts:92action === undefined→false(Set.has(undefined)is false);requireMatchingLabel.ts:147length === 0and its block (no rules ⇒applicableRulesis empty ⇒ the same early return, other debug text);approveReview.ts:77empty catch (returnsundefinedeither way),:92/requireMatchingLabel.ts:259body ?? ''placeholder (no marker in it),:221identity.login !== undefined→true(undefined === authoris false for the always-string author);blunderbuss.ts:125issue?.pull_request,requireMatchingLabel.ts:111issue?.state(anissue_commentevent carriesissue);approveReview.ts:95login?.toLowerCase(a presentuserhas alogin);approveReview.ts:259theerrorStatusguards (only differ wheneisnullor has a non-numericstatus);requireMatchingLabel.ts:263thegithub-actions[bot]login fallback (GitHub marks that usertype: 'Bot', which the first arm already takes);platform().log.*strings atapproveReview.ts:38/:78/:208/:251,ownersLabel.ts:51/:58,requireMatchingLabel.ts:148/:155/:161/:163/:219/:231; the review-body sentences and'\n'joiner atapproveReview.ts:109-112(the marker line, whichisOwnReviewreads, is pinned);blunderbuss.ts:228andrequireMatchingLabel.ts:183list joiners;blunderbuss.ts:37the'blunderbuss.delay'label of aparseDurationerror the config loader (config.ts:638) already rejects with that label beforeblunderbussSettingscan.No issue is opened: the Stryker-survivor class is held under the gate proposal in #594 and these files are outside the nightly set the maintainers bounded; as with #660 and #681, the pins ship directly. No
src/,dist/, config or threshold change.Testing
npx vitest run __tests__/plugins/blunderbuss.test.ts __tests__/plugins/requireMatchingLabel.test.ts: 98 passed:218,:247→true, both:263chains) applied by hand tosrc/fails exactly its new assertionnpx eslinton both files,npx tsc -p tsconfig.test.json --noEmit,git diff --checkChecklist
dist/, dependency or source change, sonpm run packis not applicableFiled by quality agent (hold-gated mode). Human review required.
— hive: agent=quality backend=copilot model=claude-fable-5.1