Skip to content

[Bug] Mirror issue-discovery open_issue_count inflates spam multiplier by including transferred-OPEN issues that are otherwise classified as 'ignore' #1007

@hera8939

Description

@hera8939

Bug

gittensor/validator/issue_discovery/mirror_scan.py:174 computes the spam-multiplier signal:

open_issue_count = sum(1 for i in filtered if i.state == 'OPEN')

This count includes issues whose is_transferred == True. Everywhere else in the same module, transferred issues are treated as having no scorable meaning at all:

  • Module docstring lines 12-19 list "not issue.is_transferred" among the anti-gaming gates.
  • _classify_issue (line 468-470) returns 'ignore' for transferred issues regardless of state.

The spam-multiplier path is the only place in the module that treats transferred-OPEN issues as if they were real OPEN issues this miner is responsible for.

Source

mirror_scan.py:169-175:

# Count this miner's currently-open issues across mirror-enabled repos
# (within the lookback window). Used as the spam-multiplier signal and
# also written to evaluation.total_open_issues so the DB row reflects
# mirror-scoped state ...
open_issue_count = sum(1 for i in filtered if i.state == 'OPEN')   # ← does not filter is_transferred
pending.append((evaluation, filtered, open_issue_count))

mirror_scan.py:458-470 (the canonical "no scorable meaning" check):

def _classify_issue(issue: MirrorIssue) -> str:
    """Return 'solved', 'not-solved-closed', or 'ignore' per anti-gaming gates.

    'ignore' = issue is open / transferred / has no scorable meaning at all.
    ...
    """
    if issue.is_transferred:
        bt.logging.debug(f'  issue #{issue.issue_number} ({issue.repo_full_name}): ignore (transferred)')
        return 'ignore'

Impact

  1. Inflated spam multipliercalculate_open_issue_spam_multiplier(open_issue_count, …) reads the inflated count and reduces the per-solved-issue discovery score. A miner with 5 legitimate OPEN issues plus 3 transferred-OPEN issues gets penalized as though they had 8 currently-open issues.

  2. Corrupted DB audit rowmirror_scan.py:376 writes evaluation.total_open_issues = open_issue_count. The miner_evaluations row carries the inflated number, so analytics queries (SELECT total_open_issues …) show miners as having more open issues than they actually own.

  3. Asymmetric anti-gaming — the docstring promises that transferred issues "have no scorable meaning at all," but they DO have negative scoring meaning via the spam multiplier path. An attacker controlling repo administration could file an issue, transfer it to a target miner's tracking surface, and inflate that miner's spam count even though the issue itself can never score.

Reproduction

Construct a MirrorIssue list containing two entries:

  • state='OPEN', is_transferred=False
  • state='OPEN', is_transferred=True

Drive them through _score_miner_mirror_issues. Observe open_issue_count == 2. Observe the resulting spam multiplier as if both issues were real. Then mark is_transferred=False on the second issue and run again — multiplier changes, demonstrating the transferred issue affected the score.

Suggested fix

One-line change at line 174:

open_issue_count = sum(1 for i in filtered if i.state == 'OPEN' and not i.is_transferred)

Optionally, add a regression test that asserts transferred-OPEN issues do not contribute to open_issue_count and total_open_issues.

Related

  • #929 / #930 address a different gap on the same line — old still-open issues outside the lookback window being undercounted. Fixing that does not address transferred-issue inclusion; the two filters are independent.
  • The merged #796 introduced this scoring path with is_transferred already being a recognized "ignore" signal in _classify_issue; the omission in the spam-count branch appears to be an oversight rather than a deliberate semantic choice.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions