Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 26 additions & 4 deletions gittensor/validator/issue_discovery/scan.py
Original file line number Diff line number Diff line change
Expand Up @@ -166,13 +166,21 @@ async def run_issue_discovery(

try:
current_response = await asyncio.to_thread(client.get_miner_issues, evaluation.github_id)
open_issue_count = _count_open_issues(current_response.issues, enabled_names)
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)
fetch_errors += 1
continue
open_issue_count = _get_cached_open_issue_count(evaluation, evaluation_cache)
if open_issue_count is None:
open_issue_count = _count_open_issues(response.issues, enabled_names)
bt.logging.warning(
f'├─ UID {uid}: open-issue count fetch failed ({e}) — '
f'using lookback open count ({open_issue_count})'
)
else:
bt.logging.warning(
f'├─ UID {uid}: open-issue count fetch failed ({e}) — using cached open count ({open_issue_count})'
)

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]
if not filtered:
_clear_issue_discovery_fields(evaluation)
Expand Down Expand Up @@ -265,6 +273,20 @@ def _restore_issue_discovery_from_cache(
return True


def _get_cached_open_issue_count(
evaluation: MinerEvaluation,
evaluation_cache: Optional[MinerEvaluationCache],
) -> Optional[int]:
if evaluation_cache is None:
return None

cached = evaluation_cache.get(evaluation.uid, evaluation.hotkey, evaluation.github_id or '')
if cached is None:
return None

return cached.total_open_issues


def _build_canonical_pr_owners(
pending: List[Tuple[MinerEvaluation, List[MirrorIssue], int]],
) -> Dict[Tuple[str, int], Tuple[datetime, int, int]]:
Expand Down
87 changes: 87 additions & 0 deletions tests/validator/issue_discovery/test_scan.py
Original file line number Diff line number Diff line change
Expand Up @@ -448,6 +448,93 @@ def _per_miner(github_id, since=None):
assert rewards[2] < 1.0
assert sum(rewards.values()) == pytest.approx(1.0)

def test_open_issue_count_fetch_error_uses_cached_count_without_restoring_stale_scores(self):
cache = MinerEvaluationCache()
stale = _eval(uid=1, github_id='999')
stale.issue_discovery_score = 8.12
stale.issue_token_score = 111.0
stale.issue_credibility = 0.5
stale.is_issue_eligible = False
stale.total_solved_issues = 3
stale.total_valid_solved_issues = 2
stale.total_open_issues = 4
cache.store(stale)

solved_issues = [
_issue_dict(issue_number=20 + i, author_github_id=f'discoverer{i}', solved_by_pr=200 + i) for i in range(7)
]
client = Mock()
client.get_miner_issues.side_effect = [
_response(solved_issues),
MirrorRequestError('open count down'),
]

eval_ = _eval(uid=1, github_id='999')
eval_.merged_prs = [_scored_mirror_pr('entrius/gittensor-ui', pr) for pr in range(200, 207)]
cache.store(eval_)

_run(
run_issue_discovery(
{1: eval_},
_mirror_repos('entrius/gittensor-ui'),
_EMPTY_LANGS,
_EMPTY_TOKEN_CONFIG,
client=client,
evaluation_cache=cache,
)
)

assert eval_.total_solved_issues == 7
assert eval_.total_valid_solved_issues == 7
assert eval_.issue_token_score == 700.0
assert eval_.issue_discovery_score > 0
assert eval_.total_open_issues == 4
assert client.get_miner_issues.call_count == 2

cached = cache.get(uid=1, hotkey='hk', github_id='999')
assert cached is not None
assert cached.total_solved_issues == 7
assert cached.total_valid_solved_issues == 7
assert cached.total_open_issues == 4

def test_open_issue_count_fetch_error_uses_lookback_open_count_without_cache(self):
solved_issues = [
_issue_dict(issue_number=20 + i, author_github_id=f'discoverer{i}', solved_by_pr=200 + i) for i in range(7)
]
lookback_open_issues = [
_issue_dict(
issue_number=80 + i,
state='OPEN',
state_reason=None,
solved_by_pr=None,
)
for i in range(2)
]
client = Mock()
client.get_miner_issues.side_effect = [
_response(solved_issues + lookback_open_issues),
MirrorRequestError('open count down'),
]

eval_ = _eval(uid=1, github_id='999')
eval_.merged_prs = [_scored_mirror_pr('entrius/gittensor-ui', pr) for pr in range(200, 207)]

_run(
run_issue_discovery(
{1: eval_},
_mirror_repos('entrius/gittensor-ui'),
_EMPTY_LANGS,
_EMPTY_TOKEN_CONFIG,
client=client,
)
)

assert eval_.total_solved_issues == 7
assert eval_.total_valid_solved_issues == 7
assert eval_.issue_discovery_score > 0
assert eval_.total_open_issues == 2
assert client.get_miner_issues.call_count == 2

def test_successful_issue_fetch_refreshes_cache_after_scoring(self):
cache = MinerEvaluationCache()
client = Mock()
Expand Down