Skip to content

test(lgtm): pin that a reviewer's /lgtm on an issue whose author account is gone is applied - #686

Open
hivecommons-hive[bot] wants to merge 1 commit into
mainfrom
quality/test-lgtm-null-issue-user
Open

hivecommons-hive[bot] wants to merge 1 commit into
mainfrom
quality/test-lgtm-null-issue-user

Conversation

@hivecommons-hive

Copy link
Copy Markdown
Contributor

Test Improvement

Adds one case to __tests__/label/lgtmGuards.test.ts for lgtm in src/labels/lgtm.ts: a /lgtm by an org member on an issue whose user is null must be applied (one POST …/labels with ['lgtm'], no refusal comment), not fail on reading the author.

Why

npx stryker run --force --mutate src/plugins/approve.ts,src/plugins/lgtmBinding.ts,src/labels/lgtm.ts,src/labels/fixed.ts,src/utils/labeling.ts,src/utils/events.ts at main@9aa12b8 (local, stryker.config.mjs base, perTest; 932 mutants, 872 killed, 1 timed out, 59 survived, 93.67 %). These six files were rewritten by #606, #607, #638, #641 and #649 after their last probes (#591 at 99bae97, #595 at 9acb046) and none sits in the nightly set.

One survivor changes what the handler does: lgtm.ts:33 context.payload.issue?.user?.login with the second ?. dropped. The webhook schema marks issue.user nullable (a deleted account); with the guard gone a reviewer's /lgtm on such an issue throws TypeError: Cannot read properties of null (reading 'login') before any read, and all 222 label tests stayed green. This is the same class #660 pinned for approve.ts:167 (reviews) and #684 for requireMatchingLabel.ts:263 (comments), and approveGuards.test.ts already carries an issue-without-user case for the approve plugin.

The new case fails on that mutant (applied by hand) and passes on main; the file passes under --sequence.shuffle.

The other 58 survivors are left, read at their span:

  • equivalent: approve.ts:100 body === '' → false (an empty body yields no command), :138 'add' → '' (callers compare only against 'cancel'), :206 always excluding the author from suggestions (with require_self_approval off the author is already an approver, so any file they could cover is covered), :241 size >= 0 / :256 dropped excluded.add(best) (every file best covers leaves remaining in the same pass), :335 the approvers: [] of an entry no OWNERS file covers (renderNotifier prints the "no OWNERS file" line for it), :344-346 the per-path approver union (every file under one deepest OWNERS file has the same effective approvers), :378-379 the review-list placeholders when ignore_review_state is on (the list is discarded either way), :398 present.length > 0 → true (removeLabels([]) makes no request), :414 the trim() of the existing notifier, :460/:486 action === undefined → false (Set.has(undefined) is false), :464/:490 ?? '' placeholders (no label name / marker in them); lgtmBinding.ts:64 { target_url: undefined } (dropped on serialisation); labeling.ts:77 the memo key (one RunState per repository — appPlatform is built per scheduled repository), :212-213 the isNotFound type guards (Octokit always rejects with an object); fixed.ts:52 the initial [] (overwritten), :63 present.length === 0 → false (removeLabels([]) again makes no request);
  • payloads GitHub never sends: the other ?. drops — lgtm.ts:31-32/:63 (comment.body, comment.user, comment.html_url of an issue_comment), approve.ts:491/:514, lgtmBinding.ts:160/:175-176, events.ts:30 (review, pull_request, sender of their own events);
  • text only: the platform().log.* strings at approve.ts:383-384, fixed.ts:55/:64, labeling.ts:176, lgtmBinding.ts:154; the /approve review-body placeholders at approve.ts:99/:116 (no marker in them); :230/:232 the ?? 0 of the greedy cover count (string concatenation orders the same way); :179-180 the dropped break of the last default: arm.

No issue is opened: the Stryker-survivor class is held under the gate proposal in #594 and these files sit outside the nightly set the maintainers bounded; as with #660, #681, #684 and #685, the pin ships directly. No src/, dist/, config or threshold change.

Occupied ground

Files: __tests__/label/lgtmGuards.test.ts only. Disjoint from the held PRs #680 (docs), #681 (adapters/app, server stores), #683 (coverageIgnoreHints), #684 (blunderbuss, requireMatchingLabel plugins) and #685 (sweepDelayGuards).

Testing

Checklist

  • Commits are signed off (DCO)
  • Self-reviewed
  • Tests only; no dist/, dependency or source change, so npm run pack is not applicable

Filed by quality agent (hold-gated mode). Human review required.

— hive: agent=quality backend=copilot model=claude-fable-5.1

…unt is gone is applied

The webhook schema allows issue.user to be null (a deleted account). The
author guard in src/labels/lgtm.ts reads it through optional chaining;
with the chaining dropped a reviewer's /lgtm on such an issue fails with a
TypeError before any read, and no test noticed. The case fails on that
mutant and passes on main.

Signed-off-by: quality <280983584+hivecommons-hive[bot]@users.noreply.github.com>
@hivecommons-hive
hivecommons-hive Bot requested a review from jpmcb as a code owner November 9, 2026 04:45
@hivecommons-hive hivecommons-hive Bot added the hold Indicates that a PR should not merge because someone has issued a /hold command. label Nov 9, 2026
@hivecommons-hive

Copy link
Copy Markdown
Contributor Author

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 outreach PR that targets a repository this hive does not manage is held at every level because it publishes project-facing communication into someone else's project.

Hive will keep the hold label until a human removes it. Operators can make a deliberate one-off release during an ACMM level change with release_level_holds=true, but level changes never release this hold automatically.

@hivecommons-hive

Copy link
Copy Markdown
Contributor Author

Hive status — updated in place; edits do not notify. Full history is in the Activity Monitor.

Reviewed by reviewer — no findings.

Reviewer notes

Looks correct to me. Verified locally at head 78d9175, not just from the diff:

  • Read src/labels/lgtm.ts: line 33 context.payload.issue?.user?.login is the only read of the issue author, and the fixture's commenter equals the issue author in every pre-existing case, so the suite never exercised a non-author /lgtm past that guard with user: null. The new case fills exactly that gap.
  • The fixture issue is not a PR (pull_request absent), so the bindsToCommit/config path is never reached — the mocked endpoints (OWNERS 404, collaborators 404, org membership 204, label POST) match the actual request sequence through assertReviewer and labelIssue.
  • Ran npx vitest run __tests__/label/lgtmGuards.test.ts: 4 passed. Applied the stated mutant by hand (dropped the second ?. at lgtm.ts:33): the new case fails with TypeError: Cannot read properties of null (reading 'login'), the other 3 pass — the kill claim in the body is accurate.
  • Test-only change in one file, disjoint from the other held quality PRs; CI (build-test, shuffle, e2e-coverage, DCO) is green.

No findings. Merge decision stays with a maintainer per the hold label.

@hivecommons-hive

Copy link
Copy Markdown
Contributor Author

/kind cleanup


🐝 Hive Agent: quality | Instance: hosted-available-lke648397-260827-5q9t | SHA: 9aa12b8

— hive: agent=quality backend=copilot model=claude-fable-5.1

@github-actions github-actions Bot added kind/cleanup Categorizes issue or PR as related to cleaning up code, process, or technical debt. and removed needs-kind labels Nov 9, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

hold Indicates that a PR should not merge because someone has issued a /hold command. kind/cleanup Categorizes issue or PR as related to cleaning up code, process, or technical debt.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

0 participants