From a7c4abae8dcea88a8bdf2e158b921a2fc11dda03 Mon Sep 17 00:00:00 2001 From: Desel72 <6442298+Desel72@users.noreply.github.com> Date: Thu, 14 May 2026 14:47:21 +0200 Subject: [PATCH 1/3] fix(issue-discovery): ignore zero-share repos --- gittensor/validator/issue_discovery/scan.py | 8 ++- tests/validator/issue_discovery/test_scan.py | 67 ++++++++++++++++++++ 2 files changed, 72 insertions(+), 3 deletions(-) diff --git a/gittensor/validator/issue_discovery/scan.py b/gittensor/validator/issue_discovery/scan.py index 1afa8557..e016e698 100644 --- a/gittensor/validator/issue_discovery/scan.py +++ b/gittensor/validator/issue_discovery/scan.py @@ -129,7 +129,9 @@ async def run_issue_discovery( client = client or MirrorClient() lookback_date = datetime.now(timezone.utc) - timedelta(days=PR_LOOKBACK_DAYS) - enabled_names: Set[str] = set(mirror_repos.keys()) + issue_enabled_names: Set[str] = { + name for name, config in mirror_repos.items() if config.issue_discovery_share > 0.0 + } solving_pr_cache: Dict[Tuple[str, int], CachedSolvingPR] = _build_solving_pr_cache(miner_evaluations) cache_stats = _CacheStats() @@ -171,8 +173,8 @@ async def run_issue_discovery( fetch_errors += 1 continue - open_issue_count = _count_open_issues(current_response.issues, enabled_names) - filtered = [i for i in response.issues if i.repo_full_name in enabled_names] + open_issue_count = _count_open_issues(current_response.issues, issue_enabled_names) + filtered = [i for i in response.issues if i.repo_full_name in issue_enabled_names] if not filtered: _clear_issue_discovery_fields(evaluation) evaluation.total_open_issues = open_issue_count diff --git a/tests/validator/issue_discovery/test_scan.py b/tests/validator/issue_discovery/test_scan.py index a6037b90..f2df01c2 100644 --- a/tests/validator/issue_discovery/test_scan.py +++ b/tests/validator/issue_discovery/test_scan.py @@ -1349,3 +1349,70 @@ def _score_with_emission_share(emission_share: float) -> float: return evaluation.issue_discovery_score assert _score_with_emission_share(0.1) == pytest.approx(_score_with_emission_share(0.9)) + + def test_zero_issue_discovery_share_repo_does_not_unlock_eligibility(self): + positive_repo = 'entrius/gittensor-ui' + zero_share_repo = 'entrius/gittensor' + issues = [_issue_dict(issue_number=10, repo=positive_repo, author_github_id='A', solved_by_pr=200)] + issues.extend( + _issue_dict(issue_number=20 + i, repo=zero_share_repo, author_github_id='A', solved_by_pr=300 + i) + for i in range(6) + ) + + client = Mock() + client.get_miner_issues.return_value = _response(issues) + + evaluation = _eval(uid=1, github_id='A') + seed = MinerEvaluation(uid=99, hotkey='hkS', github_id='SEED') + seed.merged_prs = [ + _scored_mirror_pr(positive_repo, 200), + *[_scored_mirror_pr(zero_share_repo, pr_number) for pr_number in range(300, 306)], + ] + + _run( + run_issue_discovery( + {1: evaluation, 99: seed}, + { + positive_repo: RepositoryConfig(emission_share=0.5, issue_discovery_share=0.5), + zero_share_repo: RepositoryConfig(emission_share=0.5, issue_discovery_share=0.0), + }, + _EMPTY_LANGS, + _EMPTY_TOKEN_CONFIG, + client=client, + ) + ) + + assert evaluation.total_solved_issues == 1 + assert evaluation.total_valid_solved_issues == 1 + assert evaluation.is_issue_eligible is False + assert evaluation.issue_discovery_score == 0.0 + assert evaluation.issue_discovery_issues == [] + + def test_positive_issue_discovery_share_repo_still_unlocks_eligibility(self): + repo = 'entrius/gittensor-ui' + issues = [ + _issue_dict(issue_number=10 + i, repo=repo, author_github_id='A', solved_by_pr=200 + i) for i in range(7) + ] + client = Mock() + client.get_miner_issues.return_value = _response(issues) + + evaluation = _eval(uid=1, github_id='A') + seed = MinerEvaluation(uid=99, hotkey='hkS', github_id='SEED') + seed.merged_prs = [_scored_mirror_pr(repo, pr_number) for pr_number in range(200, 207)] + + _run( + run_issue_discovery( + {1: evaluation, 99: seed}, + {repo: RepositoryConfig(emission_share=0.5, issue_discovery_share=0.5)}, + _EMPTY_LANGS, + _EMPTY_TOKEN_CONFIG, + client=client, + ) + ) + + assert evaluation.total_solved_issues == 7 + assert evaluation.total_valid_solved_issues == 7 + assert evaluation.is_issue_eligible is True + assert len(evaluation.issue_discovery_issues) == 7 + assert {issue.repository_full_name for issue in evaluation.issue_discovery_issues} == {repo} + assert evaluation.issue_discovery_score > 0 From 098a5998ed6b4b99743008406037fa26f4a44ac9 Mon Sep 17 00:00:00 2001 From: Desel72 Date: Mon, 18 May 2026 05:14:13 +0200 Subject: [PATCH 2/3] fix(issue-discovery): use open_counts consistently in run_issue_discovery --- gittensor/validator/issue_discovery/scan.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gittensor/validator/issue_discovery/scan.py b/gittensor/validator/issue_discovery/scan.py index 0c5e75f9..0cddb50f 100644 --- a/gittensor/validator/issue_discovery/scan.py +++ b/gittensor/validator/issue_discovery/scan.py @@ -198,8 +198,8 @@ async def run_issue_discovery( fetch_errors += 1 continue - open_issue_count = _count_open_issues(current_response.issues, issue_enabled_names) - filtered = [i for i in response.issues if i.repo_full_name in issue_enabled_names] + open_counts = _count_open_issues(current_response.issues, issue_enabled_names) + filtered = [i for i in response.issues if i.repo_full_name in issue_enabled_names and _should_include_issue(i)] if not filtered: _clear_issue_discovery_fields(evaluation) _apply_open_issue_counts(evaluation, open_counts) From babe3e577b61067ae2aec48d7df01eec75c6c303 Mon Sep 17 00:00:00 2001 From: Desel72 Date: Wed, 20 May 2026 03:44:58 +0200 Subject: [PATCH 3/3] fix(issue-discovery): narrow optional mirror client for pyright --- gittensor/validator/issue_discovery/scan.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/gittensor/validator/issue_discovery/scan.py b/gittensor/validator/issue_discovery/scan.py index eef66bf8..f53536be 100644 --- a/gittensor/validator/issue_discovery/scan.py +++ b/gittensor/validator/issue_discovery/scan.py @@ -152,6 +152,7 @@ async def run_issue_discovery( bt.logging.info('No scoring repos — issue discovery skipped') return + mirror_client: MirrorClient = client or MirrorClient() now = datetime.now(timezone.utc) # Each repo is windowed by its own pr_lookback_days; the mirror applies the # per-repo cutoffs server-side for the scoring fetch. @@ -188,7 +189,7 @@ async def run_issue_discovery( try: response = await asyncio.to_thread( - client.get_miner_issues, evaluation.github_id, since_by_repo=since_by_repo + mirror_client.get_miner_issues, evaluation.github_id, since_by_repo=since_by_repo ) except MirrorRequestError as e: bt.logging.warning(f'├─ UID {uid}: issue fetch failed ({e}) — skipped this miner') @@ -197,7 +198,7 @@ async def run_issue_discovery( continue try: - current_response = await asyncio.to_thread(client.get_miner_issues, evaluation.github_id) + current_response = await asyncio.to_thread(mirror_client.get_miner_issues, evaluation.github_id) except MirrorRequestError as e: bt.logging.warning(f'├─ UID {uid}: open-issue count fetch failed ({e}) — skipped this miner') _restore_issue_discovery_from_cache(evaluation, evaluation_cache) @@ -223,7 +224,7 @@ async def run_issue_discovery( mirror_repos, solving_pr_cache, cache_stats, - client, + mirror_client, programming_languages, token_config, open_counts=open_counts,