diff --git a/gittensor/validator/issue_discovery/scan.py b/gittensor/validator/issue_discovery/scan.py index c30a12e3..5c9c6234 100644 --- a/gittensor/validator/issue_discovery/scan.py +++ b/gittensor/validator/issue_discovery/scan.py @@ -463,11 +463,10 @@ async def _score_miner_issues( ) continue - # Valid-solved gate: solving PR must meet the repo's token threshold. - if cached.token_score >= cfg.min_token_score_for_valid_issue: - acc.valid_solved += 1 - - # Same-account: discoverer == solver gets credibility only, no score + # Same-account: discoverer == solver gets credibility only, no score. + # Must run before the valid-solved increment so self-loops don't satisfy + # the MIN_VALID_SOLVED_ISSUES eligibility gate (see module docstring: + # anti-self-issue is an applied anti-gaming gate). if issue.author_github_id == solving_pr.author_github_id: bt.logging.debug( f' issue #{issue.issue_number} ({issue.repo_full_name}): same-account ' @@ -475,6 +474,10 @@ async def _score_miner_issues( ) continue + # Valid-solved gate: solving PR must meet the repo's token threshold. + if cached.token_score >= cfg.min_token_score_for_valid_issue: + acc.valid_solved += 1 + pr_key = (issue.repo_full_name, solving_pr.pr_number) own_marker = (issue.created_at or _FAR_FUTURE, issue.issue_number, evaluation.uid) if canonical_pr_owners.get(pr_key) != own_marker: diff --git a/tests/validator/issue_discovery/test_scan.py b/tests/validator/issue_discovery/test_scan.py index bc994c67..5cecbbdf 100644 --- a/tests/validator/issue_discovery/test_scan.py +++ b/tests/validator/issue_discovery/test_scan.py @@ -307,7 +307,11 @@ def test_self_issue_counts_credibility_but_no_score(self): ) ) assert eval_.total_solved_issues == 1 # credibility counts - # But no discovery_earned_score because self-solve + # Self-solves must NOT contribute to the valid-solved gate — otherwise + # a miner could self-file + self-solve to bypass MIN_VALID_SOLVED_ISSUES + # without performing any discovery activity. + assert eval_.total_valid_solved_issues == 0 + # And no discovery_earned_score because self-solve assert eval_.issue_discovery_score == 0 def test_not_planned_bumps_closed_count(self):