Skip to content

fix(mirror): coerce null author_login so ghost-authored merged PRs aren't dropped#1632

Open
ebios-star wants to merge 1 commit into
entrius:testfrom
ebios-star:fix/mirror-null-author-login
Open

fix(mirror): coerce null author_login so ghost-authored merged PRs aren't dropped#1632
ebios-star wants to merge 1 commit into
entrius:testfrom
ebios-star:fix/mirror-null-author-login

Conversation

@ebios-star

Copy link
Copy Markdown
Contributor

Bug

MirrorPullRequest.author_login is typed str, but from_dict parses it with data.get('author_login', ''). That default is only used when the key is absent — an explicit JSON null returns None, not ''. The mirror serializes author_login: null for a ghost/deleted GitHub author, so None slips into a field the rest of the code treats as a str.

That None then reaches the merged-PR eligibility gate in _should_skip_merged_mirror_pr:

if pr.merged_by_login and pr.merged_by_login.lower() == pr.author_login.lower():

None.lower() raises AttributeError. The crash is swallowed by the load-time except Exception in _maybe_add_pr, so the PR is never appended to merged_prs — a legitimately merged contribution is silently dropped, lowering that miner's merged_count / credibility.

Fix

Coerce the null to '' exactly the way the sibling review_summary or {} and labels or [] fields in the same constructor already handle an explicit null, honouring the declared str type. A null author can't be a self-merge, so '' correctly fails the self-merge comparison instead of crashing.

The other login-bearing model, MirrorIssue, is intentionally typed Optional[str] and is left untouched.

Tests

  • test_mirror_models.py: author_login null / absent both parse to ''.
  • test_scoring.py: the self-merge gate no longer raises on a null-author merged PR (reproduces the swallowed AttributeError before the fix).

Full suite green (967 passed); ruff check, ruff format --check, and pyright clean.

@xiao-xiao-mao xiao-xiao-mao Bot added the bug Something isn't working label Jul 14, 2026
…en't dropped

MirrorPullRequest.author_login is typed `str`, but from_dict parsed it with
`data.get('author_login', '')`. That default only applies when the key is
absent — an explicit JSON `null` (which the mirror serializes for a
ghost/deleted GitHub author) passes straight through as `None`.

A `None` author_login then reaches the merged-PR eligibility gate, where
`_should_skip_merged_mirror_pr` does
`pr.merged_by_login.lower() == pr.author_login.lower()`. `None.lower()`
raises AttributeError, which `_maybe_add_pr`'s load-time `except Exception`
swallows — so the PR is silently dropped from `merged_prs` and the miner
loses credit for a legitimately merged contribution.

Coerce the null to '' the same way the sibling `review_summary or {}` /
`labels or []` fields in the same constructor already do, honouring the
declared `str` type. The other login-based model (MirrorIssue) is typed
`Optional[str]` and is intentionally left untouched.

Adds regression tests at both the parse boundary (null/absent -> '') and the
crash site (the self-merge gate no longer raises on a null author).
@ebios-star ebios-star force-pushed the fix/mirror-null-author-login branch from 7b154a0 to 7743b16 Compare July 14, 2026 05:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant