You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
In _classify_issue (gittensor/validator/issue_discovery/mirror_scan.py), a solving PR reported with state == 'MERGED' but merged_at is None is not gated. The record reaches _mirror_issue_for_scoring, which correctly drops it as unscoreable — but only aftertotal_solved_issues and total_valid_solved_issues have already been incremented.
A single corrupted record can therefore push a miner from valid_solved_count == MIN_VALID_SOLVED_ISSUES - 1 (ineligible) to MIN_VALID_SOLVED_ISSUES (eligible), flipping is_issue_eligible and producing a non-zero issue_discovery_score from the other valid records that would otherwise be discarded.
The OSS mirror scoring path already rejects this exact shape with a "MERGED but missing merged_at" guard; the issue-discovery path was missing the equivalent gate.
Steps to Reproduce
Set up a miner with exactly MIN_VALID_SOLVED_ISSUES - 1 clean solved mirror issues (one short of the eligibility floor).
Add one mirror issue whose solving_pr.state == 'MERGED' and solving_pr.merged_at is None.
Run run_mirror_issue_discovery against this miner.
Expected Behavior
The corrupted record is bucketed as not-solved-closed. total_valid_solved_issues stays at MIN_VALID_SOLVED_ISSUES - 1, is_issue_eligible is False, and issue_discovery_score is 0.
Actual Behavior
_classify_issue returns 'solved'. total_solved_issues and total_valid_solved_issues are incremented to MIN_VALID_SOLVED_ISSUES. _mirror_issue_for_scoring then drops the corrupted record, but the eligibility flag has already flipped to True, and the miner receives a non-zero issue_discovery_score derived from the other valid records.
Description
In
_classify_issue(gittensor/validator/issue_discovery/mirror_scan.py), a solving PR reported withstate == 'MERGED'butmerged_at is Noneis not gated. The record reaches_mirror_issue_for_scoring, which correctly drops it as unscoreable — but only aftertotal_solved_issuesandtotal_valid_solved_issueshave already been incremented.A single corrupted record can therefore push a miner from
valid_solved_count == MIN_VALID_SOLVED_ISSUES - 1(ineligible) toMIN_VALID_SOLVED_ISSUES(eligible), flippingis_issue_eligibleand producing a non-zeroissue_discovery_scorefrom the other valid records that would otherwise be discarded.The OSS mirror scoring path already rejects this exact shape with a "MERGED but missing merged_at" guard; the issue-discovery path was missing the equivalent gate.
Steps to Reproduce
MIN_VALID_SOLVED_ISSUES - 1clean solved mirror issues (one short of the eligibility floor).solving_pr.state == 'MERGED'andsolving_pr.merged_at is None.run_mirror_issue_discoveryagainst this miner.Expected Behavior
The corrupted record is bucketed as
not-solved-closed.total_valid_solved_issuesstays atMIN_VALID_SOLVED_ISSUES - 1,is_issue_eligibleisFalse, andissue_discovery_scoreis0.Actual Behavior
_classify_issuereturns'solved'.total_solved_issuesandtotal_valid_solved_issuesare incremented toMIN_VALID_SOLVED_ISSUES._mirror_issue_for_scoringthen drops the corrupted record, but the eligibility flag has already flipped toTrue, and the miner receives a non-zeroissue_discovery_scorederived from the other valid records.Environment
testbranch HEAD (pre-fix)Additional Context
gittensor/validator/issue_discovery/mirror_scan.py—_classify_issue.gittensor/validator/oss_contributions/mirror/scoring.py("MERGED but missing merged_at" rejection).sp.merged_at is None → 'not-solved-closed'branch in_classify_issueafter thestate != 'MERGED'check, so the gate fires before the counters increment. See PR fix: gate MERGED solving PRs missing merged_at in mirror issue discovery #920.